private static Task <Document> AddNewLineBeforeOrAfterConditionalOperatorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken = default) { string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(conditionalExpression, cancellationToken); if (document.GetConfigOptions(conditionalExpression.SyntaxTree).GetEqualsTokenNewLinePosition() == NewLinePosition.After) { return(document.WithTextChangesAsync( new TextChange[] { GetNewLineAfterTextChange(conditionalExpression.QuestionToken, indentation), GetNewLineAfterTextChange(conditionalExpression.ColonToken, indentation), }, cancellationToken)); } else { return(document.WithTextChangesAsync( new TextChange[] { GetNewLineBeforeTextChange(conditionalExpression.QuestionToken, indentation), GetNewLineBeforeTextChange(conditionalExpression.ColonToken, indentation), }, cancellationToken)); } }
public static Task <Document> AddNewLineBeforeInsteadOfAfterAsync( Document document, SyntaxNodeOrToken left, SyntaxNodeOrToken middle, SyntaxNodeOrToken right, CancellationToken cancellationToken = default) { StringBuilder sb = StringBuilderCache.GetInstance(); SyntaxTriviaList trailingTrivia = middle.GetTrailingTrivia(); if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(trailingTrivia)) { sb.Append(SyntaxTriviaAnalysis.DetermineEndOfLine(middle).ToString()); } else { sb.Append(trailingTrivia.ToString()); } sb.Append(right.GetLeadingTrivia().ToString()); sb.Append(middle.ToString()); sb.Append(" "); string newText = StringBuilderCache.GetStringAndFree(sb); var textChange = new TextChange( TextSpan.FromBounds(left.Span.End, right.SpanStart), newText); return(document.WithTextChangeAsync(textChange, cancellationToken)); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out TypeParameterConstraintClauseSyntax constraintClause)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => { return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync( document, constraintClause.WhereKeyword, SyntaxTriviaAnalysis.AnalyzeIndentation(constraintClause.Parent, ct), ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); }
private static Task <Document> WrapAndIndentEachNodeInListAsync <TNode>( Document document, SeparatedSyntaxList <TNode> nodes, CancellationToken cancellationToken) where TNode : SyntaxNode { return(document.WithTextChangesAsync(GetTextChanges().Where(f => f != default), cancellationToken)); IEnumerable <TextChange> GetTextChanges() { string newText = SyntaxTriviaAnalysis.GetEndOfLine(nodes[0]).ToString() + GetIndentation(); yield return(GetTextChange(nodes[0].GetFirstToken().GetPreviousToken(), nodes[0])); for (int i = 1; i < nodes.Count; i++) { yield return(GetTextChange(nodes.GetSeparator(i - 1), nodes[i])); } TextChange GetTextChange(SyntaxToken token, SyntaxNode node) { TextSpan span = TextSpan.FromBounds(token.Span.End, node.SpanStart); return((node.SyntaxTree.IsSingleLineSpan(span)) ? new TextChange(span, newText) : default);
private static Task <Document> AddNewLineBeforeOrAfterConditionalOperatorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken = default) { string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(conditionalExpression, cancellationToken); if (AnalyzerOptions.AddNewLineAfterEqualsSignInsteadOfBeforeIt.IsEnabled(document, conditionalExpression)) { return(document.WithTextChangesAsync( new TextChange[] { GetNewLineAfterTextChange(conditionalExpression.QuestionToken, indentation), GetNewLineAfterTextChange(conditionalExpression.ColonToken, indentation), }, cancellationToken)); } else { return(document.WithTextChangesAsync( new TextChange[] { GetNewLineBeforeTextChange(conditionalExpression.QuestionToken, indentation), GetNewLineBeforeTextChange(conditionalExpression.ColonToken, indentation), }, cancellationToken)); } }
public static Task <Document> AddNewLineBeforeAndIncreaseIndentationAsync( Document document, SyntaxToken token, CancellationToken cancellationToken = default) { return(AddNewLineBeforeAndIncreaseIndentationAsync( document, token, SyntaxTriviaAnalysis.AnalyzeIndentation(token.Parent, cancellationToken), cancellationToken)); }
public static Task <Document> AddNewLineAfterAsync( Document document, SyntaxToken token, string indentation, CancellationToken cancellationToken = default) { return(document.WithTextChangeAsync( TextSpan.FromBounds(token.Span.End, token.GetNextToken().SpanStart), SyntaxTriviaAnalysis.DetermineEndOfLine(token).ToString() + indentation, cancellationToken)); }
private static Task <Document> AddNewLineBeforeOrAfterAsync( Document document, SyntaxToken token, bool addNewLineAfter, CancellationToken cancellationToken = default) { string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(token.Parent, cancellationToken); return((addNewLineAfter) ? AddNewLineAfterAsync(document, token, indentation, cancellationToken) : AddNewLineBeforeAsync(document, token, indentation, cancellationToken)); }
public static Task <Document> AddNewLineBeforeAsync( Document document, SyntaxToken token, string indentation, CancellationToken cancellationToken = default) { var textChange = new TextChange( TextSpan.FromBounds(token.GetPreviousToken().Span.End, token.SpanStart), SyntaxTriviaAnalysis.DetermineEndOfLine(token).ToString() + indentation); return(document.WithTextChangeAsync(textChange, cancellationToken)); }
public static Task <Document> AddNewLineBeforeAsync( Document document, SyntaxToken token, CancellationToken cancellationToken = default) { SyntaxTrivia indentation = SyntaxTriviaAnalysis.DetermineIndentation(token.Parent, cancellationToken); return(AddNewLineBeforeAsync( document, token, indentation.ToString(), cancellationToken)); }
private static Task <Document> AddCallToConfigureAwaitRefactorAsync( Document document, AwaitExpressionSyntax awaitExpression, CancellationToken cancellationToken) { ExpressionSyntax expression = awaitExpression.Expression; SyntaxTriviaList leading = default; switch (expression.Kind()) { case SyntaxKind.SimpleMemberAccessExpression: { var memberAccess = (MemberAccessExpressionSyntax)expression; leading = memberAccess.OperatorToken.LeadingTrivia; break; } case SyntaxKind.InvocationExpression: { var invocation = (InvocationExpressionSyntax)expression; SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); leading = invocationInfo.OperatorToken.LeadingTrivia; break; } } SyntaxTrivia last = leading.LastOrDefault(); last = (last.IsWhitespaceTrivia()) ? last : default; ParenthesizedExpressionSyntax expression2 = expression.WithoutTrailingTrivia().Parenthesize(); if (last.IsWhitespaceTrivia()) { expression2 = expression2.WithTrailingTrivia(SyntaxTriviaAnalysis.DetermineEndOfLine(awaitExpression)); } InvocationExpressionSyntax newInvocationExpression = InvocationExpression( SimpleMemberAccessExpression( expression2, Token(SyntaxKind.DotToken).WithLeadingTrivia(last), IdentifierName("ConfigureAwait")), ArgumentList( Token(SyntaxKind.OpenParenToken), SingletonSeparatedList(Argument(FalseLiteralExpression())), Token(default, SyntaxKind.CloseParenToken, expression.GetTrailingTrivia())));
private static Task <Document> WrapForStatementAsync( Document document, ForStatementSyntax forStatement, CancellationToken cancellationToken = default) { string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(forStatement, cancellationToken); return(document.WithTextChangesAsync( new TextChange[] { GetNewLineAfterTextChange(forStatement.OpenParenToken, indentation), GetNewLineAfterTextChange(forStatement.FirstSemicolonToken, indentation), GetNewLineAfterTextChange(forStatement.SecondSemicolonToken, indentation), }, cancellationToken)); }
public static Task <Document> AddEmptyLineAfterDirectiveAsync( Document document, DirectiveTriviaSyntax directiveTrivia, CancellationToken cancellationToken = default) { SyntaxTrivia parentTrivia = directiveTrivia.ParentTrivia; SyntaxToken token = parentTrivia.Token; SyntaxTriviaList leadingTrivia = token.LeadingTrivia; int index = leadingTrivia.IndexOf(parentTrivia); SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index + 1, SyntaxTriviaAnalysis.DetermineEndOfLine(token)); SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia); return(document.ReplaceTokenAsync(token, newToken, cancellationToken)); }
public override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.FormatTypeDeclarationBraces: { CodeAction codeAction = CodeAction.Create( "Format braces on multiple lines", ct => FormatTypeDeclarationBracesOnMultipleLinesAsync(document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.PutConstructorInitializerOnItsOwnLine: { CodeAction codeAction = CodeAction.Create( "Put constructor initializer on its own line", ct => { return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync( document, ((ConstructorDeclarationSyntax)memberDeclaration).Initializer.ColonToken, SyntaxTriviaAnalysis.AnalyzeIndentation(memberDeclaration, ct), ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
private static Task <Document> AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { ExpressionSyntax condition = conditionalExpression.Condition; ExpressionSyntax whenTrue = conditionalExpression.WhenTrue; ExpressionSyntax whenFalse = conditionalExpression.WhenFalse; SyntaxToken questionToken = conditionalExpression.QuestionToken; SyntaxToken colonToken = conditionalExpression.ColonToken; ExpressionSyntax newCondition = condition; ExpressionSyntax newWhenTrue = whenTrue; ExpressionSyntax newWhenFalse = whenFalse; SyntaxToken newQuestionToken = questionToken; SyntaxToken newColonToken = colonToken; if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(condition, questionToken, whenTrue)) { var(left, token, right) = CodeFixHelpers.AddNewLineAfterTokenInsteadOfBeforeIt(condition, questionToken, whenTrue); newCondition = left; newQuestionToken = token; newWhenTrue = right; } if (SyntaxTriviaAnalysis.IsTokenPrecededWithNewLineAndNotFollowedWithNewLine(whenTrue, colonToken, whenFalse)) { var(left, token, right) = CodeFixHelpers.AddNewLineAfterTokenInsteadOfBeforeIt(newWhenTrue, colonToken, whenFalse); newWhenTrue = left; newColonToken = token; newWhenFalse = right; } ConditionalExpressionSyntax newConditionalExpression = ConditionalExpression( newCondition, newQuestionToken, newWhenTrue, newColonToken, newWhenFalse); return(document.ReplaceNodeAsync(conditionalExpression, newConditionalExpression, cancellationToken)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.AddNewLineAfterOpeningBraceOfTypeDeclaration: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => AddNewLineAfterOpeningBraceOfTypeDeclarationAsync(document, memberDeclaration, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineBeforeConstructorInitializer: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => { return(CodeFixHelpers.AddNewLineBeforeAndIncreaseIndentationAsync( document, ((ConstructorDeclarationSyntax)memberDeclaration).Initializer.ColonToken, SyntaxTriviaAnalysis.AnalyzeIndentation(memberDeclaration, ct), ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax block, BlockExpressionAnalysis analysis, BodyStyle style) { if (style.UseBlockWhenExpressionIsMultiLine == true && analysis.Expression.IsMultiLine()) { return; } if (!style.UseExpression) return; if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(block.OpenBraceToken)) return; if (!analysis.ReturnOrThrowKeyword.LeadingTrivia.IsEmptyOrWhitespace()) return; ReportDiagnostic(context, analysis.Block); }
private static void AnalyzeBlock(SyntaxNodeAnalysisContext context, BlockSyntax block, BlockExpressionAnalysis analysis) { if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine.IsEnabled(context) && analysis.Expression.IsMultiLine()) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(block.OpenBraceToken)) { return; } if (!analysis.ReturnOrThrowKeyword.LeadingTrivia.IsEmptyOrWhitespace()) { return; } ReportDiagnostic(context, analysis.Block, analysis.Expression); }
public static async Task <Document> RefactorAsync( Document document, ArrowExpressionClauseSyntax expressionBody, CancellationToken cancellationToken = default) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SyntaxNode newNode = Refactor(expressionBody, semanticModel, cancellationToken); SyntaxToken token = expressionBody.ArrowToken.GetPreviousToken(); if (SyntaxTriviaAnalysis.IsOptionalWhitespaceThenEndOfLineTrivia(token.TrailingTrivia)) { SyntaxToken newToken = token.WithTrailingTrivia(ElasticSpace); newNode = newNode.ReplaceToken(token, newToken); } return(await document.ReplaceNodeAsync(expressionBody.Parent, newNode, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> AddBlankLineBeforeUsingDirectiveAsync( Document document, UsingDirectiveSyntax usingDirective, CancellationToken cancellationToken) { SyntaxTriviaList leadingTrivia = usingDirective.GetLeadingTrivia(); int index = leadingTrivia.Count; if (index > 0 && leadingTrivia.Last().IsWhitespaceTrivia()) { index--; } SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index, SyntaxTriviaAnalysis.DetermineEndOfLine(usingDirective)); UsingDirectiveSyntax newUsingDirective = usingDirective.WithLeadingTrivia(newLeadingTrivia); return(document.ReplaceNodeAsync(usingDirective, newUsingDirective, cancellationToken)); }
private static ArrowExpressionClauseSyntax CreateExpressionBody(BlockExpressionAnalysis analysis, SyntaxNode declaration) { SyntaxToken arrowToken = Token(SyntaxKind.EqualsGreaterThanToken); ExpressionSyntax expression = analysis.Expression; SyntaxToken keyword = analysis.ReturnOrThrowKeyword; switch (keyword.Kind()) { case SyntaxKind.ThrowKeyword: { expression = ThrowExpression(keyword, expression); break; } case SyntaxKind.ReturnKeyword: { SyntaxTriviaList leading = keyword.LeadingTrivia; if (!leading.IsEmptyOrWhitespace()) { arrowToken = arrowToken.WithLeadingTrivia(leading); } SyntaxTriviaList trailing = keyword.TrailingTrivia; if (!trailing.IsEmptyOrWhitespace()) { arrowToken = arrowToken.WithTrailingTrivia(trailing); } break; } } expression = SyntaxTriviaAnalysis.SetIndentation(expression, declaration); return(ArrowExpressionClause(arrowToken, expression)); }
public static Task <Document> AddEmptyLineBeforeDirectiveAsync( Document document, DirectiveTriviaSyntax directiveTrivia, CancellationToken cancellationToken = default) { SyntaxTrivia parentTrivia = directiveTrivia.ParentTrivia; SyntaxToken token = parentTrivia.Token; SyntaxTriviaList leadingTrivia = token.LeadingTrivia; int index = leadingTrivia.IndexOf(parentTrivia); if (index > 0 && leadingTrivia[index - 1].IsWhitespaceTrivia()) { index--; } SyntaxTriviaList newLeadingTrivia = leadingTrivia.Insert(index, SyntaxTriviaAnalysis.GetEndOfLine(token)); SyntaxToken newToken = token.WithLeadingTrivia(newLeadingTrivia); return(document.ReplaceTokenAsync(token, newToken, cancellationToken)); }
public static async Task <Document> RefactorAsync( Document document, UseMethodChainingAnalysis analysis, ExpressionStatementSyntax expressionStatement, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); InvocationExpressionSyntax invocationExpression = GetInvocationExpression(expressionStatement); SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression); ITypeSymbol returnType = semanticModel.GetMethodSymbol(invocationExpression, cancellationToken).ReturnType; string name = ((IdentifierNameSyntax)UseMethodChainingAnalysis.WalkDownMethodChain(invocationInfo).Expression).Identifier.ValueText; StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(expressionStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(expressionStatement); string indentation = SyntaxTriviaAnalysis.GetIncreasedIndentation(expressionStatement, cancellationToken); var sb = new StringBuilder(invocationExpression.ToString()); int j = index; while (j < statements.Count - 1) { StatementSyntax statement = statements[j + 1]; if (!analysis.IsFixableStatement(statement, name, returnType, semanticModel, cancellationToken)) { break; } sb.AppendLine(); sb.Append(indentation); sb.Append(GetTextToAppend((ExpressionStatementSyntax)statement)); j++; } StatementSyntax lastStatement = statements[j]; SyntaxList <StatementSyntax> newStatements = statements; while (j > index) { newStatements = newStatements.RemoveAt(j); j--; } ExpressionSyntax newInvocationExpression = SyntaxFactory.ParseExpression(sb.ToString()); SyntaxTriviaList trailingTrivia = statementsInfo .Parent .DescendantTrivia(TextSpan.FromBounds(invocationExpression.Span.End, lastStatement.Span.End)) .ToSyntaxTriviaList() .EmptyIfWhitespace() .AddRange(lastStatement.GetTrailingTrivia()); ExpressionStatementSyntax newExpressionStatement = expressionStatement .ReplaceNode(invocationExpression, newInvocationExpression) .WithLeadingTrivia(expressionStatement.GetLeadingTrivia()) .WithTrailingTrivia(trailingTrivia) .WithFormatterAndSimplifierAnnotation(); newStatements = newStatements.ReplaceAt(index, newExpressionStatement); return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> RefactorAsync( Document document, RecordDeclarationSyntax recordDeclaration, CancellationToken cancellationToken = default) { ParameterListSyntax parameterList = recordDeclaration.ParameterList; BaseListSyntax baseList = recordDeclaration.BaseList; SeparatedSyntaxList <ParameterSyntax> parameters = parameterList.Parameters; var identifiersMap = new Dictionary <string, SyntaxToken>(); var statements = new List <StatementSyntax>(); var properties = new List <PropertyDeclarationSyntax>(); var allAttributeLists = new List <AttributeListSyntax>(); var baseType = baseList? .Types .FirstOrDefault(f => f.IsKind(SyntaxKind.PrimaryConstructorBaseType)) as PrimaryConstructorBaseTypeSyntax; ImmutableHashSet <string> basePropertyNames = ImmutableHashSet <string> .Empty; if (baseType != null) { basePropertyNames = baseType .ArgumentList? .Arguments .Select(f => f.ToString()) .ToImmutableHashSet(); } bool isWritable = !recordDeclaration.Modifiers.Contains(SyntaxKind.ReadOnlyKeyword) && recordDeclaration.ClassOrStructKeyword.IsKind(SyntaxKind.StructKeyword); foreach (ParameterSyntax parameter in parameters) { SyntaxToken identifier = parameter.Identifier; string identifierText = identifier.ValueText; SyntaxToken parameterIdentifier = Identifier(StringUtility.FirstCharToLower(identifierText)); SyntaxToken propertyIdentifier = Identifier(StringUtility.FirstCharToUpper(identifierText)); identifiersMap.Add(identifier.ValueText, parameterIdentifier); IEnumerable <AttributeListSyntax> attributeLists = parameter.AttributeLists.Where(f => f.Target?.Identifier.IsKind(SyntaxKind.PropertyKeyword) == true); allAttributeLists.AddRange(attributeLists); statements.Add(SimpleAssignmentStatement( IdentifierName(propertyIdentifier).QualifyWithThis(), IdentifierName(parameterIdentifier.WithTriviaFrom(identifier)))); if (!basePropertyNames.Contains(identifierText)) { properties.Add(PropertyDeclaration( attributeLists.Select(f => f.WithTarget(null)).ToSyntaxList(), Modifiers.Public(), parameter.Type, default(ExplicitInterfaceSpecifierSyntax), propertyIdentifier, AccessorList( AutoGetAccessorDeclaration(), (isWritable) ? AutoSetAccessorDeclaration() : AutoInitAccessorDeclaration() ))); } } ParameterListSyntax newParameterList = parameterList.RemoveNodes( allAttributeLists, SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.KeepUnbalancedDirectives); newParameterList = newParameterList.ReplaceTokens( newParameterList.Parameters.Select(parameter => parameter.Identifier), (identifier, _) => identifiersMap[identifier.ValueText]); ParameterSyntax firstParameter = parameterList.Parameters[0]; if (firstParameter.GetLeadingTrivia().SingleOrDefault(shouldThrow: false).IsKind(SyntaxKind.WhitespaceTrivia)) { SyntaxTriviaList newIndentation = SyntaxTriviaAnalysis.GetIncreasedIndentationTriviaList(firstParameter, cancellationToken); newParameterList = newParameterList.ReplaceNodes( newParameterList.Parameters, (parameter, _) => { return((parameter.GetLeadingTrivia().SingleOrDefault().IsKind(SyntaxKind.WhitespaceTrivia)) ? parameter.WithLeadingTrivia(newIndentation) : parameter); }); } ConstructorDeclarationSyntax constructor = ConstructorDeclaration( Modifiers.Public(), recordDeclaration.Identifier.WithoutTrivia(), newParameterList, Block(statements)); RecordDeclarationSyntax newRecord = recordDeclaration .WithIdentifier(recordDeclaration.Identifier.WithTrailingTrivia(recordDeclaration.ParameterList.GetTrailingTrivia())) .WithParameterList(null) .WithSemicolonToken(default);
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.AddEmptyLineBetweenBlockAndStatement: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddEmptyLine, ct => CodeFixHelpers.AppendEndOfLineAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineBeforeConditionalOperatorInsteadOfAfterIt: { var conditionalExpression = (ConditionalExpressionSyntax)token.Parent; string title = null; if (token.IsKind(SyntaxKind.QuestionToken)) { title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse)) ? "Add newline before '?' and ':' instead of after it" : "Add newline before '?' instead of after it"; } else { title = "Add newline before ':' instead of after it"; } CodeAction codeAction = CodeAction.Create( title, ct => AddNewLineBeforeConditionalOperatorInsteadOfAfterItAsync(document, conditionalExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineAfterConditionalOperatorInsteadOfBeforeIt: { var conditionalExpression = (ConditionalExpressionSyntax)token.Parent; string title = null; if (token.IsKind(SyntaxKind.QuestionToken)) { title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse)) ? "Add newline after '?' and ':' instead of before it" : "Add newline after '?' instead of before it"; } else { title = "Add newline after ':' instead of before it"; } CodeAction codeAction = CodeAction.Create( title, ct => AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync(document, conditionalExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineAfterExpressionBodyArrowInsteadOfBeforeIt: { CodeAction codeAction = CodeAction.Create( "Add newline after '=>' instead of before it", ct => { var expressionBody = (ArrowExpressionClauseSyntax)token.Parent; return(CodeFixHelpers.AddNewLineAfterInsteadOfBeforeAsync(document, token.GetPreviousToken(), token, expressionBody.Expression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineBeforeExpressionBodyArrowInsteadOfAfterIt: { CodeAction codeAction = CodeAction.Create( "Add newline before '=>' instead of after it", ct => { var expressionBody = (ArrowExpressionClauseSyntax)token.Parent; return(CodeFixHelpers.AddNewLineBeforeInsteadOfAfterAsync(document, token.GetPreviousToken(), token, expressionBody.Expression, ct)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineAfterAttributeList: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } }
private static void AnalyzeAccessorDeclarationBlock( SyntaxNodeAnalysisContext context, AccessorDeclarationSyntax accessor, BlockSyntax body) { if (body.ContainsDirectives) return; if (accessor.AttributeLists.Any()) return; BodyStyle style = context.GetBodyStyle(); if (style.IsDefault) return; bool isGetter = accessor.IsKind(SyntaxKind.GetAccessorDeclaration); BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(body, allowExpressionStatement: !isGetter); ExpressionSyntax expression = analysis.Expression; if (expression == null) return; if (!style.UseExpression) return; if (style.UseBlockWhenExpressionIsMultiLine == true && expression.IsMultiLine()) { return; } if (isGetter && accessor.Parent is AccessorListSyntax accessorList && accessorList.Accessors.Count == 1) { if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessorList.OpenBraceToken)) return; if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessor.Keyword)) return; if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken)) return; if (style.UseBlockWhenDeclarationIsMultiLine == true) { switch (accessorList.Parent.Kind()) { case SyntaxKind.PropertyDeclaration: { if (accessor.SyntaxTree.IsMultiLineSpan(((PropertyDeclarationSyntax)accessorList.Parent).HeaderSpan())) return; break; } case SyntaxKind.IndexerDeclaration: { if (accessor.SyntaxTree.IsMultiLineSpan(((IndexerDeclarationSyntax)accessorList.Parent).HeaderSpan())) return; break; } default: { SyntaxDebug.Fail(accessorList.Parent); break; } } return; } ReportDiagnostic(context, accessorList); return; } if (!accessor.Keyword.TrailingTrivia.IsEmptyOrWhitespace()) return; if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken)) return; if (!accessor.Keyword.LeadingTrivia.IsEmptyOrWhitespace()) return; ReportDiagnostic(context, body); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindToken(root, context.Span.Start, out SyntaxToken token)) { return; } Document document = context.Document; Diagnostic diagnostic = context.Diagnostics[0]; switch (diagnostic.Id) { case DiagnosticIdentifiers.AddEmptyLineBetweenBlockAndStatement: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddEmptyLine, ct => CodeFixHelpers.AppendEndOfLineAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineBeforeConditionalOperatorInsteadOfAfterItOrViceVersa: { if (DiagnosticProperties.ContainsInvert(diagnostic.Properties)) { var conditionalExpression = (ConditionalExpressionSyntax)token.Parent; string title = null; if (token.IsKind(SyntaxKind.QuestionToken)) { title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse)) ? "Add newline after '?' and ':' instead of before it" : "Add newline after '?' instead of before it"; } else { title = "Add newline after ':' instead of before it"; } CodeAction codeAction = CodeAction.Create( title, ct => AddNewLineAfterConditionalOperatorInsteadOfBeforeItAsync(document, conditionalExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { var conditionalExpression = (ConditionalExpressionSyntax)token.Parent; string title = null; if (token.IsKind(SyntaxKind.QuestionToken)) { title = (SyntaxTriviaAnalysis.IsTokenFollowedWithNewLineAndNotPrecededWithNewLine(conditionalExpression.WhenTrue, conditionalExpression.ColonToken, conditionalExpression.WhenFalse)) ? "Add newline before '?' and ':' instead of after it" : "Add newline before '?' instead of after it"; } else { title = "Add newline before ':' instead of after it"; } CodeAction codeAction = CodeAction.Create( title, ct => AddNewLineBeforeConditionalOperatorInsteadOfAfterItAsync(document, conditionalExpression, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case DiagnosticIdentifiers.AddNewLineBeforeExpressionBodyArrowInsteadOfAfterItOrViceVersa: case DiagnosticIdentifiers.AddNewLineBeforeEqualsSignInsteadOfAfterItOrViceVersa: { AddNewLineBeforeOrAfter(); break; } case DiagnosticIdentifiers.AddNewLineAfterAttributeList: { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case DiagnosticIdentifiers.AddNewLineBetweenClosingBraceAndWhileKeywordOrViceVersa: { if (DiagnosticProperties.ContainsInvert(diagnostic.Properties)) { CodeAction codeAction = CodeAction.Create( CodeFixTitles.RemoveNewLine, ct => CodeFixHelpers.ReplaceTriviaBetweenAsync(document, token, token.GetNextToken(), cancellationToken: ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( CodeFixTitles.AddNewLine, ct => CodeFixHelpers.AddNewLineBeforeAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } } void AddNewLineBeforeOrAfter() { if (DiagnosticProperties.ContainsInvert(diagnostic.Properties)) { CodeAction codeAction = CodeAction.Create( $"Add newline after '{token}' instead of before it", ct => CodeFixHelpers.AddNewLineAfterInsteadOfBeforeAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } else { CodeAction codeAction = CodeAction.Create( $"Add newline before '{token}' instead of after it", ct => CodeFixHelpers.AddNewLineBeforeInsteadOfAfterAsync(document, token, ct), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } }
private static void AnalyzeFinallyClause(SyntaxNodeAnalysisContext context) { var finallyClause = (FinallyClauseSyntax)context.Node; if (finallyClause.Parent is not TryStatementSyntax tryStatement) { return; } BlockSyntax finallyBlock = finallyClause.Block; if (finallyBlock?.Statements.Any() != false) { return; } if (!finallyClause.FinallyKeyword.TrailingTrivia.IsEmptyOrWhitespace()) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(finallyBlock.OpenBraceToken)) { return; } if (!finallyBlock.CloseBraceToken.LeadingTrivia.IsEmptyOrWhitespace()) { return; } if (tryStatement.Catches.Any()) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClause, finallyClause); } else { BlockSyntax tryBlock = tryStatement.Block; if (tryBlock?.Statements.Any() != true) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryStatement.TryKeyword)) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryBlock.OpenBraceToken)) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(tryBlock.CloseBraceToken)) { return; } if (!finallyClause.FinallyKeyword.LeadingTrivia.IsEmptyOrWhitespace()) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClause, finallyClause); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryStatement.TryKeyword); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryBlock.OpenBraceToken); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveEmptyFinallyClauseFadeOut, tryBlock.CloseBraceToken); } }
private static void AnalyzeAccessorDeclarationBlock( SyntaxNodeAnalysisContext context, AccessorDeclarationSyntax accessor, BlockSyntax body) { if (body.ContainsDirectives) { return; } if (accessor.AttributeLists.Any()) { return; } bool isGetter = accessor.IsKind(SyntaxKind.GetAccessorDeclaration); BlockExpressionAnalysis analysis = BlockExpressionAnalysis.Create(body, allowExpressionStatement: !isGetter); ExpressionSyntax expression = analysis.Expression; if (expression == null) { return; } if (AnalyzerOptions.ConvertExpressionBodyToBlockBody.IsEnabled(context)) { return; } if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenExpressionIsMultiLine.IsEnabled(context) && expression.IsMultiLine()) { return; } if (isGetter && accessor.Parent is AccessorListSyntax accessorList && accessorList.Accessors.Count == 1) { if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessorList.OpenBraceToken)) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(accessor.Keyword)) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken)) { return; } if (AnalyzerOptions.ConvertExpressionBodyToBlockBodyWhenDeclarationIsMultiLine.IsEnabled(context)) { switch (accessorList.Parent.Kind()) { case SyntaxKind.PropertyDeclaration: { if (accessor.SyntaxTree.IsMultiLineSpan(((PropertyDeclarationSyntax)accessorList.Parent).HeaderSpan())) { return; } break; } case SyntaxKind.IndexerDeclaration: { if (accessor.SyntaxTree.IsMultiLineSpan(((IndexerDeclarationSyntax)accessorList.Parent).HeaderSpan())) { return; } break; } default: { Debug.Fail(accessorList.Parent.Kind().ToString()); break; } } return; } ReportDiagnostic(context, accessorList, expression); ReportFadeOut(context, accessor.Keyword, body); return; } if (!accessor.Keyword.TrailingTrivia.IsEmptyOrWhitespace()) { return; } if (!SyntaxTriviaAnalysis.IsExteriorTriviaEmptyOrWhitespace(body.OpenBraceToken)) { return; } if (!accessor.Keyword.LeadingTrivia.IsEmptyOrWhitespace()) { return; } ReportDiagnostic(context, body, expression); }
private static Task <Document> RefactorAsync( Document document, XmlElementSyntax xmlElement, CancellationToken cancellationToken) { SyntaxList <XmlNodeSyntax> nodes = xmlElement.Content; (TextSpan span1, TextSpan span2, List <TextSpan> spans) = AddParagraphToDocumentationCommentAnalyzer.FindFixableSpan(nodes, stopOnFirstMatch: false, cancellationToken: cancellationToken); var textChanges = new List <TextChange>(); string newLine = nodes .OfType <XmlTextSyntax>() .SelectMany(f => f.TextTokens) .First(f => f.IsKind(SyntaxKind.XmlTextLiteralNewLineToken)) .ValueText; string indentation = SyntaxTriviaAnalysis.DetermineIndentation(xmlElement, cancellationToken).ToString(); string s = $"{newLine}{indentation}/// "; int prevEnd = -1; foreach (TextSpan span in spans) { cancellationToken.ThrowIfCancellationRequested(); if (prevEnd != -1) { textChanges.Add(TextSpan.FromBounds(prevEnd, span.Start), s); } SyntaxToken token = xmlElement.FindToken(span.Start); SyntaxToken endToken = xmlElement.FindToken(span.End - 1); bool isMultiline = xmlElement.SyntaxTree.IsMultiLineSpan(span, cancellationToken); var text = "<para>"; if (isMultiline) { text += s; } int start = token.SpanStart; int length = 0; if (token.IsKind(SyntaxKind.XmlTextLiteralToken) && token.ValueText[0] == ' ') { if (prevEnd == -1) { start++; } else { length++; } } textChanges.Add(new TextSpan(start, length), text); text = ""; if (isMultiline) { text += s; } text += "</para>"; textChanges.Add(new TextSpan(span.End, 0), text); prevEnd = endToken.Span.End; } cancellationToken.ThrowIfCancellationRequested(); return(document.WithTextChangesAsync(textChanges, cancellationToken)); }