public async Task VerifyGetIndentationStepsAsync(string indentationString, int expectedIndentationSteps, int indentationSize, int tabSize) { var testSource = $"{indentationString}public class TestClass {{}}"; var document = CreateTestDocument(testSource, indentationSize, false, tabSize); StyleCopSettings settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, CancellationToken.None); var syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false); var firstToken = syntaxRoot.GetFirstToken(); Assert.Equal(expectedIndentationSteps, IndentationHelper.GetIndentationSteps(settings.Indentation, firstToken)); }
public async Task VerifyGetIndentationStepsForTokenNotAtStartOfLineAsync() { var testSource = " public class TestClass {}"; var document = CreateTestDocument(testSource); StyleCopSettings settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, CancellationToken.None); var syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false); var secondToken = syntaxRoot.GetFirstToken().GetNextToken(); Assert.Equal(0, IndentationHelper.GetIndentationSteps(settings.Indentation, secondToken)); }
/// <summary> /// Gets a whitespace trivia containing the proper amount of indentation for new lines in the given query. /// </summary> /// <param name="indentationOptions">The indentation options to use.</param> /// <param name="queryExpression">The query expression to determine indentation from.</param> /// <returns>A whitespace trivia containing the proper amount of indentation.</returns> internal static SyntaxTrivia GetQueryIndentationTrivia(IndentationOptions indentationOptions, QueryExpressionSyntax queryExpression) { var firstTokenOnTextLine = IndentationHelper.GetFirstTokenOnTextLine(queryExpression.FromClause.FromKeyword); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationOptions, firstTokenOnTextLine); // add an extra indentation step when the first from clause is not properly indented yet if (!firstTokenOnTextLine.IsKind(SyntaxKind.OpenParenToken) && (firstTokenOnTextLine != queryExpression.FromClause.FromKeyword)) { indentationSteps++; } return(IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps)); }
private static SyntaxNode ReformatAccessorAsMultipleLines(IndentationSettings indentationSettings, AccessorDeclarationSyntax accessor) { var accessorList = (AccessorListSyntax)accessor.Parent; var indentationSteps = IndentationHelper.GetIndentationSteps(indentationSettings, accessorList.OpenBraceToken) + 1; var indentation = IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationSteps); var indentationStatements = IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationSteps + 1); var newAccessor = accessor .WithModifiers(ReformatModifiersAsMultipleLines(accessor.Modifiers, indentation)) .WithKeyword(ReformatKeywordAsMultipleLines(accessor.Keyword, indentation, accessor.Modifiers.Count == 0)) .WithBody(ReformatBodyAsMultipleLines(accessor.Body, indentation, indentationStatements)); return(newAccessor); }
private static SyntaxNode ReformatAccessorAsSingleLine(IndentationSettings indentationSettings, AccessorDeclarationSyntax accessor) { var newAccessor = accessor .WithModifiers(ReformatModifiersAsSingleLine(accessor.Modifiers)) .WithKeyword(ReformatKeywordAsSingleLine(accessor.Keyword)) .WithBody(ReformatBodyAsSingleLine(accessor.Body)); var accessorList = (AccessorListSyntax)accessor.Parent; var indentationSteps = IndentationHelper.GetIndentationSteps(indentationSettings, accessorList.OpenBraceToken); var indentation = IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationSteps + 1); newAccessor = newAccessor.WithLeadingTrivia(newAccessor.GetLeadingTrivia().Insert(0, indentation)); return(newAccessor); }
private static StatementSyntax ReformatStatement(Document document, StatementSyntax statement) { var indentationOptions = IndentationOptions.FromDocument(document); var parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, GetStatementParent(statement.Parent)); // use one additional step of indentation for lambdas / anonymous methods switch (statement.Parent.Kind()) { case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: parentIndentationLevel++; break; } var statementIndentationString = IndentationHelper.GenerateIndentationString(indentationOptions, parentIndentationLevel + 1); var newFirstTokenLeadingTrivia = statement.GetFirstToken().LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(statementIndentationString)); var newLastTokenTrailingTrivia = statement.GetLastToken().TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); var firstToken = statement.GetFirstToken().WithLeadingTrivia(newFirstTokenLeadingTrivia); var lastToken = statement.GetLastToken().WithTrailingTrivia(newLastTokenTrailingTrivia); return(statement.ReplaceTokens( new[] { statement.GetFirstToken(), statement.GetLastToken() }, (originalToken, rewrittenToken) => { if (originalToken == statement.GetFirstToken()) { return firstToken; } else if (originalToken == statement.GetLastToken()) { return lastToken; } else { return rewrittenToken; } })); }
private static string DetermineIndentation(CompilationUnitSyntax compilationUnit, IndentationSettings indentationSettings, UsingDirectivesPlacement usingDirectivesPlacement) { string usingsIndentation; if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { var rootNamespace = compilationUnit.Members.OfType <NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationSettings, indentationLevel + 1); } else { usingsIndentation = string.Empty; } return(usingsIndentation); }
private static void ReformatStatementAndSurroundings(StatementSyntax statement, IndentationSettings indentationSettings, Dictionary <SyntaxToken, SyntaxToken> tokenReplaceMap) { var block = statement as BlockSyntax; var previousToken = statement.GetFirstToken().GetPreviousToken(); var previousTokenEndLine = previousToken.GetEndLine(); var statementStartLine = statement.GetFirstToken().GetLine(); if (previousTokenEndLine == statementStartLine) { var newTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); AddToReplaceMap(tokenReplaceMap, previousToken, previousToken.WithTrailingTrivia(newTrailingTrivia)); } if (block != null) { ReformatBlock(indentationSettings, block, tokenReplaceMap); } else { ReformatStatement(indentationSettings, statement, tokenReplaceMap); } var nextToken = statement.GetLastToken().GetNextToken(); if ((block != null) && nextToken.IsKind(SyntaxKind.SemicolonToken)) { // skip trailing semicolon tokens for blocks nextToken = nextToken.GetNextToken(); } var nextTokenStartLine = nextToken.GetLine(); var statementEndLine = statement.GetLastToken().GetEndLine(); if (nextTokenStartLine == statementEndLine) { var indentationLevel = DetermineIndentationLevel(indentationSettings, tokenReplaceMap, statement); var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationLevel); AddToReplaceMap(tokenReplaceMap, nextToken, nextToken.WithLeadingTrivia(indentationTrivia)); } }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var nodeInSourceSpan = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); AttributeListSyntax attributeList = nodeInSourceSpan.FirstAncestorOrSelf <AttributeListSyntax>(); var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var indentationSteps = IndentationHelper.GetIndentationSteps(settings.Indentation, attributeList); var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(settings.Indentation, indentationSteps); List <AttributeListSyntax> newAttributeLists = GetNewAttributeList(attributeList, indentationTrivia); var newSyntaxRoot = syntaxRoot.ReplaceNode(attributeList, newAttributeLists); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(newDocument); }
private async Task <Document> RemoveLeadingBlankLineAsync(Document document, ArgumentListSyntax syntax, CancellationToken cancellationToken) { var tabSize = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.TabSize, LanguageNames.CSharp); bool useTabs = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.UseTabs, LanguageNames.CSharp); var root = await document.GetSyntaxRootAsync(); var newSyntax = syntax.ReplaceToken( syntax.OpenParenToken, syntax.OpenParenToken .WithTrailingTrivia(SyntaxFactory.EndOfLine(Environment.NewLine))); newSyntax = newSyntax.ReplaceTokens( newSyntax.Arguments.GetSeparators(), (oldNode, newNode) => { if (oldNode.IsKind(SyntaxKind.CommaToken)) { return(oldNode.WithTrailingTrivia(SyntaxFactory.EndOfLine(Environment.NewLine)).WithLeadingTrivia()); } return(oldNode); }); var argumentTrivia = IndentationHelper.GetIndentationTriviaByNode(useTabs, tabSize, root, syntax.OpenParenToken, cancellationToken); newSyntax = newSyntax.ReplaceNodes( newSyntax.Arguments, (oldNode, newNode) => { if (oldNode.IsKind(SyntaxKind.Argument)) { return(IndentationHelper.FormatNodeRecursive(oldNode, argumentTrivia, useTabs, tabSize)); } return(oldNode); }); var newRoot = root.ReplaceNode(syntax, newSyntax); var newDoc = document.WithSyntaxRoot(newRoot); return(newDoc); }
private static int DetermineIndentationLevel(IndentationSettings indentationSettings, Dictionary <SyntaxToken, SyntaxToken> tokenReplaceMap, StatementSyntax statement) { var parent = GetStatementParent(statement.Parent); int parentIndentationLevel; SyntaxToken replacementToken; if (tokenReplaceMap.TryGetValue(parent.GetFirstToken(), out replacementToken)) { // if the parent is being modified, use the new leading trivia from the parent for determining the indentation parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, replacementToken); } else { parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, GetFirstOnLineParent(parent)); } return(parentIndentationLevel); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, syntaxRoot.SyntaxTree, cancellationToken); var attributeListSyntax = (AttributeListSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); // use the containing type to determine the indentation level, anything else is less reliable. var containingType = attributeListSyntax.Parent?.Parent; var indentationSteps = (containingType != null) ? IndentationHelper.GetIndentationSteps(settings.Indentation, containingType) + 1 : 0; var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(settings.Indentation, indentationSteps); var tokensToReplace = new Dictionary <SyntaxToken, SyntaxToken>(); if (diagnostic.Properties.ContainsKey(SA1134AttributesMustNotShareLine.FixWithNewLineBeforeKey)) { var token = attributeListSyntax.OpenBracketToken; var prevToken = token.GetPreviousToken(); tokensToReplace[prevToken] = prevToken.WithTrailingTrivia(prevToken.TrailingTrivia.WithoutTrailingWhitespace().Add(SyntaxFactory.CarriageReturnLineFeed)); var newLeadingTrivia = token.LeadingTrivia.Insert(0, indentationTrivia); tokensToReplace[token] = token.WithLeadingTrivia(newLeadingTrivia); } if (diagnostic.Properties.ContainsKey(SA1134AttributesMustNotShareLine.FixWithNewLineAfterKey)) { var token = attributeListSyntax.CloseBracketToken; var nextToken = token.GetNextToken(); tokensToReplace[token] = token.WithTrailingTrivia(token.TrailingTrivia.WithoutTrailingWhitespace().Add(SyntaxFactory.CarriageReturnLineFeed)); var newLeadingTrivia = nextToken.LeadingTrivia.Insert(0, indentationTrivia); tokensToReplace[nextToken] = nextToken.WithLeadingTrivia(newLeadingTrivia); } var newSyntaxRoot = syntaxRoot.ReplaceTokens(tokensToReplace.Keys, (original, rewritten) => tokensToReplace[original]); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(newDocument); }
private static string DetermineIndentation(CompilationUnitSyntax compilationUnit, IndentationSettings indentationSettings, UsingDirectivesPlacement usingDirectivesPlacement) { string usingsIndentation; if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { var rootNamespace = compilationUnit.Members.First(member => BaseNamespaceDeclarationSyntaxWrapper.IsInstance(member)); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, rootNamespace); if (!rootNamespace.IsKind(SyntaxKindEx.FileScopedNamespaceDeclaration)) { indentationLevel++; } usingsIndentation = IndentationHelper.GenerateIndentationString(indentationSettings, indentationLevel); } else { usingsIndentation = string.Empty; } return(usingsIndentation); }
protected override async Task AssertContentIsAsync( TestWorkspace workspace, Document document, int position, string expectedContent, string expectedDocumentationComment = null) { var provider = CreateProvider(workspace); var info = await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, CancellationToken.None)); Assert.NotNull(info); Assert.NotEqual(0, info.RelatedSpans.Length); var tabSize = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Formatting.FormattingOptions.TabSize, document.Project.Language); var text = await document.GetTextAsync(); var classifiedSpans = info.RelatedSpans.Select(s => new ClassifiedSpan(ClassificationTypeNames.Text, s)); var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpans.ToImmutableArray(), tabSize); var actualText = string.Concat(spans.Select(s => text.GetSubText(s.TextSpan).ToString())); Assert.Equal(expectedContent, actualText); }
protected override async Task <SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document, ImmutableArray <Diagnostic> diagnostics) { if (diagnostics.IsEmpty) { return(null); } var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, fixAllContext.CancellationToken); var syntaxRoot = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); var nodes = diagnostics.Select(diagnostic => syntaxRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true).FirstAncestorOrSelf <AttributeListSyntax>()); var newRoot = syntaxRoot.TrackNodes(nodes); foreach (var attributeList in nodes) { var indentationSteps = IndentationHelper.GetIndentationSteps(settings.Indentation, attributeList); var indentationTrivia = IndentationHelper.GenerateWhitespaceTrivia(settings.Indentation, indentationSteps); newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(attributeList), GetNewAttributeList(attributeList, indentationTrivia)); } return(newRoot); }
private static SyntaxNode MoveMember(SyntaxNode syntaxRoot, MemberDeclarationSyntax member, MemberDeclarationSyntax targetMember, IndentationSettings indentationSettings) { var firstToken = syntaxRoot.GetFirstToken(); var fileHeader = GetFileHeader(firstToken.LeadingTrivia); syntaxRoot = syntaxRoot.TrackNodes(member, targetMember, firstToken.Parent); var memberToMove = syntaxRoot.GetCurrentNode(member); var targetMemberTracked = syntaxRoot.GetCurrentNode(targetMember); if (!memberToMove.HasLeadingTrivia) { var targetIndentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, targetMember); var indentationString = IndentationHelper.GenerateIndentationString(indentationSettings, targetIndentationLevel); memberToMove = memberToMove.WithLeadingTrivia(SyntaxFactory.Whitespace(indentationString)); } if (!HasLeadingBlankLines(targetMember) && HasLeadingBlankLines(member)) { memberToMove = memberToMove.WithTrailingTrivia(memberToMove.GetTrailingTrivia().Add(SyntaxFactory.CarriageReturnLineFeed)); memberToMove = memberToMove.WithLeadingTrivia(GetLeadingTriviaWithoutLeadingBlankLines(memberToMove)); } syntaxRoot = syntaxRoot.InsertNodesBefore(targetMemberTracked, new[] { memberToMove }); var fieldToMoveTracked = syntaxRoot.GetCurrentNodes(member).Last(); syntaxRoot = syntaxRoot.RemoveNode(fieldToMoveTracked, SyntaxRemoveOptions.KeepNoTrivia); if (fileHeader.Any()) { var oldFirstToken = syntaxRoot.GetCurrentNode(firstToken.Parent).ChildTokens().First(); syntaxRoot = syntaxRoot.ReplaceToken(oldFirstToken, oldFirstToken.WithLeadingTrivia(StripFileHeader(oldFirstToken.LeadingTrivia))); var newFirstToken = syntaxRoot.GetFirstToken(); syntaxRoot = syntaxRoot.ReplaceToken(newFirstToken, newFirstToken.WithLeadingTrivia(fileHeader.AddRange(newFirstToken.LeadingTrivia))); } return(syntaxRoot); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var whereToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); var precedingToken = whereToken.GetPreviousToken(); var endToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.End); var afterEndToken = endToken.GetNextToken(); var parentIndentation = GetParentIndentation(whereToken); var indentationOptions = IndentationOptions.FromDocument(document); var indentationTrivia = SyntaxFactory.Whitespace(parentIndentation + IndentationHelper.GenerateIndentationString(indentationOptions, 1)); var replaceMap = new Dictionary <SyntaxToken, SyntaxToken>() { [precedingToken] = precedingToken.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed), [whereToken] = whereToken.WithLeadingTrivia(indentationTrivia), [endToken] = endToken.WithTrailingTrivia(RemoveUnnecessaryWhitespaceTrivia(endToken).Add(SyntaxFactory.CarriageReturnLineFeed)), }; if (afterEndToken.IsKind(SyntaxKind.EqualsGreaterThanToken)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(indentationTrivia)); } else if (afterEndToken.IsKind(SyntaxKind.OpenBraceToken)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(SyntaxFactory.Whitespace(parentIndentation))); } else if (afterEndToken.IsKind(SyntaxKind.WhereKeyword)) { replaceMap.Add(afterEndToken, afterEndToken.WithLeadingTrivia(indentationTrivia)); } var newSyntaxRoot = syntaxRoot.ReplaceTokens(replaceMap.Keys, (t1, t2) => replaceMap[t1]).WithoutFormatting(); return(document.WithSyntaxRoot(newSyntaxRoot)); }
private static ConstructorDeclarationSyntax ReformatConstructorDeclaration(ConstructorDeclarationSyntax constructorDeclaration, IndentationSettings indentationSettings, SyntaxTrivia newLine) { var constructorInitializer = constructorDeclaration.Initializer; var newParameterList = constructorDeclaration.ParameterList .WithTrailingTrivia(constructorDeclaration.ParameterList.GetTrailingTrivia().WithoutTrailingWhitespace().Add(newLine)); var indentationSteps = IndentationHelper.GetIndentationSteps(indentationSettings, constructorDeclaration); var indentation = IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationSteps + 1); var newColonTrailingTrivia = constructorInitializer.ColonToken.TrailingTrivia.WithoutTrailingWhitespace(); var newColonToken = constructorInitializer.ColonToken .WithLeadingTrivia(indentation) .WithTrailingTrivia(newColonTrailingTrivia); var newInitializer = constructorInitializer .WithColonToken(newColonToken) .WithThisOrBaseKeyword(constructorInitializer.ThisOrBaseKeyword.WithLeadingTrivia(SyntaxFactory.Space)); return(constructorDeclaration .WithParameterList(newParameterList) .WithInitializer(newInitializer)); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, syntaxRoot.SyntaxTree, cancellationToken); var enumMemberDeclaration = (EnumMemberDeclarationSyntax)syntaxRoot.FindNode(diagnostic.Location.SourceSpan); var enumDeclaration = (EnumDeclarationSyntax)enumMemberDeclaration.Parent; var memberIndex = enumDeclaration.Members.IndexOf(enumMemberDeclaration); var precedingSeparatorToken = enumDeclaration.Members.GetSeparator(memberIndex - 1); // determine the indentation for enum members (which is parent + 1 step) var parentIndentationSteps = IndentationHelper.GetIndentationSteps(settings.Indentation, enumDeclaration); var indentation = IndentationHelper.GenerateWhitespaceTrivia(settings.Indentation, parentIndentationSteps + 1); // combine all trivia between the separator and the enum member and place them after the separator, followed by a new line. var enumMemberDeclarationFirstToken = enumMemberDeclaration.GetFirstToken(); var sharedTrivia = TriviaHelper.MergeTriviaLists(precedingSeparatorToken.TrailingTrivia, enumMemberDeclarationFirstToken.LeadingTrivia); var newTrailingTrivia = SyntaxFactory.TriviaList(sharedTrivia) .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); // replace the trivia for the tokens var replacements = new Dictionary <SyntaxToken, SyntaxToken> { [precedingSeparatorToken] = precedingSeparatorToken.WithTrailingTrivia(newTrailingTrivia), [enumMemberDeclarationFirstToken] = enumMemberDeclarationFirstToken.WithLeadingTrivia(indentation), }; var newSyntaxRoot = syntaxRoot.ReplaceTokens(replacements.Keys, (original, rewritten) => replacements[original]); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(newDocument); }
private static async Task <ContainerElement> BuildInteractiveContentAsync(CodeAnalysisQuickInfoItem quickInfoItem, IntellisenseQuickInfoBuilderContext?context, CancellationToken cancellationToken) { // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style var glyphs = quickInfoItem.Tags.GetGlyphs(); var symbolGlyph = glyphs.FirstOrDefault(g => g != Glyph.CompletionWarning); var warningGlyph = glyphs.FirstOrDefault(g => g == Glyph.CompletionWarning); var firstLineElements = new List <object>(); if (symbolGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(symbolGlyph.GetImageId())); } if (warningGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(warningGlyph.GetImageId())); } var elements = new List <object>(); var descSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); if (descSection != null) { var isFirstElement = true; foreach (var element in Helpers.BuildInteractiveTextElements(descSection.TaggedParts, context)) { if (isFirstElement) { isFirstElement = false; firstLineElements.Add(element); } else { // If the description section contains multiple paragraphs, the second and additional paragraphs // are not wrapped in firstLineElements (they are normal paragraphs). elements.Add(element); } } } elements.Insert(0, new ContainerElement(ContainerElementStyle.Wrapped, firstLineElements)); var documentationCommentSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.DocumentationComments); if (documentationCommentSection != null) { var isFirstElement = true; foreach (var element in Helpers.BuildInteractiveTextElements(documentationCommentSection.TaggedParts, context)) { if (isFirstElement) { isFirstElement = false; // Stack the first paragraph of the documentation comments with the last line of the description // to avoid vertical padding between the two. var lastElement = elements[elements.Count - 1]; elements[elements.Count - 1] = new ContainerElement( ContainerElementStyle.Stacked, lastElement, element); } else { elements.Add(element); } } } // Add the remaining sections as Stacked style elements.AddRange( quickInfoItem.Sections.Where(s => s.Kind is not QuickInfoSectionKinds.Description and not QuickInfoSectionKinds.DocumentationComments) .SelectMany(s => Helpers.BuildInteractiveTextElements(s.TaggedParts, context))); // build text for RelatedSpan if (quickInfoItem.RelatedSpans.Any() && context?.Document is Document document) { var textRuns = new List <ClassifiedTextRun>(); var spanSeparatorNeededBefore = false; foreach (var span in quickInfoItem.RelatedSpans) { var classifiedSpans = await ClassifierHelper.GetClassifiedSpansAsync(document, span, cancellationToken).ConfigureAwait(false); var tabSize = document.Project.Solution.Options.GetOption(FormattingOptions.TabSize, document.Project.Language); var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpans.ToImmutableArray(), tabSize); var textRunsOfSpan = spans.Select(s => new ClassifiedTextRun(s.ClassificationType, text.GetSubText(s.TextSpan).ToString(), ClassifiedTextRunStyle.UseClassificationFont)).ToList(); if (textRunsOfSpan.Count > 0) { if (spanSeparatorNeededBefore) { textRuns.Add(new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, "\r\n", ClassifiedTextRunStyle.UseClassificationFont)); } textRuns.AddRange(textRunsOfSpan); spanSeparatorNeededBefore = true; } } if (textRuns.Any()) { elements.Add(new ClassifiedTextElement(textRuns)); } } return(new ContainerElement( ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding, elements)); }
private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var indentationOptions = IndentationOptions.FromDocument(document); var usingsHelper = new UsingsHelper(document, compilationUnit); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - SA1200 is enabled // - There are no global attributes // - There is only a single namespace declared at the top level var moveInsideNamespace = !document.Project.CompilationOptions.IsAnalyzerSuppressed(SA1200UsingDirectivesMustBePlacedWithinNamespace.DiagnosticId) && !compilationUnit.AttributeLists.Any() && compilationUnit.Members.Count == 1 && namespaceCount == 1; string usingsIndentation; if (moveInsideNamespace) { var rootNamespace = compilationUnit.Members.OfType <NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List <UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (namespaceCount > 1) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, indentationOptions); stripList = new List <UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (moveInsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (namespaceCount <= 1) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } newSyntaxRoot = ReAddFileHeader(syntaxRoot, newSyntaxRoot); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(Task.FromResult(newDocument)); }
private static Dictionary <SyntaxToken, SyntaxToken> GenerateBraceFixes(IndentationSettings indentationSettings, ImmutableArray <SyntaxToken> braceTokens) { var tokenReplacements = new Dictionary <SyntaxToken, SyntaxToken>(); foreach (var braceToken in braceTokens) { var braceLine = LocationHelpers.GetLineSpan(braceToken).StartLinePosition.Line; var braceReplacementToken = braceToken; var indentationSteps = DetermineIndentationSteps(indentationSettings, braceToken); var previousToken = braceToken.GetPreviousToken(); if (IsAccessorWithSingleLineBlock(previousToken, braceToken)) { var newTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Space); AddReplacement(tokenReplacements, previousToken, previousToken.WithTrailingTrivia(newTrailingTrivia)); braceReplacementToken = braceReplacementToken.WithLeadingTrivia(braceToken.LeadingTrivia.WithoutLeadingWhitespace()); } else { // Check if we need to apply a fix before the brace if (LocationHelpers.GetLineSpan(previousToken).StartLinePosition.Line == braceLine) { if (!braceTokens.Contains(previousToken)) { var sharedTrivia = braceReplacementToken.LeadingTrivia.WithoutTrailingWhitespace(); var previousTokenNewTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); AddReplacement(tokenReplacements, previousToken, previousToken.WithTrailingTrivia(previousTokenNewTrailingTrivia)); } braceReplacementToken = braceReplacementToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, indentationSteps)); } // Check if we need to apply a fix after the brace. No fix is needed when: // - The closing brace is followed by a semi-colon or closing paren // - The closing brace is the last token in the file var nextToken = braceToken.GetNextToken(); var nextTokenLine = nextToken.IsKind(SyntaxKind.None) ? -1 : LocationHelpers.GetLineSpan(nextToken).StartLinePosition.Line; var isMultiDimensionArrayInitializer = braceToken.IsKind(SyntaxKind.OpenBraceToken) && braceToken.Parent.IsKind(SyntaxKind.ArrayInitializerExpression) && braceToken.Parent.Parent.IsKind(SyntaxKind.ArrayInitializerExpression); if ((nextTokenLine == braceLine) && (!braceToken.IsKind(SyntaxKind.CloseBraceToken) || !IsValidFollowingToken(nextToken)) && !isMultiDimensionArrayInitializer) { var sharedTrivia = nextToken.LeadingTrivia.WithoutTrailingWhitespace(); var newTrailingTrivia = braceReplacementToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); if (!braceTokens.Contains(nextToken)) { int newIndentationSteps = indentationSteps; if (braceToken.IsKind(SyntaxKind.OpenBraceToken)) { newIndentationSteps++; } if (nextToken.IsKind(SyntaxKind.CloseBraceToken)) { newIndentationSteps = Math.Max(0, newIndentationSteps - 1); } AddReplacement(tokenReplacements, nextToken, nextToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationSettings, newIndentationSteps))); } braceReplacementToken = braceReplacementToken.WithTrailingTrivia(newTrailingTrivia); } } AddReplacement(tokenReplacements, braceToken, braceReplacementToken); } return(tokenReplacements); }
internal static async Task <IntellisenseQuickInfoItem> BuildItemAsync(ITrackingSpan trackingSpan, CodeAnalysisQuickInfoItem quickInfoItem, ITextSnapshot snapshot, Document document, Lazy <IStreamingFindUsagesPresenter> streamingPresenter, CancellationToken cancellationToken) { // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style var glyphs = quickInfoItem.Tags.GetGlyphs(); var symbolGlyph = glyphs.FirstOrDefault(g => g != Glyph.CompletionWarning); var warningGlyph = glyphs.FirstOrDefault(g => g == Glyph.CompletionWarning); var firstLineElements = new List <object>(); if (symbolGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(symbolGlyph.GetImageId())); } if (warningGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(warningGlyph.GetImageId())); } var elements = new List <object>(); var descSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); if (descSection != null) { var isFirstElement = true; foreach (var element in Helpers.BuildInteractiveTextElements(descSection.TaggedParts, document, streamingPresenter)) { if (isFirstElement) { isFirstElement = false; firstLineElements.Add(element); } else { // If the description section contains multiple paragraphs, the second and additional paragraphs // are not wrapped in firstLineElements (they are normal paragraphs). elements.Add(element); } } } elements.Insert(0, new ContainerElement(ContainerElementStyle.Wrapped, firstLineElements)); var documentationCommentSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.DocumentationComments); if (documentationCommentSection != null) { var isFirstElement = true; foreach (var element in Helpers.BuildInteractiveTextElements(documentationCommentSection.TaggedParts, document, streamingPresenter)) { if (isFirstElement) { isFirstElement = false; // Stack the first paragraph of the documentation comments with the last line of the description // to avoid vertical padding between the two. var lastElement = elements[elements.Count - 1]; elements[elements.Count - 1] = new ContainerElement( ContainerElementStyle.Stacked, lastElement, element); } else { elements.Add(element); } } } // Add the remaining sections as Stacked style elements.AddRange( quickInfoItem.Sections.Where(s => s.Kind != QuickInfoSectionKinds.Description && s.Kind != QuickInfoSectionKinds.DocumentationComments) .SelectMany(s => Helpers.BuildInteractiveTextElements(s.TaggedParts, document, streamingPresenter))); // build text for RelatedSpan if (quickInfoItem.RelatedSpans.Any()) { var classifiedSpanList = new List <ClassifiedSpan>(); foreach (var span in quickInfoItem.RelatedSpans) { var classifiedSpans = await ClassifierHelper.GetClassifiedSpansAsync(document, span, cancellationToken).ConfigureAwait(false); classifiedSpanList.AddRange(classifiedSpans); } var tabSize = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.TabSize, document.Project.Language); var text = await document.GetTextAsync().ConfigureAwait(false); var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpanList.ToImmutableArray(), tabSize); var textRuns = spans.Select(s => new ClassifiedTextRun(s.ClassificationType, snapshot.GetText(s.TextSpan.ToSpan()), ClassifiedTextRunStyle.UseClassificationFont)); if (textRuns.Any()) { elements.Add(new ClassifiedTextElement(textRuns)); } } var content = new ContainerElement( ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding, elements); return(new IntellisenseQuickInfoItem(trackingSpan, content)); }
private SyntaxNode ReformatElement(SyntaxNode syntaxRoot, SyntaxNode element, SyntaxToken openBraceToken, SyntaxToken closeBraceToken, IndentationOptions indentationOptions) { var tokenSubstitutions = new Dictionary <SyntaxToken, SyntaxToken>(); var parentLastToken = openBraceToken.GetPreviousToken(); var parentEndLine = parentLastToken.GetLineSpan().EndLinePosition.Line; var blockStartLine = openBraceToken.GetLineSpan().StartLinePosition.Line; // reformat parent if it is on the same line as the block. if (parentEndLine == blockStartLine) { var newTrailingTrivia = parentLastToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); tokenSubstitutions.Add(parentLastToken, parentLastToken.WithTrailingTrivia(newTrailingTrivia)); } var parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, element); var indentationString = IndentationHelper.GenerateIndentationString(indentationOptions, parentIndentationLevel); var contentIndentationString = IndentationHelper.GenerateIndentationString(indentationOptions, parentIndentationLevel + 1); // reformat opening brace tokenSubstitutions.Add(openBraceToken, this.FormatBraceToken(openBraceToken, indentationString)); // reformat start of content var startOfContentToken = openBraceToken.GetNextToken(); if (startOfContentToken != closeBraceToken) { var newStartOfContentTokenLeadingTrivia = startOfContentToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(contentIndentationString)); tokenSubstitutions.Add(startOfContentToken, startOfContentToken.WithLeadingTrivia(newStartOfContentTokenLeadingTrivia)); } // reformat end of content var endOfContentToken = closeBraceToken.GetPreviousToken(); if (endOfContentToken != openBraceToken) { var newEndOfContentTokenTrailingTrivia = endOfContentToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); // check if the token already exists (occurs when there is only one token in the block) if (tokenSubstitutions.ContainsKey(endOfContentToken)) { tokenSubstitutions[endOfContentToken] = tokenSubstitutions[endOfContentToken].WithTrailingTrivia(newEndOfContentTokenTrailingTrivia); } else { tokenSubstitutions.Add(endOfContentToken, endOfContentToken.WithTrailingTrivia(newEndOfContentTokenTrailingTrivia)); } } // reformat closing brace tokenSubstitutions.Add(closeBraceToken, this.FormatBraceToken(closeBraceToken, indentationString)); var rewriter = new TokenRewriter(tokenSubstitutions); var newSyntaxRoot = rewriter.Visit(syntaxRoot); return(newSyntaxRoot); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode syntaxRoot, CancellationToken cancellationToken) { var fileHeader = GetFileHeader(syntaxRoot); var compilationUnit = (CompilationUnitSyntax)syntaxRoot; var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, cancellationToken); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var indentationOptions = IndentationOptions.FromDocument(document); var usingsHelper = new UsingsHelper(settings, semanticModel, compilationUnit, fileHeader); var namespaceCount = CountNamespaces(compilationUnit.Members); // Only move using declarations inside the namespace when // - There are no global attributes // - There is only a single namespace declared at the top level // - OrderingSettings.UsingDirectivesPlacement is set to InsideNamespace UsingDirectivesPlacement usingDirectivesPlacement; switch (settings.OrderingRules.UsingDirectivesPlacement) { case UsingDirectivesPlacement.InsideNamespace: if (compilationUnit.AttributeLists.Any() || compilationUnit.Members.Count > 1 || namespaceCount > 1) { // Override the user's setting with a more conservative one usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; } else if (namespaceCount == 0) { usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; } else { usingDirectivesPlacement = UsingDirectivesPlacement.InsideNamespace; } break; case UsingDirectivesPlacement.OutsideNamespace: usingDirectivesPlacement = UsingDirectivesPlacement.OutsideNamespace; break; case UsingDirectivesPlacement.Preserve: default: usingDirectivesPlacement = UsingDirectivesPlacement.Preserve; break; } string usingsIndentation; if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { var rootNamespace = compilationUnit.Members.OfType <NamespaceDeclarationSyntax>().First(); var indentationLevel = IndentationHelper.GetIndentationSteps(indentationOptions, rootNamespace); usingsIndentation = IndentationHelper.GenerateIndentationString(indentationOptions, indentationLevel + 1); } else { usingsIndentation = string.Empty; } // - The strategy is to strip all using directive that are not inside a conditional directive and replace them later with a sorted list at the correct spot // - The using directives that are inside a conditional directive are replaced (in sorted order) on the spot. // - Conditional directives are not moved, as correctly parsing them is too tricky // - No using directives will be stripped when there are multiple namespaces. In that case everything is replaced on the spot. List <UsingDirectiveSyntax> stripList; var replaceMap = new Dictionary <UsingDirectiveSyntax, UsingDirectiveSyntax>(); // When there are multiple namespaces, do not move using statements outside of them, only sort. if (usingDirectivesPlacement == UsingDirectivesPlacement.Preserve) { BuildReplaceMapForNamespaces(usingsHelper, replaceMap, indentationOptions, false); stripList = new List <UsingDirectiveSyntax>(); } else { stripList = usingsHelper.GetContainedUsings(usingsHelper.RootSpan); } BuildReplaceMapForConditionalDirectives(usingsHelper, replaceMap, indentationOptions, usingsHelper.RootSpan); var usingSyntaxRewriter = new UsingSyntaxRewriter(stripList, replaceMap, fileHeader); var newSyntaxRoot = usingSyntaxRewriter.Visit(syntaxRoot); if (usingDirectivesPlacement == UsingDirectivesPlacement.InsideNamespace) { newSyntaxRoot = AddUsingsToNamespace(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } else if (usingDirectivesPlacement == UsingDirectivesPlacement.OutsideNamespace) { newSyntaxRoot = AddUsingsToCompilationRoot(newSyntaxRoot, usingsHelper, usingsIndentation, replaceMap.Any()); } // Final cleanup newSyntaxRoot = StripMultipleBlankLines(newSyntaxRoot); newSyntaxRoot = ReAddFileHeader(newSyntaxRoot, fileHeader); var newDocument = document.WithSyntaxRoot(newSyntaxRoot.WithoutFormatting()); return(newDocument); }
private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken) { var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var curlyBracketToken = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start); var curlyBracketLine = curlyBracketToken.GetLocation().GetLineSpan().StartLinePosition.Line; var curlyBracketReplacementToken = curlyBracketToken; var indentationOptions = IndentationOptions.FromDocument(document); var indentationSteps = DetermineIndentationSteps(indentationOptions, curlyBracketToken); var previousToken = curlyBracketToken.GetPreviousToken(); var nextToken = curlyBracketToken.GetNextToken(); var rewriter = new Rewriter(); if (IsAccessorWithSingleLineBlock(previousToken, curlyBracketToken)) { var newTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Space); rewriter.AddReplacement(previousToken, previousToken.WithTrailingTrivia(newTrailingTrivia)); curlyBracketReplacementToken = curlyBracketReplacementToken.WithLeadingTrivia(curlyBracketToken.LeadingTrivia.WithoutLeadingWhitespace()); } else { // Check if we need to apply a fix before the curly bracket if (previousToken.GetLocation().GetLineSpan().StartLinePosition.Line == curlyBracketLine) { var sharedTrivia = curlyBracketReplacementToken.LeadingTrivia.WithoutTrailingWhitespace(); var previousTokenNewTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); rewriter.AddReplacement(previousToken, previousToken.WithTrailingTrivia(previousTokenNewTrailingTrivia)); curlyBracketReplacementToken = curlyBracketReplacementToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps)); } // Check if we need to apply a fix after the curly bracket // if a closing curly bracket is followed by a semi-colon or closing paren, no fix is needed. if ((nextToken.GetLocation().GetLineSpan().StartLinePosition.Line == curlyBracketLine) && (!curlyBracketToken.IsKind(SyntaxKind.CloseBraceToken) || !IsValidFollowingToken(nextToken))) { var sharedTrivia = nextToken.LeadingTrivia.WithoutTrailingWhitespace(); var newTrailingTrivia = curlyBracketReplacementToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); int newIndentationSteps; if (curlyBracketToken.IsKind(SyntaxKind.OpenBraceToken)) { newIndentationSteps = indentationSteps + 1; } else if (nextToken.IsKind(SyntaxKind.CloseBraceToken)) { newIndentationSteps = Math.Max(0, indentationSteps - 1); } else { newIndentationSteps = indentationSteps; } rewriter.AddReplacement(nextToken, nextToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, newIndentationSteps))); curlyBracketReplacementToken = curlyBracketReplacementToken.WithTrailingTrivia(newTrailingTrivia); } } rewriter.AddReplacement(curlyBracketToken, curlyBracketReplacementToken); var newSyntaxRoot = rewriter.Visit(syntaxRoot).WithoutFormatting(); return(document.WithSyntaxRoot(newSyntaxRoot)); }
private static BlockSyntax ReformatBlock(Document document, IndentationSettings indentationSettings, BlockSyntax block) { var parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, GetStatementParent(block.Parent)); // use one additional step of indentation for lambdas / anonymous methods switch (block.Parent.Kind()) { case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: parentIndentationLevel++; break; } var indentationString = IndentationHelper.GenerateIndentationString(indentationSettings, parentIndentationLevel); var statementIndentationString = IndentationHelper.GenerateIndentationString(indentationSettings, parentIndentationLevel + 1); var newOpenBraceLeadingTrivia = block.OpenBraceToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(indentationString)); var newOpenBraceTrailingTrivia = block.OpenBraceToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); var newCloseBraceLeadingTrivia = block.CloseBraceToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(indentationString)); var newCloseBraceTrailingTrivia = block.CloseBraceToken.TrailingTrivia .WithoutTrailingWhitespace(); bool addNewLineAfterCloseBrace; switch (block.CloseBraceToken.GetNextToken().Kind()) { case SyntaxKind.CloseParenToken: case SyntaxKind.CommaToken: case SyntaxKind.SemicolonToken: addNewLineAfterCloseBrace = false; break; default: addNewLineAfterCloseBrace = (newCloseBraceTrailingTrivia.Count == 0) || !newCloseBraceTrailingTrivia.Last().IsKind(SyntaxKind.EndOfLineTrivia); break; } if (addNewLineAfterCloseBrace) { newCloseBraceTrailingTrivia = newCloseBraceTrailingTrivia.Add(SyntaxFactory.CarriageReturnLineFeed); } var openBraceToken = SyntaxFactory.Token(SyntaxKind.OpenBraceToken) .WithLeadingTrivia(newOpenBraceLeadingTrivia) .WithTrailingTrivia(newOpenBraceTrailingTrivia); var closeBraceToken = SyntaxFactory.Token(SyntaxKind.CloseBraceToken) .WithLeadingTrivia(newCloseBraceLeadingTrivia) .WithTrailingTrivia(newCloseBraceTrailingTrivia); var statements = SyntaxFactory.List <StatementSyntax>(); foreach (var statement in block.Statements) { var newLeadingTrivia = statement.GetLeadingTrivia() .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(statementIndentationString)); var newTrailingTrivia = statement.GetTrailingTrivia() .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); var modifiedStatement = statement .WithLeadingTrivia(newLeadingTrivia) .WithTrailingTrivia(newTrailingTrivia); statements = statements.Add(modifiedStatement); } return(SyntaxFactory.Block(openBraceToken, statements, closeBraceToken)); }
private static void ReformatBlock(IndentationSettings indentationSettings, BlockSyntax block, Dictionary <SyntaxToken, SyntaxToken> tokenReplaceMap) { var parentIndentationLevel = IndentationHelper.GetIndentationSteps(indentationSettings, GetStatementParent(block.Parent)); // use one additional step of indentation for lambdas / anonymous methods switch (block.Parent.Kind()) { case SyntaxKind.AnonymousMethodExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: parentIndentationLevel++; break; } var indentationString = IndentationHelper.GenerateIndentationString(indentationSettings, parentIndentationLevel); var statementIndentationString = IndentationHelper.GenerateIndentationString(indentationSettings, parentIndentationLevel + 1); var newOpenBraceLeadingTrivia = block.OpenBraceToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(indentationString)); var newOpenBraceTrailingTrivia = block.OpenBraceToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); var newCloseBraceLeadingTrivia = block.CloseBraceToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(indentationString)); var newCloseBraceTrailingTrivia = block.CloseBraceToken.TrailingTrivia .WithoutTrailingWhitespace(); bool addNewLineAfterCloseBrace; switch (block.CloseBraceToken.GetNextToken().Kind()) { case SyntaxKind.CloseParenToken: case SyntaxKind.CommaToken: case SyntaxKind.SemicolonToken: addNewLineAfterCloseBrace = false; break; default: addNewLineAfterCloseBrace = (newCloseBraceTrailingTrivia.Count == 0) || !newCloseBraceTrailingTrivia.Last().IsKind(SyntaxKind.EndOfLineTrivia); break; } if (addNewLineAfterCloseBrace) { newCloseBraceTrailingTrivia = newCloseBraceTrailingTrivia.Add(SyntaxFactory.CarriageReturnLineFeed); } AddToReplaceMap(tokenReplaceMap, block.OpenBraceToken, block.OpenBraceToken.WithLeadingTrivia(newOpenBraceLeadingTrivia).WithTrailingTrivia(newOpenBraceTrailingTrivia)); AddToReplaceMap(tokenReplaceMap, block.CloseBraceToken, block.CloseBraceToken.WithLeadingTrivia(newCloseBraceLeadingTrivia).WithTrailingTrivia(newCloseBraceTrailingTrivia)); foreach (var statement in block.Statements) { var firstToken = statement.GetFirstToken(); var lastToken = statement.GetLastToken(); var newLeadingTrivia = firstToken.LeadingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Whitespace(statementIndentationString)); var newTrailingTrivia = lastToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.CarriageReturnLineFeed); AddToReplaceMap(tokenReplaceMap, firstToken, firstToken.WithLeadingTrivia(newLeadingTrivia)); AddToReplaceMap(tokenReplaceMap, lastToken, lastToken.WithTrailingTrivia(newTrailingTrivia)); } }
private static Dictionary <SyntaxToken, SyntaxToken> GenerateBraceFixes(Document document, ImmutableArray <SyntaxToken> braceTokens) { var tokenReplacements = new Dictionary <SyntaxToken, SyntaxToken>(); foreach (var braceToken in braceTokens) { var braceLine = LocationHelpers.GetLineSpan(braceToken).StartLinePosition.Line; var braceReplacementToken = braceToken; var indentationOptions = IndentationOptions.FromDocument(document); var indentationSteps = DetermineIndentationSteps(indentationOptions, braceToken); var previousToken = braceToken.GetPreviousToken(); var nextToken = braceToken.GetNextToken(); if (IsAccessorWithSingleLineBlock(previousToken, braceToken)) { var newTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .Add(SyntaxFactory.Space); AddReplacement(tokenReplacements, previousToken, previousToken.WithTrailingTrivia(newTrailingTrivia)); braceReplacementToken = braceReplacementToken.WithLeadingTrivia(braceToken.LeadingTrivia.WithoutLeadingWhitespace()); } else { // Check if we need to apply a fix before the brace if (LocationHelpers.GetLineSpan(previousToken).StartLinePosition.Line == braceLine) { if (!braceTokens.Contains(previousToken)) { var sharedTrivia = braceReplacementToken.LeadingTrivia.WithoutTrailingWhitespace(); var previousTokenNewTrailingTrivia = previousToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); AddReplacement(tokenReplacements, previousToken, previousToken.WithTrailingTrivia(previousTokenNewTrailingTrivia)); } braceReplacementToken = braceReplacementToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, indentationSteps)); } // Check if we need to apply a fix after the brace // if a closing brace is followed by a semi-colon or closing paren, no fix is needed. if ((LocationHelpers.GetLineSpan(nextToken).StartLinePosition.Line == braceLine) && (!braceToken.IsKind(SyntaxKind.CloseBraceToken) || !IsValidFollowingToken(nextToken))) { var sharedTrivia = nextToken.LeadingTrivia.WithoutTrailingWhitespace(); var newTrailingTrivia = braceReplacementToken.TrailingTrivia .WithoutTrailingWhitespace() .AddRange(sharedTrivia) .Add(SyntaxFactory.CarriageReturnLineFeed); if (!braceTokens.Contains(nextToken)) { int newIndentationSteps; if (braceToken.IsKind(SyntaxKind.OpenBraceToken)) { newIndentationSteps = indentationSteps + 1; } else if (nextToken.IsKind(SyntaxKind.CloseBraceToken)) { newIndentationSteps = Math.Max(0, indentationSteps - 1); } else { newIndentationSteps = indentationSteps; } AddReplacement(tokenReplacements, nextToken, nextToken.WithLeadingTrivia(IndentationHelper.GenerateWhitespaceTrivia(indentationOptions, newIndentationSteps))); } braceReplacementToken = braceReplacementToken.WithTrailingTrivia(newTrailingTrivia); } } AddReplacement(tokenReplacements, braceToken, braceReplacementToken); } return(tokenReplacements); }
internal static async Task <IntellisenseQuickInfoItem> BuildItemAsync(ITrackingSpan trackingSpan, CodeAnalysisQuickInfoItem quickInfoItem, ITextSnapshot snapshot, Document document, CancellationToken cancellationToken) { // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style var glyphs = quickInfoItem.Tags.GetGlyphs(); var symbolGlyph = glyphs.FirstOrDefault(g => g != Glyph.CompletionWarning); var warningGlyph = glyphs.FirstOrDefault(g => g == Glyph.CompletionWarning); var firstLineElements = new List <object>(); if (symbolGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(symbolGlyph.GetImageId())); } if (warningGlyph != Glyph.None) { firstLineElements.Add(new ImageElement(warningGlyph.GetImageId())); } var descSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); if (descSection != null) { firstLineElements.Add(BuildClassifiedTextElement(descSection)); } var elements = new List <object> { new ContainerElement(ContainerElementStyle.Wrapped, firstLineElements) }; // Add the remaining sections as Stacked style elements.AddRange( quickInfoItem.Sections.Where(s => s.Kind != QuickInfoSectionKinds.Description) .Select(BuildClassifiedTextElement)); // build text for RelatedSpan if (quickInfoItem.RelatedSpans.Any()) { var classifiedSpanList = new List <ClassifiedSpan>(); foreach (var span in quickInfoItem.RelatedSpans) { var classifiedSpans = await EditorClassifier.GetClassifiedSpansAsync(document, span, cancellationToken).ConfigureAwait(false); classifiedSpanList.AddRange(classifiedSpans); } var tabSize = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.TabSize, document.Project.Language); var text = await document.GetTextAsync().ConfigureAwait(false); var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpanList.ToImmutableArray(), tabSize); var textRuns = spans.Select(s => new ClassifiedTextRun(s.ClassificationType, snapshot.GetText(s.TextSpan.ToSpan()))); if (textRuns.Any()) { elements.Add(new ClassifiedTextElement(textRuns)); } } var content = new ContainerElement( ContainerElementStyle.Stacked, elements); return(new IntellisenseQuickInfoItem(trackingSpan, content)); }