private static SyntaxNode SetNewType(SyntaxNode node, TypeSyntax newType) { switch (node.Kind()) { case SyntaxKind.MethodDeclaration: { var declaration = (MethodDeclarationSyntax)node; return(declaration.WithReturnType(newType.WithTriviaFrom(declaration.ReturnType))); } case SyntaxKind.PropertyDeclaration: { var declaration = (PropertyDeclarationSyntax)node; return(declaration.WithType(newType.WithTriviaFrom(declaration.Type))); } case SyntaxKind.IndexerDeclaration: { var declaration = (IndexerDeclarationSyntax)node; return(declaration.WithType(newType.WithTriviaFrom(declaration.Type))); } default: { return(null); } } }
static TSyntaxNode ReplaceNodes <TSyntaxNode>(TSyntaxNode node, string name, TypeSyntax replacement) where TSyntaxNode : SyntaxNode { var uses = node.DescendantNodesAndSelf().OfType <SimpleNameSyntax>().Where(i => i.Identifier.ValueText == name).ToList(); return(node.ReplaceNodes(uses, (old, _) => replacement.WithTriviaFrom(old))); }
private static async Task <Document> FixIncorrectCastAsync(Document document, CastExpressionSyntax cast, string requiredType, CancellationToken cancellationToken) { // Split the type name into its namespace and type. QualifiedNameSyntax qualifiedName = (QualifiedNameSyntax)SyntaxFactory.ParseTypeName(requiredType); NameSyntax namespaceName = qualifiedName.Left; TypeSyntax type = qualifiedName.Right; // Change the type in the cast statement. SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken); CastExpressionSyntax?newCast = cast.WithType(type.WithTriviaFrom(cast.Type)); // Update the cast statement and, if required, change the // type of the variable that the cast is being assigned to. root = await ReplaceNodeAndUpdateVariableTypeAsync(document, root, cast, newCast, type, cancellationToken); // Add a using directive for the namespace // if the namespace is not already imported. if (root is CompilationUnitSyntax unit) { root = unit.WithUsings(AddUsingDirectiveIfMissing(unit.Usings, namespaceName)); } return(document.WithSyntaxRoot(root)); }
public static async Task <Document> ChangeTypeAsync( Document document, TypeSyntax type, TypeSyntax newType, CancellationToken cancellationToken = default(CancellationToken)) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (newType == null) { throw new ArgumentNullException(nameof(newType)); } SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); newType = newType .WithTriviaFrom(type) .WithSimplifierAnnotation(); SyntaxNode newRoot = root.ReplaceNode(type, newType); return(document.WithSyntaxRoot(newRoot)); }
private static Task <Document> RefactorAsync( Document document, LocalDeclarationStatementSyntax localDeclarationStatement, ExpressionSyntax value, ITypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { int position = localDeclarationStatement.SpanStart; ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(semanticModel, position); LocalDeclarationStatementSyntax newNode = localDeclarationStatement.ReplaceNode( value, defaultValue.WithTriviaFrom(value)); TypeSyntax oldType = newNode.Declaration.Type; if (oldType.IsVar && !defaultValue.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.SimpleMemberAccessExpression)) { TypeSyntax type = typeSymbol.ToMinimalTypeSyntax(semanticModel, position); newNode = newNode.ReplaceNode(oldType, type.WithTriviaFrom(oldType)); } return(document.ReplaceNodeAsync(localDeclarationStatement, newNode, cancellationToken)); }
public static void ChangeLocalFunctionReturnType( CodeFixContext context, Diagnostic diagnostic, LocalFunctionStatementSyntax localFunction, ITypeSymbol typeSymbol, SemanticModel semanticModel, string additionalKey = null) { if (typeSymbol.IsErrorType()) { return; } Document document = context.Document; CodeAction codeAction = CodeAction.Create( $"Change return type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, localFunction.SpanStart, SymbolDisplayFormats.Default)}'", cancellationToken => { TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, localFunction.SpanStart); LocalFunctionStatementSyntax newNode = localFunction.WithReturnType(newType.WithTriviaFrom(localFunction.ReturnType)); return(document.ReplaceNodeAsync(localFunction, newNode, cancellationToken)); }, EquivalenceKey.Create(diagnostic, additionalKey)); context.RegisterCodeFix(codeAction, diagnostic); }
public static async Task <Document> RefactorAsync( Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken) { TypeSyntax type = localDeclaration.Declaration.Type; LocalDeclarationStatementSyntax newNode = localDeclaration; if (type.IsVar) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, cancellationToken); TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, localDeclaration.SpanStart); newNode = newNode.ReplaceNode(type, newType.WithTriviaFrom(type)); } Debug.Assert(!newNode.Modifiers.Any(), newNode.Modifiers.ToString()); if (newNode.Modifiers.Any()) { newNode = newNode.InsertModifier(SyntaxKind.ConstKeyword); } else { newNode = newNode .WithoutLeadingTrivia() .WithModifiers(TokenList(Token(SyntaxKind.ConstKeyword).WithLeadingTrivia(newNode.GetLeadingTrivia()))); } return(await document.ReplaceNodeAsync(localDeclaration, newNode, cancellationToken).ConfigureAwait(false)); }
public static Task <Document> ChangeTypeAsync( Document document, TypeSyntax type, TypeSyntax newType, CancellationToken cancellationToken = default(CancellationToken)) { return(document.ReplaceNodeAsync(type, newType.WithTriviaFrom(type), cancellationToken)); }
private static Task <Document> RefactorAsync( Document document, VariableDeclarationSyntax variableDeclaration, INamedTypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { TypeSyntax type = typeSymbol.ToMinimalTypeSyntax(semanticModel, variableDeclaration.SpanStart); VariableDeclarationSyntax newNode = variableDeclaration.WithType(type.WithTriviaFrom(variableDeclaration.Type)); return(document.ReplaceNodeAsync(variableDeclaration, newNode, cancellationToken)); }
private static Task <Document> RefactorAsync( Document document, SingleLocalDeclarationStatementInfo localInfo, TypeSyntax type, CancellationToken cancellationToken) { LocalDeclarationStatementSyntax localStatement = localInfo.Statement; StatementsInfo statementsInfo = SyntaxInfo.StatementsInfo(localStatement); int index = statementsInfo.IndexOf(localStatement); VariableDeclaratorSyntax declarator = localInfo.Declarator; VariableDeclaratorSyntax newDeclarator = declarator.WithInitializer(null); VariableDeclarationSyntax newDeclaration = localInfo.Declaration.ReplaceNode(declarator, newDeclarator); if (type != null) { newDeclaration = newDeclaration.WithType(type.WithTriviaFrom(newDeclaration.Type)); } LocalDeclarationStatementSyntax newLocalStatement = localStatement .WithDeclaration(newDeclaration) .WithTrailingTrivia(NewLine()) .WithFormatterAnnotation(); ExpressionStatementSyntax assignmentStatement = SimpleAssignmentStatement(IdentifierName(localInfo.Identifier), localInfo.Initializer.Value) .WithTrailingTrivia(localStatement.GetTrailingTrivia()) .WithFormatterAnnotation(); StatementsInfo newStatementsInfo = statementsInfo .Insert(index + 1, assignmentStatement) .ReplaceAt(index, newLocalStatement); return(document.ReplaceStatementsAsync(statementsInfo, newStatementsInfo, cancellationToken)); }
public static Task <Document> ChangeTypeAsync( Document document, TypeSyntax type, TypeSyntax newType, CancellationToken cancellationToken = default(CancellationToken)) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (type == null) { throw new ArgumentNullException(nameof(type)); } if (newType == null) { throw new ArgumentNullException(nameof(newType)); } return(document.ReplaceNodeAsync(type, newType.WithTriviaFrom(type), cancellationToken)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.AddArgumentList, CodeFixIdentifiers.ChangeArrayType)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out SimpleNameSyntax simpleName)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotConvertMethodGroupToNonDelegateType: { if (!simpleName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { break; } var memberAccess = (MemberAccessExpressionSyntax)simpleName.Parent; CodeAction codeAction = CodeAction.Create( "Add argument list", cancellationToken => { InvocationExpressionSyntax invocationExpression = InvocationExpression( memberAccess.WithoutTrailingTrivia(), ArgumentList().WithTrailingTrivia(memberAccess.GetTrailingTrivia())); return(context.Document.ReplaceNodeAsync(memberAccess, invocationExpression, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.TypeOrNamespaceNameCouldNotBeFound: { if (!(simpleName.Parent is ArrayTypeSyntax arrayType)) { break; } if (!(arrayType.Parent is ArrayCreationExpressionSyntax arrayCreation)) { break; } if (!object.ReferenceEquals(simpleName, arrayType.ElementType)) { break; } ExpressionSyntax expression = arrayCreation.Initializer?.Expressions.FirstOrDefault(); if (expression == null) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken); if (typeSymbol?.SupportsExplicitDeclaration() != true) { break; } TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, simpleName.SpanStart); CodeAction codeAction = CodeAction.Create( $"Change element type to '{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, simpleName.SpanStart, SymbolDisplayFormats.Default)}'", cancellationToken => context.Document.ReplaceNodeAsync(simpleName, newType.WithTriviaFrom(simpleName), cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
static void BindEnumerableAndEnumerator(EnumerableDetails details, TypeSyntax newOutType, out TypeSyntax updatedEnumerable, out TypeSyntax updatedEnumerator) { var baseEnumerable = details.BridgeEnumerable; var baseEnumerator = details.BridgeEnumerator; var enumerableMentionsOfOutType = baseEnumerable.DescendantNodesAndSelf().OfType <SimpleNameSyntax>().Where(i => i.Identifier.ValueText == details.OutItem).ToList(); var enumeratorMentionsOfOutType = baseEnumerator.DescendantNodesAndSelf().OfType <SimpleNameSyntax>().Where(i => i.Identifier.ValueText == details.OutItem).ToList(); updatedEnumerable = baseEnumerable.ReplaceNodes(enumerableMentionsOfOutType, (old, _) => newOutType.WithTriviaFrom(old)); updatedEnumerator = baseEnumerator.ReplaceNodes(enumeratorMentionsOfOutType, (old, _) => newOutType.WithTriviaFrom(old)); }
private static Task <Document> RefactorAsync( Document document, CastExpressionSyntax castExpression, CancellationToken cancellationToken) { ExpressionSyntax expression = castExpression.Expression; TypeSyntax type = castExpression.Type; BinaryExpressionSyntax newNode = CSharpFactory.AsExpression(expression.WithTriviaFrom(type), type.WithTriviaFrom(expression)) .WithTriviaFrom(castExpression) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(castExpression, newNode, cancellationToken)); }
static MethodDeclarationSyntax InjectIdentityAndEnumerator(MethodDeclarationSyntax mtd, TypeSyntax enumerable, TypeSyntax enumerator) { var updated = mtd; // replace calls to CommonImplementation methods so that the appropriate enumerable and enumerators // are used var commonNonBridge = (updated.Body?.DescendantNodesAndSelf() ?? updated.ExpressionBody?.DescendantNodesAndSelf() ) .OfType <InvocationExpressionSyntax>() .Where(o => o.Expression is MemberAccessExpressionSyntax) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Expression is IdentifierNameSyntax) .Where(o => ((IdentifierNameSyntax)((MemberAccessExpressionSyntax)o.Expression).Expression).Identifier.ValueText == COMMON_IMPLEMENTATION_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != BRIDGE_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != FORBIDDEN_CALL_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != UNEXPECTED_PATH_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != UNINITIALIZED_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != ARGUMENT_NULL_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != SEQUENCE_EMPTY_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != OUT_OF_RANGE_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != NO_ITEMS_MATCHED_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != MULTIPLE_MATCHING_ELEMENTS_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != MULTIPLE_ELEMENTS_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != UNINITIALIZED_PROJECTION_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != UNEXPECTED_STATE_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != NOT_IMPLEMENTED_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != INNER_UNINITIALIZED_NAME) .Where(o => ((MemberAccessExpressionSyntax)o.Expression).Name.Identifier.ValueText != INVALID_OPERATION_NAME) .ToList(); var replacements = new Dictionary <InvocationExpressionSyntax, InvocationExpressionSyntax>(); foreach (var invocation in commonNonBridge) { var method = ((MemberAccessExpressionSyntax)invocation.Expression).Name; GenericNameSyntax genericMethod; if (method is GenericNameSyntax) { genericMethod = (GenericNameSyntax)method; } else { genericMethod = SyntaxFactory.GenericName(method.Identifier); } var withMoreTerms = genericMethod.AddTypeArgumentListArguments(enumerable, enumerator); var commonAccess = ((MemberAccessExpressionSyntax)invocation.Expression).WithName(withMoreTerms); var updatedInvocation = invocation.WithExpression(commonAccess); replacements[invocation] = updatedInvocation; } updated = updated.ReplaceNodes(replacements.Keys, (old, _) => replacements[old].WithTriviaFrom(old)); var retVal = updated.ReturnType; if (retVal != null) { var updatedRetVal = retVal; var mentionsOfEnumerable = updatedRetVal.DescendantNodesAndSelf().OfType <SimpleNameSyntax>().Where(t => t.Identifier.ValueText == BUILTIN_ENUMERABLE_NAME).ToList(); updatedRetVal = updatedRetVal.ReplaceNodes(mentionsOfEnumerable, (old, _) => enumerable.WithTriviaFrom(old)); var mentionsOfEnumerator = updatedRetVal.DescendantNodesAndSelf().OfType <SimpleNameSyntax>().Where(t => t.Identifier.ValueText == BUILTIN_ENUMERATOR_NAME).ToList(); updatedRetVal = updatedRetVal.ReplaceNodes(mentionsOfEnumerator, (old, _) => enumerator.WithTriviaFrom(old)); updated = updated.WithReturnType(updatedRetVal.WithTriviaFrom(retVal)); } return(updated); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.AddArgumentList, CodeFixIdentifiers.ReorderModifiers, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, CodeFixIdentifiers.ReturnDefaultValue, CodeFixIdentifiers.AddMissingType)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxKind kind = token.Kind(); foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.OperatorCannotBeAppliedToOperandOfType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList)) { break; } if (kind != SyntaxKind.QuestionToken) { break; } if (!token.IsParentKind(SyntaxKind.ConditionalAccessExpression)) { break; } var conditionalAccess = (ConditionalAccessExpressionSyntax)token.Parent; SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(conditionalAccess.Expression, context.CancellationToken); if (typeSymbol == null || typeSymbol.IsErrorType() || !typeSymbol.IsValueType || typeSymbol.IsConstructedFrom(SpecialType.System_Nullable_T)) { break; } CodeAction codeAction = CodeAction.Create( "Remove '?' operator", cancellationToken => { var textChange = new TextChange(token.Span, ""); return(context.Document.WithTextChangeAsync(textChange, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReorderModifiers)) { break; } ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token); break; } case CompilerDiagnosticIdentifiers.ValueCannotBeUsedAsDefaultParameter: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } if (!(token.Parent is ParameterSyntax parameter)) { break; } ExpressionSyntax value = parameter.Default?.Value; if (value == null) { break; } if (value.Kind() != SyntaxKind.NullLiteralExpression) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel); break; } case CompilerDiagnosticIdentifiers.ObjectOfTypeConvertibleToTypeIsRequired: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReturnDefaultValue)) { break; } if (token.Kind() != SyntaxKind.ReturnKeyword) { break; } if (!token.IsParentKind(SyntaxKind.ReturnStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken); if (symbol == null) { break; } SymbolKind symbolKind = symbol.Kind; ITypeSymbol typeSymbol = null; if (symbolKind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)symbol; typeSymbol = methodSymbol.ReturnType; if (methodSymbol.IsAsync && (typeSymbol is INamedTypeSymbol namedTypeSymbol)) { ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments; if (typeArguments.Any()) { typeSymbol = typeArguments[0]; } } } else if (symbolKind == SymbolKind.Property) { typeSymbol = ((IPropertySymbol)symbol).Type; } else { Debug.Fail(symbolKind.ToString()); } if (typeSymbol == null) { break; } if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } if (!typeSymbol.SupportsExplicitDeclaration()) { break; } var returnStatement = (ReturnStatementSyntax)token.Parent; CodeAction codeAction = CodeAction.Create( "Return default value", cancellationToken => { ExpressionSyntax expression = typeSymbol.ToDefaultValueSyntax(semanticModel, returnStatement.SpanStart); ReturnStatementSyntax newNode = returnStatement.WithExpression(expression); return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.TypeExpected: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddMissingType)) { break; } if (token.Kind() != SyntaxKind.CloseParenToken) { break; } if (!(token.Parent is DefaultExpressionSyntax defaultExpression)) { break; } if (!(defaultExpression.Type is IdentifierNameSyntax identifierName)) { break; } if (!identifierName.IsMissing) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken); ITypeSymbol convertedType = typeInfo.ConvertedType; if (convertedType?.SupportsExplicitDeclaration() != true) { break; } CodeAction codeAction = CodeAction.Create( $"Add type '{SymbolDisplay.GetMinimalString(convertedType, semanticModel, defaultExpression.SpanStart)}'", cancellationToken => { TypeSyntax newNode = convertedType.ToMinimalTypeSyntax(semanticModel, defaultExpression.SpanStart); newNode = newNode .WithTriviaFrom(identifierName) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(identifierName, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
public static TypeSyntax GetMappedType(this TypeSyntax type, TypeInfo typeInfo) { TypeSyntax mappedType = typeInfo.GetMappedType(); return(mappedType.ToString() == type.ToString() ? type : mappedType.WithTriviaFrom(type)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReorderModifiers) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReturnDefaultValue) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddMissingType) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSemicolon) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionalAccess) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeForEachType)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxKind kind = token.Kind(); foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.OperatorCannotBeAppliedToOperandOfType: { if (kind == SyntaxKind.QuestionToken && token.Parent is ConditionalAccessExpressionSyntax conditionalAccess) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(conditionalAccess.Expression, context.CancellationToken); if (typeSymbol?.IsErrorType() == false && !typeSymbol.IsConstructedFrom(SpecialType.System_Nullable_T)) { if (typeSymbol.IsValueType) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionalAccess)) { CodeAction codeAction = CodeAction.Create( "Remove '?' operator", cancellationToken => { var textChange = new TextChange(token.Span, ""); return(context.Document.WithTextChangeAsync(textChange, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (typeSymbol.IsReferenceType) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList) && conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression) { ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull( InvocationExpression( memberBindingExpression.WithoutTrailingTrivia(), ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia()))); CodeAction codeAction = CodeAction.Create( "Add argument list", cancellationToken => context.Document.ReplaceNodeAsync(conditionalAccess, newNode, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddArgumentList)) { break; } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionalAccess)) { } } break; } case CompilerDiagnosticIdentifiers.PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReorderModifiers)) { break; } ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token); break; } case CompilerDiagnosticIdentifiers.ValueCannotBeUsedAsDefaultParameter: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } if (!(token.Parent is ParameterSyntax parameter)) { break; } ExpressionSyntax value = parameter.Default?.Value; if (value == null) { break; } if (value.Kind() != SyntaxKind.NullLiteralExpression) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel); break; } case CompilerDiagnosticIdentifiers.ObjectOfTypeConvertibleToTypeIsRequired: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReturnDefaultValue)) { break; } if (token.Kind() != SyntaxKind.ReturnKeyword) { break; } if (!token.IsParentKind(SyntaxKind.ReturnStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol symbol = semanticModel.GetEnclosingSymbol(token.SpanStart, context.CancellationToken); if (symbol == null) { break; } SymbolKind symbolKind = symbol.Kind; ITypeSymbol typeSymbol = null; if (symbolKind == SymbolKind.Method) { var methodSymbol = (IMethodSymbol)symbol; typeSymbol = methodSymbol.ReturnType; if (methodSymbol.IsAsync && (typeSymbol is INamedTypeSymbol namedTypeSymbol)) { ImmutableArray <ITypeSymbol> typeArguments = namedTypeSymbol.TypeArguments; if (typeArguments.Any()) { typeSymbol = typeArguments[0]; } } } else if (symbolKind == SymbolKind.Property) { typeSymbol = ((IPropertySymbol)symbol).Type; } else { Debug.Fail(symbolKind.ToString()); } if (typeSymbol == null) { break; } if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } if (!typeSymbol.SupportsExplicitDeclaration()) { break; } var returnStatement = (ReturnStatementSyntax)token.Parent; CodeAction codeAction = CodeAction.Create( "Return default value", cancellationToken => { ExpressionSyntax expression = typeSymbol.ToDefaultValueSyntax(semanticModel, returnStatement.SpanStart); ReturnStatementSyntax newNode = returnStatement.WithExpression(expression); return(context.Document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.TypeExpected: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddMissingType)) { break; } if (token.Kind() != SyntaxKind.CloseParenToken) { break; } if (!(token.Parent is DefaultExpressionSyntax defaultExpression)) { break; } if (!(defaultExpression.Type is IdentifierNameSyntax identifierName)) { break; } if (!identifierName.IsMissing) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(defaultExpression, context.CancellationToken); ITypeSymbol convertedType = typeInfo.ConvertedType; if (convertedType?.SupportsExplicitDeclaration() != true) { break; } CodeAction codeAction = CodeAction.Create( $"Add type '{SymbolDisplay.GetMinimalString(convertedType, semanticModel, defaultExpression.SpanStart)}'", cancellationToken => { TypeSyntax newNode = convertedType.ToMinimalTypeSyntax(semanticModel, defaultExpression.SpanStart); newNode = newNode .WithTriviaFrom(identifierName) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(identifierName, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.SemicolonAfterMethodOrAccessorBlockIsNotValid: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSemicolon)) { break; } if (token.Kind() != SyntaxKind.SemicolonToken) { break; } switch (token.Parent) { case MethodDeclarationSyntax methodDeclaration: { BlockSyntax body = methodDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); MethodDeclarationSyntax newNode = methodDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case PropertyDeclarationSyntax propertyDeclaration: { AccessorListSyntax accessorList = propertyDeclaration.AccessorList; if (accessorList == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = accessorList .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); PropertyDeclarationSyntax newNode = propertyDeclaration .WithAccessorList(accessorList.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case AccessorDeclarationSyntax accessorDeclaration: { BlockSyntax body = accessorDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", cancellationToken => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); AccessorDeclarationSyntax newNode = accessorDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(context.Document.ReplaceNodeAsync(accessorDeclaration, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } break; } case CompilerDiagnosticIdentifiers.CannotConvertType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeForEachType)) { break; } if (token.Kind() != SyntaxKind.ForEachKeyword) { break; } if (!(token.Parent is ForEachStatementSyntax forEachStatement)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ForEachStatementInfo info = semanticModel.GetForEachStatementInfo(forEachStatement); ITypeSymbol typeSymbol = info.ElementType; if (typeSymbol.SupportsExplicitDeclaration()) { CodeFixRegistrator.ChangeType(context, diagnostic, forEachStatement.Type, typeSymbol, semanticModel, CodeFixIdentifiers.ChangeForEachType); } CodeFixRegistrator.ChangeTypeToVar(context, diagnostic, forEachStatement.Type, CodeFixIdentifiers.ChangeTypeToVar); break; } } } }
public static void ChangeMemberDeclarationType( CodeFixContext context, Diagnostic diagnostic, MemberDeclarationSyntax memberDeclaration, ITypeSymbol typeSymbol, SemanticModel semanticModel, string additionalKey = null) { if (typeSymbol.IsErrorType()) { return; } Document document = context.Document; string typeName = SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, memberDeclaration.SpanStart, SymbolDisplayFormats.Default); string title = (memberDeclaration.IsKind(SyntaxKind.MethodDeclaration)) ? $"Change return type to '{typeName}'" : $"Change type to '{typeName}'"; CodeAction codeAction = CodeAction.Create( title, cancellationToken => RefactorAsync(cancellationToken), EquivalenceKey.Create(diagnostic, additionalKey)); context.RegisterCodeFix(codeAction, diagnostic); Task <Document> RefactorAsync(CancellationToken cancellationToken) { TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, memberDeclaration.SpanStart); switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax newNode = methodDeclaration.WithReturnType(newType.WithTriviaFrom(methodDeclaration.ReturnType)); return(document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken)); } case SyntaxKind.PropertyDeclaration: { var propertyDeclaration = (PropertyDeclarationSyntax)memberDeclaration; PropertyDeclarationSyntax newNode = propertyDeclaration.WithType(newType.WithTriviaFrom(propertyDeclaration.Type)); return(document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken)); } case SyntaxKind.IndexerDeclaration: { var indexerDeclaration = (IndexerDeclarationSyntax)memberDeclaration; IndexerDeclarationSyntax newNode = indexerDeclaration.WithType(newType.WithTriviaFrom(indexerDeclaration.Type)); return(document.ReplaceNodeAsync(indexerDeclaration, newNode, cancellationToken)); } case SyntaxKind.EventDeclaration: { var eventDeclaration = (EventDeclarationSyntax)memberDeclaration; EventDeclarationSyntax newNode = eventDeclaration.WithType(newType.WithTriviaFrom(eventDeclaration.Type)); return(document.ReplaceNodeAsync(eventDeclaration, newNode, cancellationToken)); } case SyntaxKind.EventFieldDeclaration: { var eventDeclaration = (EventFieldDeclarationSyntax)memberDeclaration; VariableDeclarationSyntax declaration = eventDeclaration.Declaration; EventFieldDeclarationSyntax newNode = eventDeclaration.WithDeclaration(declaration.WithType(newType.WithTriviaFrom(declaration.Type))); return(document.ReplaceNodeAsync(eventDeclaration, newNode, cancellationToken)); } default: { Debug.Fail(memberDeclaration.Kind().ToString()); return(Task.FromResult(document)); } } } }
public static async Task <Document> RefactorAsync( Document document, MemberDeclarationSyntax memberDeclaration, ITypeSymbol typeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { TypeSyntax newType = typeSymbol.ToMinimalTypeSyntax(semanticModel, memberDeclaration.SpanStart); switch (memberDeclaration.Kind()) { case SyntaxKind.MethodDeclaration: { var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration; MethodDeclarationSyntax newNode = methodDeclaration.WithReturnType(newType.WithTriviaFrom(methodDeclaration.ReturnType)); return(await document.ReplaceNodeAsync(methodDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.PropertyDeclaration: { var propertyDeclaration = (PropertyDeclarationSyntax)memberDeclaration; PropertyDeclarationSyntax newNode = propertyDeclaration.WithType(newType.WithTriviaFrom(propertyDeclaration.Type)); return(await document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.IndexerDeclaration: { var indexerDeclaration = (IndexerDeclarationSyntax)memberDeclaration; IndexerDeclarationSyntax newNode = indexerDeclaration.WithType(newType.WithTriviaFrom(indexerDeclaration.Type)); return(await document.ReplaceNodeAsync(indexerDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.EventDeclaration: { var eventDeclaration = (EventDeclarationSyntax)memberDeclaration; EventDeclarationSyntax newNode = eventDeclaration.WithType(newType.WithTriviaFrom(eventDeclaration.Type)); return(await document.ReplaceNodeAsync(eventDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } case SyntaxKind.EventFieldDeclaration: { var eventDeclaration = (EventFieldDeclarationSyntax)memberDeclaration; VariableDeclarationSyntax declaration = eventDeclaration.Declaration; VariableDeclaratorSyntax declarator = declaration.Variables.First(); EventFieldDeclarationSyntax newNode = eventDeclaration.WithDeclaration(declaration.WithType(newType.WithTriviaFrom(declaration.Type))); return(await document.ReplaceNodeAsync(eventDeclaration, newNode, cancellationToken).ConfigureAwait(false)); } default: { Debug.Fail(memberDeclaration.Kind().ToString()); return(document); } } }
private static async Task <SyntaxNode> ReplaceNodeAndUpdateVariableTypeAsync(Document document, SyntaxNode root, SyntaxNode originalNode, SyntaxNode newNode, TypeSyntax newType, CancellationToken cancellationToken) { // Check if the original node was the value being // assigned to the variable in a variable declaration. if (originalNode.Parent is EqualsValueClauseSyntax equalsSyntax) { if (IsDeclaratorForObject(equalsSyntax.Parent, out VariableDeclarationSyntax declaration)) { // The original node is being assigned to a variable // of type `object`. Change the type of the variable // and replace the original node with the new node. return(root.ReplaceNode( declaration, declaration.ReplaceNode(originalNode, newNode).WithType(newType.WithTriviaFrom(declaration.Type)) )); } } else { // Check if the node is being assigned to something. if ((originalNode.Parent is AssignmentExpressionSyntax assignment) && (assignment.Left is IdentifierNameSyntax identifier)) { // If it's being assigned to a local variable or a field in the same // document, then we will try to change the type of that variable or field. SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken); SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(identifier); if (symbolInfo.Symbol?.DeclaringSyntaxReferences.Length == 1) { VariableDeclarationSyntax?originalDeclaration = null; VariableDeclarationSyntax?newDeclaration = null; switch (symbolInfo.Symbol.Kind) { case SymbolKind.Local: if (IsDeclaratorForObject(symbolInfo.Symbol.DeclaringSyntaxReferences[0].GetSyntax(), out originalDeclaration)) { newDeclaration = originalDeclaration.WithType(newType.WithTriviaFrom(originalDeclaration.Type)); } break; case SymbolKind.Field: SyntaxNode fieldSyntax = symbolInfo.Symbol.DeclaringSyntaxReferences[0].GetSyntax(); // We can only change the type of the field if it's in the // same document that we're replacing the original node in. if (ReferenceEquals(fieldSyntax.SyntaxTree, originalNode.SyntaxTree)) { if (IsDeclaratorForObject(fieldSyntax, out originalDeclaration)) { newDeclaration = originalDeclaration.WithType(newType.WithTriviaFrom(originalDeclaration.Type)); } } break; } // If a declaration was found, then replace the original node // with the new node, and replace the original declaration with // the new declaration that will change the type of the variable. if (originalDeclaration is not null && newDeclaration is not null) { return(root.ReplaceNodes( new[] { originalNode, originalDeclaration }, (node, _) => (node == originalNode) ? newNode : newDeclaration )); } } } } // If we get to this point, then the original node is not part // of a statement that requires us to update any variable types, // so just replace the original node with the new node. return(root.ReplaceNode(originalNode, newNode)); }