public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; // NOTE(DustinCa): Not supported in REPL for now. if (document.SourceCodeKind == SourceCodeKind.Interactive) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService <IGenerateDefaultConstructorsService>(); var result = await service.GenerateDefaultConstructorsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!result.ContainsChanges) { return; } var actions = result.GetCodeRefactoring(cancellationToken).Actions; context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; // TODO: https://github.com/dotnet/roslyn/issues/5778 // Not supported in REPL for now. if (document.Project.IsSubmission) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService <IGenerateDefaultConstructorsService>(); var actions = await service.GenerateDefaultConstructorsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { context.RegisterRefactorings(actions); } }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var service = context.Document.GetLanguageService <AbstractEncapsulateFieldService>(); var actions = await service.GetEncapsulateFieldCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { // Don't bother if there isn't a selection var(document, textSpan, cancellationToken) = context; if (textSpan.IsEmpty) { return; } var workspace = document.Project.Solution.Workspace; if (workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var activeInlineRenameSession = workspace.Services.GetService <ICodeRefactoringHelpersService>().ActiveInlineRenameSession; if (activeInlineRenameSession) { return; } if (cancellationToken.IsCancellationRequested) { return; } var actions = await GetCodeActionsAsync(document, textSpan, cancellationToken : cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var workspace = document.Project.Solution.Workspace; if (workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } if (document.IsGeneratedCode()) { return; } var service = document.GetLanguageService <IMoveTypeService>(); var actions = await service.GetRefactoringAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { context.RegisterRefactorings(actions); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (model.IsFromGeneratedCode(cancellationToken)) { return; } var result = await service.IntroduceVariableAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!result.ContainsChanges) { return; } var actions = result.GetCodeRefactoring(cancellationToken).Actions; context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; // TODO: https://github.com/dotnet/roslyn/issues/5778 // Not supported in REPL for now. if (document.Project.IsSubmission) { return; } if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService<IGenerateDefaultConstructorsService>(); var actions = await service.GenerateDefaultConstructorsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { context.RegisterRefactorings(actions); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var workspace = document.Project.Solution.Workspace; if (workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var generatedCodeRecognitionService = workspace.Services.GetService<IGeneratedCodeRecognitionService>(); if (generatedCodeRecognitionService.IsGeneratedCode(document)) { return; } var service = document.GetLanguageService<IMoveTypeService>(); var actions = await service.GetRefactoringAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { context.RegisterRefactorings(actions); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var moveToNamespaceService = context.Document.GetLanguageService <IMoveToNamespaceService>(); var actions = await moveToNamespaceService.GetCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false); if (state == null) { return; } // No move file action if rootnamespace isn't a prefix of current declared namespace if (state.RelativeDeclaredNamespace != null) { context.RegisterRefactorings(MoveFileCodeAction.Create(state)); } // No change namespace action if we can't construct a valid namespace from rootnamespace and folder names. if (state.TargetNamespace != null) { var service = document.GetLanguageService <IChangeNamespaceService>(); var solutionChangeAction = new SolutionChangeAction(ChangeNamespaceActionTitle(state), token => service.ChangeNamespaceAsync(state.Solution, state.DocumentIds, state.DeclaredNamespace, state.TargetNamespace, token)); context.RegisterRefactoring(solutionChangeAction); } }
private async Task ComputeRefactoringsAsync( CodeRefactoringContext context, TOptionKind option, bool analyzerActive ) { var(document, span, cancellationToken) = context; var computationTask = analyzerActive ? ComputeOpposingRefactoringsWhenAnalyzerActiveAsync( document, span, option, cancellationToken ) : ComputeAllRefactoringsWhenAnalyzerInactiveAsync( document, span, cancellationToken ); var codeActions = await computationTask.ConfigureAwait(false); context.RegisterRefactorings(codeActions); }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var service = document.GetLanguageService <AbstractExtractInterfaceService>(); var actions = await service.GetExtractInterfaceCodeActionAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false); if (state == null) { return; } // No move file action if rootnamespace isn't a prefix of current declared namespace if (state.RelativeDeclaredNamespace != null) { // These code actions try to move file to a new location based on declared namespace // and the default namespace of the project. The new location is a list of folders // determined by the relateive part of the declared namespace compare to the default namespace. // // For example, if he default namespace is `A.B.C`, file path is // "[project root dir]\Class1.cs" and declared namespace in the file is // `A.B.C.D.E`, then this action will move the file to [project root dir]\D\E\Class1.cs". . // // We also try to use existing folders as target if possible, using the same example above, // if folder "[project root dir]\D.E\" already exist, we will also offer to move file to // "[project root dir]\D.E\Class1.cs". context.RegisterRefactorings(MoveFileCodeAction.Create(state)); } // No change namespace action if we can't construct a valid namespace from rootnamespace and folder names. if (state.TargetNamespace != null) { // This code action tries to change the name of the namespace declaration to // match the folder hierarchy of the document. The new namespace is constructed // by concatenating the default namespace of the project and all the folders in // the file path up to the project root. // // For example, if he default namespace is `A.B.C`, file path is // "[project root dir]\D\E\F\Class1.cs" and declared namespace in the file is // `Foo.Bar.Baz`, then this action will change the namespace declaration // to `A.B.C.D.E.F`. // // Note that it also handles the case where the target namespace or declared namespace // is global namespace, i.e. default namespace is "" and the file is located at project // root directory, and no namespace declaration in the document, respectively. var service = document.GetLanguageService <IChangeNamespaceService>(); var solutionChangeAction = new ChangeNamespaceCodeAction( state.TargetNamespace.Length == 0 ? FeaturesResources.Change_to_global_namespace : string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace), token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, token)); context.RegisterRefactoring(solutionChangeAction); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var position = context.Span.Start; var document = context.Document; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var refactoringHelperService = document.GetLanguageService <IRefactoringHelpersService>(); var parameterNode = await refactoringHelperService.TryGetSelectedNodeAsync <TParameterSyntax>(document, context.Span, cancellationToken).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)); } }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { if (context.Span.IsEmpty) { var service = context.Document.GetLanguageService <AbstractChangeSignatureService>(); var actions = await service.GetChangeSignatureCodeActionAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, span, cancellationToken) = context; if (!span.IsEmpty) { return; } var position = span.Start; var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var configOptions = await document.GetAnalyzerConfigOptionsAsync(cancellationToken).ConfigureAwait(false); var options = GetWrappingOptions(configOptions, context.Options); foreach (var node in token.GetRequiredParent().AncestorsAndSelf()) { var containsSyntaxError = node.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error); // Check if any wrapper can handle this node. If so, then we're done, otherwise // keep walking up. foreach (var wrapper in _wrappers) { cancellationToken.ThrowIfCancellationRequested(); var computer = await wrapper.TryCreateComputerAsync( document, position, node, options, containsSyntaxError, cancellationToken).ConfigureAwait(false); if (computer == null) { continue; } var actions = await computer.GetTopLevelCodeActionsAsync().ConfigureAwait(false); if (actions.IsDefaultOrEmpty) { continue; } context.RegisterRefactorings(actions); return; } // if we hit a syntax error and the computer couldn't handle it, then bail out. Don't want to format if // we don't really understand what's going on. if (containsSyntaxError) { return; } } }
private async Task HandleNonSelectionAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // We offer the refactoring when the user is either on the header of a class/struct, // or if they're between any members of a class/struct and are on a blank line. if (!syntaxFacts.IsOnTypeHeader(root, textSpan.Start) && !syntaxFacts.IsBetweenTypeMembers(sourceText, root, textSpan.Start)) { return; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Only supported on classes/structs. var containingType = GetEnclosingNamedType(semanticModel, root, textSpan.Start, cancellationToken); if (containingType?.TypeKind != TypeKind.Class && containingType?.TypeKind != TypeKind.Struct) { return; } // No overrides in static classes. if (containingType.IsStatic) { return; } // Find all the possible instance fields/properties. If there are any, then // show a dialog to the user to select the ones they want. var viableMembers = containingType.GetMembers().WhereAsArray(IsViableInstanceFieldOrProperty); if (viableMembers.Length == 0) { return; } GetExistingMemberInfo( containingType, out var hasEquals, out var hasGetHashCode); var actions = CreateActions( document, textSpan, containingType, viableMembers, hasEquals, hasGetHashCode, withDialog: true); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var service = document.GetLanguageService <ISyncNamespaceService>(); var actions = await service.GetRefactoringsAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var actions = await AddConstructorParametersFromMembersAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var span = context.Span; if (!span.IsEmpty) { return; } var position = span.Start; var document = context.Document; var cancellationToken = context.CancellationToken; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); foreach (var node in token.Parent.AncestorsAndSelf()) { // Make sure we don't have any syntax errors here. Don't want to format if we don't // really understand what's going on. if (node.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error)) { return; } // Check if any wrapper can handle this node. If so, then we're done, otherwise // keep walking up. foreach (var wrapper in _wrappers) { cancellationToken.ThrowIfCancellationRequested(); var computer = await wrapper.TryCreateComputerAsync( document, position, node, cancellationToken).ConfigureAwait(false); if (computer == null) { continue; } var actions = await computer.GetTopLevelCodeActionsAsync().ConfigureAwait(false); if (actions.IsDefaultOrEmpty) { continue; } context.RegisterRefactorings(actions); return; } } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var actions = await this.GenerateConstructorFromMembersAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
private static async Task ComputeRefactoringsAsync( CodeRefactoringContext context, ExpressionBodyPreference option, bool analyzerActive) { var document = context.Document; var span = context.Span; var cancellationToken = context.CancellationToken; var computationTask = analyzerActive ? ComputeOpposingRefactoringsWhenAnalyzerActiveAsync(document, span, option, cancellationToken) : ComputeAllRefactoringsWhenAnalyzerInactiveAsync(document, span, cancellationToken); var codeActions = await computationTask.ConfigureAwait(false); context.RegisterRefactorings(codeActions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService <IIntroduceVariableService>(); var actions = await service.IntroduceVariableAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var (document, textSpan, cancellationToken) = context; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var actions = await GenerateEqualsAndGetHashCodeFromMembersAsync(document, textSpan, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); if (actions.IsDefaultOrEmpty && textSpan.IsEmpty) { await HandleNonSelectionAsync(context).ConfigureAwait(false); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService<IGenerateEqualsAndGetHashCodeService>(); var actions = await service.GenerateEqualsAndGetHashCodeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!actions.IsDefault) { context.RegisterRefactorings(actions); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var actions = await this.GenerateConstructorFromMembersAsync( document, textSpan, addNullChecks : false, cancellationToken : cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); if (actions.IsDefaultOrEmpty && textSpan.IsEmpty) { await HandleNonSelectionAsync(context).ConfigureAwait(false); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles) { return; } var service = document.GetLanguageService <IGenerateEqualsAndGetHashCodeService>(); var result = await service.GenerateEqualsAndGetHashCodeAsync(document, textSpan, cancellationToken).ConfigureAwait(false); if (!result.ContainsChanges) { return; } var actions = result.GetCodeRefactoring(cancellationToken).Actions; context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var position = context.Span.Start; var document = context.Document; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var parameterNode = GetParameterNode(token, position); if (parameterNode == null) { return; } // Only offered when there isn't a selection, or the selection exactly selects // a parameter name. var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); if (!context.Span.IsEmpty) { var parameterName = syntaxFacts.GetNameOfParameter(parameterNode); if (parameterName == null || parameterName.Value.Span != context.Span) { return; } } var functionDeclaration = parameterNode.FirstAncestorOrSelf <SyntaxNode>(IsFunctionDeclaration); if (functionDeclaration == null) { return; } var parameterDefault = syntaxFacts.GetDefaultOfParameter(parameterNode); // Don't offer inside the "=initializer" of a parameter if (parameterDefault?.Span.Contains(position) == true) { 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; } 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)); } }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { // Only offered when there isn't a selection. if (context.Span.Length > 0) { return; } var position = context.Span.Start; var document = context.Document; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var parameterNode = GetParameterNode(token, position); if (parameterNode == null) { return; } var functionDeclaration = parameterNode.FirstAncestorOrSelf <SyntaxNode>(IsFunctionDeclaration); if (functionDeclaration == null) { return; } var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var parameterDefault = syntaxFacts.GetDefaultOfParameter(parameterNode); // Don't offer inside the "=initializer" of a parameter if (parameterDefault?.Span.Contains(position) == true) { 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; } // We support initializing parameters, even when the containing member doesn't have a // body. This is useful for when the user is typing a new constructor and hasn't written // the body yet. var blockStatementOpt = GetBlockOperation(functionDeclaration, semanticModel, cancellationToken); // 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)); }
private async Task HandleNonSelectionAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // We offer the refactoring when the user is either on the header of a class/struct, // or if they're between any members of a class/struct and are on a blank line. if (!syntaxFacts.IsOnTypeHeader(root, textSpan.Start) && !syntaxFacts.IsBetweenTypeMembers(sourceText, root, textSpan.Start)) { return; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Only supported on classes/structs. var containingType = GetEnclosingNamedType(semanticModel, root, textSpan.Start, cancellationToken); if (containingType?.TypeKind != TypeKind.Class && containingType?.TypeKind != TypeKind.Struct) { return; } // No overrides in static classes. if (containingType.IsStatic) { return; } // Find all the possible instance fields/properties. If there are any, then // show a dialog to the user to select the ones they want. var viableMembers = containingType.GetMembers().WhereAsArray(IsViableInstanceFieldOrProperty); if (viableMembers.Length == 0) { return; } GetExistingMemberInfo( containingType, out var hasEquals, out var hasGetHashCode); var pickMembersOptions = ArrayBuilder <PickMembersOption> .GetInstance(); var equatableTypeOpt = semanticModel.Compilation.GetTypeByMetadataName(typeof(IEquatable <>).FullName); if (equatableTypeOpt != null) { var constructedType = equatableTypeOpt.Construct(containingType); if (!containingType.AllInterfaces.Contains(constructedType)) { var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var value = options.GetOption(GenerateEqualsAndGetHashCodeFromMembersOptions.ImplementIEquatable); var displayName = constructedType.ToDisplayString(new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameOnly, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters)); pickMembersOptions.Add(new PickMembersOption( ImplementIEquatableId, string.Format(FeaturesResources.Implement_0, displayName), value)); } } if (!HasOperators(containingType)) { var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false); var value = options.GetOption(GenerateEqualsAndGetHashCodeFromMembersOptions.GenerateOperators); pickMembersOptions.Add(new PickMembersOption( GenerateOperatorsId, FeaturesResources.Generate_operators, value)); } var actions = CreateActions( document, textSpan, containingType, viableMembers, pickMembersOptions.ToImmutableAndFree(), hasEquals, hasGetHashCode, withDialog: true); context.RegisterRefactorings(actions); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; var position = context.Span.Start; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var selectedParameter = await context.TryGetRelevantNodeAsync <TParameterSyntax>().ConfigureAwait(false); if (selectedParameter == null) { return; } var functionDeclaration = selectedParameter.FirstAncestorOrSelf <SyntaxNode>(IsFunctionDeclaration); if (functionDeclaration is null) { return; } var generator = SyntaxGenerator.GetGenerator(document); var parameterNodes = generator.GetParameters(functionDeclaration); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); // Only offered when there isn't a selection, or the selection exactly selects a parameter name. if (!context.Span.IsEmpty) { var parameterName = syntaxFacts.GetNameOfParameter(selectedParameter); if (parameterName == null || parameterName.Value.Span != context.Span) { return; } } var parameterDefault = syntaxFacts.GetDefaultOfParameter(selectedParameter); // Don't offer inside the "=initializer" of a parameter if (parameterDefault?.Span.Contains(position) == true) { return; } // 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 if (!TryGetParameterSymbol(selectedParameter, semanticModel, out var parameter, cancellationToken)) { return; } var methodSymbol = (IMethodSymbol)parameter.ContainingSymbol; if (methodSymbol.IsAbstract || methodSymbol.IsExtern || methodSymbol.PartialImplementationPart != null || methodSymbol.ContainingType.TypeKind == TypeKind.Interface) { return; } if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) { // Ok. Looks like the selected parameter could be refactored. Defer to subclass to // actually determine if there are any viable refactorings here. context.RegisterRefactorings(await GetRefactoringsForSingleParameterAsync( document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false)); } // List with parameterNodes that pass all checks var listOfPotentiallyValidParametersNodes = ArrayBuilder <SyntaxNode> .GetInstance(); foreach (var parameterNode in parameterNodes) { if (!TryGetParameterSymbol(parameterNode, semanticModel, out parameter, cancellationToken)) { return; } // Update the list of valid parameter nodes listOfPotentiallyValidParametersNodes.Add(parameterNode); } if (listOfPotentiallyValidParametersNodes.Count > 1) { // Looks like we can offer a refactoring for more than one parameter. Defer to subclass to // actually determine if there are any viable refactorings here. context.RegisterRefactorings(await GetRefactoringsForAllParametersAsync( document, functionDeclaration, methodSymbol, blockStatementOpt, listOfPotentiallyValidParametersNodes.ToImmutableAndFree(), position, cancellationToken).ConfigureAwait(false)); }
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var(document, textSpan, cancellationToken) = context; // TODO: One could try to retrieve TParameterList and then filter out parameters that intersect with // textSpan and use that as `parameterNodes`, where `selectedParameter` would be the first one. var selectedParameter = await context.TryGetRelevantNodeAsync <TParameterSyntax>().ConfigureAwait(false); if (selectedParameter == null) { return; } var functionDeclaration = selectedParameter.FirstAncestorOrSelf(_isFunctionDeclarationFunc); if (functionDeclaration is null) { return; } var generator = SyntaxGenerator.GetGenerator(document); var parameterNodes = generator.GetParameters(functionDeclaration); var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false); var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>(); // 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 if (!TryGetParameterSymbol(selectedParameter, semanticModel, out var parameter, cancellationToken)) { return; } var methodSymbol = (IMethodSymbol)parameter.ContainingSymbol; if (methodSymbol.IsAbstract || methodSymbol.IsExtern || methodSymbol.PartialImplementationPart != null || methodSymbol.ContainingType.TypeKind == TypeKind.Interface) { return; } if (CanOfferRefactoring(functionDeclaration, semanticModel, syntaxFacts, cancellationToken, out var blockStatementOpt)) { // Ok. Looks like the selected parameter could be refactored. Defer to subclass to // actually determine if there are any viable refactorings here. var refactorings = await GetRefactoringsForSingleParameterAsync( document, parameter, functionDeclaration, methodSymbol, blockStatementOpt, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(refactorings, context.Span); } // List with parameterNodes that pass all checks using var _ = ArrayBuilder <SyntaxNode> .GetInstance(out var listOfPotentiallyValidParametersNodes); foreach (var parameterNode in parameterNodes) { if (!TryGetParameterSymbol(parameterNode, semanticModel, out parameter, cancellationToken)) { return; } // Update the list of valid parameter nodes listOfPotentiallyValidParametersNodes.Add(parameterNode); } if (listOfPotentiallyValidParametersNodes.Count > 1) { // Looks like we can offer a refactoring for more than one parameter. Defer to subclass to // actually determine if there are any viable refactorings here. var refactorings = await GetRefactoringsForAllParametersAsync( document, functionDeclaration, methodSymbol, blockStatementOpt, listOfPotentiallyValidParametersNodes.ToImmutable(), selectedParameter.Span, cancellationToken).ConfigureAwait(false); context.RegisterRefactorings(refactorings, context.Span); } return;
public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { // Only offered when there isn't a selection. if (context.Span.Length > 0) { return; } var position = context.Span.Start; var document = context.Document; var cancellationToken = context.CancellationToken; var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(position); var parameterNode = GetParameterNode(token, position); if (parameterNode == null) { return; } var containingMember = parameterNode.FirstAncestorOrSelf <TMemberDeclarationSyntax>(); if (containingMember == null) { return; } var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>(); var parameterDefault = syntaxFacts.GetDefaultOfParameter(parameterNode); // Don't offer inside the "=initializer" of a parameter if (parameterDefault?.Span.Contains(position) == true) { return; } var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var method = (IMethodSymbol)semanticModel.GetDeclaredSymbol(containingMember, cancellationToken); if (method.IsAbstract || method.IsExtern || method.PartialImplementationPart != null || method.ContainingType.TypeKind == TypeKind.Interface) { return; } var parameter = (IParameterSymbol)semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken); if (!method.Parameters.Contains(parameter)) { return; } if (parameter.Name == "") { return; } // Only offered on method-like things that have a body (i.e. non-interface/non-abstract). var bodyOpt = GetBody(containingMember); // We support initializing parameters, even when the containing member doesn't have a // body. This is useful for when the user is typing a new constructor and hasn't written // the body yet. var blockStatementOpt = default(IBlockOperation); if (bodyOpt != null) { blockStatementOpt = semanticModel.GetOperation(bodyOpt, cancellationToken) as IBlockOperation; if (blockStatementOpt == null) { return; } } // 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, containingMember, blockStatementOpt, cancellationToken).ConfigureAwait(false)); }
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var service = context.Document.GetLanguageService<AbstractEncapsulateFieldService>(); var actions = await service.GetEncapsulateFieldCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false); context.RegisterRefactorings(actions); }