private static bool CanReplaceWithReducedName( this MemberAccessExpressionSyntax memberAccess, ExpressionSyntax reducedName, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!IsThisOrTypeOrNamespace(memberAccess, semanticModel)) { return false; } var speculationAnalyzer = new SpeculationAnalyzer(memberAccess, reducedName, semanticModel, cancellationToken); if (!speculationAnalyzer.SymbolsForOriginalAndReplacedNodesAreCompatible() || speculationAnalyzer.ReplacementChangesSemantics()) { return false; } if (WillConflictWithExistingLocal(memberAccess, reducedName)) { return false; } if (IsMemberAccessADynamicInvocation(memberAccess, semanticModel)) { return false; } if (memberAccess.AccessMethodWithDynamicArgumentInsideStructConstructor(semanticModel)) { return false; } if (memberAccess.Expression.Kind() == SyntaxKind.BaseExpression) { var enclosingNamedType = semanticModel.GetEnclosingNamedType(memberAccess.SpanStart, cancellationToken); var symbol = semanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken).Symbol; if (enclosingNamedType != null && !enclosingNamedType.IsSealed && symbol != null && symbol.IsOverridable()) { return false; } } var invalidTransformation1 = ParserWouldTreatExpressionAsCast(reducedName, memberAccess); return !invalidTransformation1; }
protected override INamedTypeSymbol DetermineTypeToGenerateIn(SemanticModel semanticModel, SimpleNameSyntax simpleName, CancellationToken cancellationToken) { return(semanticModel.GetEnclosingNamedType(simpleName.SpanStart, cancellationToken)); }
public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node) { if (!ValidateNode(node, context.Span)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken); if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol))) { return; } TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false); if (declaration == null) { return; } for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent) { if (object.ReferenceEquals(declaration, parent)) { return; } } (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration); SyntaxNode nodeIncludingConditionalAccess = node.WalkUp(f => f.IsKind(SyntaxKind.ConditionalAccessExpression)); if (expression != null || (statements.Any() && nodeIncludingConditionalAccess.IsParentKind(SyntaxKind.ExpressionStatement))) { ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol); if (parameterInfos.IsDefault) { return; } INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken); SemanticModel declarationSemanticModel = semanticModel; if (node.SyntaxTree != declaration.SyntaxTree) { Document document = context.Solution.GetDocument(declaration.SyntaxTree); // https://github.com/dotnet/roslyn/issues/5260 if (document == null) { return; } declarationSemanticModel = await document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); } InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, nodeIncludingConditionalAccess, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken); string title = CSharpFacts.GetTitle(declaration); if (expression != null) { context.RegisterRefactoring($"Inline {title}", ct => refactoring.InlineAsync(nodeIncludingConditionalAccess, expression, ct), GetDescriptor()); context.RegisterRefactoring($"Inline and remove {title}", ct => refactoring.InlineAndRemoveAsync(nodeIncludingConditionalAccess, expression, ct), GetDescriptor(), "Remove"); } else { var expressionStatement = (ExpressionStatementSyntax)nodeIncludingConditionalAccess.Parent; context.RegisterRefactoring($"Inline {title}", ct => refactoring.InlineAsync(expressionStatement, statements, ct), GetDescriptor()); context.RegisterRefactoring($"Inline and remove {title}", ct => refactoring.InlineAndRemoveAsync(expressionStatement, statements, ct), GetDescriptor(), "Remove"); } } }
private ExpressionSyntax VisitSimpleName(SimpleNameSyntax rewrittenSimpleName, SimpleNameSyntax originalSimpleName) { _cancellationToken.ThrowIfCancellationRequested(); // if this is "var", then do not process further if (originalSimpleName.IsVar) { return(rewrittenSimpleName); } var identifier = rewrittenSimpleName.Identifier; ExpressionSyntax newNode = rewrittenSimpleName; var isInsideCref = originalSimpleName.AncestorsAndSelf(ascendOutOfTrivia: true).Any(n => n is CrefSyntax); //// //// 1. if this identifier is an alias, we'll expand it here and replace the node completely. //// if (!SyntaxFacts.IsAliasQualifier(originalSimpleName)) { var aliasInfo = _semanticModel.GetAliasInfo(originalSimpleName, _cancellationToken); if (aliasInfo != null) { var aliasTarget = aliasInfo.Target; if (aliasTarget.IsNamespace() && ((INamespaceSymbol)aliasTarget).IsGlobalNamespace) { return(rewrittenSimpleName); } // if the enclosing expression is a typeof expression that already contains open type we cannot // we need to insert an open type as well. var typeOfExpression = originalSimpleName.GetAncestor <TypeOfExpressionSyntax>(); if (typeOfExpression != null && IsTypeOfUnboundGenericType(_semanticModel, typeOfExpression)) { aliasTarget = ((INamedTypeSymbol)aliasTarget).ConstructUnboundGenericType(); } // the expanded form replaces the current identifier name. var replacement = FullyQualifyIdentifierName( aliasTarget, newNode, originalSimpleName, replaceNode: true, isInsideCref: isInsideCref, omitLeftHandSide: false) .WithAdditionalAnnotations(Simplifier.Annotation); // We replace the simple name completely, so we can't continue and rename the token // with a RenameLocationAnnotation. // There's also no way of removing annotations, so we just add a DoNotRenameAnnotation. if (replacement.Kind() == SyntaxKind.AliasQualifiedName) { var qualifiedReplacement = (AliasQualifiedNameSyntax)replacement; var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Name.Identifier); if (_annotationForReplacedAliasIdentifier != null) { newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier); } var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name); newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo); replacement = replacement.ReplaceNode( qualifiedReplacement.Name, qualifiedReplacement.Name.WithIdentifier(newIdentifier)); replacement = newNode.CopyAnnotationsTo(replacement); var firstReplacementToken = replacement.GetFirstToken(true, false, true, true); var firstOriginalToken = originalSimpleName.GetFirstToken(true, false, true, true); SyntaxToken tokenWithLeadingWhitespace; if (TryAddLeadingElasticTriviaIfNecessary(firstReplacementToken, firstOriginalToken, out tokenWithLeadingWhitespace)) { replacement = replacement.ReplaceToken(firstOriginalToken, tokenWithLeadingWhitespace); } replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } if (replacement.Kind() == SyntaxKind.QualifiedName) { var qualifiedReplacement = (QualifiedNameSyntax)replacement; var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Right.Identifier); if (_annotationForReplacedAliasIdentifier != null) { newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier); } var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name); newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo); replacement = replacement.ReplaceNode( qualifiedReplacement.Right, qualifiedReplacement.Right.WithIdentifier(newIdentifier)); replacement = newNode.CopyAnnotationsTo(replacement); replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } throw new NotImplementedException(); } } var symbol = _semanticModel.GetSymbolInfo(originalSimpleName.Identifier).Symbol; if (symbol == null) { return(newNode); } var typeArgumentSymbols = TypeArgumentSymbolsPresentInName(originalSimpleName); var omitLeftSideOfExpression = false; // Check to see if the type Arguments in the resultant Symbol is recursively defined. if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: true)) { if (symbol.ContainingSymbol.Equals(symbol.OriginalDefinition.ContainingSymbol) && symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).IsStatic) { if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: false)) { return(newNode); } else { omitLeftSideOfExpression = true; } } else { return(newNode); } } if (IsInvocationWithDynamicArguments(originalSimpleName, _semanticModel)) { return(newNode); } //// //// 2. If it's an attribute, make sure the identifier matches the attribute's class name. //// if (originalSimpleName.GetAncestor <AttributeSyntax>() != null) { if (symbol.IsConstructor() && symbol.ContainingType?.IsAttribute() == true) { symbol = symbol.ContainingType; var name = symbol.Name; Debug.Assert(name.StartsWith(originalSimpleName.Identifier.ValueText, StringComparison.Ordinal)); // if the user already used the Attribute suffix in the attribute, we'll maintain it. if (identifier.ValueText == name && name.EndsWith("Attribute", StringComparison.Ordinal)) { identifier = identifier.WithAdditionalAnnotations(SimplificationHelpers.DontSimplifyAnnotation); } identifier = identifier.CopyAnnotationsTo(SyntaxFactory.VerbatimIdentifier(identifier.LeadingTrivia, name, name, identifier.TrailingTrivia)); } } //// //// 3. Always try to escape keyword identifiers //// identifier = TryEscapeIdentifierToken(identifier, originalSimpleName, _semanticModel).WithAdditionalAnnotations(Simplifier.Annotation); if (identifier != rewrittenSimpleName.Identifier) { switch (newNode.Kind()) { case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: newNode = ((SimpleNameSyntax)newNode).WithIdentifier(identifier); break; default: throw new NotImplementedException(); } } var parent = originalSimpleName.Parent; // do not complexify further for location where only simple names are allowed if (parent is MemberDeclarationSyntax || parent is MemberBindingExpressionSyntax || originalSimpleName.GetAncestor <NameEqualsSyntax>() != null || (parent is MemberAccessExpressionSyntax && parent.Kind() != SyntaxKind.SimpleMemberAccessExpression) || ((parent.Kind() == SyntaxKind.SimpleMemberAccessExpression || parent.Kind() == SyntaxKind.NameMemberCref) && originalSimpleName.IsRightSideOfDot()) || (parent.Kind() == SyntaxKind.QualifiedName && originalSimpleName.IsRightSideOfQualifiedName()) || (parent.Kind() == SyntaxKind.AliasQualifiedName)) { return(TryAddTypeArgumentToIdentifierName(newNode, symbol)); } //// //// 4. If this is a standalone identifier or the left side of a qualified name or member access try to fully qualify it //// // we need to treat the constructor as type name, so just get the containing type. if (symbol.IsConstructor() && (parent.Kind() == SyntaxKind.ObjectCreationExpression || parent.Kind() == SyntaxKind.NameMemberCref)) { symbol = symbol.ContainingType; } // if it's a namespace or type name, fully qualify it. if (symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.Namespace) { var replacement = FullyQualifyIdentifierName( (INamespaceOrTypeSymbol)symbol, newNode, originalSimpleName, replaceNode: false, isInsideCref: isInsideCref, omitLeftHandSide: omitLeftSideOfExpression) .WithAdditionalAnnotations(Simplifier.Annotation); replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } // if it's a member access, we're fully qualifying the left side and make it a member access. if (symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Property) { if (symbol.IsStatic || originalSimpleName.IsParentKind(SyntaxKind.NameMemberCref) || _semanticModel.SyntaxTree.IsNameOfContext(originalSimpleName.SpanStart, _semanticModel, _cancellationToken)) { newNode = FullyQualifyIdentifierName( symbol, newNode, originalSimpleName, replaceNode: false, isInsideCref: isInsideCref, omitLeftHandSide: omitLeftSideOfExpression); } else { if (!IsPropertyNameOfObjectInitializer(originalSimpleName)) { ExpressionSyntax left; // Assumption here is, if the enclosing and containing types are different then there is Inheritence relationship if (_semanticModel.GetEnclosingNamedType(originalSimpleName.SpanStart, _cancellationToken) != symbol.ContainingType) { left = SyntaxFactory.BaseExpression(); } else { left = SyntaxFactory.ThisExpression(); } var identifiersLeadingTrivia = newNode.GetLeadingTrivia(); newNode = TryAddTypeArgumentToIdentifierName(newNode, symbol); newNode = newNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)newNode.WithLeadingTrivia(null)) .WithLeadingTrivia(identifiersLeadingTrivia)); } } } var result = newNode.WithAdditionalAnnotations(Simplifier.Annotation); result = AppendElasticTriviaIfNecessary(result, originalSimpleName); return(result); }
private static async Task HandleSingleTypeAsync(CompletionContext context, SemanticModel semanticModel, SyntaxToken token, ITypeSymbol type, CancellationToken cancellationToken) { // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { var typeArg = type.GetTypeArguments().FirstOrDefault(); if (typeArg == null) { return; } type = typeArg; } // When true, this completion provider shows both the type (e.g. DayOfWeek) and its qualified members (e.g. // DayOfWeek.Friday). We set this to false for enum-like cases (static members of structs and classes) so we // only show the qualified members in these cases. var showType = true; var position = context.Position; var enclosingNamedType = semanticModel.GetEnclosingNamedType(position, cancellationToken); if (type.TypeKind != TypeKind.Enum) { var enumType = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ?? TryGetCompletionListType(type, enclosingNamedType, semanticModel.Compilation); if (enumType == null) { if (context.Trigger.Kind == CompletionTriggerKind.Insertion && s_triggerCharacters.Contains(context.Trigger.Character)) { // This completion provider understands static members of matching types, but doesn't // proactively trigger completion for them to avoid interfering with common typing patterns. return; } // If this isn't an enum or marked with completionlist, also check if it contains static members of // a matching type. These 'enum-like' types have similar characteristics to enum completion, but do // not show the containing type as a separate item in completion. showType = false; enumType = TryGetTypeWithStaticMembers(type); if (enumType == null) { return; } } type = enumType; } var hideAdvancedMembers = context.CompletionOptions.HideAdvancedMembers; if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation)) { return; } // Does type have any aliases? var alias = await type.FindApplicableAliasAsync(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayText = alias != null ? alias.Name : type.ToMinimalDisplayString(semanticModel, position); // Add the enum itself. var symbol = alias ?? type; var sortText = symbol.Name; if (showType) { context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText, displayTextSuffix: "", symbols: ImmutableArray.Create(symbol), rules: s_enumTypeRules, contextPosition: position, sortText: sortText)); } // And now all the accessible members of the enum. if (type.TypeKind == TypeKind.Enum) { // We'll want to build a list of the actual enum members and all accessible instances of that enum, too var index = 0; var fields = type.GetMembers().OfType <IFieldSymbol>().Where(f => f.IsConst).Where(f => f.HasConstantValue); foreach (var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue))) { index++; if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation)) { continue; } var memberDisplayName = $"{displayText}.{field.Name}"; context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: memberDisplayName, displayTextSuffix: "", symbols: ImmutableArray.Create <ISymbol>(field), rules: CompletionItemRules.Default, contextPosition: position, sortText: $"{sortText}_{index:0000}", filterText: memberDisplayName)); } } else if (enclosingNamedType is not null) { // Build a list of the members with the same type as the target foreach (var member in type.GetMembers()) { ISymbol staticSymbol; ITypeSymbol symbolType; if (member is IFieldSymbol { IsStatic: true } field) { staticSymbol = field; symbolType = field.Type; } else if (member is IPropertySymbol { IsStatic: true, IsIndexer: false } property) { staticSymbol = property; symbolType = property.Type; }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation) { if (CheckSpan(invocation, context.Span)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); IMethodSymbol methodSymbol = GetMethodSymbol(invocation, semanticModel, context.CancellationToken); if (methodSymbol != null) { MethodDeclarationSyntax methodDeclaration = await GetMethodDeclarationAsync(methodSymbol, context.CancellationToken).ConfigureAwait(false); if (methodDeclaration != null && !invocation.Ancestors().Any(f => f == methodDeclaration)) { ExpressionSyntax expression = GetMethodExpression(methodDeclaration); if (expression != null) { List <ParameterInfo> parameterInfos = GetParameterInfos(invocation, methodSymbol, semanticModel, context.CancellationToken); if (parameterInfos != null) { INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(invocation.SpanStart, context.CancellationToken); SemanticModel declarationSemanticModel = (invocation.SyntaxTree == methodDeclaration.SyntaxTree) ? semanticModel : await context.Solution.GetDocument(methodDeclaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var refactoring = new InlineMethodExpressionRefactoring(context.Document, invocation, enclosingType, methodSymbol, methodDeclaration, parameterInfos.ToArray(), semanticModel, declarationSemanticModel, context.CancellationToken); context.RegisterRefactoring("Inline method", c => refactoring.InlineMethodAsync(invocation, expression)); context.RegisterRefactoring("Inline and remove method", c => refactoring.InlineAndRemoveMethodAsync(invocation, expression)); } } else if (methodSymbol.ReturnsVoid && invocation.IsParentKind(SyntaxKind.ExpressionStatement)) { BlockSyntax body = methodDeclaration.Body; if (body != null) { SyntaxList <StatementSyntax> statements = body.Statements; if (statements.Any()) { List <ParameterInfo> parameterInfos = GetParameterInfos(invocation, methodSymbol, semanticModel, context.CancellationToken); if (parameterInfos != null) { var expressionStatement = (ExpressionStatementSyntax)invocation.Parent; INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(invocation.SpanStart, context.CancellationToken); SemanticModel declarationSemanticModel = (invocation.SyntaxTree == methodDeclaration.SyntaxTree) ? semanticModel : await context.Solution.GetDocument(methodDeclaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); var refactoring = new InlineMethodStatementsRefactoring(context.Document, invocation, enclosingType, methodSymbol, methodDeclaration, parameterInfos.ToArray(), semanticModel, declarationSemanticModel, context.CancellationToken); context.RegisterRefactoring("Inline method", c => refactoring.InlineMethodAsync(expressionStatement, statements)); context.RegisterRefactoring("Inline and remove method", c => refactoring.InlineAndRemoveMethodAsync(expressionStatement, statements)); } } } } } } } }
private static async Task HandleSingleTypeAsync(CompletionContext context, SemanticModel semanticModel, SyntaxToken token, ITypeSymbol type, CancellationToken cancellationToken) { // If we have a Nullable<T>, unwrap it. if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { var typeArg = type.GetTypeArguments().FirstOrDefault(); if (typeArg == null) return; type = typeArg; } var position = context.Position; if (type.TypeKind != TypeKind.Enum) { var enumType = TryGetEnumTypeInEnumInitializer(semanticModel, token, type, cancellationToken) ?? TryGetCompletionListType(type, semanticModel.GetEnclosingNamedType(position, cancellationToken), semanticModel.Compilation); if (enumType == null) return; type = enumType; } var options = context.Options; var hideAdvancedMembers = options.GetOption(CompletionOptions.HideAdvancedMembers, semanticModel.Language); if (!type.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation)) return; // Does type have any aliases? var alias = await type.FindApplicableAliasAsync(position, semanticModel, cancellationToken).ConfigureAwait(false); var displayText = alias != null ? alias.Name : type.ToMinimalDisplayString(semanticModel, position); // Add the enum itself. var symbol = alias ?? type; var sortText = symbol.Name; context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText, displayTextSuffix: "", symbols: ImmutableArray.Create(symbol), rules: s_enumTypeRules, contextPosition: position, sortText: sortText)); // And now all the accessible members of the enum. if (type.TypeKind == TypeKind.Enum) { // We'll want to build a list of the actual enum members and all accessible instances of that enum, too var index = 0; var fields = type.GetMembers().OfType<IFieldSymbol>().Where(f => f.IsConst).Where(f => f.HasConstantValue); foreach (var field in fields.OrderBy(f => IntegerUtilities.ToInt64(f.ConstantValue))) { index++; if (!field.IsEditorBrowsable(hideAdvancedMembers, semanticModel.Compilation)) continue; var memberDisplayName = $"{displayText}.{field.Name}"; context.AddItem(SymbolCompletionItem.CreateWithSymbolId( displayText: memberDisplayName, displayTextSuffix: "", symbols: ImmutableArray.Create<ISymbol>(field), rules: CompletionItemRules.Default, contextPosition: position, sortText: $"{sortText}_{index:0000}", filterText: memberDisplayName)); } } }
public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node) { if (!CheckNode(node, context.Span)) { return; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken); if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol))) { return; } TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false); if (declaration == null) { return; } for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent) { if (object.ReferenceEquals(declaration, parent)) { return; } } (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration); if (expression != null || (statements.Any() && node.IsParentKind(SyntaxKind.ExpressionStatement))) { ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol); if (parameterInfos.IsDefault) { return; } INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken); SemanticModel declarationSemanticModel = (node.SyntaxTree == declaration.SyntaxTree) ? semanticModel : await context.Solution.GetDocument(declaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, node, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken); string title = declaration.GetTitle(); if (expression != null) { context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(node, expression, cancellationToken)); context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(node, expression, cancellationToken)); } else { var expressionStatement = (ExpressionStatementSyntax)node.Parent; context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(expressionStatement, statements, cancellationToken)); context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(expressionStatement, statements, cancellationToken)); } } }