public static BlockSyntax AddTrailingBlankLine(BlockSyntax block) { Debug.Assert(block != null && NeedsTrailingBlankLine(block)); return block .WithTrailingTrivia(block.GetTrailingTrivia().Add(SyntaxFactory.CarriageReturnLineFeed)) .WithAdditionalAnnotations(Formatter.Annotation); }
protected bool ExpandWithStatements(SyntaxList <StatementSyntax> statements, out SyntaxList <StatementSyntax> newStatements) { //check if list contains "with" syntax if (!statements.Where(p => (p.Kind == SyntaxKind.WithStatement)).Any()) { newStatements = statements; return(false); } //collect new list of statements List <StatementSyntax> newStatementsList = new List <StatementSyntax>(); foreach (StatementSyntax statementSyntax in statements) { if (statementSyntax.Kind == SyntaxKind.WithStatement) { SyntaxNode newWithNode = this.Visit(statementSyntax); if (newWithNode.Kind == SyntaxKind.Block) { BlockSyntax newWithBlock = (BlockSyntax)newWithNode; if (newWithBlock.Statements.Count > 0) { int newStartIdx = newStatementsList.Count; newStatementsList.AddRange(newWithBlock.Statements); //copy leading and trailing trivia from block to the first and last block statements //as they might contain important information newStatementsList[newStartIdx] = newStatementsList[newStartIdx] .WithLeadingTrivia( newWithBlock.GetLeadingTrivia() .AddRange(newStatementsList[newStartIdx].GetLeadingTrivia()) .NormalizeSyntaxTriviaList()); int newEndIdx = newStatementsList.Count - 1; newStatementsList[newEndIdx] = newStatementsList[newEndIdx] .WithTrailingTrivia( newStatementsList[newEndIdx].GetTrailingTrivia() .AddRange(newWithBlock.EndKeywordToken.LeadingTrivia) .AddRange(newWithBlock.GetTrailingTrivia()) .NormalizeSyntaxTriviaList()); } } else { newStatementsList.Add((StatementSyntax)newWithNode); } } else { newStatementsList.Add(statementSyntax); } } newStatements = SyntaxFactory.List <StatementSyntax>(newStatementsList); return(true); }
public static Task <Document> RefactorAsync( Document document, BlockSyntax block, CancellationToken cancellationToken) { StatementSyntax statement = block .Statements[0] .TrimTrivia() .PrependToLeadingTrivia(block.GetLeadingTrivia()) .AppendToTrailingTrivia(block.GetTrailingTrivia()) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(block, statement, cancellationToken)); }
public static Task <Document> RefactorAsync( Document document, UnsafeStatementSyntax unsafeStatement, SyntaxNode containingNode, CancellationToken cancellationToken) { SyntaxToken keyword = unsafeStatement.UnsafeKeyword; BlockSyntax block = unsafeStatement.Block; SyntaxList <StatementSyntax> statements = block.Statements; SyntaxNode newNode = null; int count = statements.Count; if (count == 0) { newNode = containingNode.RemoveNode(unsafeStatement); } else { StatementSyntax first = statements.First(); StatementSyntax last = statements.Last(); SyntaxTriviaList leadingTrivia = keyword.LeadingTrivia .AddRange(keyword.TrailingTrivia.EmptyIfWhitespace()) .AddRange(block.GetLeadingTrivia().EmptyIfWhitespace()) .AddRange(block.OpenBraceToken.TrailingTrivia.EmptyIfWhitespace()) .AddRange(first.GetLeadingTrivia().EmptyIfWhitespace()); SyntaxTriviaList trailingTrivia = last.GetTrailingTrivia().EmptyIfWhitespace() .AddRange(block.CloseBraceToken.LeadingTrivia.EmptyIfWhitespace()) .AddRange(block.GetTrailingTrivia()); statements = statements .ReplaceAt(0, first.WithLeadingTrivia(leadingTrivia)) .ReplaceAt(count - 1, last.WithTrailingTrivia(trailingTrivia)); newNode = containingNode.ReplaceNode(unsafeStatement, statements.Select(f => f.WithFormatterAnnotation())); } newNode = newNode.InsertModifier(SyntaxKind.UnsafeKeyword); return(document.ReplaceNodeAsync(containingNode, newNode, cancellationToken)); }
private static async Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { ExpressionSyntax condition = ifStatement.Condition; ElseClauseSyntax elseClause = ifStatement.Else; if ((ifStatement.Statement as BlockSyntax)?.Statements.Any() == false) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newCondition = Inverter.LogicallyNegate(condition, semanticModel, cancellationToken); StatementSyntax statement = elseClause.Statement; if (statement is IfStatementSyntax nestedIf) { newCondition = LogicalAndExpression(newCondition.Parenthesize(), nestedIf.Condition.Parenthesize()); statement = nestedIf.Statement; } cancellationToken.ThrowIfCancellationRequested(); IfStatementSyntax newNode = ifStatement.Update( ifStatement.IfKeyword, ifStatement.OpenParenToken, newCondition, ifStatement.CloseParenToken, statement, default(ElseClauseSyntax)); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, newNode, cancellationToken).ConfigureAwait(false)); } else if (elseClause != null) { WhileStatementSyntax whileStatement; if (ifStatement.Parent is BlockSyntax block) { whileStatement = (WhileStatementSyntax)block.Parent; } else { block = Block(); whileStatement = (WhileStatementSyntax)ifStatement.Parent; } cancellationToken.ThrowIfCancellationRequested(); BlockSyntax newBlock = (ifStatement.Statement is BlockSyntax ifBlock) ? block.WithStatements(ifBlock.Statements) : block.WithStatements(SingletonList(ifStatement.Statement)); SyntaxNode newNode = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, ifStatement.Condition, whileStatement.CloseParenToken, newBlock); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(whileStatement, newNode, cancellationToken).ConfigureAwait(false)); } else { var block = (BlockSyntax)ifStatement.Parent; SyntaxList <StatementSyntax> statements = block.Statements; BlockSyntax newBlock = block.WithStatements(statements.Remove(ifStatement)); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newCondition = Inverter.LogicallyNegate(condition, semanticModel, cancellationToken); SyntaxNode newNode = block.Parent; switch (block.Parent) { case WhileStatementSyntax whileStatement: { cancellationToken.ThrowIfCancellationRequested(); if (statements.IsFirst(ifStatement)) { newNode = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, newCondition, whileStatement.CloseParenToken, newBlock); } else { newNode = DoStatement( Token(whileStatement.WhileKeyword.LeadingTrivia, SyntaxKind.DoKeyword, whileStatement.CloseParenToken.TrailingTrivia), newBlock.WithoutTrailingTrivia(), Token(SyntaxKind.WhileKeyword), OpenParenToken(), newCondition, CloseParenToken(), SemicolonToken().WithTrailingTrivia(newBlock.GetTrailingTrivia())); } break; } case DoStatementSyntax doStatement: { cancellationToken.ThrowIfCancellationRequested(); if (statements.IsLast(ifStatement)) { newNode = doStatement.Update( doStatement.DoKeyword, newBlock, doStatement.WhileKeyword, doStatement.OpenParenToken, newCondition, doStatement.CloseParenToken, doStatement.SemicolonToken); } else { newNode = WhileStatement( Token(doStatement.DoKeyword.LeadingTrivia, SyntaxKind.WhileKeyword, SyntaxTriviaList.Empty), OpenParenToken(), newCondition, Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, doStatement.DoKeyword.TrailingTrivia), newBlock.WithTrailingTrivia(doStatement.GetTrailingTrivia())); } break; } default: { Debug.Fail(block.Parent.Kind().ToString()); break; } } newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(block.Parent, newNode, cancellationToken).ConfigureAwait(false)); } }
SyntaxNode ApplyNodeChange(BlockSyntax blockNode) { if (blockNode.Parent is ConversionOperatorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is OperatorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is AccessorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is ConstructorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is DestructorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is TryStatementSyntax) { return(blockNode); } if (blockNode.Parent is CatchClauseSyntax) { return(blockNode); } if (blockNode.Parent is FinallyClauseSyntax) { return(blockNode); } if (blockNode.Parent is IfStatementSyntax) { return(blockNode); } if (blockNode.Parent is ElseClauseSyntax) { return(blockNode); } // if (blockNode.Parent is ParenthesizedExpressionSyntax) return blockNode; if (blockNode.Parent is SimpleLambdaExpressionSyntax) { return(blockNode); } if (blockNode.Parent is ParenthesizedLambdaExpressionSyntax) { return(blockNode); } if (blockNode.Parent is AnonymousMethodExpressionSyntax) { return(blockNode); } if (blockNode.Parent is LocalFunctionStatementSyntax) { return(blockNode); } if (blockNode.Parent is MethodDeclarationSyntax == false && blockNode.Statements.Count == 1) { var singleStatement = blockNode.Statements.FirstOrDefault(); if (singleStatement.Span.Length <= NormalizeWhiteSpace.Options.Block_Single_Statement_Max_Length) { if (isReportOnlyMode) { var lineSpan = singleStatement.GetFileLinePosSpan(); AddReport(new ChangesReport(singleStatement) { LineNumber = lineSpan.StartLinePosition.Line, Column = lineSpan.StartLinePosition.Character, Message = "remove brackets from on line lambda expression", Generator = nameof(BlockRewriter) }); } singleStatement = singleStatement .WithTrailingTrivia( CleanUpListWithExactNumberOfWhiteSpaces( SyntaxFactory.TriviaList( blockNode.CloseBraceToken.LeadingTrivia .AddRange(singleStatement.GetTrailingTrivia()) .AddRange(blockNode.GetTrailingTrivia()) ), 1, null) ); lastBlockToken = singleStatement.GetLastToken(); return(singleStatement); } } return(blockNode); }
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; } } } }
SyntaxNode ApplyNodeChange(BlockSyntax blockNode) { if (blockNode.Parent is ConversionOperatorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is OperatorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is AccessorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is ConstructorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is DestructorDeclarationSyntax) { return(blockNode); } if (blockNode.Parent is TryStatementSyntax) { return(blockNode); } if (blockNode.Parent is CatchClauseSyntax) { return(blockNode); } if (blockNode.Parent is FinallyClauseSyntax) { return(blockNode); } if (blockNode.Parent is IfStatementSyntax) { return(blockNode); } if (blockNode.Parent is ElseClauseSyntax) { return(blockNode); } //if (blockNode.Parent is ParenthesizedExpressionSyntax) return blockNode; if (blockNode.Parent is SimpleLambdaExpressionSyntax) { return(blockNode); } if (blockNode.Parent is ParenthesizedLambdaExpressionSyntax) { return(blockNode); } if (blockNode.Parent is AnonymousMethodExpressionSyntax) { return(blockNode); } if (blockNode.Parent is MethodDeclarationSyntax == false && blockNode.Statements.Count == 1) { var singleStatement = blockNode.Statements.First(); if (singleStatement.Span.Length <= BLOCK_SINGLE_STATEMENT_MAX_LENGTH) { singleStatement = singleStatement .WithTrailingTrivia( CleanUpList( SyntaxFactory.TriviaList( singleStatement .GetTrailingTrivia() .AddRange(blockNode.GetTrailingTrivia()) ), 1) ); lastBlockToken = singleStatement.GetLastToken(); return(singleStatement); } } return(blockNode); }
private static async Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ExpressionSyntax condition = ifStatement.Condition; ElseClauseSyntax elseClause = ifStatement.Else; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SimplifyCodeBranchingKind kind = SimplifyCodeBranchingAnalyzer.GetKind(ifStatement, semanticModel, cancellationToken).Value; if (kind == SimplifyCodeBranchingKind.IfElseWithEmptyIf) { ExpressionSyntax newCondition = SyntaxInverter.LogicallyInvert(condition, semanticModel, cancellationToken); StatementSyntax statement = elseClause.Statement; if (statement is IfStatementSyntax nestedIf) { newCondition = LogicalAndExpression(newCondition.Parenthesize(), nestedIf.Condition.Parenthesize()); statement = nestedIf.Statement; } IfStatementSyntax newIfStatement = ifStatement.Update( ifStatement.IfKeyword, ifStatement.OpenParenToken, newCondition, ifStatement.CloseParenToken, statement, default(ElseClauseSyntax)); newIfStatement = newIfStatement.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, newIfStatement, cancellationToken).ConfigureAwait(false)); } else if (kind == SimplifyCodeBranchingKind.IfElseInsideWhile) { bool elseContainsBreak = elseClause.SingleNonBlockStatementOrDefault()?.Kind() == SyntaxKind.BreakStatement; SyntaxList <StatementSyntax> statements; if (elseContainsBreak) { statements = (ifStatement.Statement is BlockSyntax block2) ? block2.Statements : SingletonList(ifStatement.Statement); } else { statements = (elseClause.Statement is BlockSyntax block2) ? block2.Statements : SingletonList(elseClause.Statement); } WhileStatementSyntax whileStatement; if (ifStatement.Parent is BlockSyntax block) { whileStatement = (WhileStatementSyntax)block.Parent; block = block.WithStatements(block.Statements.ReplaceRange(ifStatement, statements)); } else { whileStatement = (WhileStatementSyntax)ifStatement.Parent; block = Block(statements); } if (!elseContainsBreak) { condition = SyntaxInverter.LogicallyInvert(condition, semanticModel, cancellationToken); } WhileStatementSyntax newWhileStatement = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, condition, whileStatement.CloseParenToken, block); newWhileStatement = newWhileStatement.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(whileStatement, newWhileStatement, cancellationToken).ConfigureAwait(false)); } else if (kind == SimplifyCodeBranchingKind.SimplifIfInsideWhileOrDo) { var block = (BlockSyntax)ifStatement.Parent; SyntaxList <StatementSyntax> statements = block.Statements; BlockSyntax newBlock = block.WithStatements(statements.Remove(ifStatement)); ExpressionSyntax newCondition = SyntaxInverter.LogicallyInvert(condition, semanticModel, cancellationToken); SyntaxNode newNode; switch (block.Parent) { case WhileStatementSyntax whileStatement: { if (statements.IsFirst(ifStatement)) { newNode = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, newCondition, whileStatement.CloseParenToken, newBlock); } else { newNode = DoStatement( Token(whileStatement.WhileKeyword.LeadingTrivia, SyntaxKind.DoKeyword, whileStatement.CloseParenToken.TrailingTrivia), newBlock.WithoutTrailingTrivia(), Token(SyntaxKind.WhileKeyword), OpenParenToken(), newCondition, CloseParenToken(), SemicolonToken().WithTrailingTrivia(newBlock.GetTrailingTrivia())); } break; } case DoStatementSyntax doStatement: { if (statements.IsLast(ifStatement)) { newNode = doStatement.Update( doStatement.DoKeyword, newBlock, doStatement.WhileKeyword, doStatement.OpenParenToken, newCondition, doStatement.CloseParenToken, doStatement.SemicolonToken); } else { newNode = WhileStatement( Token(doStatement.DoKeyword.LeadingTrivia, SyntaxKind.WhileKeyword, SyntaxTriviaList.Empty), OpenParenToken(), newCondition, Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, doStatement.DoKeyword.TrailingTrivia), newBlock.WithTrailingTrivia(doStatement.GetTrailingTrivia())); } break; } default: { throw new InvalidOperationException(); } } newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(block.Parent, newNode, cancellationToken).ConfigureAwait(false)); } else if (kind == SimplifyCodeBranchingKind.SimpleIfContainingOnlyDo) { StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); var doStatement = (DoStatementSyntax)statement; WhileStatementSyntax whileStatement = WhileStatement( Token(ifStatement.GetLeadingTrivia(), SyntaxKind.WhileKeyword, SyntaxTriviaList.Empty), OpenParenToken(), doStatement.Condition, Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, doStatement.DoKeyword.TrailingTrivia), doStatement.Statement.WithTrailingTrivia(ifStatement.GetTrailingTrivia())); whileStatement = whileStatement.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, whileStatement, cancellationToken).ConfigureAwait(false)); } else { throw new InvalidOperationException(); } }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } SyntaxKind kind = token.Kind(); Diagnostic diagnostic = context.Diagnostics[0]; Document document = context.Document; switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CS0023_OperatorCannotBeAppliedToOperand: { 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.IsNullableType()) { if (typeSymbol.IsValueType) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionalAccess, document, root.SyntaxTree)) { CodeAction codeAction = CodeAction.Create( "Remove '?' operator", ct => document.WithTextChangeAsync(token.Span, "", ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (typeSymbol.IsReferenceType) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList, document, root.SyntaxTree) && conditionalAccess.WhenNotNull is MemberBindingExpressionSyntax memberBindingExpression) { ConditionalAccessExpressionSyntax newNode = conditionalAccess.WithWhenNotNull( InvocationExpression( memberBindingExpression.WithoutTrailingTrivia(), ArgumentList().WithTrailingTrivia(memberBindingExpression.GetTrailingTrivia()))); CodeAction codeAction = CodeAction.Create( "Add argument list", ct => document.ReplaceNodeAsync(conditionalAccess, newNode, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } } } break; } case CompilerDiagnosticIdentifiers.CS0267_PartialModifierCanOnlyAppearImmediatelyBeforeClassStructInterfaceOrVoid: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.OrderModifiers, document, root.SyntaxTree)) { break; } ModifiersCodeFixRegistrator.MoveModifier(context, diagnostic, token.Parent, token); break; } case CompilerDiagnosticIdentifiers.CS1750_ValueCannotBeUsedAsDefaultParameter: { if (token.Parent is not ParameterSyntax parameter) { break; } ExpressionSyntax value = parameter.Default?.Value; if (value == null) { break; } if (value.IsKind(SyntaxKind.NullLiteralExpression)) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue, document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, value, semanticModel); } } else if (!value.IsKind(SyntaxKind.DefaultExpression, SyntaxKind.DefaultLiteralExpression)) { if (IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeParameterType, document, root.SyntaxTree)) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(value, context.CancellationToken); if (!typeSymbol.IsKind(SymbolKind.ErrorType)) { CodeFixRegistrator.ChangeType(context, diagnostic, parameter.Type, typeSymbol, semanticModel); } } } break; } case CompilerDiagnosticIdentifiers.CS0126_ObjectOfTypeConvertibleToTypeIsRequired: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReturnDefaultValue, document, root.SyntaxTree)) { break; } if (!token.IsKind(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", ct => { ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); if (expression.IsKind(SyntaxKind.DefaultExpression) && document.SupportsLanguageFeature(CSharpLanguageFeature.DefaultLiteral)) { expression = CSharpFactory.DefaultLiteralExpression().WithTriviaFrom(expression); } ReturnStatementSyntax newNode = returnStatement.WithExpression(expression); return(document.ReplaceNodeAsync(returnStatement, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1031_TypeExpected: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddMissingType, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.CloseParenToken)) { break; } if (token.Parent is not DefaultExpressionSyntax defaultExpression) { break; } if (defaultExpression.Type is not 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.ToMinimalDisplayString(convertedType, semanticModel, defaultExpression.SpanStart, SymbolDisplayFormats.DisplayName)}'", ct => { TypeSyntax newType = convertedType.ToTypeSyntax() .WithTriviaFrom(identifierName) .WithFormatterAndSimplifierAnnotation(); return(document.ReplaceNodeAsync(identifierName, newType, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS1597_SemicolonAfterMethodOrAccessorBlockIsNotValid: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveSemicolon, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.SemicolonToken)) { break; } switch (token.Parent) { case MethodDeclarationSyntax methodDeclaration: { BlockSyntax body = methodDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); MethodDeclarationSyntax newNode = methodDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(methodDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case PropertyDeclarationSyntax propertyDeclaration: { AccessorListSyntax accessorList = propertyDeclaration.AccessorList; if (accessorList == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = accessorList .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); PropertyDeclarationSyntax newNode = propertyDeclaration .WithAccessorList(accessorList.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(propertyDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case AccessorDeclarationSyntax accessorDeclaration: { BlockSyntax body = accessorDeclaration.Body; if (body == null) { break; } CodeAction codeAction = CodeAction.Create( "Remove semicolon", ct => { SyntaxTriviaList trivia = body .GetTrailingTrivia() .EmptyIfWhitespace() .AddRange(token.LeadingTrivia.EmptyIfWhitespace()) .AddRange(token.TrailingTrivia); AccessorDeclarationSyntax newNode = accessorDeclaration .WithBody(body.WithTrailingTrivia(trivia)) .WithSemicolonToken(default(SyntaxToken)); return(document.ReplaceNodeAsync(accessorDeclaration, newNode, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } break; } case CompilerDiagnosticIdentifiers.CS0030_CannotConvertType: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeForEachType, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.ForEachKeyword)) { break; } if (token.Parent is not 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; } case CompilerDiagnosticIdentifiers.CS1737_OptionalParametersMustAppearAfterAllRequiredParameters: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddDefaultValueToParameter, document, root.SyntaxTree)) { break; } if (token.Parent is not BaseParameterListSyntax parameterList) { break; } SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; ParameterSyntax parameter = null; for (int i = 0; i < parameters.Count; i++) { ParameterSyntax p = parameters[i]; if (p.FullSpan.End <= token.SpanStart) { parameter = p; } else { break; } } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, context.CancellationToken); ITypeSymbol typeSymbol = parameterSymbol.Type; if (typeSymbol.Kind == SymbolKind.ErrorType) { break; } CodeAction codeAction = CodeAction.Create( "Add default value", ct => { ExpressionSyntax defaultValue = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions()); ParameterSyntax newParameter = parameter .WithDefault(EqualsValueClause(defaultValue).WithTrailingTrivia(parameter.GetTrailingTrivia())) .WithoutTrailingTrivia() .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(parameter, newParameter, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8632_AnnotationForNullableReferenceTypesShouldOnlyBeUsedWithinNullableAnnotationsContext: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveAnnotationForNullableReferenceTypes, document, root.SyntaxTree)) { break; } if (!token.IsKind(SyntaxKind.QuestionToken)) { return; } CodeAction codeAction = CodeAction.Create( "Remove 'nullable' annotation", ct => { var textChange = new TextChange(token.Span, ""); return(document.WithTextChangeAsync(textChange, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CS8602_DereferenceOfPossiblyNullReference: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (!token.IsParentKind(SyntaxKind.IdentifierName)) { return; } SyntaxNode node = token.Parent .WalkUp(f => f.IsKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.InvocationExpression, SyntaxKind.ElementAccessExpression)) .Parent; if (node.IsKind(SyntaxKind.ExpressionStatement) && token.SpanStart == node.SpanStart) { CodeAction codeAction = CodeAction.Create( "Use null propagation operator", ct => { var textChange = new TextChange(new TextSpan(token.Span.End, 0), "?"); return(document.WithTextChangeAsync(textChange, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } return; } case CompilerDiagnosticIdentifiers.CS8604_PossibleNullReferenceArgumentForParameter: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (!token.IsParentKind(SyntaxKind.IdentifierName)) { return; } CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var identifierName = (IdentifierNameSyntax)token.Parent; PostfixUnaryExpressionSyntax newExpression = SuppressNullableWarningExpression(identifierName.WithoutTrivia()) .WithTriviaFrom(identifierName); return(document.ReplaceNodeAsync(identifierName, newExpression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); return; } case CompilerDiagnosticIdentifiers.CS8618_NonNullableMemberIsUninitialized: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseNullForgivingOperator, document, root.SyntaxTree)) { break; } Debug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token.Kind().ToString()); if (!token.IsKind(SyntaxKind.IdentifierToken)) { return; } if (token.IsParentKind(SyntaxKind.PropertyDeclaration)) { CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var property = (PropertyDeclarationSyntax)token.Parent; PropertyDeclarationSyntax newProperty = property .WithoutTrailingTrivia() .WithInitializer(EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression()))) .WithSemicolonToken(SemicolonToken().WithTrailingTrivia(property.GetTrailingTrivia())); return(document.ReplaceNodeAsync(property, newProperty, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { SyntaxDebug.Assert( (token.IsParentKind(SyntaxKind.VariableDeclarator) && token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) && token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration)) || token.IsParentKind(SyntaxKind.ConstructorDeclaration), token); if (token.IsParentKind(SyntaxKind.VariableDeclarator) && token.Parent.IsParentKind(SyntaxKind.VariableDeclaration) && token.Parent.Parent.IsParentKind(SyntaxKind.FieldDeclaration)) { CodeAction codeAction = CodeAction.Create( "Use null-forgiving operator", ct => { var declarator = (VariableDeclaratorSyntax)token.Parent; VariableDeclaratorSyntax newDeclarator = declarator .WithoutTrailingTrivia() .WithInitializer( EqualsValueClause(SuppressNullableWarningExpression(NullLiteralExpression())) .WithTrailingTrivia(declarator.GetTrailingTrivia())); return(document.ReplaceNodeAsync(declarator, newDeclarator, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.CS8403_MethodWithIteratorBlockMustBeAsyncToReturnIAsyncEnumerableOfT: { if (!IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddAsyncModifier, document, root.SyntaxTree)) { break; } SyntaxDebug.Assert(token.IsKind(SyntaxKind.IdentifierToken), token); SyntaxDebug.Assert(token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement), token.Parent); if (token.IsParentKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)) { ModifiersCodeFixRegistrator.AddModifier( context, diagnostic, token.Parent, SyntaxKind.AsyncKeyword, additionalKey: CodeFixIdentifiers.AddAsyncModifier); } break; } } }
public static BlockSyntax Trivia(this BlockSyntax node, BlockSyntax that) { return node.WithLeadingTrivia(that.GetLeadingTrivia()).WithTrailingTrivia(that.GetTrailingTrivia()); }