public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; // First, see if we're inside a conditional. If so, attempt to use that to offer fixes on. var conditionalExpression = await context.TryGetRelevantNodeAsync <TConditionalExpressionSyntax>().ConfigureAwait(false); if (conditionalExpression is not null) { TryHandleConditionalExpression(context, conditionalExpression); return; } // If not, see if we're on an supported statement. If so, see if it has an applicable conditional within it // that we could support this on. var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var statement = await context.TryGetRelevantNodeAsync <TStatementSyntax>().ConfigureAwait(false); if (IsSupportedSimpleStatement(syntaxFacts, statement)) { TryHandleConditionalExpression(context, TryFindConditional(statement, cancellationToken)); return; } if (statement is TLocalDeclarationStatementSyntax localDeclarationStatement) { var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(localDeclarationStatement); if (variables.Count == 1) { TryHandleConditionalExpression( context, TryFindConditional(syntaxFacts.GetInitializerOfVariableDeclarator(variables[0]), cancellationToken)); return; } } }
protected override async Task <SyntaxNode> GetSelectedNodeAsync(CodeRefactoringContext context) { // Consider: // MemberDeclaration: member that can be declared in type (those are the ones we can pull up) // VariableDeclaratorSyntax: for fields the MemberDeclaration can actually represent multiple declarations, e.g. `int a = 0, b = 1;`. // ..Since the user might want to select & pull up only one of them (e.g. `int a = 0, [|b = 1|];` we also look for closest VariableDeclaratorSyntax. return(await context.TryGetRelevantNodeAsync <MemberDeclarationSyntax>().ConfigureAwait(false) as SyntaxNode ?? await context.TryGetRelevantNodeAsync <VariableDeclaratorSyntax>().ConfigureAwait(false)); }
private static async Task <SyntaxNode> GetDeclarationAsync(CodeRefactoringContext context) { // We want to provide refactoring for changing the Type of newly introduced variables in following cases: // - DeclarationExpressionSyntax: `"42".TryParseInt32(out var number)` // - VariableDeclarationSyntax: General field / variable declaration statement `var number = 42` // - ForEachStatementSyntax: The variable that gets introduced by foreach `foreach(var number in numbers)` // // In addition to providing the refactoring when the whole node (i.e. the node that introduces the new variable) in question is selected // we also want to enable it when only the type node is selected because this refactoring changes the type. We still have to make sure // we're only working on TypeNodes for in above-mentioned situations. // // For foreach we need to guard against selecting just the expression because it is also of type `TypeSyntax`. var declNode = await context.TryGetRelevantNodeAsync <DeclarationExpressionSyntax>().ConfigureAwait(false); if (declNode != null) { return(declNode); } var variableNode = await context.TryGetRelevantNodeAsync <VariableDeclarationSyntax>().ConfigureAwait(false); if (variableNode != null) { return(variableNode); } var foreachStatement = await context.TryGetRelevantNodeAsync <ForEachStatementSyntax>().ConfigureAwait(false); if (foreachStatement != null) { return(foreachStatement); } var syntaxFacts = context.Document.GetLanguageService <ISyntaxFactsService>(); var typeNode = await context.TryGetRelevantNodeAsync <TypeSyntax>().ConfigureAwait(false); var typeNodeParent = typeNode?.Parent; if (typeNodeParent != null && (typeNodeParent.IsKind(SyntaxKind.DeclarationExpression, SyntaxKind.VariableDeclaration) || (typeNodeParent.IsKind(SyntaxKind.ForEachStatement) && !syntaxFacts.IsExpressionOfForeach(typeNode)))) { return(typeNodeParent); } return(null); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false); if (localFunction == null) { return; } if (!localFunction.Parent.IsKind(SyntaxKind.Block, out BlockSyntax parentBlock)) { return; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_method, c => UpdateDocumentAsync(root, document, parentBlock, localFunction, c)), localFunction.Span); }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var ifNode = await context.TryGetRelevantNodeAsync <TIfStatementSyntax>().ConfigureAwait(false); if (ifNode == null) { return; } if (!CanInvert(ifNode)) { return; } var title = GetTitle(); context.RegisterRefactoring( CodeAction.Create( title, c => InvertIfAsync(document, ifNode, c), title), ifNode.Span); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)) !; if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(((CSharpParseOptions)syntaxTree.Options).LanguageVersion)) { return; } var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false); if (localFunction == null) { return; } if (localFunction.Modifiers.Any(SyntaxKind.StaticKeyword)) { return; } var semanticModel = (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false)) !; if (MakeLocalFunctionStaticHelper.CanMakeLocalFunctionStaticByRefactoringCaptures(localFunction, semanticModel, out var captures)) { context.RegisterRefactoring(new MyCodeAction( c => MakeLocalFunctionStaticCodeFixHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c))); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, span, cancellationToken) = context; var expression = await context.TryGetRelevantNodeAsync <TBinaryExpressionSyntax>().ConfigureAwait(false) as SyntaxNode; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); if (expression == null || (!syntaxFacts.IsLogicalAndExpression(expression) && !syntaxFacts.IsLogicalOrExpression(expression))) { return; } if (span.IsEmpty) { // Walk up to the topmost binary of the same type. When converting || to && (or vice versa) // we want to grab the entire set. i.e. `!a && !b && !c` should become `!(a || b || c)` not // `!(a || b) && !c` while (expression.Parent?.RawKind == expression.RawKind) { expression = expression.Parent; } } context.RegisterRefactoring( new MyCodeAction( GetTitle(GetKind(expression.RawKind)), c => InvertLogicalAsync(document, expression, c)), expression.Span); }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var ifStatement = await context .TryGetRelevantNodeAsync <TIfStatementSyntax>() .ConfigureAwait(false); if ( ifStatement == null || ifStatement.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error) ) { return; } var semanticModel = await document .GetRequiredSemanticModelAsync(cancellationToken) .ConfigureAwait(false); var ifOperation = semanticModel.GetOperation(ifStatement); if (!(ifOperation is IConditionalOperation { Parent : IBlockOperation parentBlock }))
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var declaration = await context.TryGetRelevantNodeAsync <TLocalDeclaration>().ConfigureAwait(false); if (declaration == null) { return; } var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(declaration); if (variables.Count != 1) { return; } var service = document.GetRequiredLanguageService <IMoveDeclarationNearReferenceService>(); if (!await service.CanMoveDeclarationNearReferenceAsync(document, declaration, cancellationToken).ConfigureAwait(false)) { return; } context.RegisterRefactoring( CodeAction.CreateWithPriority( CodeActionPriority.Low, FeaturesResources.Move_declaration_near_reference, c => MoveDeclarationNearReferenceAsync(document, declaration, c), nameof(FeaturesResources.Move_declaration_near_reference)), declaration.Span); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var forEachStatement = await context.TryGetRelevantNodeAsync <TForEachStatement>().ConfigureAwait(false); if (forEachStatement == null) { return; } if (forEachStatement.ContainsDiagnostics) { return; } // Do not try to refactor queries with conditional compilation in them. if (forEachStatement.ContainsDirectives) { return; } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (!TryBuildConverter(forEachStatement, semanticModel, convertLocalDeclarations: true, cancellationToken, out var queryConverter)) { return; } if (semanticModel.GetDiagnostics(forEachStatement.Span, cancellationToken) .Any(static diagnostic => diagnostic.DefaultSeverity == DiagnosticSeverity.Error))
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var awaitable = await context.TryGetRelevantNodeAsync <TInvocationExpressionSyntax>().ConfigureAwait(false); if (awaitable == null || !IsValidAwaitableExpression(awaitable, model, syntaxFacts)) { return; } context.RegisterRefactoring( new MyCodeAction( GetTitle(), c => AddAwaitAsync(document, awaitable, withConfigureAwait: false, c)), awaitable.Span); context.RegisterRefactoring( new MyCodeAction( GetTitleWithConfigureAwait(), c => AddAwaitAsync(document, awaitable, withConfigureAwait: true, c)), awaitable.Span); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var foreachStatement = await context.TryGetRelevantNodeAsync <TForEachStatement>().ConfigureAwait(false); if (foreachStatement == null || !IsValid(foreachStatement)) { return; } var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var semanticFact = document.GetLanguageService <ISemanticFactsService>(); var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var foreachInfo = GetForeachInfo(semanticFact, options, model, foreachStatement, cancellationToken); if (foreachInfo == null || !ValidLocation(foreachInfo)) { return; } context.RegisterRefactoring( new ForEachToForCodeAction( Title, c => ConvertForeachToForAsync(document, foreachInfo, c))); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var syntaxTree = (await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)) !; if (!MakeLocalFunctionStaticHelper.IsStaticLocalFunctionSupported(syntaxTree)) { return; } var localFunction = await context.TryGetRelevantNodeAsync <LocalFunctionStatementSyntax>().ConfigureAwait(false); if (localFunction == null) { return; } if (localFunction.Modifiers.Any(SyntaxKind.StaticKeyword)) { return; } var semanticModel = (await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false)) !; if (MakeLocalFunctionStaticHelper.TryGetCaputuredSymbolsAndCheckApplicability(localFunction, semanticModel, out var captures)) { context.RegisterRefactoring(new MyCodeAction( FeaturesResources.Make_local_function_static, c => MakeLocalFunctionStaticHelper.MakeLocalFunctionStaticAsync(document, localFunction, captures, c))); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var declaration = await context.TryGetRelevantNodeAsync <TLocalDeclaration>().ConfigureAwait(false); if (declaration == null) { return; } var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(declaration); if (variables.Count != 1) { return; } var service = document.GetLanguageService <IMoveDeclarationNearReferenceService>(); if (!await service.CanMoveDeclarationNearReferenceAsync(document, declaration, cancellationToken).ConfigureAwait(false)) { return; } context.RegisterRefactoring( new MyCodeAction(c => MoveDeclarationNearReferenceAsync(document, declaration, c)), declaration.Span); }
private static async Task <(TTypeDeclarationSyntax type, CodeActionPriority priority)?> GetRelevantTypeFromMethodAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; var method = await context.TryGetRelevantNodeAsync <TMethodDeclarationSyntax>().ConfigureAwait(false); if (method == null) { return(null); } var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetRequiredDeclaredSymbol(method, cancellationToken); var isDebuggerDisplayMethod = IsDebuggerDisplayMethod(methodSymbol); if (!isDebuggerDisplayMethod && !IsToStringMethod(methodSymbol)) { return(null); } // Show the feature if we're on a ToString or GetDebuggerDisplay method. For the former, // have this be low-pri so we don't override more important light-bulb options. var typeDecl = method.FirstAncestorOrSelf <TTypeDeclarationSyntax>(); if (typeDecl == null) { return(null); } var priority = isDebuggerDisplayMethod ? CodeActionPriority.Medium : CodeActionPriority.Low; return(typeDecl, priority); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, _, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var variableDeclarator = await context.TryGetRelevantNodeAsync <VariableDeclaratorSyntax>().ConfigureAwait(false); if (variableDeclarator == null) { return; } if (!variableDeclarator.IsParentKind(SyntaxKind.VariableDeclaration) || !variableDeclarator.Parent.IsParentKind(SyntaxKind.LocalDeclarationStatement)) { return; } var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent; if (variableDeclarator.Initializer == null || variableDeclarator.Initializer.Value.IsMissing || variableDeclarator.Initializer.Value.IsKind(SyntaxKind.StackAllocArrayCreationExpression)) { return; } if (variableDeclaration.Type.Kind() == SyntaxKind.RefType) { // TODO: inlining ref returns: // https://github.com/dotnet/roslyn/issues/17132 return; } var localDeclarationStatement = (LocalDeclarationStatementSyntax)variableDeclaration.Parent; if (localDeclarationStatement.ContainsDiagnostics || localDeclarationStatement.UsingKeyword != default) { return; } var references = await GetReferencesAsync(document, variableDeclarator, cancellationToken).ConfigureAwait(false); if (!references.Any()) { return; } context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Inline_temporary_variable, c => this.InlineTemporaryAsync(document, variableDeclarator, c)), variableDeclarator.Span); }
protected async Task <TExpressionStatementSyntax> GetExpressionStatementAsync(CodeRefactoringContext context) { var expressionStatement = await context.TryGetRelevantNodeAsync <TExpressionStatementSyntax>().ConfigureAwait(false); if (expressionStatement == null) { // If an expression-statement wasn't selected, see if they're selecting // an expression belonging to an expression-statement instead. var expression = await context.TryGetRelevantNodeAsync <TExpressionSyntax>().ConfigureAwait(false); expressionStatement = expression?.Parent as TExpressionStatementSyntax; } return(expressionStatement != null && IsValid(expressionStatement, context.Span) ? expressionStatement : null); }
protected async Task <TExpressionStatementSyntax> GetExpressionStatementAsync(CodeRefactoringContext context) { var expressionStatement = await context.TryGetRelevantNodeAsync <TExpressionStatementSyntax>().ConfigureAwait(false); return(expressionStatement != null && IsValid(expressionStatement, context.Span) ? expressionStatement : null); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var forStatement = await context.TryGetRelevantNodeAsync <ForStatementSyntax>().ConfigureAwait(false); if (forStatement == null) { return; } // We support the following cases // // for (var x = start; x < end ; x++) // for (... ; ... ; ++x) // for (... ; x <= end; ...) // for (... ; ... ; x += 1) // // for (var x = end ; x >= start; x--) // for (... ; ... ; --x) // for (... ; ... ; x -= 1) var declaration = forStatement.Declaration; if (declaration == null || declaration.Variables.Count != 1 || forStatement.Incrementors.Count != 1) { return; } var variable = declaration.Variables[0]; var after = forStatement.Incrementors[0]; if (forStatement.Condition is not BinaryExpressionSyntax condition) { return; } var(document, _, cancellationToken) = context; if (MatchesIncrementPattern(variable, condition, after, out var start, out var equals, out var end) || MatchesDecrementPattern(variable, condition, after, out end, out start)) { var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (IsUnsignedBoundary(semanticModel, variable, start, end, cancellationToken)) { // Don't allow reversing when you have unsigned types and are on the start/end // of the legal values for that type. i.e. `for (byte i = 0; i < 10; i++)` it's // not trivial to reverse this. return; } context.RegisterRefactoring( CodeAction.Create( CSharpFeaturesResources.Reverse_for_statement, c => ReverseForStatementAsync(document, forStatement, c), nameof(CSharpFeaturesResources.Reverse_for_statement))); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; if (cancellationToken.IsCancellationRequested) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var semanticDocument = await SemanticDocument .CreateAsync(document, cancellationToken) .ConfigureAwait(false); var lambda = await context .TryGetRelevantNodeAsync <LambdaExpressionSyntax>() .ConfigureAwait(false); if (lambda == null) { return; } if ( !CanSimplify( semanticDocument, lambda as SimpleLambdaExpressionSyntax, cancellationToken ) && !CanSimplify( semanticDocument, lambda as ParenthesizedLambdaExpressionSyntax, cancellationToken ) ) { return; } context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_lambda_expression, c => SimplifyLambdaAsync(document, lambda, c) ), lambda.Span ); context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Simplify_all_occurrences, c => SimplifyAllLambdasAsync(document, c) ), lambda.Span ); }
private static async Task<SyntaxNode?> GetPropertyAsync(CodeRefactoringContext context) { var containingProperty = await context.TryGetRelevantNodeAsync<TPropertyDeclarationNode>().ConfigureAwait(false); if (containingProperty?.Parent is not TTypeDeclarationNode) { return null; } return containingProperty; }
private async Task <SyntaxNode> GetPropertyAsync(CodeRefactoringContext context) { var containingProperty = await context.TryGetRelevantNodeAsync <TPropertyDeclarationNode>().ConfigureAwait(false); if (!(containingProperty?.Parent is TTypeDeclarationNode)) { return(null); } return(containingProperty); }
private static async Task <(TTypeDeclarationSyntax type, CodeActionPriority priority)?> GetRelevantTypeFromHeaderAsync(CodeRefactoringContext context) { var type = await context.TryGetRelevantNodeAsync <TTypeDeclarationSyntax>().ConfigureAwait(false); if (type is null) { return(null); } return(type, CodeActionPriority.Low); }
private async Task <TTypeDeclarationSyntax?> GetRelevantTypeFromHeaderAsync(CodeRefactoringContext context) { var type = await context.TryGetRelevantNodeAsync <TTypeDeclarationSyntax>(RefactoringHelpers).ConfigureAwait(false); if (type is null) { return(null); } return(type); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var parameterNode = await context.TryGetRelevantNodeAsync <TParameterSyntax>().ConfigureAwait(false); if (parameterNode == null) { return; } var functionDeclaration = parameterNode.FirstAncestorOrSelf <SyntaxNode>(IsFunctionDeclaration); if (functionDeclaration == null) { return; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // we can't just call GetDeclaredSymbol on functionDeclaration because it could an anonymous function, // so first we have to get the parameter symbol and then its containing method symbol var parameter = (IParameterSymbol)semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken); if (parameter == null || parameter.Name == "") { return; } var method = (IMethodSymbol)parameter.ContainingSymbol; if (method.IsAbstract || method.IsExtern || method.PartialImplementationPart != null || method.ContainingType.TypeKind == TypeKind.Interface) { return; } var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) { // Ok. Looks like a reasonable parameter to analyze. Defer to subclass to // actually determine if there are any viable refactorings here. context.RegisterRefactorings(await GetRefactoringsAsync( document, parameter, functionDeclaration, method, blockStatementOpt, cancellationToken).ConfigureAwait(false)); } }
internal virtual async Task <SyntaxToken> GetNumericTokenAsync(CodeRefactoringContext context) { var syntaxFacts = context.Document.GetRequiredLanguageService <ISyntaxFactsService>(); var literalNode = await context.TryGetRelevantNodeAsync <TNumericLiteralExpression>().ConfigureAwait(false); var numericLiteralExpressionNode = syntaxFacts.IsNumericLiteralExpression(literalNode) ? literalNode : null; return(numericLiteralExpressionNode != null ? numericLiteralExpressionNode.GetFirstToken() // We know that TNumericLiteralExpression has always only one token: NumericLiteralToken : default);
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var literalExpression = await context .TryGetRelevantNodeAsync <TStringExpressionSyntax>() .ConfigureAwait(false); if (literalExpression == null || !IsAppropriateLiteralKind(literalExpression)) { return; } var(document, _, cancellationToken) = context; var charService = document.GetRequiredLanguageService <IVirtualCharLanguageService>(); using var _ = ArrayBuilder <SyntaxToken> .GetInstance(out var subStringTokens); // First, ensure that we understand all text parts of the interpolation. AddSubStringTokens(literalExpression, subStringTokens); foreach (var subToken in subStringTokens) { var chars = charService.TryConvertToVirtualChars(subToken); if (chars.IsDefault) { return; } } if (IsVerbatim(literalExpression)) { // always offer to convert from verbatim string to normal string. context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_regular_string, c => ConvertToRegularStringAsync(document, literalExpression, c) ) ); } else if (ContainsSimpleEscape(charService, subStringTokens)) { // Offer to convert to a verbatim string if the normal string contains simple // escapes that can be directly embedded in the verbatim string. context.RegisterRefactoring( new MyCodeAction( CSharpFeaturesResources.Convert_to_verbatim_string, c => ConvertToVerbatimStringAsync(document, literalExpression, c) ) ); } }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var literalExpression = await context.TryGetRelevantNodeAsync <TStringExpressionSyntax>().ConfigureAwait(false); if (literalExpression == null || !IsAppropriateLiteralKind(literalExpression)) { return; } var(document, _, cancellationToken) = context; var charService = document.GetRequiredLanguageService <IVirtualCharLanguageService>(); using var _ = ArrayBuilder <SyntaxToken> .GetInstance(out var subStringTokens); // First, ensure that we understand all text parts of the interpolation. AddSubStringTokens(literalExpression, subStringTokens); foreach (var subToken in subStringTokens) { var chars = charService.TryConvertToVirtualChars(subToken); if (chars.IsDefault) { return; } } // Note: This is a generally useful feature on strings. But it's not likely to be something // people want to use a lot. Make low priority so it doesn't interfere with more // commonly useful refactorings. if (IsVerbatim(literalExpression)) { // always offer to convert from verbatim string to normal string. context.RegisterRefactoring(CodeAction.CreateWithPriority( CodeActionPriority.Low, CSharpFeaturesResources.Convert_to_regular_string, c => ConvertToRegularStringAsync(document, literalExpression, c), nameof(CSharpFeaturesResources.Convert_to_regular_string))); } else if (ContainsSimpleEscape(charService, subStringTokens)) { // Offer to convert to a verbatim string if the normal string contains simple // escapes that can be directly embedded in the verbatim string. context.RegisterRefactoring(CodeAction.CreateWithPriority( CodeActionPriority.Low, CSharpFeaturesResources.Convert_to_verbatim_string, c => ConvertToVerbatimStringAsync(document, literalExpression, c), nameof(CSharpFeaturesResources.Convert_to_verbatim_string))); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, span, cancellationToken) = context; var expression = (SyntaxNode?)await context.TryGetRelevantNodeAsync <TBinaryExpressionSyntax>().ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); var syntaxKinds = document.GetRequiredLanguageService <ISyntaxKindsService>(); if (expression == null || (!syntaxFacts.IsLogicalAndExpression(expression) && !syntaxFacts.IsLogicalOrExpression(expression))) { return; } if (span.IsEmpty) { // Walk up to the topmost binary of the same type. When converting || to && (or vice versa) // we want to grab the entire set. i.e. `!a && !b && !c` should become `!(a || b || c)` not // `!(a || b) && !c` while (expression.Parent?.RawKind == expression.RawKind) { expression = expression.Parent; } } else { // When selection is non-empty -> allow only top-level full selections. // Currently the refactoring can't handle invert of arbitrary nodes but only whole subtrees // and allowing it just for selection of those nodes that - by chance - form a full subtree // would produce only confusion. if (CodeRefactoringHelpers.IsNodeUnderselected(expression, span) || syntaxFacts.IsLogicalAndExpression(expression.Parent) || syntaxFacts.IsLogicalOrExpression(expression.Parent)) { return; } } context.RegisterRefactoring( new MyCodeAction( GetTitle(syntaxKinds, expression.RawKind), c => InvertLogicalAsync(document, expression, c)), expression.Span); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var literal = await context.TryGetRelevantNodeAsync <LiteralExpressionSyntax>(CSharpRefactoringHelpers.Instance).ConfigureAwait(false); if (literal is null) { return; } if (literal.Kind() == SyntaxKind.StringLiteralExpression && !IsProperlyNumbered(literal.Token.ValueText)) { var action = CodeAction.Create( RoslynDiagnosticsAnalyzersResources.FixNumberedComments, c => FixCommentsAsync(context.Document, literal, c)); context.RegisterRefactoring(action); } }