private static async Task <Document> RefactorAsync( Document document, ParameterSyntax parameter, ParameterListSyntax parameterList, CancellationToken cancellationToken) { SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken); SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; int index = parameters.IndexOf(parameter); ParameterSyntax nextParameter = parameters[index + 1] .WithTriviaFrom(parameter); parameters = parameters .Replace(parameter, nextParameter); parameters = parameters .Replace(parameters[index + 1], parameter.WithTriviaFrom(nextParameter)); ParameterListSyntax newNode = parameterList.WithParameters(parameters); SyntaxNode newRoot = oldRoot.ReplaceNode(parameterList, newNode); return(document.WithSyntaxRoot(newRoot)); }
public override SyntaxNode VisitParameterList(ParameterListSyntax node) { ParameterListSyntax processedNode = (ParameterListSyntax)base.VisitParameterList(node); if (node.Equals(this.parameterList)) { // Get the lowest index on ParameterList of compressed Parameters // Considers: // void foo(int a, >int b, int c<, int d) -> void foo(int a, ParameterObject o, int d) int order = this.parameters.Min(n => this.parameterList.Parameters.IndexOf(n)); // Create new parameter declaration // TODO: hard-coded type name! ParameterSyntax newParameter = Syntax.Parameter(Syntax.Identifier(this.parameterObjectName)) .WithType(Syntax.ParseTypeName("ParameterObject")) .WithAdditionalAnnotations(CodeAnnotations.Formatting); // Insert new parameter's declaration to the list ParameterListSyntax newParameterList = processedNode.WithParameters(processedNode.Parameters.Insert(order, newParameter)); return(newParameterList); } return(processedNode); }
public override SyntaxNode VisitParameterList(ParameterListSyntax node) { if (node.Parent?.Equals(constructorDeclaration) == true && parameterToRemove != null) { var pl = constructorDeclaration.ParameterList; return(node.WithParameters(pl.Parameters.Remove(parameterToRemove))); } return(base.VisitParameterList(node)); }
private async Task <CSharpSyntaxNode> ConvertToFunctionDeclarationOrNull(VBSyntax.LambdaExpressionSyntax vbNode, ParameterListSyntax param, BlockSyntax block, ArrowExpressionClauseSyntax arrow) { if (!(_semanticModel.GetOperation(vbNode) is IAnonymousFunctionOperation anonFuncOp)) { return(null); } var potentialAncestorDeclarationOperation = anonFuncOp.GetParentIgnoringConversions(); // Could do: See if we can improve upon returning "object" for pretty much everything (which is what the symbols say) // I believe that in general, special VB functions such as MultiplyObject are designed to work the same as integer when given two integers for example. // If all callers currently pass an integer, perhaps it'd be more idiomatic in C# to specify "int", than to have Operators var paramsWithTypes = anonFuncOp.Symbol.Parameters.Select(p => CommonConversions.CsSyntaxGenerator.ParameterDeclaration(p)); var paramListWithTypes = param.WithParameters(SyntaxFactory.SeparatedList(paramsWithTypes)); if (potentialAncestorDeclarationOperation is IFieldInitializerOperation fieldInit) { var fieldSymbol = fieldInit.InitializedFields.Single(); if (fieldSymbol.GetResultantVisibility() != SymbolVisibility.Public && !fieldSymbol.Type.IsDelegateReferencableByName() && await _solution.IsNeverWritten(fieldSymbol)) { return(CreateMethodDeclaration(anonFuncOp, fieldSymbol, block, arrow)); } } if (potentialAncestorDeclarationOperation is IVariableInitializerOperation vio) { if (vio.GetParentIgnoringConversions() is IVariableDeclarationGroupOperation go) { potentialAncestorDeclarationOperation = go.Declarations.First(d => d.Syntax.FullSpan.Contains(vbNode.FullSpan)); } else { potentialAncestorDeclarationOperation = vio.Parent; } if (potentialAncestorDeclarationOperation is IVariableDeclarationOperation variableDeclaration) { var variableDeclaratorOperation = variableDeclaration.Declarators.Single(); if (!variableDeclaratorOperation.Symbol.Type.IsDelegateReferencableByName() && await _solution.IsNeverWritten(variableDeclaratorOperation.Symbol)) { //Should do: Check no (other) write usages exist: SymbolFinder.FindReferencesAsync + checking if they're an assignment LHS or out parameter return(CreateLocalFunction(anonFuncOp, variableDeclaratorOperation, paramListWithTypes, block, arrow)); } } } return(null); }
private ParameterListSyntax ToNullableParameter(ParameterListSyntax parameterListSyntax, string parameterName) { var parameter = parameterListSyntax.Parameters.FirstOrDefault(param => param.Identifier.ToString() == parameterName); if (parameter == null) { return(parameterListSyntax); } var nullableParameter = parameter.WithType(NullUtilities.ToNullable(parameter.Type !)); return(parameterListSyntax.WithParameters(parameterListSyntax.Parameters.Replace(parameter, nullableParameter))); }
public static Task <Document> RefactorAsync( Document document, ParenthesizedLambdaExpressionSyntax parenthesizedLambda, MemberDeclarationSyntax memberDeclaration, TypeDeclarationSyntax typeDeclaration, string methodName, SemanticModel semanticModel, CancellationToken cancellationToken) { methodName = NameGenerator.Default.EnsureUniqueLocalName(methodName, semanticModel, parenthesizedLambda.SpanStart, cancellationToken: cancellationToken); MemberDeclarationSyntax newMemberDeclaration = memberDeclaration.ReplaceNode(parenthesizedLambda, IdentifierName(methodName).WithTriviaFrom(parenthesizedLambda)); IMethodSymbol lambdaSymbol = semanticModel.GetMethodSymbol(parenthesizedLambda, cancellationToken); ParameterListSyntax parameterList = parenthesizedLambda.ParameterList; SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; ImmutableArray <IParameterSymbol> parameterSymbols = lambdaSymbol.Parameters; parameters = parameters .ReplaceAt(0, AddTypeIfMissing(parameters[0], parameterSymbols[0])) .ReplaceAt(1, AddTypeIfMissing(parameters[1], parameterSymbols[1])); cancellationToken.ThrowIfCancellationRequested(); MethodDeclarationSyntax newMethodDeclaration = MethodDeclaration( (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) ? Modifiers.Private_Static() : Modifiers.Private(), VoidType(), Identifier(methodName).WithRenameAnnotation(), parameterList.WithParameters(parameters), CreateMethodBody(parenthesizedLambda.Body)) .WithFormatterAnnotation(); SyntaxList <MemberDeclarationSyntax> newMembers = typeDeclaration.Members.Replace(memberDeclaration, newMemberDeclaration); newMembers = MemberDeclarationInserter.Default.Insert(newMembers, newMethodDeclaration); return(document.ReplaceNodeAsync(typeDeclaration, typeDeclaration.WithMembers(newMembers), cancellationToken));
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameTupleElement)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; CodeFixRegistrator.ChangeMemberDeclarationType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", cancellationToken => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First(); var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } CodeFixRegistrator.ChangeMemberDeclarationType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.MissingPartialModifier: case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredInPartialClassOrPartialStruct: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } SyntaxNode node = null; switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration)) { node = memberDeclaration.Parent; } break; } case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.InterfaceDeclaration: { node = memberDeclaration; break; } } Debug.Assert(node != null, memberDeclaration.ToString()); if (node == null) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); break; } case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, memberDeclaration.Parent, SyntaxKind.AbstractKeyword, title: "Make containing class abstract"); break; } case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", cancellationToken => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct: case CompilerDiagnosticIdentifiers.InterfacesCannotContainFields: case CompilerDiagnosticIdentifiers.InterfacesCannotContainOperators: case CompilerDiagnosticIdentifiers.InterfacesCannotDeclareTypes: case CompilerDiagnosticIdentifiers.OnlyClassTypesCanContainDestructors: case CompilerDiagnosticIdentifiers.StructsCannotContainExplicitParameterlessConstructors: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration)) { break; } CodeFixRegistrator.RemoveMember(context, diagnostic, memberDeclaration); break; } case CompilerDiagnosticIdentifiers.NameOfDestructorMustMatchNameOfClass: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName)) { break; } if (!(memberDeclaration is DestructorDeclarationSyntax destructorDeclaration)) { break; } if (!(memberDeclaration.Parent is ClassDeclarationSyntax classDeclaration)) { break; } if (classDeclaration.Identifier.ValueText.Length == 0) { break; } CodeAction codeAction = CodeAction.Create( "Rename destructor to match class name", cancellationToken => { DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier)); return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CannotChangeTupleElementNameWhenOverridingInheritedMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RenameTupleElement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (!(methodSymbol.ReturnType is INamedTypeSymbol tupleType)) { break; } if (!tupleType.IsTupleType) { break; } if (!(methodSymbol.OverriddenMethod?.ReturnType is INamedTypeSymbol baseTupleType)) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration) { IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken); if (!(propertySymbol.Type is INamedTypeSymbol tupleType)) { break; } if (!tupleType.IsTupleType) { break; } if (!(propertySymbol.OverriddenProperty?.Type is INamedTypeSymbol baseTupleType)) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } } } }
private static Task <Document> RefactorAsync( Document document, ImmutableArray <FieldInfo> fieldInfos, TypeDeclarationSyntax typeDeclaration, CancellationToken cancellationToken) { SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members; HashSet <string> reservedNames = null; for (int i = 0; i < members.Count; i++) { if (!(members[i] is ConstructorDeclarationSyntax constructorDeclaration)) { continue; } if (constructorDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) { continue; } ParameterListSyntax parameterList = constructorDeclaration.ParameterList; if (parameterList == null) { continue; } BlockSyntax body = constructorDeclaration.Body; if (body == null) { continue; } SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; reservedNames?.Clear(); ConstructorInitializerSyntax initializer = null; ArgumentListSyntax argumentList = null; var arguments = default(SeparatedSyntaxList <ArgumentSyntax>); if (constructorDeclaration.Initializer?.Kind() == SyntaxKind.ThisConstructorInitializer) { initializer = constructorDeclaration.Initializer; argumentList = initializer.ArgumentList; arguments = argumentList.Arguments; } SyntaxList <StatementSyntax> statements = body.Statements; foreach (FieldInfo fieldInfo in fieldInfos) { string parameterName = GetParameterName(fieldInfo.NameCamelCase, parameters, ref reservedNames); parameters = parameters.Add(Parameter(fieldInfo.Type.WithoutTrivia(), parameterName)); if (initializer != null) { arguments = arguments.Add(Argument(IdentifierName(parameterName))); } statements = statements.Add( SimpleAssignmentStatement( SimpleMemberAccessExpression(ThisExpression(), IdentifierName(fieldInfo.Name)).WithSimplifierAnnotation(), IdentifierName(parameterName)).WithFormatterAnnotation()); } parameterList = parameterList.WithParameters(parameters).WithFormatterAnnotation(); if (initializer != null) { initializer = initializer .WithArgumentList(argumentList.WithArguments(arguments)) .WithFormatterAnnotation(); } body = body.WithStatements(statements); constructorDeclaration = constructorDeclaration.Update( constructorDeclaration.AttributeLists, constructorDeclaration.Modifiers, constructorDeclaration.Identifier, parameterList, initializer, body, constructorDeclaration.SemicolonToken); members = members.ReplaceAt(i, constructorDeclaration); } TypeDeclarationSyntax newNode = typeDeclaration.WithMembers(members); return(document.ReplaceNodeAsync(typeDeclaration, newNode, cancellationToken)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.OverridingMemberCannotChangeAccessModifiers) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberNonStatic) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); MemberDeclarationSyntax memberDeclaration = root .FindNode(context.Span, getInnermostNodeForTie: true)? .FirstAncestorOrSelf <MemberDeclarationSyntax>(); Debug.Assert(memberDeclaration != null, $"{nameof(memberDeclaration)} is null"); if (memberDeclaration == null) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotChangeAccessModifiersWhenOverridingInheritedMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.OverridingMemberCannotChangeAccessModifiers)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); OverrideInfo overrideInfo = OverridingMemberCannotChangeAccessModifiersRefactoring.GetOverrideInfo(memberDeclaration, semanticModel, context.CancellationToken); Accessibility newAccessibility = overrideInfo.OverriddenSymbol.DeclaredAccessibility; string title = $"Change accessibility to '{AccessibilityHelper.GetAccessibilityName(newAccessibility)}'"; CodeAction codeAction = CodeAction.Create( title, cancellationToken => OverridingMemberCannotChangeAccessModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, newAccessibility, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; if (typeSymbol?.IsErrorType() == false) { TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, memberDeclaration.SpanStart); CodeAction codeAction = CodeAction.Create( $"Change return type to '{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, memberDeclaration.SpanStart)}'", cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", cancellationToken => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, rewrittenNode) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First(); var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } if (typeSymbol?.IsErrorType() == false) { string title = $"Change type to '{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, memberDeclaration.SpanStart)}'"; CodeAction codeAction = CodeAction.Create( title, cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.MissingPartialModifier: case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredWithinPartialClassOrPartialStruct: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } CodeAction codeAction = CodeAction.Create( "Add 'partial' modifier", cancellationToken => { if (memberDeclaration.IsKind(SyntaxKind.MethodDeclaration) && memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration)) { return(context.Document.InsertModifierAsync(memberDeclaration.Parent, SyntaxKind.PartialKeyword, ModifierComparer.Instance, cancellationToken)); } else if (memberDeclaration.IsKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration)) { return(context.Document.InsertModifierAsync(memberDeclaration, SyntaxKind.PartialKeyword, ModifierComparer.Instance, cancellationToken)); } return(Task.FromResult(context.Document)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } CodeAction codeAction = CodeAction.Create( "Make containing class abstract", cancellationToken => context.Document.InsertModifierAsync(memberDeclaration.Parent, SyntaxKind.AbstractKeyword, ModifierComparer.Instance, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ObjectReferenceIsRequiredForNonStaticMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberNonStatic)) { break; } SyntaxTokenList modifiers = memberDeclaration.GetModifiers(); Debug.Assert(modifiers.Contains(SyntaxKind.StaticKeyword), memberDeclaration.ToString()); if (!modifiers.Contains(SyntaxKind.StaticKeyword)) { break; } CodeAction codeAction = CodeAction.Create( $"Make containing {memberDeclaration.GetTitle()} non-static", cancellationToken => context.Document.RemoveModifierAsync(memberDeclaration, SyntaxKind.StaticKeyword, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", cancellationToken => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddDocumentationComment)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; if (typeSymbol?.IsErrorType() == false) { CodeAction codeAction = CodeAction.Create( $"Change return type to '{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, memberDeclaration.SpanStart)}'", cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeMethodReturnType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", cancellationToken => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, rewrittenNode) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First(); var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } if (typeSymbol?.IsErrorType() == false) { string title = $"Change type to '{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, memberDeclaration.SpanStart)}'"; CodeAction codeAction = CodeAction.Create( title, cancellationToken => MemberTypeMustMatchOverriddenMemberTypeRefactoring.RefactorAsync(context.Document, memberDeclaration, typeSymbol, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.MissingPartialModifier: case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredWithinPartialClassOrPartialStruct: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier)) { break; } SyntaxNode node = null; switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration)) { node = memberDeclaration.Parent; } break; } case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.InterfaceDeclaration: { node = memberDeclaration; break; } } Debug.Assert(node != null, memberDeclaration.ToString()); if (node == null) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword); break; } case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassAbstract)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, memberDeclaration.Parent, SyntaxKind.AbstractKeyword, title: "Make containing class abstract"); break; } case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", cancellationToken => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveMemberDeclaration)) { break; } CodeFixRegistrator.RemoveMember(context, diagnostic, memberDeclaration); break; } } } }
private static ParameterListSyntax RemoveType(ParameterListSyntax parameterList) { return(parameterList.WithParameters(SyntaxFactory.SeparatedList(parameterList.Parameters.Select(x => RemoveType(x)), parameterList.Parameters.GetSeparators()))); }
public static Task <Document> RefactorAsync( Document document, ParenthesizedLambdaExpressionSyntax parenthesizedLambda, MemberDeclarationSyntax memberDeclaration, TypeDeclarationSyntax typeDeclaration, string methodName, SemanticModel semanticModel, CancellationToken cancellationToken) { methodName = NameGenerator.Default.EnsureUniqueLocalName(methodName, semanticModel, parenthesizedLambda.SpanStart, cancellationToken: cancellationToken); MemberDeclarationSyntax newMemberDeclaration = memberDeclaration.ReplaceNode(parenthesizedLambda, IdentifierName(methodName).WithTriviaFrom(parenthesizedLambda)); IMethodSymbol lambdaSymbol = semanticModel.GetMethodSymbol(parenthesizedLambda, cancellationToken); ParameterListSyntax parameterList = parenthesizedLambda.ParameterList; SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; ImmutableArray <IParameterSymbol> parameterSymbols = lambdaSymbol.Parameters; parameters = parameters .ReplaceAt(0, AddTypeIfMissing(parameters[0], parameterSymbols[0])) .ReplaceAt(1, AddTypeIfMissing(parameters[1], parameterSymbols[1])); cancellationToken.ThrowIfCancellationRequested(); MethodDeclarationSyntax newMethodDeclaration = MethodDeclaration( (SyntaxInfo.ModifierListInfo(memberDeclaration).IsStatic) ? Modifiers.Private_Static() : Modifiers.Private(), VoidType(), Identifier(methodName).WithRenameAnnotation(), parameterList.WithParameters(parameters), CreateMethodBody(parenthesizedLambda.Body)).WithFormatterAnnotation(); SyntaxList <MemberDeclarationSyntax> newMembers = typeDeclaration.Members.Replace(memberDeclaration, newMemberDeclaration); newMembers = MemberDeclarationInserter.Default.Insert(newMembers, newMethodDeclaration); return(document.ReplaceNodeAsync(typeDeclaration, typeDeclaration.WithMembers(newMembers), cancellationToken)); BlockSyntax CreateMethodBody(CSharpSyntaxNode lambdaBody) { switch (lambdaBody) { case BlockSyntax block: return(block); case ExpressionSyntax expression: return(Block(ExpressionStatement(expression))); default: return(Block()); } } ParameterSyntax AddTypeIfMissing(ParameterSyntax parameter, IParameterSymbol parameterSymbol) { TypeSyntax type = parameter.Type; if (type?.IsMissing == false) { return(parameter); } type = parameterSymbol.Type.ToMinimalTypeSyntax(semanticModel, typeDeclaration.OpenBraceToken.Span.End); return(parameter.WithType(type)); } }
private static Task <Document> RefactorAsync( Document document, VariableDeclaratorSyntax variableDeclarator, TypeDeclarationSyntax typeDeclaration, CancellationToken cancellationToken) { SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members; string name = variableDeclarator.Identifier.ValueText; string camelCaseName = StringUtility.ToCamelCase(name); HashSet <string> reservedNames = null; for (int i = 0; i < members.Count; i++) { if (!(members[i] is ConstructorDeclarationSyntax constructorDeclaration)) { continue; } if (constructorDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword)) { continue; } ParameterListSyntax parameterList = constructorDeclaration.ParameterList; if (parameterList == null) { continue; } BlockSyntax body = constructorDeclaration.Body; if (body == null) { continue; } SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; reservedNames?.Clear(); string parameterName = GetParameterName(camelCaseName, parameters, ref reservedNames); ParameterSyntax parameter = Parameter(((VariableDeclarationSyntax)variableDeclarator.Parent).Type.WithoutTrivia(), parameterName); parameterList = parameterList.WithParameters(parameters.Add(parameter)).WithFormatterAnnotation(); ConstructorInitializerSyntax initializer = constructorDeclaration.Initializer; if (initializer?.Kind() == SyntaxKind.ThisConstructorInitializer) { ArgumentListSyntax argumentList = initializer.ArgumentList; if (argumentList != null) { SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments; initializer = initializer.WithArgumentList( argumentList.WithArguments( arguments.Add(Argument(IdentifierName(parameterName))))).WithFormatterAnnotation(); } } body = body.WithStatements( body.Statements.Add( SimpleAssignmentStatement( SimpleMemberAccessExpression(ThisExpression(), IdentifierName(name)).WithSimplifierAnnotation(), IdentifierName(parameterName)).WithFormatterAnnotation())); constructorDeclaration = constructorDeclaration.Update( constructorDeclaration.AttributeLists, constructorDeclaration.Modifiers, constructorDeclaration.Identifier, parameterList, initializer, body, constructorDeclaration.SemicolonToken); members = members.ReplaceAt(i, constructorDeclaration); } TypeDeclarationSyntax newNode = typeDeclaration.WithMembers(members); return(document.ReplaceNodeAsync(typeDeclaration, newNode, cancellationToken)); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS1591_MissingXmlCommentForPubliclyVisibleTypeOrMember: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDocumentationComment, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( "Add documentation comment", ct => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); CodeAction codeAction2 = CodeAction.Create( "Add documentation comment (copy from base if available)", ct => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, ct), GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable")); context.RegisterCodeFix(codeAction2, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0508_MethodReturnTypeMustMatchOverriddenMethodReturnType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType; CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.CS0766_PartialMethodsMustHaveVoidReturnType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMethodReturnType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken); if (otherPart == null) { break; } CodeAction codeAction = CodeAction.Create( "Change return type to 'void'", ct => { return(context.Document.Solution().ReplaceNodesAsync( new MethodDeclarationSyntax[] { methodDeclaration, otherPart }, (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)), ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1715_MemberTypeMustMatchOverriddenMemberType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = null; switch (memberDeclaration.Kind()) { case SyntaxKind.PropertyDeclaration: case SyntaxKind.IndexerDeclaration: { var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = propertySymbol.OverriddenProperty.Type; break; } case SyntaxKind.EventDeclaration: { var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } case SyntaxKind.EventFieldDeclaration: { VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables[0]; var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); typeSymbol = eventSymbol.OverriddenEvent.Type; break; } } CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel); break; } case CompilerDiagnosticIdentifiers.CS0260_MissingPartialModifier: case CompilerDiagnosticIdentifiers.CS0751_PartialMethodMustBeDeclaredInPartialClassOrPartialStruct: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddPartialModifier, context.Document, root.SyntaxTree)) { break; } SyntaxNode node = null; switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { if (memberDeclaration.IsParentKind( SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.RecordDeclaration, SyntaxKind.RecordStructDeclaration)) { node = memberDeclaration.Parent; } break; } case SyntaxKind.ClassDeclaration: case SyntaxKind.StructDeclaration: case SyntaxKind.RecordStructDeclaration: case SyntaxKind.InterfaceDeclaration: case SyntaxKind.RecordDeclaration: { node = memberDeclaration; break; } } SyntaxDebug.Assert(node != null, memberDeclaration); if (node == null) { break; } ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword, title: $"Make {CSharpFacts.GetTitle(node)} partial"); break; } case CompilerDiagnosticIdentifiers.CS0513_MemberIsAbstractButItIsContainedInNonAbstractClass: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeContainingClassAbstract, context.Document, root.SyntaxTree)) { break; } if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration)) { break; } ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, memberDeclaration.Parent, SyntaxKind.AbstractKeyword, title: "Make containing class abstract"); break; } case CompilerDiagnosticIdentifiers.CS0132_StaticConstructorMustBeParameterless: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveParametersFromStaticConstructor, context.Document, root.SyntaxTree)) { break; } var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration; CodeAction codeAction = CodeAction.Create( "Remove parameters", ct => { ParameterListSyntax parameterList = constructorDeclaration.ParameterList; ParameterListSyntax newParameterList = parameterList .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>)) .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia()) .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia()); ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList); return(context.Document.ReplaceNodeAsync(constructorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0541_ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct: case CompilerDiagnosticIdentifiers.CS0525_InterfacesCannotContainFields: case CompilerDiagnosticIdentifiers.CS0567_InterfacesCannotContainOperators: case CompilerDiagnosticIdentifiers.CS0524_InterfacesCannotDeclareTypes: case CompilerDiagnosticIdentifiers.CS0575_OnlyClassTypesCanContainDestructors: case CompilerDiagnosticIdentifiers.CS0568_StructsCannotContainExplicitParameterlessConstructors: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveMemberDeclaration, context.Document, root.SyntaxTree)) { break; } CodeFixRegistrator.RemoveMemberDeclaration(context, diagnostic, memberDeclaration); break; } case CompilerDiagnosticIdentifiers.CS0574_NameOfDestructorMustMatchNameOfClass: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameDestructorToMatchClassName, context.Document, root.SyntaxTree)) { break; } if (memberDeclaration is not DestructorDeclarationSyntax destructorDeclaration) { break; } if (memberDeclaration.Parent is not ClassDeclarationSyntax classDeclaration) { break; } if (classDeclaration.Identifier.ValueText.Length == 0) { break; } CodeAction codeAction = CodeAction.Create( "Rename destructor to match class name", ct => { DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier)); return(context.Document.ReplaceNodeAsync(destructorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8139_CannotChangeTupleElementNameWhenOverridingInheritedMember: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RenameTupleElement, context.Document, root.SyntaxTree)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) { IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken); if (methodSymbol.ReturnType is not INamedTypeSymbol tupleType) { break; } if (!tupleType.IsTupleType) { break; } if (methodSymbol.OverriddenMethod?.ReturnType is not INamedTypeSymbol baseTupleType) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration) { IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken); if (propertySymbol.Type is not INamedTypeSymbol tupleType) { break; } if (!tupleType.IsTupleType) { break; } if (propertySymbol.OverriddenProperty?.Type is not INamedTypeSymbol baseTupleType) { break; } if (!baseTupleType.IsTupleType) { break; } ImmutableArray <IFieldSymbol> elements = tupleType.TupleElements; ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements; if (elements.Length != baseElements.Length) { break; } int i = 0; while (i < elements.Length) { if (elements[i].Name != baseElements[i].Name) { break; } i++; } if (i == elements.Length) { break; } TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i]; CodeAction codeAction = CodeAction.Create( $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'", ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.CS3000_MethodsWithVariableArgumentsAreNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3001_ArgumentTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3002_ReturnTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3003_TypeOfVariableIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3005_IdentifierDifferingOnlyInCaseIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3006_OverloadedMethodDifferingOnlyInRefOrOutOrInArrayRankIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3007_OverloadedMethodDifferingOnlyByUnnamedArrayTypesIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3008_IdentifierIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3009_BaseTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3016_ArraysAsAttributeArgumentsIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3024_ConstraintTypeIsNotCLSCompliant: case CompilerDiagnosticIdentifiers.CS3027_TypeIsNotCLSCompliantBecauseBaseInterfaceIsNotCLSCompliant: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant, context.Document, root.SyntaxTree)) { break; } CodeAction codeAction = CodeAction.Create( $"Mark {CSharpFacts.GetTitle(memberDeclaration)} as non-CLS-compliant", ct => MarkDeclarationAsNonCLSCompliantAsync(context.Document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS0539_ExplicitInterfaceDeclarationIsNotMemberOfInterface: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddParameterToExplicitlyImplementedInterfaceMember, context.Document, root.SyntaxTree)) { break; } var context2 = new CommonFixContext( context.Document, GetEquivalenceKey(diagnostic), await context.GetSemanticModelAsync().ConfigureAwait(false), context.CancellationToken); CodeAction codeAction = AddParameterToInterfaceMemberRefactoring.ComputeRefactoringForExplicitImplementation(context2, memberDeclaration); if (codeAction != null) { context.RegisterCodeFix(codeAction, diagnostic); } break; } } } }
public SyntaxNode ComputeReplacementNode(SyntaxNode replacedNode) => _parameterList .WithParameters(_parameterList.Parameters.Remove(_parameter)) // there's no way for the parameter list to be rewritten by any other changes .WithAdditionalAnnotations(Formatter.Annotation);
private static ParameterListSyntax NormalizeParameterList(ParameterListSyntax node) { int count = node.Parameters.Count; SyntaxTriviaList[] argumentTriviasLeading = new SyntaxTriviaList[count]; SyntaxTriviaList[] argumentTriviasTrailing = new SyntaxTriviaList[count]; for (int j = 0; j < count; j++) { argumentTriviasLeading[j] = SyntaxTriviaList.Empty; argumentTriviasTrailing[j] = SyntaxTriviaList.Empty; } if (count > 0) { // save trivia after open paren SyntaxTriviaList trailing = SyntaxTriviaList.Empty.AddRange(node.OpenParenToken.TrailingTrivia.Where(MultiLineCommentPredicate)); argumentTriviasLeading[0] = argumentTriviasLeading[0].AddRange(trailing); } for (int j = 0; j < count - 1; j++) { // save trivia on trailing edge of separator to next argument SyntaxTriviaList trailing = SyntaxTriviaList.Empty.AddRange(node.Parameters.GetSeparator(j).TrailingTrivia.Where(MultiLineCommentPredicate)); argumentTriviasLeading[j + 1] = argumentTriviasLeading[j + 1].AddRange(trailing); } for (int j = 0; j < count; j++) { // save leading and trailing trivia from argument SyntaxTriviaList leading = node.Parameters[j].GetLeadingTrivia(); SyntaxTriviaList trailing = node.Parameters[j].GetTrailingTrivia(); argumentTriviasLeading[j] = argumentTriviasLeading[j].AddRange(leading); argumentTriviasTrailing[j] = argumentTriviasTrailing[j].AddRange(trailing); } for (int j = 0; j < count - 1; j++) { // save trivia on leading edge of separator to previous argument SyntaxTriviaList leading = SyntaxTriviaList.Empty.AddRange(node.Parameters.GetSeparator(j).LeadingTrivia.Where(MultiLineCommentPredicate)); argumentTriviasTrailing[j] = argumentTriviasTrailing[j].AddRange(leading); } if (count > 0) { // save trivia before close paren SyntaxTriviaList leading = node.CloseParenToken.LeadingTrivia; argumentTriviasTrailing[count - 1] = argumentTriviasTrailing[count - 1].AddRange(leading); } bool multiline; int indent; DetectMultiLineArgumentList(node.Parameters, out multiline, out indent); // strip all trivia node = node.WithOpenParenToken(node.OpenParenToken.WithTrailingTrivia(SyntaxTriviaList.Empty)); node = node.WithCloseParenToken(node.CloseParenToken.WithLeadingTrivia(SyntaxTriviaList.Empty)); for (int j = 0; j < count - 1; j++) { node = node.WithParameters( node.Parameters.ReplaceSeparator( node.Parameters.GetSeparator(j), node.Parameters.GetSeparator(j).WithLeadingTrivia(SyntaxTriviaList.Empty).WithTrailingTrivia(SyntaxTriviaList.Empty))); } // reformat SyntaxTriviaList delimiterTrailing = CreateDelimiterTrailer(multiline, indent); if (multiline) { node = node.WithOpenParenToken(node.OpenParenToken.WithTrailingTrivia(delimiterTrailing)); } for (int j = 0; j < count - 1; j++) { node = node.WithParameters( node.Parameters.ReplaceSeparator( node.Parameters.GetSeparator(j), node.Parameters.GetSeparator(j).WithTrailingTrivia(delimiterTrailing))); } // reassociate comment trivia to arguments for (int j = 0; j < count; j++) { node = node.WithParameters( node.Parameters.Replace( node.Parameters[j], node.Parameters[j] .WithoutTrivia() .WithLeadingTrivia(argumentTriviasLeading[j]) .WithTrailingTrivia(argumentTriviasTrailing[j]))); } return(node); }