| File: ExtractMethod\CSharpSelectionResult.cs | Web Access |
| Project: src\roslyn\src\Features\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Features.csproj (Microsoft.CodeAnalysis.CSharp.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ExtractMethod; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.ExtractMethod; internal sealed partial class CSharpExtractMethodService { internal abstract partial class CSharpSelectionResult( SemanticDocument document, SelectionType selectionType, TextSpan finalSpan) : SelectionResult( document, selectionType, finalSpan) { public static async Task<CSharpSelectionResult> CreateAsync( SemanticDocument document, FinalSelectionInfo selectionInfo, CancellationToken cancellationToken) { Contract.ThrowIfNull(document); var root = await document.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newDocument = await SemanticDocument.CreateAsync(document.Document.WithSyntaxRoot(AddAnnotations( root, [ (selectionInfo.FirstTokenInFinalSpan, s_firstTokenAnnotation), (selectionInfo.LastTokenInFinalSpan, s_lastTokenAnnotation) ])), cancellationToken).ConfigureAwait(false); var selectionType = selectionInfo.GetSelectionType(); var finalSpan = selectionInfo.FinalSpan; return selectionType == SelectionType.Expression ? new ExpressionResult(newDocument, selectionType, finalSpan) : new StatementResult(newDocument, selectionType, finalSpan); } protected override OperationStatus ValidateLanguageSpecificRules(CancellationToken cancellationToken) { // Nothing language specific for C#. return OperationStatus.SucceededStatus; } protected override SyntaxNode GetNodeForDataFlowAnalysis() { var node = base.GetNodeForDataFlowAnalysis(); // If we're returning a value by ref we actually want to do the analysis on the underlying expression. return node is RefExpressionSyntax refExpression ? refExpression.Expression : node; } public override StatementSyntax GetFirstStatementUnderContainer() { Contract.ThrowIfTrue(IsExtractMethodOnExpression); var firstToken = GetFirstTokenInSelection(); var statement = firstToken.Parent.GetStatementUnderContainer(); Contract.ThrowIfNull(statement); return statement; } public override StatementSyntax GetLastStatementUnderContainer() { Contract.ThrowIfTrue(IsExtractMethodOnExpression); var lastToken = GetLastTokenInSelection(); var statement = lastToken.Parent.GetStatementUnderContainer(); return statement; } public SyntaxNode GetInnermostStatementContainer() { Contract.ThrowIfFalse(IsExtractMethodOnExpression); var containingScope = GetContainingScope(); var statements = containingScope.GetAncestorsOrThis<StatementSyntax>(); StatementSyntax last = null; foreach (var statement in statements) { if (statement.IsStatementContainerNode()) return statement; last = statement; } // expression bodied member case var expressionBodiedMember = GetContainingScopeOf<ArrowExpressionClauseSyntax>(); if (expressionBodiedMember != null) { // the class/struct declaration is the innermost statement container, since the // member does not have a block body return GetContainingScopeOf<TypeDeclarationSyntax>(); } // constructor initializer case var constructorInitializer = GetContainingScopeOf<ConstructorInitializerSyntax>(); if (constructorInitializer != null) return constructorInitializer.Parent; // field initializer case var field = GetContainingScopeOf<FieldDeclarationSyntax>(); if (field != null) return field.Parent; var primaryConstructorBaseType = GetContainingScopeOf<PrimaryConstructorBaseTypeSyntax>(); if (primaryConstructorBaseType != null) return primaryConstructorBaseType.Parent; Contract.ThrowIfFalse(last.IsParentKind(SyntaxKind.GlobalStatement)); Contract.ThrowIfFalse(last.Parent.IsParentKind(SyntaxKind.CompilationUnit)); return last.Parent.Parent; } public override bool ContainsUnsupportedExitPointsStatements(ImmutableArray<SyntaxNode> exitPoints) => exitPoints.Any(n => n is not (BreakStatementSyntax or ContinueStatementSyntax or ReturnStatementSyntax)); public override ImmutableArray<StatementSyntax> GetOuterReturnStatements(SyntaxNode commonRoot, ImmutableArray<SyntaxNode> exitPoints) => exitPoints.OfType<ReturnStatementSyntax>().ToImmutableArray().CastArray<StatementSyntax>(); public override bool IsFinalSpanSemanticallyValidSpan( ImmutableArray<StatementSyntax> returnStatements, CancellationToken cancellationToken) { // Once we've gotten this far, everything is valid for us to return. Only VB has special additional logic // it needs to apply at this point. return true; } } }