Exemple #1
0
        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));
        }
Exemple #2
0
        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);
        }
Exemple #6
0
        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;
                }
            }));
        }
Exemple #7
0
        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));
            }
        }
Exemple #9
0
        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);
        }
Exemple #15
0
            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);
        }
Exemple #17
0
        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));
        }
Exemple #18
0
        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);
        }
Exemple #20
0
        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));
        }
Exemple #22
0
        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);
        }
Exemple #26
0
        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);
        }
Exemple #30
0
        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));
        }