private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var firstToken = context.Tree.GetRoot().GetFirstToken(includeZeroWidth: true);

            if (firstToken.HasLeadingTrivia)
            {
                var leadingTrivia = firstToken.LeadingTrivia;

                var firstNonBlankLineTriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(leadingTrivia);
                switch (firstNonBlankLineTriviaIndex)
                {
                case 0:
                    // no blank lines
                    break;

                case -1:
                    // only blank lines
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, leadingTrivia.Span)));
                    break;

                default:
                    var textSpan = TextSpan.FromBounds(leadingTrivia[0].Span.Start, leadingTrivia[firstNonBlankLineTriviaIndex].Span.Start);
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan)));
                    break;
                }
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsWhitespaceOnly(context.CancellationToken))
            {
                // Handling of empty documents is now the responsibility of the analyzers
                return;
            }

            var firstToken = context.Tree.GetRoot().GetFirstToken(includeZeroWidth: true);

            if (firstToken.HasLeadingTrivia)
            {
                var leadingTrivia = firstToken.LeadingTrivia;

                var firstNonBlankLineTriviaIndex = TriviaHelper.IndexOfFirstNonBlankLineTrivia(leadingTrivia);
                switch (firstNonBlankLineTriviaIndex)
                {
                case 0:
                    // no blank lines
                    break;

                case -1:
                    // only blank lines
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, leadingTrivia.Span)));
                    break;

                default:
                    var textSpan = TextSpan.FromBounds(leadingTrivia[0].Span.Start, leadingTrivia[firstNonBlankLineTriviaIndex].Span.Start);
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan)));
                    break;
                }
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node != null && !node.IsKind(SyntaxKind.ClassDeclaration));

            bool foundNode = false;

            foreach (var node in descentNodes)
            {
                if (node.IsKind(SyntaxKind.NamespaceDeclaration))
                {
                    if (foundNode)
                    {
                        var location = NamedTypeHelpers.GetNameOrIdentifierLocation(node);
                        if (location != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                    else
                    {
                        foundNode = true;
                    }
                }
            }
        }
        private static void HandleSyntaxTreeAxtion(SyntaxTreeAnalysisContext context)
        {
            var root = context.Tree.GetRoot(context.CancellationToken);

            var fileHeader = FileHeaderHelpers.ParseFileHeader(root);
            if (fileHeader.IsMissing || fileHeader.IsMalformed)
            {
                // this will be handled by SA1633
                return;
            }

            var copyrightElement = fileHeader.GetElement("copyright");
            if (copyrightElement == null)
            {
                // this will be handled by SA1634
                return;
            }

            var companyAttribute = copyrightElement.Attribute("company");
            if (string.IsNullOrWhiteSpace(companyAttribute?.Value))
            {
                var location = fileHeader.GetElementLocation(context.Tree, copyrightElement);
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
            }
        }
        private void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            var descentNodes = syntaxRoot.DescendantNodes(descendIntoChildren: node => node != null && !node.IsKind(SyntaxKind.ClassDeclaration));

            string foundClassName = null;
            bool isPartialClass = false;

            foreach (var node in descentNodes)
            {
                if (node.IsKind(SyntaxKind.ClassDeclaration))
                {
                    ClassDeclarationSyntax classDeclaration = node as ClassDeclarationSyntax;
                    if (foundClassName != null)
                    {
                        if (isPartialClass && foundClassName == classDeclaration.Identifier.Text)
                        {
                            continue;
                        }

                        var location = NamedTypeHelpers.GetNameOrIdentifierLocation(node);
                        if (location != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, location));
                        }
                    }
                    else
                    {
                        foundClassName = classDeclaration.Identifier.Text;
                        isPartialClass = classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword);
                    }
                }
            }
        }
        // If you want a full implementation of this analyzer with system tests and a code fix, go to
        // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/StyleCop.Analyzers/StyleCop.Analyzers/ReadabilityRules/SA1120CommentsMustContainText.cs
        private void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            SyntaxNode root = context.Tree.GetCompilationUnitRoot(context.CancellationToken);

            foreach (var node in root.DescendantTrivia())
            {
                switch (node.Kind())
                {
                    case SyntaxKind.SingleLineCommentTrivia:
                        // Remove the leading // from the comment
                        var commentText = node.ToString().Substring(2);
                        int index = 0;

                        var list = TriviaHelper.GetContainingTriviaList(node, out index);
                        bool isFirst = IsFirstComment(list, index);
                        bool isLast = IsLastComment(list, index);

                        if (string.IsNullOrWhiteSpace(commentText) && (isFirst || isLast))
                        {
                            var diagnostic = Diagnostic.Create(Rule, node.GetLocation());
                            context.ReportDiagnostic(diagnostic);
                        }

                        break;
                }
            }
        }
 private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     if (context.Tree.Options.DocumentationMode != DocumentationMode.Diagnose)
     {
         context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Tree.GetLocation(new TextSpan(0, 0))));
     }
 }
        private static void AnalyzeTree(SyntaxTreeAnalysisContext context)
        {
            var tree = context.Tree;
            var emptyStrings = tree.GetRoot().DescendantTokens()
                .Where(x => x.RawKind == (int)SyntaxKind.StringLiteralToken
                       && string.IsNullOrEmpty(x.ValueText)).ToList();

            foreach (var s in emptyStrings)
            {
                // Skip if it is inside method parameter definition or as case switch or a attribute argument.
                if (s.Parent.Parent.Parent.IsKind(SyntaxKind.Parameter) ||
                    s.Parent.Parent.IsKind(SyntaxKind.CaseSwitchLabel) ||
                    s.Parent.Parent.IsKind(SyntaxKind.AttributeArgument))
                {
                    continue;
                }

                FieldDeclarationSyntax fieldSyntax = s.Parent.Parent.Parent.Parent.Parent as FieldDeclarationSyntax;
                if (fieldSyntax != null && fieldSyntax.DescendantTokens().Any(x => x.IsKind(SyntaxKind.ConstKeyword)))
                {
                    continue;
                }

                var line = s.SyntaxTree.GetLineSpan(s.FullSpan);
                var diagnostic = Diagnostic.Create(Rule, s.GetLocation());

                context.ReportDiagnostic(diagnostic);
            }
        }
        private static void HandleOpenBraceToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool followedBySpace = token.IsFollowedByWhitespace();

            if (token.Parent is InterpolationSyntax)
            {
                if (followedBySpace)
                {
                    // Opening curly bracket must{} be {followed} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), " not", "followed"));
                }

                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace();

            if (!precededBySpace)
            {
                // Opening curly bracket must{} be {preceded} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "preceded"));
            }

            if (!token.IsLastInLine() && !followedBySpace)
            {
                // Opening curly bracket must{} be {followed} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "followed"));
            }
        }
 private void AnalyzeType(SyntaxTreeAnalysisContext context, TypeDeclarationSyntax typeDeclaration)
 {
     var numberOfFields = typeDeclaration.Members.Count(member => member is FieldDeclarationSyntax);
     if (numberOfFields > MaximumNumberOfFields)
     {
         context.ReportDiagnostic(Diagnostic.Create(Rule, typeDeclaration.Identifier.GetLocation(), typeDeclaration.Identifier.Text, numberOfFields));
     }
 }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            byte[] preamble = context.Tree.Encoding.GetPreamble();

            if (!IsUtf8Preamble(preamble))
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(0, 0))));
            }
        }
        private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var diagnostics = RenameTrackingTaggerProvider.GetDiagnosticsAsync(context.Tree, DiagnosticDescriptor, context.CancellationToken).WaitAndGetResult(context.CancellationToken);

            foreach (var diagnostic in diagnostics)
            {
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void HandleWhitespaceTrivia(SyntaxTreeAnalysisContext context, SyntaxTrivia trivia)
        {
            if (trivia.ToFullString().IndexOf('\t') < 0)
            {
                return;
            }

            // Tabs must not be used.
            context.ReportDiagnostic(Diagnostic.Create(Descriptor, trivia.GetLocation()));
        }
Ejemplo n.º 14
0
 private static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     // Find source files with documentation comment diagnostics turned off.
     if (context.Tree.Options.DocumentationMode != DocumentationMode.Diagnose)
     {
         // For all such files, produce a diagnostic.
         var diagnostic = Diagnostic.Create(Rule, Location.None, Path.GetFileName(context.Tree.FilePath));
         context.ReportDiagnostic(diagnostic);
     }
 }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            byte[] preamble = context.Tree.Encoding.GetPreamble();

            if (!IsUtf8Preamble(preamble))
            {
                ImmutableDictionary<string, string> properties = ImmutableDictionary<string, string>.Empty.SetItem(EncodingProperty, context.Tree.Encoding?.WebName ?? "<null>");
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(0, 0)), properties));
            }
        }
        private static void HandleCloseBraceToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace();

            if (token.Parent is InterpolationSyntax)
            {
                if (precededBySpace)
                {
                    // Closing curly bracket must{ not} be {preceded} by a space.
                    var properties = TokenSpacingCodeFixProvider.RemovePreceding;
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, " not", "preceded"));
                }

                return;
            }

            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine = token.IsLastInLine();
            bool precedesSpecialCharacter;

            if (!followedBySpace && !lastInLine)
            {
                SyntaxToken nextToken = token.GetNextToken();
                precedesSpecialCharacter =
                    nextToken.IsKind(SyntaxKind.CloseParenToken)
                    || nextToken.IsKind(SyntaxKind.CommaToken)
                    || nextToken.IsKind(SyntaxKind.SemicolonToken)
                    || nextToken.IsKind(SyntaxKind.DotToken)
                    || (nextToken.IsKind(SyntaxKind.QuestionToken) && nextToken.GetNextToken(includeZeroWidth: true).IsKind(SyntaxKind.DotToken))
                    || nextToken.IsKind(SyntaxKind.CloseBracketToken);
            }
            else
            {
                precedesSpecialCharacter = false;
            }

            if (!precededBySpace)
            {
                // Closing curly bracket must{} be {preceded} by a space.
                var properties = TokenSpacingCodeFixProvider.InsertPreceding;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, string.Empty, "preceded"));
            }

            if (!lastInLine && !precedesSpecialCharacter && !followedBySpace)
            {
                // Closing curly bracket must{} be {followed} by a space.
                var properties = TokenSpacingCodeFixProvider.InsertFollowing;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, string.Empty, "followed"));
            }
        }
        private static void AnalyzeTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsWhitespaceOnly(context.CancellationToken))
            {
                // Handling of empty documents is now the responsibility of the analyzers
                return;
            }

            // Report a diagnostic if we got called
            context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Tree.GetLocation(TextSpan.FromBounds(0, 0))));
        }
 private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     SyntaxNode root;
     if (!context.Tree.TryGetRoot(out root))
         return;
     IEnumerable<SyntaxTrivia> tabTrivias = root.DescendantTrivia(descendIntoTrivia: true)
         .Where(trivia => trivia.IsKind(SyntaxKind.WhitespaceTrivia) && trivia.ToString().IndexOf('\t') >= 0);
     foreach (SyntaxTrivia st in tabTrivias)
     {
         context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.IndentWithFourSpaces, st.GetLocation()));
     }
 }
        private static async void AnalyzeSymbol(SyntaxTreeAnalysisContext context)
        {
            var cancel = context.CancellationToken;
            var tree = await context.Tree.GetRootAsync(cancel);
            var foreachs = tree.DescendantNodes().OfType<ForEachStatementSyntax>().ToList();
            foreach (var fe in foreachs)
            {
                var loopVariableName = fe.Identifier.Text;

                IfStatementSyntax ifStatement;
                string ifType;

                if (TrySearchForIfThenContinueStatement(fe, out ifStatement, out ifType) ||
                    TrySearchForSingleIfStatement(fe, out ifStatement, out ifType))
                {
                    var ifExpression = ifStatement.Condition;
                    var identifiersInExpression = ifExpression.DescendantNodesAndSelf().OfType<IdentifierNameSyntax>();
                    var containsLoopVariable = identifiersInExpression.Any(x => x.Identifier.Text == loopVariableName);
                    if (containsLoopVariable)
                    {
                        var properties = new Dictionary<string, string> { { RefactorType, ifType } }.ToImmutableDictionary();
                        context.ReportDiagnostic(Diagnostic.Create(Rule, ifStatement.Condition.GetLocation(), properties));
                    }
                }

                LocalDeclarationStatementSyntax assignmentStatement;
                if (TrySearchForVariableToSelect(fe, out assignmentStatement, loopVariableName))
                {
                    var declaratorsBasedOnLoopVariable = assignmentStatement.Declaration.Variables
                        .Where(x => x.Initializer?.DescendantNodes()?.OfType<IdentifierNameSyntax>()?.Any(y => y.Identifier.Text == loopVariableName) ?? false);

                    if (declaratorsBasedOnLoopVariable.Count() == 1)
                    {
                        var declarator = declaratorsBasedOnLoopVariable.Single();
                        var properties = new Dictionary<string, string> { { RefactorType, VariableToSelect } }.ToImmutableDictionary();
                        context.ReportDiagnostic(Diagnostic.Create(Rule, declarator.GetLocation(), properties));
                    }
                }
            }
        }
        private static void HandleMultiLineComment(SyntaxTreeAnalysisContext context, SyntaxTrivia multiLineComment)
        {
            var nodeText = multiLineComment.ToString();

            // We remove the /* and the */ and determine if the comment has any content.
            var commentText = nodeText.Substring(2, nodeText.Length - 4);

            if (string.IsNullOrWhiteSpace(commentText))
            {
                var diagnostic = Diagnostic.Create(Descriptor, multiLineComment.GetLocation());
                context.ReportDiagnostic(diagnostic);
            }
        }
        private static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
            var typeDeclarations = syntaxRoot.DescendantNodes(IgnoreNodesInsideClassDeclarations).Where(NodeIsTypeDeclaration).ToList();

            if (typeDeclarations.Count <= 1) { return; }

            foreach (var node in typeDeclarations)
            {
                var identifier = ((BaseTypeDeclarationSyntax)node).Identifier;
                context.ReportDiagnostic(Diagnostic.Create(Rule, identifier.GetLocation(), identifier.Text));
            }
        }
        private static void HandleCloseBraceToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace();

            if (token.Parent is InterpolationSyntax)
            {
                if (precededBySpace)
                {
                    // Closing curly bracket must{ not} be {preceded} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), " not", "preceded"));
                }

                return;
            }

            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine = token.IsLastInLine();
            bool precedesSpecialCharacter;

            if (!followedBySpace && !lastInLine)
            {
                SyntaxToken nextToken = token.GetNextToken();
                precedesSpecialCharacter =
                    nextToken.IsKind(SyntaxKind.CloseParenToken)
                    || nextToken.IsKind(SyntaxKind.CommaToken)
                    || nextToken.IsKind(SyntaxKind.SemicolonToken);
            }
            else
            {
                precedesSpecialCharacter = false;
            }

            if (!precededBySpace)
            {
                // Closing curly bracket must{} be {preceded} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "preceded"));
            }

            if (!lastInLine && !precedesSpecialCharacter && !followedBySpace)
            {
                // Closing curly bracket must{} be {followed} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "followed"));
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var lastToken = context.Tree.GetRoot().GetLastToken(includeZeroWidth: true);

            if (lastToken.HasLeadingTrivia)
            {
                var leadingTrivia = lastToken.LeadingTrivia;

                var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(leadingTrivia);
                if (trailingWhitespaceIndex != -1)
                {
                    var textSpan = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, leadingTrivia[leadingTrivia.Count - 1].Span.End);
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, textSpan)));
                }
            }
        }
        private static void HandleSyntaxTreeAxtion(SyntaxTreeAnalysisContext context)
        {
            var root = context.Tree.GetRoot(context.CancellationToken);

            var fileHeader = FileHeaderHelpers.ParseFileHeader(root);
            if (fileHeader.IsMissing || fileHeader.IsMalformed)
            {
                // this will be handled by SA1633
                return;
            }

            if (fileHeader.GetElement("copyright") == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, fileHeader.GetLocation(context.Tree)));
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsWhitespaceOnly(context.CancellationToken))
            {
                // Handling of empty documents is now the responsibility of the analyzers
                return;
            }

            byte[] preamble = context.Tree.Encoding.GetPreamble();

            if (!IsUtf8Preamble(preamble))
            {
                ImmutableDictionary<string, string> properties = ImmutableDictionary<string, string>.Empty.SetItem(EncodingProperty, context.Tree.Encoding?.WebName ?? "<null>");
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(0, 0)), properties));
            }
        }
        private static void AnalyzeTree(SyntaxTreeAnalysisContext context)
        {
            var root = context.Tree.GetRoot();
            var allTrivia = root.DescendantTrivia();
            var commentTriva = allTrivia.Where(x => x.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                x.IsKind(SyntaxKind.MultiLineCommentTrivia)).ToList();

            foreach (var trivia in commentTriva)
            {
                //Only continue if the comment contains "sh!t"
                if (!trivia.ToString().Contains("sh!t")) continue;

                var diagnostic = Diagnostic.Create(Rule, trivia.GetLocation(), trivia.ToString());

                context.ReportDiagnostic(diagnostic);
            }
        }
        private static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsGenerated())
            {
                return;
            }

            var leadingTrivia = context.Tree.GetRoot().GetLeadingTrivia();

            if (!leadingTrivia.Any(x => x.IsKind(SyntaxKind.WhitespaceTrivia) || x.IsKind(SyntaxKind.EndOfLineTrivia)))
            {
                return;
            }

            var span = TextSpan.FromBounds(leadingTrivia.Span.Start, leadingTrivia.Span.End);
            var location = Location.Create(context.Tree, span);
            context.ReportDiagnostic(Diagnostic.Create(Rule, location));
        }
Ejemplo n.º 28
0
 private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation compilation)
 {
     if (context.IsGenerated()) return;
     if (!compilation.SyntaxTrees.Contains(context.Tree)) return;
     var semanticModel = compilation.GetSemanticModel(context.Tree);
     SyntaxNode root;
     if (!context.Tree.TryGetRoot(out root)) return;
     var types = GetTypesInRoot(root);
     foreach (var type in types)
     {
         var fieldDeclarations = type.ChildNodes().OfType<FieldDeclarationSyntax>();
         var variablesToMakeReadonly = GetCandidateVariables(semanticModel, fieldDeclarations);
         var typeSymbol = semanticModel.GetDeclaredSymbol(type);
         if (typeSymbol == null) continue;
         var methods = typeSymbol.GetAllMethodsIncludingFromInnerTypes();
         foreach (var method in methods)
         {
             foreach (var syntaxReference in method.DeclaringSyntaxReferences)
             {
                 var syntaxRefSemanticModel = syntaxReference.SyntaxTree.Equals(context.Tree)
                         ? semanticModel
                         : compilation.GetSemanticModel(syntaxReference.SyntaxTree);
                 var assignments = syntaxReference.GetSyntax().DescendantNodes().OfType<AssignmentExpressionSyntax>();
                 foreach (var assignment in assignments)
                 {
                     var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(assignment.Left).Symbol as IFieldSymbol;
                     if (fieldSymbol == null) continue;
                     if (method.MethodKind == MethodKind.StaticConstructor && fieldSymbol.IsStatic)
                         AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol, assignment);
                     else if (method.MethodKind == MethodKind.Constructor && !fieldSymbol.IsStatic)
                         AddVariableThatWasSkippedBeforeBecauseItLackedAInitializer(variablesToMakeReadonly, fieldSymbol, assignment);
                     else
                         RemoveVariableThatHasAssignment(variablesToMakeReadonly, fieldSymbol);
                 }
             }
         }
         foreach (var readonlyVariable in variablesToMakeReadonly.Values)
         {
             var props = new Dictionary<string, string> { { "identifier", readonlyVariable.Identifier.Text } }.ToImmutableDictionary();
             var diagnostic = Diagnostic.Create(Rule, readonlyVariable.GetLocation(), props, readonlyVariable.Identifier.Text);
             context.ReportDiagnostic(diagnostic);
         }
     }
 }
        private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
            var settings = _settingsHandler.GetArnolyzerSettingsForProject(context.Tree.FilePath);

            var classDeclarations =
                syntaxRoot.DescendantNodes(DoNotDescendIntoTypeDeclarations)
                          .Where(NodeIsPublicClassDeclaration)
                          .Cast<ClassDeclarationSyntax>().ToList();

            var propertyDeclarations = from node in classDeclarations
                                       from property in
                                           node.DescendantNodes()
                                               .Where(NodeIsPropertyDeclaration)
                                               .Cast<PropertyDeclarationSyntax>()
                                       where SyntaxNodeIsPublic(property.Modifiers) &&
                                             !AutoGenerated(property) &&
                                             !IgnoredFile(property, settings) &&
                                             !PropertyHasIgnoreRuleAttribute(property, SuppressionAttributes)
                                       select new
                                       {
                                           className = node.Identifier.Text,
                                           property
                                       };

            foreach (var propertyDeclaration in propertyDeclarations)
            {
                propertyDeclaration.property.DescendantNodes()
                                   .Where(p => p.IsKind(SyntaxKind.SetAccessorDeclaration))
                                   .Cast<AccessorDeclarationSyntax>()
                                   .Where(s => s.Modifiers.Count == 0)
                                   .TryFirst()
                                   .Match()
                                   .Some()
                                   .Do(setter => context.ReportDiagnostic(
                                       Diagnostic.Create(Rule,
                                                         setter.Keyword.GetLocation(),
                                                         propertyDeclaration.property.Identifier,
                                                         propertyDeclaration.className)))
                                   .IgnoreElse()
                                   .Exec();
            }
        }
        private static void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsGenerated())
            {
                return;
            }

            var lastToken = context.Tree.GetRoot().GetLastToken();
            var trailingTrivia = lastToken.TrailingTrivia;

            if (trailingTrivia.Count == 1 && trailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia))
            {
                return;
            }

            var span = TextSpan.FromBounds(lastToken.Span.Start, lastToken.Span.End);
            var location = Location.Create(context.Tree, span);
            context.ReportDiagnostic(Diagnostic.Create(Rule, location));
        }
        private static void HandleCloseBracketToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            // attribute brackets are handled separately
            if (token.Parent.IsKind(SyntaxKind.AttributeList))
            {
                return;
            }

            bool firstInLine     = token.IsFirstInLine();
            bool precededBySpace = firstInLine || token.IsPrecededByWhitespace();
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();
            bool precedesSpecialCharacter;

            // Tests for this rule have a lot of exclusions which are supposed to be caught by other rules
            bool suppressFollowingSpaceError = true;

            if (!lastInLine)
            {
                SyntaxToken nextToken = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKind.CloseBracketToken:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.CommaToken:
                case SyntaxKind.SemicolonToken:
                // TODO: "certain types of operator symbols"
                case SyntaxKind.DotToken:
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.CloseParenToken:
                    precedesSpecialCharacter = true;
                    break;

                case SyntaxKind.PlusPlusToken:
                case SyntaxKind.MinusMinusToken:
                    precedesSpecialCharacter    = true;
                    suppressFollowingSpaceError = false;
                    break;

                case SyntaxKind.GreaterThanToken:
                    precedesSpecialCharacter = nextToken.Parent.IsKind(SyntaxKind.TypeArgumentList);
                    break;

                case SyntaxKind.QuestionToken:
                    precedesSpecialCharacter = nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression);
                    break;

                case SyntaxKind.CloseBraceToken:
                    precedesSpecialCharacter = nextToken.Parent is InterpolationSyntax;
                    break;

                default:
                    precedesSpecialCharacter = false;
                    break;
                }
            }
            else
            {
                precedesSpecialCharacter = false;
            }

            if (!firstInLine && precededBySpace)
            {
                // Closing square bracket must{ not} be {preceded} by a space.
                var properties = new Dictionary <string, string>
                {
                    [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationPreceding,
                    [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                };
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "preceded"));
            }

            if (!lastInLine)
            {
                if (!precedesSpecialCharacter && !followedBySpace)
                {
                    // Closing square bracket must{} be {followed} by a space.
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionInsert
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), string.Empty, "followed"));
                }
                else if (precedesSpecialCharacter && followedBySpace && !suppressFollowingSpaceError)
                {
                    // Closing square brackets must {not} be {followed} by a space
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "followed"));
                }
            }
        }
        private static void HandleCloseParenToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace();
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();
            bool precedesStickyCharacter;
            bool allowEndOfLine = false;

            bool suppressFollowingSpaceError = false;

            SyntaxToken nextToken = token.GetNextToken();

            switch (nextToken.Kind())
            {
            case SyntaxKind.OpenParenToken:
            case SyntaxKind.CloseParenToken:
            case SyntaxKind.OpenBracketToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.QuestionToken:
                if (nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression))
                {
                    // allow a space for this case, but only if the ')' character is the last on the line
                    allowEndOfLine          = true;
                    precedesStickyCharacter = true;
                }
                else
                {
                    precedesStickyCharacter = false;
                }

                break;

            case SyntaxKind.PlusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryPlusExpression);

                // this will be reported as SA1022
                suppressFollowingSpaceError = true;
                break;

            case SyntaxKind.MinusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryMinusExpression);

                // this will be reported as SA1021
                suppressFollowingSpaceError = true;
                break;

            case SyntaxKind.DotToken:
                // allow a space for this case, but only if the ')' character is the last on the line
                allowEndOfLine          = true;
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.ColonToken:
                bool requireSpace =
                    nextToken.Parent.IsKind(SyntaxKind.ConditionalExpression) ||
                    nextToken.Parent.IsKind(SyntaxKind.BaseConstructorInitializer) ||
                    nextToken.Parent.IsKind(SyntaxKind.ThisConstructorInitializer);
                precedesStickyCharacter = !requireSpace;
                break;

            case SyntaxKind.PlusPlusToken:
            case SyntaxKind.MinusMinusToken:
                precedesStickyCharacter     = true;
                suppressFollowingSpaceError = false;
                break;

            case SyntaxKind.CloseBraceToken:
                precedesStickyCharacter = nextToken.Parent is InterpolationSyntax;
                break;

            default:
                precedesStickyCharacter = false;
                break;
            }

            switch (token.Parent.Kind())
            {
            case SyntaxKind.CastExpression:
                precedesStickyCharacter = true;
                break;

            default:
                break;
            }

            foreach (var trivia in token.TrailingTrivia)
            {
                if (trivia.IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    break;
                }
                else if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                         trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))
                {
                    lastInLine = false;
                    precedesStickyCharacter = false;
                    break;
                }
            }

            if (precededBySpace)
            {
                // Closing parenthesis must{ not} be {preceded} by a space.
                var properties = new Dictionary <string, string>
                {
                    [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationPreceding,
                    [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                };
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "preceded"));
            }

            if (!suppressFollowingSpaceError)
            {
                if (!precedesStickyCharacter && !followedBySpace && !lastInLine)
                {
                    // Closing parenthesis must{} be {followed} by a space.
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionInsert
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), string.Empty, "followed"));
                }
                else if (precedesStickyCharacter && followedBySpace && (!lastInLine || !allowEndOfLine))
                {
                    // Closing parenthesis must{ not} be {followed} by a space.
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "followed"));
                }
            }
        }
Ejemplo n.º 33
0
 /// <summary>
 /// Creates a new instance of the <see cref="ContextualLoggableGeneratorDiagnosticReceiver{T}"/> class that accepts only <see cref="SyntaxTreeAnalysisContext"/>.
 /// </summary>
 /// <param name="generator">Target <see cref="LoggableSourceGenerator"/>.</param>
 /// <param name="context">Context of this <see cref="ContextualLoggableGeneratorDiagnosticReceiver{T}"/>.</param>
 public static ContextualLoggableGeneratorDiagnosticReceiver <SyntaxTreeAnalysisContext> SyntaxTree(LoggableSourceGenerator generator, SyntaxTreeAnalysisContext context)
 {
     return(new ContextualLoggableGeneratorDiagnosticReceiver <SyntaxTreeAnalysisContext>(generator, (context, diag) => context.ReportDiagnostic(diag), context));
 }
        private static void HandleAsteriskToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool allowAtLineStart;
            bool allowAtLineEnd;
            bool allowPrecedingSpace;
            bool allowTrailingSpace;

            switch (token.Parent.Kind())
            {
            case SyntaxKind.PointerType:
                allowAtLineStart    = false;
                allowAtLineEnd      = true;
                allowPrecedingSpace = false;
                var nextToken = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.CloseParenToken:
                case SyntaxKind.AsteriskToken:
                    allowTrailingSpace = false;
                    break;

                default:
                    allowTrailingSpace = true;
                    break;
                }

                break;

            case SyntaxKind.PointerIndirectionExpression:
                allowAtLineStart   = true;
                allowAtLineEnd     = false;
                allowTrailingSpace = false;
                var prevToken = token.GetPreviousToken();
                switch (prevToken.Kind())
                {
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.CloseParenToken:
                    allowPrecedingSpace = false;
                    break;

                default:
                    allowPrecedingSpace = true;
                    break;
                }

                break;

            default:
                return;
            }

            bool firstInLine     = token.IsFirstInLine();
            bool precededBySpace = firstInLine || token.IsPrecededByWhitespace();
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();

            if (!allowAtLineStart && firstInLine)
            {
                // Dereference symbol '*' must {not appear at the beginning of a line}.
                var properties = TokenSpacingCodeFixProvider.RemovePreceding;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, "not appear at the beginning of a line"));
            }
            else if (!allowPrecedingSpace && precededBySpace)
            {
                // Dereference symbol '*' must {not be preceded by a space}.
                var properties = TokenSpacingCodeFixProvider.RemovePreceding;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, "not be preceded by a space"));
            }

            if (!allowAtLineEnd && lastInLine)
            {
                // Dereference symbol '*' must {not appear at the end of a line}.
                var properties = TokenSpacingCodeFixProvider.RemoveFollowing;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, "not appear at the end of a line"));
            }
            else if (!allowTrailingSpace && followedBySpace)
            {
                // Dereference symbol '*' must {not be followed by a space}.
                var properties = TokenSpacingCodeFixProvider.RemoveFollowing;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, "not be followed by a space"));
            }

            if (!followedBySpace && allowTrailingSpace)
            {
                // Dereference symbol '*' must {be followed by a space}.
                var properties = TokenSpacingCodeFixProvider.InsertFollowing;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, "be followed by a space"));
            }
        }
Ejemplo n.º 35
0
        private static void ReportIncorrectTabUsage(SyntaxTreeAnalysisContext context, IndentationSettings indentationSettings, ImmutableArray <TextSpan> excludedSpans)
        {
            SyntaxTree syntaxTree = context.Tree;
            SourceText sourceText = syntaxTree.GetText(context.CancellationToken);

            string completeText = sourceText.ToString();
            int    length       = completeText.Length;

            bool useTabs = indentationSettings.UseTabs;
            int  tabSize = indentationSettings.TabSize;

            int      excludedSpanIndex = 0;
            var      lastExcludedSpan  = new TextSpan(completeText.Length, 0);
            TextSpan nextExcludedSpan  = !excludedSpans.IsEmpty ? excludedSpans[0] : lastExcludedSpan;

            int lastLineStart = 0;

            for (int startIndex = 0; startIndex < length; startIndex++)
            {
                if (startIndex == nextExcludedSpan.Start)
                {
                    startIndex = nextExcludedSpan.End - 1;
                    excludedSpanIndex++;
                    nextExcludedSpan = excludedSpanIndex < excludedSpans.Length ? excludedSpans[excludedSpanIndex] : lastExcludedSpan;
                    continue;
                }

                int  tabCount       = 0;
                bool containsSpaces = false;
                bool tabAfterSpace  = false;
                switch (completeText[startIndex])
                {
                case ' ':
                    containsSpaces = true;
                    break;

                case '\t':
                    tabCount++;
                    break;

                case '\r':
                case '\n':
                    // Handle newlines. We can ignore CR/LF/CRLF issues because we are only tracking column position
                    // in a line, and not the line numbers themselves.
                    lastLineStart = startIndex + 1;
                    continue;

                default:
                    continue;
                }

                int endIndex;
                for (endIndex = startIndex + 1; endIndex < length; endIndex++)
                {
                    if (endIndex == nextExcludedSpan.Start)
                    {
                        break;
                    }

                    if (completeText[endIndex] == ' ')
                    {
                        containsSpaces = true;
                    }
                    else if (completeText[endIndex] == '\t')
                    {
                        tabCount++;
                        tabAfterSpace = containsSpaces;
                    }
                    else
                    {
                        break;
                    }
                }

                if (useTabs && startIndex == lastLineStart)
                {
                    // For the case we care about in the following condition (tabAfterSpace is false), spaceCount is
                    // the number of consecutive trailing spaces.
                    int spaceCount = (endIndex - startIndex) - tabCount;
                    if (tabAfterSpace || spaceCount >= tabSize)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                Location.Create(syntaxTree, TextSpan.FromBounds(startIndex, endIndex)),
                                ConvertToTabsProperties));
                    }
                }
                else
                {
                    if (tabCount > 0)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                Location.Create(syntaxTree, TextSpan.FromBounds(startIndex, endIndex)),
                                ConvertToSpacesProperties));
                    }
                }

                // Make sure to not analyze overlapping spans
                startIndex = endIndex - 1;
            }
        }
        private static void AnalyzeTree(SyntaxTreeAnalysisContext context, Compilation compilation)
        {
            if (context.IsGenerated())
            {
                return;
            }
            if (!compilation.SyntaxTrees.Contains(context.Tree))
            {
                return;
            }
            var        semanticModel = compilation.GetSemanticModel(context.Tree);
            SyntaxNode root;

            if (!context.Tree.TryGetRoot(out root))
            {
                return;
            }
            var types = GetTypesInRoot(root);

            foreach (var type in types)
            {
                var fieldDeclarations       = type.ChildNodes().OfType <FieldDeclarationSyntax>();
                var variablesToMakeReadonly = GetCandidateVariables(semanticModel, fieldDeclarations);
                var typeSymbol = semanticModel.GetDeclaredSymbol(type);
                if (typeSymbol == null)
                {
                    continue;
                }
                var methods = typeSymbol.GetAllMethodsIncludingFromInnerTypes();
                foreach (var method in methods)
                {
                    foreach (var syntaxReference in method.DeclaringSyntaxReferences)
                    {
                        var syntaxRefSemanticModel = syntaxReference.SyntaxTree.Equals(context.Tree)
                                ? semanticModel
                                : compilation.GetSemanticModel(syntaxReference.SyntaxTree);
                        var descendants = syntaxReference.GetSyntax().DescendantNodes().ToList();
                        var assignments = descendants.OfKind(SyntaxKind.SimpleAssignmentExpression,
                                                             SyntaxKind.AddAssignmentExpression, SyntaxKind.AndAssignmentExpression, SyntaxKind.DivideAssignmentExpression,
                                                             SyntaxKind.ExclusiveOrAssignmentExpression, SyntaxKind.LeftShiftAssignmentExpression, SyntaxKind.ModuloAssignmentExpression,
                                                             SyntaxKind.MultiplyAssignmentExpression, SyntaxKind.OrAssignmentExpression, SyntaxKind.RightShiftAssignmentExpression,
                                                             SyntaxKind.SubtractAssignmentExpression);
                        foreach (AssignmentExpressionSyntax assignment in assignments)
                        {
                            var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(assignment.Left).Symbol as IFieldSymbol;
                            VerifyVariable(variablesToMakeReadonly, method, syntaxRefSemanticModel, assignment, fieldSymbol);
                        }
                        var postFixUnaries = descendants.OfKind(SyntaxKind.PostIncrementExpression, SyntaxKind.PostDecrementExpression);
                        foreach (PostfixUnaryExpressionSyntax postFixUnary in postFixUnaries)
                        {
                            var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(postFixUnary.Operand).Symbol as IFieldSymbol;
                            VerifyVariable(variablesToMakeReadonly, method, syntaxRefSemanticModel, postFixUnary, fieldSymbol);
                        }
                        var preFixUnaries = descendants.OfKind(SyntaxKind.PreDecrementExpression, SyntaxKind.PreIncrementExpression);
                        foreach (PrefixUnaryExpressionSyntax preFixUnary in preFixUnaries)
                        {
                            var fieldSymbol = syntaxRefSemanticModel.GetSymbolInfo(preFixUnary.Operand).Symbol as IFieldSymbol;
                            VerifyVariable(variablesToMakeReadonly, method, syntaxRefSemanticModel, preFixUnary, fieldSymbol);
                        }
                    }
                }
                foreach (var readonlyVariable in variablesToMakeReadonly.Values)
                {
                    var props = new Dictionary <string, string> {
                        { "identifier", readonlyVariable.Identifier.Text }
                    }.ToImmutableDictionary();
                    var diagnostic = Diagnostic.Create(Rule, readonlyVariable.GetLocation(), props, readonlyVariable.Identifier.Text);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
Ejemplo n.º 37
0
 private void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     context.ReportDiagnostic(Diagnostic.Create(
                                  Descriptor,
                                  Location.Create(context.Tree, new TextSpan(0, 0))));
 }
 private void Analyze(SyntaxTreeAnalysisContext context)
 => context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(1000, 2000))));
Ejemplo n.º 39
0
        private void HandleSemicolonToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            // check for a following space
            bool missingFollowingSpace = true;

            if (token.HasTrailingTrivia)
            {
                if (token.TrailingTrivia.First().IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    missingFollowingSpace = false;
                }
                else if (token.TrailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    missingFollowingSpace = false;
                }
            }
            else
            {
                SyntaxToken nextToken = token.GetNextToken();
                if (nextToken.IsKind(SyntaxKind.CloseParenToken))
                {
                    // Special handling for the following case:
                    // for (; ;)
                    missingFollowingSpace = false;
                }
            }

            bool hasPrecedingSpace    = false;
            bool ignorePrecedingSpace = false;

            if (!token.HasLeadingTrivia)
            {
                // only the first token on the line has leading trivia, and those are ignored
                SyntaxToken precedingToken = token.GetPreviousToken();
                if (precedingToken.HasTrailingTrivia)
                {
                    hasPrecedingSpace = true;
                }

                if (precedingToken.IsKind(SyntaxKind.SemicolonToken))
                {
                    // Special handling for the following case:
                    // for (; ;)
                    ignorePrecedingSpace = true;
                }
            }

            if (missingFollowingSpace)
            {
                // semicolon must{} be {followed} by a space
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "followed"));
            }

            if (hasPrecedingSpace && !ignorePrecedingSpace)
            {
                // semicolon must{ not} be {preceded} by a space
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), " not", "preceded"));
            }
        }
Ejemplo n.º 40
0
        private static void HandleGreaterThanToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            switch (token.Parent.Kind())
            {
            case SyntaxKind.TypeArgumentList:
            case SyntaxKind.TypeParameterList:
                break;

            default:
                // not a generic bracket
                return;
            }

            bool firstInLine     = token.IsFirstInLine();
            bool lastInLine      = token.IsLastInLine();
            bool precededBySpace = firstInLine || token.IsPrecededByWhitespace();
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool allowTrailingNoSpace;
            bool allowTrailingSpace;

            if (!lastInLine)
            {
                SyntaxToken nextToken = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKind.OpenParenToken:
                // DotToken isn't listed above, but it's required for reasonable member access formatting
                case SyntaxKind.DotToken:
                // CommaToken isn't listed above, but it's required for reasonable nested generic type arguments formatting
                case SyntaxKind.CommaToken:
                // OpenBracketToken isn't listed above, but it's required for reasonable array type formatting
                case SyntaxKind.OpenBracketToken:
                // SemicolonToken isn't listed above, but it's required for reasonable using alias declaration formatting
                case SyntaxKind.SemicolonToken:
                    allowTrailingNoSpace = true;
                    allowTrailingSpace   = false;
                    break;

                case SyntaxKind.CloseParenToken:
                case SyntaxKind.GreaterThanToken:
                    allowTrailingNoSpace = true;
                    allowTrailingSpace   = true;
                    break;

                case SyntaxKind.QuestionToken:
                    allowTrailingNoSpace = nextToken.Parent.IsKind(SyntaxKind.NullableType);
                    allowTrailingSpace   = true;
                    break;

                default:
                    allowTrailingNoSpace = false;
                    allowTrailingSpace   = true;
                    break;
                }
            }
            else
            {
                allowTrailingNoSpace = true;
                allowTrailingSpace   = true;
            }

            if (!firstInLine && precededBySpace)
            {
                // Closing generic bracket must{ not} be {preceded} by a space.
                var properties = new Dictionary <string, string>
                {
                    [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationPreceding,
                    [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                };
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "preceded"));
            }

            if (!lastInLine)
            {
                if (!allowTrailingNoSpace && !followedBySpace)
                {
                    // Closing generic bracket must{} be {followed} by a space.
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionInsert
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), string.Empty, "followed"));
                }
                else if (!allowTrailingSpace && followedBySpace)
                {
                    // Closing generic bracket must{ not} be {followed} by a space.
                    var properties = new Dictionary <string, string>
                    {
                        [OpenCloseSpacingCodeFixProvider.LocationKey] = OpenCloseSpacingCodeFixProvider.LocationFollowing,
                        [OpenCloseSpacingCodeFixProvider.ActionKey]   = OpenCloseSpacingCodeFixProvider.ActionRemove
                    };
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties.ToImmutableDictionary(), " not", "followed"));
                }
            }
        }
Ejemplo n.º 41
0
        private void ProcessMemberDeclaration(
            SyntaxTreeAnalysisContext context, SyntaxGenerator generator,
            CodeStyleOption <AccessibilityModifiersRequired> option, MemberDeclarationSyntax member)
        {
            if (member.IsKind(SyntaxKind.NamespaceDeclaration, out NamespaceDeclarationSyntax namespaceDeclaration))
            {
                ProcessMembers(context, generator, option, namespaceDeclaration.Members);
            }

            // If we have a class or struct, recurse inwards.
            if (member.IsKind(SyntaxKind.ClassDeclaration, out TypeDeclarationSyntax typeDeclaration) ||
                member.IsKind(SyntaxKind.StructDeclaration, out typeDeclaration))
            {
                ProcessMembers(context, generator, option, typeDeclaration.Members);
            }

#if false
            // Add this once we have the language version for C# that supports accessibility
            // modifiers on interface methods.
            if (option.Value == AccessibilityModifiersRequired.Always &&
                member.IsKind(SyntaxKind.InterfaceDeclaration, out typeDeclaration))
            {
                // Only recurse into an interface if the user wants accessibility modifiers on
                ProcessTypeDeclaration(context, generator, option, typeDeclaration);
            }
#endif

            // Have to have a name to report the issue on.
            var name = member.GetNameToken();
            if (name.Kind() == SyntaxKind.None)
            {
                return;
            }

            // Certain members never have accessibility. Don't bother reporting on them.
            if (!generator.CanHaveAccessibility(member))
            {
                return;
            }

            // This analyzer bases all of its decisions on the accessibility
            var accessibility = generator.GetAccessibility(member);

            // Omit will flag any accessibility values that exist and are default
            // The other options will remove or ignore accessibility
            var isOmit = option.Value == AccessibilityModifiersRequired.OmitIfDefault;

            if (isOmit)
            {
                if (accessibility == Accessibility.NotApplicable)
                {
                    return;
                }

                var parentKind = member.Parent.Kind();
                switch (parentKind)
                {
                // Check for default modifiers in namespace and outside of namespace
                case SyntaxKind.CompilationUnit:
                case SyntaxKind.NamespaceDeclaration:
                {
                    // Default is internal
                    if (accessibility != Accessibility.Internal)
                    {
                        return;
                    }
                }
                break;

                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.StructDeclaration:
                {
                    // Inside a type, default is private
                    if (accessibility != Accessibility.Private)
                    {
                        return;
                    }
                }
                break;

                default:
                    return;     // Unknown parent kind, don't do anything
                }
            }
            else
            {
                // Mode is always, so we have to flag missing modifiers
                if (accessibility != Accessibility.NotApplicable)
                {
                    return;
                }
            }

            // Have an issue to flag, either add or remove. Report issue to user.
            var additionalLocations = ImmutableArray.Create(member.GetLocation());
            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         name.GetLocation(),
                                         option.Notification.Severity,
                                         additionalLocations: additionalLocations,
                                         properties: null));
        }
Ejemplo n.º 42
0
        /// <summary>
        /// Scans an entire document for lines with trailing whitespace.
        /// </summary>
        /// <param name="context">The context that provides the document to scan.</param>
        private void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var root = context.Tree.GetRoot(context.CancellationToken);
            var text = root.GetText();

            foreach (var trivia in root.DescendantTrivia(descendIntoTrivia: true))
            {
                switch (trivia.Kind())
                {
                case SyntaxKind.WhitespaceTrivia:
                    bool             reportWarning = false;
                    var              token         = trivia.Token;
                    SyntaxTriviaList triviaList;
                    if (token.LeadingTrivia.Contains(trivia))
                    {
                        triviaList = token.LeadingTrivia;
                    }
                    else
                    {
                        triviaList = token.TrailingTrivia;
                    }

                    bool foundWhitespace = false;
                    foreach (var innerTrivia in triviaList)
                    {
                        if (!foundWhitespace)
                        {
                            if (innerTrivia.Equals(trivia))
                            {
                                foundWhitespace = true;
                            }

                            continue;
                        }

                        if (innerTrivia.IsKind(SyntaxKind.EndOfLineTrivia))
                        {
                            reportWarning = true;
                        }

                        break;
                    }

                    if (reportWarning)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, trivia.GetLocation()));
                    }

                    break;

                case SyntaxKind.SingleLineCommentTrivia:
                    TextSpan trailingWhitespace = FindTrailingWhitespace(text, trivia.Span);
                    if (!trailingWhitespace.IsEmpty)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                    }

                    break;

                case SyntaxKind.MultiLineCommentTrivia:
                case SyntaxKind.SingleLineDocumentationCommentTrivia:
                    var line = text.Lines.GetLineFromPosition(trivia.Span.Start);
                    do
                    {
                        trailingWhitespace = FindTrailingWhitespace(text, line.Span);
                        if (!trailingWhitespace.IsEmpty)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                        }

                        if (line.EndIncludingLineBreak == text.Length)
                        {
                            // We've reached the end of the document.
                            break;
                        }

                        line = text.Lines.GetLineFromPosition(line.EndIncludingLineBreak + 1);
                    }while (line.End <= trivia.Span.End);

                    break;

                case SyntaxKind.IfDirectiveTrivia:
                case SyntaxKind.ElifDirectiveTrivia:
                case SyntaxKind.ElseDirectiveTrivia:
                case SyntaxKind.EndIfDirectiveTrivia:
                case SyntaxKind.DefineDirectiveTrivia:
                case SyntaxKind.UndefDirectiveTrivia:
                case SyntaxKind.WarningDirectiveTrivia:
                case SyntaxKind.ErrorDirectiveTrivia:
                case SyntaxKind.RegionDirectiveTrivia:
                case SyntaxKind.EndRegionDirectiveTrivia:
                    trailingWhitespace = FindTrailingWhitespace(text, trivia.Span);
                    if (!trailingWhitespace.IsEmpty)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                    }

                    break;

                default:
                    break;
                }
            }
        }
        private void HandleOpenBraceToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace;
            bool firstInLine;
            bool allowLeadingSpace;
            bool allowLeadingNoSpace;

            bool followedBySpace;
            bool lastInLine;

            firstInLine = token.HasLeadingTrivia || token.GetLocation()?.GetMappedLineSpan().StartLinePosition.Character == 0;
            if (firstInLine)
            {
                precededBySpace     = true;
                allowLeadingSpace   = true;
                allowLeadingNoSpace = true;
            }
            else
            {
                SyntaxToken precedingToken = token.GetPreviousToken();
                precededBySpace = precedingToken.HasTrailingTrivia;
                switch (precedingToken.Kind())
                {
                case SyntaxKind.OpenParenToken:
                    allowLeadingNoSpace = true;
                    allowLeadingSpace   = false;
                    break;

                default:
                    allowLeadingNoSpace = false;
                    allowLeadingSpace   = true;
                    break;
                }
            }

            followedBySpace = token.HasTrailingTrivia;
            lastInLine      = followedBySpace && token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia);

            if (token.Parent is InterpolationSyntax)
            {
                // Don't report for interpolation string inlets
                return;
            }

            if (!firstInLine)
            {
                if (!allowLeadingSpace && precededBySpace)
                {
                    // Opening curly bracket must{ not} be {preceded} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), " not", "preceded"));
                }
                else if (!allowLeadingNoSpace && !precededBySpace)
                {
                    // Opening curly bracket must{} be {preceded} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "preceded"));
                }
            }

            if (!lastInLine && !followedBySpace)
            {
                // Opening curly bracket must{} be {followed} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "followed"));
            }
        }
        private void HandleAsteriskToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool allowAtLineStart;
            bool allowAtLineEnd;
            bool allowPrecedingSpace;
            bool allowPrecedingNoSpace;
            bool allowTrailingSpace;
            bool allowTrailingNoSpace;

            switch (token.Parent.Kind())
            {
            case SyntaxKind.PointerType:
                allowAtLineStart      = false;
                allowAtLineEnd        = true;
                allowPrecedingNoSpace = true;
                allowPrecedingSpace   = false;
                allowTrailingNoSpace  = true;
                allowTrailingSpace    = true;
                break;

            case SyntaxKind.PointerIndirectionExpression:
                allowAtLineStart      = true;
                allowAtLineEnd        = false;
                allowPrecedingNoSpace = true;
                allowPrecedingSpace   = true;
                allowTrailingNoSpace  = true;
                allowTrailingSpace    = false;
                break;

            default:
                return;
            }

            bool precededBySpace;
            bool firstInLine;

            firstInLine = token.HasLeadingTrivia || token.GetLocation()?.GetMappedLineSpan().StartLinePosition.Character == 0;
            if (firstInLine)
            {
                precededBySpace = true;
            }
            else
            {
                SyntaxToken precedingToken = token.GetPreviousToken();
                precededBySpace = precedingToken.HasTrailingTrivia;
            }

            bool followedBySpace = token.HasTrailingTrivia;
            bool lastInLine      = followedBySpace && token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia);

            if (!allowAtLineStart && firstInLine)
            {
                // Dereference symbol '*' must {not appear at the beginning of a line}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "not appear at the beginning of a line"));
            }

            if (!allowAtLineEnd && lastInLine)
            {
                // Dereference symbol '*' must {not appear at the end of a line}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "not appear at the end of a line"));
            }

            if (!allowPrecedingSpace && precededBySpace)
            {
                // Dereference symbol '*' must {not be preceded by a space}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "not be preceded by a space"));
            }
            else if (!allowPrecedingNoSpace && !precededBySpace)
            {
                // Dereference symbol '*' must {be preceded by a space}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "be preceded by a space"));
            }

            if (!allowTrailingSpace && followedBySpace)
            {
                // Dereference symbol '*' must {not be followed by a space}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "not be followed by a space"));
            }
            else if (!allowTrailingNoSpace && !followedBySpace)
            {
                // Dereference symbol '*' must {be followed by a space}.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), "be followed by a space"));
            }
        }
        private static void HandleCloseParenToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace(context.CancellationToken);
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();
            bool precedesStickyCharacter;
            bool allowEndOfLine = false;
            bool preserveLayout = false;

            bool suppressFollowingSpaceError = false;

            SyntaxToken nextToken = token.GetNextToken();

            switch (nextToken.Kind())
            {
            case SyntaxKind.OpenParenToken:
                // Allow a space between an open and a close paren when:
                // - they are part of an if statement
                // - they are on the same line
                // - the open paren is part of a parenthesized expression or a tuple expression.
                precedesStickyCharacter =
                    !(token.Parent.IsKind(SyntaxKind.IfStatement) &&
                      (token.GetLine() == nextToken.GetLine()) &&
                      (nextToken.Parent.IsKind(SyntaxKind.ParenthesizedExpression) || nextToken.Parent.IsKind(SyntaxKindEx.TupleExpression)));
                break;

            case SyntaxKind.CloseParenToken:
            case SyntaxKind.OpenBracketToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
            case SyntaxKind.DoubleQuoteToken:
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.GreaterThanToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.TypeArgumentList);
                break;

            case SyntaxKind.QuestionToken:
                if (nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression))
                {
                    // allow a space for this case, but only if the ')' character is the last on the line
                    allowEndOfLine          = true;
                    precedesStickyCharacter = true;
                }
                else
                {
                    // A space follows unless this is a nullable tuple type
                    precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.NullableType);
                }

                break;

            case SyntaxKind.PlusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryPlusExpression);

                // this will be reported as SA1022
                suppressFollowingSpaceError = precedesStickyCharacter;
                break;

            case SyntaxKind.MinusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryMinusExpression);

                // this will be reported as SA1021
                suppressFollowingSpaceError = precedesStickyCharacter;
                break;

            case SyntaxKind.DotToken:
                // allow a space for this case, but only if the ')' character is the last on the line
                allowEndOfLine          = true;
                precedesStickyCharacter = true;

                preserveLayout = nextToken.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression);
                break;

            case SyntaxKind.MinusGreaterThanToken:
                // allow a space for this case, but only if the ')' character is the last on the line
                allowEndOfLine          = true;
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.ColonToken:
                bool requireSpace =
                    nextToken.Parent.IsKind(SyntaxKind.ConditionalExpression) ||
                    nextToken.Parent.IsKind(SyntaxKind.BaseConstructorInitializer) ||
                    nextToken.Parent.IsKind(SyntaxKind.ThisConstructorInitializer);
                precedesStickyCharacter = !requireSpace;
                break;

            case SyntaxKind.PlusPlusToken:
            case SyntaxKind.MinusMinusToken:
                precedesStickyCharacter     = true;
                suppressFollowingSpaceError = false;
                break;

            case SyntaxKind.CloseBraceToken:
                precedesStickyCharacter = nextToken.Parent is InterpolationSyntax;
                break;

            default:
                precedesStickyCharacter = false;
                break;
            }

            switch (token.Parent.Kind())
            {
            case SyntaxKind.CastExpression:
                precedesStickyCharacter = true;
                break;

            default:
                break;
            }

            foreach (var trivia in token.TrailingTrivia)
            {
                if (trivia.IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    break;
                }
                else if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                         trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))
                {
                    lastInLine = false;
                    precedesStickyCharacter = false;
                    break;
                }
            }

            if (precededBySpace)
            {
                // Closing parenthesis should{ not} be {preceded} by a space.
                ImmutableDictionary <string, string> properties;

                if (preserveLayout)
                {
                    properties = TokenSpacingProperties.RemovePrecedingPreserveLayout;
                }
                else
                {
                    properties = token.IsFirstInLine()
                        ? TokenSpacingProperties.RemovePreceding
                        : TokenSpacingProperties.RemoveImmediatePreceding;
                }

                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, " not", "preceded"));
            }

            if (!suppressFollowingSpaceError)
            {
                if (!precedesStickyCharacter && !followedBySpace && !lastInLine)
                {
                    // Closing parenthesis should{} be {followed} by a space.
                    var properties = TokenSpacingProperties.InsertFollowing;
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, string.Empty, "followed"));
                }
                else if (precedesStickyCharacter && followedBySpace && (!lastInLine || !allowEndOfLine))
                {
                    // Closing parenthesis should{ not} be {followed} by a space.
                    var properties = TokenSpacingProperties.RemoveFollowing;
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, " not", "followed"));
                }
            }
        }
 public void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     context.ReportDiagnostic(Diagnostic.Create(s_syntaxDiagnosticDescriptor, context.Tree.GetRoot().GetFirstToken().GetLocation()));
 }
        private static void HandleAsteriskToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool allowAtLineStart;
            bool allowAtLineEnd;
            bool allowPrecedingSpace;
            bool allowTrailingSpace;

            switch (token.Parent.Kind())
            {
            case SyntaxKindEx.FunctionPointerType:
                allowAtLineStart    = true;
                allowAtLineEnd      = true;
                allowPrecedingSpace = false;
                var nextToken = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKindEx.ManagedKeyword:
                case SyntaxKindEx.UnmanagedKeyword:
                    allowTrailingSpace = true;
                    break;

                default:
                    allowTrailingSpace = false;
                    break;
                }

                break;

            case SyntaxKind.PointerType when token.Parent.Parent.IsKind(SyntaxKindEx.FunctionPointerParameter):
                allowAtLineStart = true;

                allowAtLineEnd      = true;
                allowPrecedingSpace = false;
                allowTrailingSpace  = false;
                break;

            case SyntaxKind.PointerType:
                allowAtLineStart    = false;
                allowAtLineEnd      = true;
                allowPrecedingSpace = false;
                nextToken           = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.CloseParenToken:
                case SyntaxKind.AsteriskToken:
                    allowTrailingSpace = false;
                    break;

                default:
                    allowTrailingSpace = true;
                    break;
                }

                break;

            case SyntaxKind.PointerIndirectionExpression:
                allowAtLineStart   = true;
                allowAtLineEnd     = false;
                allowTrailingSpace = false;
                var prevToken = token.GetPreviousToken();
                switch (prevToken.Kind())
                {
                case SyntaxKind.OpenBracketToken:
                case SyntaxKind.OpenParenToken:
                case SyntaxKind.CloseParenToken:
                    allowPrecedingSpace = false;
                    break;

                default:
                    allowPrecedingSpace = true;
                    break;
                }

                break;

            default:
                return;
            }

            bool firstInLine     = token.IsFirstInLine();
            bool precededBySpace = firstInLine || token.IsPrecededByWhitespace(context.CancellationToken);
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();

            if (!allowAtLineStart && firstInLine)
            {
                // Dereference symbol '*' should {not appear at the beginning of a line}.
                var properties = TokenSpacingProperties.RemovePreceding;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotAtBeginningOfLine, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
            }
            else if (!allowPrecedingSpace && precededBySpace)
            {
                // Dereference symbol '*' should {not be preceded by a space}.
                var properties = TokenSpacingProperties.RemovePreceding;
                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotPreceded, token.GetLocation(), properties));
            }

            if (!allowAtLineEnd && lastInLine)
            {
                // Dereference symbol '*' should {not appear at the end of a line}.
                var properties = TokenSpacingProperties.RemoveFollowing;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotAtEndOfLine, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
            }
            else if (!allowTrailingSpace && followedBySpace)
            {
                // Dereference symbol '*' should {not be followed by a space}.
                var properties = TokenSpacingProperties.RemoveFollowing;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotFollowed, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
            }

            if (!followedBySpace && allowTrailingSpace)
            {
                // Dereference symbol '*' should {be followed by a space}.
                var properties = TokenSpacingProperties.InsertFollowing;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                context.ReportDiagnostic(Diagnostic.Create(DescriptorFollowed, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
            }
        }
Ejemplo n.º 48
0
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context, StyleCopSettings settings)
        {
            var      endOfFileToken = context.Tree.GetRoot().GetLastToken(includeZeroWidth: true);
            TextSpan reportedSpan   = new TextSpan(endOfFileToken.SpanStart, 0);

            SyntaxTrivia precedingTrivia = default(SyntaxTrivia);
            bool         checkPrecedingToken;

            if (endOfFileToken.HasLeadingTrivia)
            {
                var leadingTrivia           = endOfFileToken.LeadingTrivia;
                var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(leadingTrivia);
                if (trailingWhitespaceIndex > 0)
                {
                    checkPrecedingToken = false;
                    reportedSpan        = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End);
                    precedingTrivia     = leadingTrivia[trailingWhitespaceIndex - 1];
                }
                else if (trailingWhitespaceIndex == 0)
                {
                    checkPrecedingToken = true;
                    reportedSpan        = TextSpan.FromBounds(leadingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End);
                }
                else
                {
                    checkPrecedingToken = false;
                    precedingTrivia     = leadingTrivia.Last();
                }
            }
            else
            {
                checkPrecedingToken = true;
            }

            if (checkPrecedingToken)
            {
                var previousToken           = endOfFileToken.GetPreviousToken(includeZeroWidth: true, includeSkipped: true, includeDirectives: true, includeDocumentationComments: true);
                var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia);
                if (trailingWhitespaceIndex > 0)
                {
                    reportedSpan    = TextSpan.FromBounds(previousToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End);
                    precedingTrivia = previousToken.TrailingTrivia[trailingWhitespaceIndex - 1];
                }
                else if (trailingWhitespaceIndex == 0)
                {
                    reportedSpan    = TextSpan.FromBounds(previousToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End);
                    precedingTrivia = default(SyntaxTrivia);
                }
                else
                {
                    if (previousToken.TrailingTrivia.Count > 0)
                    {
                        precedingTrivia = previousToken.TrailingTrivia.Last();
                    }
                }
            }

            if (precedingTrivia.IsDirective)
            {
                DirectiveTriviaSyntax directiveTriviaSyntax = precedingTrivia.GetStructure() as DirectiveTriviaSyntax;
                if (directiveTriviaSyntax != null && directiveTriviaSyntax.EndOfDirectiveToken.HasTrailingTrivia)
                {
                    var trailingWhitespaceIndex = TriviaHelper.IndexOfTrailingWhitespace(directiveTriviaSyntax.EndOfDirectiveToken.TrailingTrivia);
                    if (trailingWhitespaceIndex >= 0)
                    {
                        reportedSpan = TextSpan.FromBounds(directiveTriviaSyntax.EndOfDirectiveToken.TrailingTrivia[trailingWhitespaceIndex].SpanStart, reportedSpan.End);
                    }
                }
            }
            else if (precedingTrivia.IsKind(SyntaxKind.EndOfLineTrivia))
            {
                reportedSpan = TextSpan.FromBounds(precedingTrivia.SpanStart, reportedSpan.End);
            }

            SourceText sourceText             = context.Tree.GetText(context.CancellationToken);
            string     trailingWhitespaceText = sourceText.ToString(reportedSpan);
            int        firstNewline           = trailingWhitespaceText.IndexOf('\n');
            int        secondNewline          = firstNewline >= 0 ? trailingWhitespaceText.IndexOf('\n', firstNewline + 1) : -1;

            DiagnosticDescriptor descriptorToReport;

            switch (settings.LayoutRules.NewlineAtEndOfFile)
            {
            case OptionSetting.Omit:
                if (firstNewline < 0)
                {
                    return;
                }

                descriptorToReport = DescriptorOmit;
                break;

            case OptionSetting.Require:
                if (firstNewline >= 0 && firstNewline == trailingWhitespaceText.Length - 1)
                {
                    return;
                }

                descriptorToReport = DescriptorRequire;
                break;

            case OptionSetting.Allow:
            default:
                if (secondNewline < 0)
                {
                    // 1. A newline is allowed but not required
                    // 2. If a newline is included, it cannot be followed by whitespace
                    if (firstNewline < 0 || firstNewline == trailingWhitespaceText.Length - 1)
                    {
                        return;
                    }
                }

                descriptorToReport = DescriptorAllow;
                break;
            }

            context.ReportDiagnostic(Diagnostic.Create(descriptorToReport, Location.Create(context.Tree, reportedSpan)));
        }
Ejemplo n.º 49
0
        /// <summary>
        /// Scans an entire document for lines with trailing whitespace.
        /// </summary>
        /// <param name="context">The context that provides the document to scan.</param>
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            if (context.Tree.IsWhitespaceOnly(context.CancellationToken))
            {
                // Handling of empty documents is now the responsibility of the analyzers
                return;
            }

            var root = context.Tree.GetRoot(context.CancellationToken);
            var text = context.Tree.GetText(context.CancellationToken);

            SyntaxTrivia previousTrivia = default;

            foreach (var trivia in root.DescendantTrivia(descendIntoTrivia: true))
            {
                switch (trivia.Kind())
                {
                case SyntaxKind.WhitespaceTrivia:
                    break;

                case SyntaxKind.EndOfLineTrivia:
                    if (previousTrivia.Span.End < trivia.SpanStart)
                    {
                        // Some token appeared between the previous trivia and the end of the line.
                        break;
                    }

                    if (previousTrivia.IsKind(SyntaxKind.WhitespaceTrivia))
                    {
                        // Report warning for whitespace token followed by the end of a line
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, previousTrivia.GetLocation()));
                    }
                    else if (previousTrivia.IsKind(SyntaxKind.PreprocessingMessageTrivia))
                    {
                        TextSpan trailinMessageWhitespace = FindTrailingWhitespace(text, previousTrivia.Span);
                        if (!trailinMessageWhitespace.IsEmpty)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailinMessageWhitespace)));
                        }
                    }

                    break;

                case SyntaxKind.SingleLineCommentTrivia:
                    TextSpan trailingWhitespace = FindTrailingWhitespace(text, trivia.Span);
                    if (!trailingWhitespace.IsEmpty)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                    }

                    break;

                case SyntaxKind.MultiLineCommentTrivia:
                    var line = text.Lines.GetLineFromPosition(trivia.Span.Start);
                    while (line.End <= trivia.Span.End)
                    {
                        trailingWhitespace = FindTrailingWhitespace(text, line.Span);
                        if (!trailingWhitespace.IsEmpty)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                        }

                        if (line.EndIncludingLineBreak == text.Length)
                        {
                            // We've reached the end of the document.
                            break;
                        }

                        line = text.Lines.GetLineFromPosition(line.EndIncludingLineBreak + 1);
                    }

                    break;

                case SyntaxKind.SingleLineDocumentationCommentTrivia:
                case SyntaxKind.MultiLineDocumentationCommentTrivia:
                    SyntaxToken previousToken = default;
                    foreach (var token in trivia.GetStructure().DescendantTokens(descendIntoTrivia: true))
                    {
                        if (token.IsKind(SyntaxKind.XmlTextLiteralNewLineToken) &&
                            previousToken.IsKind(SyntaxKind.XmlTextLiteralToken) &&
                            previousToken.Span.End == token.SpanStart)
                        {
                            trailingWhitespace = FindTrailingWhitespace(text, previousToken.Span);
                            if (!trailingWhitespace.IsEmpty)
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, trailingWhitespace)));
                            }
                        }

                        previousToken = token;
                    }

                    break;

                default:
                    break;
                }

                previousTrivia = trivia;
            }

            if (previousTrivia.IsKind(SyntaxKind.WhitespaceTrivia) && previousTrivia.Span.End == previousTrivia.SyntaxTree.Length)
            {
                // Report whitespace at the end of the last line in the document
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, previousTrivia.GetLocation()));
            }
        }
        private static void HandleSyntaxTree(SyntaxTreeAnalysisContext context)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);
            var previousCommentNotOnOwnLine = false;

            foreach (var trivia in syntaxRoot.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia)))
            {
                if (trivia.FullSpan.Start == 0)
                {
                    // skip the trivia if it is at the start of the file
                    previousCommentNotOnOwnLine = false;
                    continue;
                }

                if (trivia.ToString().StartsWith("////", StringComparison.Ordinal))
                {
                    // ignore commented out code
                    previousCommentNotOnOwnLine = false;
                    continue;
                }

                int triviaIndex;
                var triviaList = TriviaHelper.GetContainingTriviaList(trivia, out triviaIndex);

                if (!IsOnOwnLine(triviaList, triviaIndex))
                {
                    // ignore comments after other code elements.
                    previousCommentNotOnOwnLine = true;
                    continue;
                }

                if (IsPrecededByBlankLine(triviaList, triviaIndex))
                {
                    // allow properly formatted blank line comments.
                    previousCommentNotOnOwnLine = false;
                    continue;
                }

                if (!previousCommentNotOnOwnLine && IsPrecededBySingleLineCommentOrDocumentation(triviaList, triviaIndex))
                {
                    // allow consecutive single line comments.
                    previousCommentNotOnOwnLine = false;
                    continue;
                }

                previousCommentNotOnOwnLine = false;

                if (IsAtStartOfScope(trivia))
                {
                    // allow single line comment at scope start.
                    continue;
                }

                if (IsPrecededByDirectiveTrivia(triviaList, triviaIndex))
                {
                    // allow single line comment that is preceded by some directive trivia (if, elif, else)
                    continue;
                }

                var diagnosticSpan = TextSpan.FromBounds(trivia.SpanStart, trivia.SpanStart + 2);
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, diagnosticSpan)));
            }
        }
Ejemplo n.º 51
0
        private static void HandleSyntaxTreeAnalysis(SyntaxTreeAnalysisContext context, ImmutableDictionary <string, ReportDiagnostic> specificDiagnosticOptions)
        {
            var syntaxRoot = context.Tree.GetRoot(context.CancellationToken);

            foreach (var trivia in syntaxRoot.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia)))
            {
                if (trivia.ToString().StartsWith("////", StringComparison.Ordinal))
                {
                    // ignore commented out code
                    continue;
                }

                int triviaIndex;

                // PERF: Explicitly cast to IReadOnlyList so we only box once.
                var triviaList = TriviaHelper.GetContainingTriviaList(trivia, out triviaIndex);

                if (!IsOnOwnLine(triviaList, triviaIndex))
                {
                    // ignore comments after other code elements.
                    continue;
                }

                if (IsPartOfFileHeader(triviaList, triviaIndex))
                {
                    // ignore comments that are part of the file header.
                    continue;
                }

                var trailingBlankLineCount = GetTrailingBlankLineCount(triviaList, ref triviaIndex);
                if (trailingBlankLineCount == 0)
                {
                    // ignore comments that are not followed by a blank line
                    continue;
                }
                else if (trailingBlankLineCount > 1)
                {
                    if (specificDiagnosticOptions.GetValueOrDefault(SA1507CodeMustNotContainMultipleBlankLinesInARow.DiagnosticId, ReportDiagnostic.Default) != ReportDiagnostic.Suppress)
                    {
                        // ignore comments that are followed by multiple blank lines -> the multiple blank lines will be reported by SA1507
                        continue;
                    }
                }
                else
                {
                    if (triviaIndex < triviaList.Count)
                    {
                        switch (triviaList[triviaIndex].Kind())
                        {
                        case SyntaxKind.SingleLineCommentTrivia:
                        case SyntaxKind.SingleLineDocumentationCommentTrivia:
                        case SyntaxKind.MultiLineCommentTrivia:
                        case SyntaxKind.MultiLineDocumentationCommentTrivia:
                            // ignore a single blank line in between two comments.
                            continue;
                        }
                    }
                }

                var diagnosticSpan = TextSpan.FromBounds(trivia.SpanStart, trivia.SpanStart + 2);
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, diagnosticSpan)));
            }
        }
 private static void AnalyzeTree(SyntaxTreeAnalysisContext context)
 {
     // Report a diagnostic if we got called
     context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Tree.GetLocation(TextSpan.FromBounds(0, 0))));
 }
        private static void HandlePlusToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            if (!token.Parent.IsKind(SyntaxKind.UnaryPlusExpression))
            {
                return;
            }

            var isInInterpolationAlignmentClause = token.Parent.Parent.IsKind(SyntaxKind.InterpolationAlignmentClause);

            if (isInInterpolationAlignmentClause && !token.IsFollowedByWhitespace())
            {
                // SA1001 is already handling the case like: line.Append($"{testResult.DisplayName, +75}");
                // Where the extra space before the plus sign is undesirable.
                return;
            }

            bool precededBySpace         = true;
            bool firstInLine             = token.IsFirstInLine();
            bool followsSpecialCharacter = false;

            bool followedBySpace             = token.IsFollowedByWhitespace();
            bool interpolatedUnaryExpression = token.IsInterpolatedUnaryExpression();
            bool lastInLine = token.IsLastInLine();

            if (!firstInLine)
            {
                precededBySpace = token.IsPrecededByWhitespace(context.CancellationToken);
                SyntaxToken precedingToken = token.GetPreviousToken();

                followsSpecialCharacter =
                    precedingToken.IsKind(SyntaxKind.OpenBracketToken) ||
                    precedingToken.IsKind(SyntaxKind.OpenParenToken) ||
                    precedingToken.IsKind(SyntaxKind.CloseParenToken) ||
                    (precedingToken.IsKind(SyntaxKind.OpenBraceToken) && interpolatedUnaryExpression);
            }

            if (!firstInLine && !isInInterpolationAlignmentClause)
            {
                if (!followsSpecialCharacter && !precededBySpace)
                {
                    // Positive sign should{} be {preceded} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.InsertPreceding, string.Empty, "preceded"));
                }
                else if (followsSpecialCharacter && precededBySpace)
                {
                    // Positive sign should{ not} be {preceded} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemovePreceding, " not", "preceded"));
                }
            }

            if (lastInLine || followedBySpace)
            {
                // Positive sign should{ not} be {followed} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemoveFollowing, " not", "followed"));
            }
        }
Ejemplo n.º 54
0
 public static void ReportDiagnosticWhenActive(this SyntaxTreeAnalysisContext context, Diagnostic diagnostic)
 {
     ReportWhenNotSuppressed(diagnostic, d => context.ReportDiagnostic(d));
 }
Ejemplo n.º 55
0
        private static void HandleSemicolonToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            // check for a following space
            bool missingFollowingSpace = true;

            if (token.HasTrailingTrivia)
            {
                if (token.TrailingTrivia.First().IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    missingFollowingSpace = false;
                }
                else if (token.TrailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    missingFollowingSpace = false;
                }
            }
            else
            {
                SyntaxToken nextToken = token.GetNextToken();
                switch (nextToken.Kind())
                {
                case SyntaxKind.CloseParenToken:
                    // Special handling for the following case:
                    // for (; ;)
                    missingFollowingSpace = false;
                    break;

                case SyntaxKind.SemicolonToken:
                    // Special handling for the following case:
                    // Statement();;
                    if (nextToken.Parent.IsKind(SyntaxKind.EmptyStatement))
                    {
                        missingFollowingSpace = false;
                    }

                    break;

                case SyntaxKind.None:
                    // The semi colon is the last character in the file.
                    return;

                default:
                    break;
                }
            }

            bool hasPrecedingSpace    = false;
            bool ignorePrecedingSpace = false;

            if (!token.IsFirstInLine())
            {
                // only the first token on the line has leading trivia, and those are ignored
                SyntaxToken      precedingToken = token.GetPreviousToken();
                SyntaxTriviaList trailingTrivia = precedingToken.TrailingTrivia;
                if (trailingTrivia.Any() && trailingTrivia.Last().IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    hasPrecedingSpace = true;
                }

                if (precedingToken.IsKind(SyntaxKind.SemicolonToken))
                {
                    // Special handling for the following case:
                    // for (; ;)
                    ignorePrecedingSpace = true;
                }
            }

            if (missingFollowingSpace)
            {
                // semicolon should{} be {followed} by a space
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.InsertFollowing, string.Empty, "followed"));
            }

            if (hasPrecedingSpace && !ignorePrecedingSpace)
            {
                // semicolon should{ not} be {preceded} by a space
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.RemoveImmediatePreceding, " not", "preceded"));
            }
        }
        private void HandleDocumentationCommentExteriorTrivia(SyntaxTreeAnalysisContext context, SyntaxTrivia trivia)
        {
            SyntaxToken token = trivia.Token;

            if (token.IsMissing)
            {
                return;
            }

            switch (token.Kind())
            {
            case SyntaxKind.EqualsToken:
            case SyntaxKind.DoubleQuoteToken:
            case SyntaxKind.SingleQuoteToken:
            case SyntaxKind.IdentifierToken:
            case SyntaxKind.GreaterThanToken:
            case SyntaxKind.SlashGreaterThanToken:
            case SyntaxKind.LessThanToken:
            case SyntaxKind.LessThanSlashToken:
            case SyntaxKind.XmlCommentStartToken:
            case SyntaxKind.XmlCommentEndToken:
            case SyntaxKind.XmlCDataStartToken:
            case SyntaxKind.XmlCDataEndToken:
                if (!token.HasLeadingTrivia)
                {
                    break;
                }

                SyntaxTrivia lastLeadingTrivia = token.LeadingTrivia.Last();
                switch (lastLeadingTrivia.Kind())
                {
                case SyntaxKind.WhitespaceTrivia:
                    if (lastLeadingTrivia.ToFullString().StartsWith(" "))
                    {
                        return;
                    }

                    break;

                case SyntaxKind.DocumentationCommentExteriorTrivia:
                    if (lastLeadingTrivia.ToFullString().EndsWith(" "))
                    {
                        return;
                    }

                    break;

                default:
                    break;
                }

                break;

            case SyntaxKind.EndOfDocumentationCommentToken:
            case SyntaxKind.XmlTextLiteralNewLineToken:
                return;

            case SyntaxKind.XmlTextLiteralToken:
                if (token.Text.StartsWith(" "))
                {
                    return;
                }
                else if (trivia.ToFullString().EndsWith(" "))
                {
                    // javadoc-style documentation comments without a leading * on one of the lines.
                    return;
                }

                break;

            default:
                break;
            }

            // Documentation line must begin with a space.
            context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation()));
        }
        private static void HandleColonToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool requireBefore;
            var  checkRequireAfter = true;

            switch (token.Parent.Kind())
            {
            case SyntaxKind.BaseList:
            case SyntaxKind.BaseConstructorInitializer:
            case SyntaxKind.ThisConstructorInitializer:
            case SyntaxKind.TypeParameterConstraintClause:
            case SyntaxKind.ConditionalExpression:
                requireBefore = true;
                break;

            case SyntaxKind.LabeledStatement:
            case SyntaxKind.CaseSwitchLabel:
            case SyntaxKind.DefaultSwitchLabel:
            case SyntaxKindEx.CasePatternSwitchLabel:
            // NameColon is not explicitly listed in the description of this warning, but the behavior is inferred
            case SyntaxKind.NameColon:
                requireBefore = false;
                break;

            case SyntaxKind.InterpolationFormatClause:
                requireBefore     = false;
                checkRequireAfter = false;
                break;

            default:
                return;
            }

            // check for a following space
            bool missingFollowingSpace = true;

            if (token.HasTrailingTrivia)
            {
                if (token.TrailingTrivia.First().IsKind(SyntaxKind.WhitespaceTrivia))
                {
                    missingFollowingSpace = false;
                }
                else if (token.TrailingTrivia.First().IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    missingFollowingSpace = false;
                }
            }

            bool hasPrecedingSpace = token.HasLeadingTrivia;

            if (!hasPrecedingSpace)
            {
                // only the first token on the line has leading trivia, and those are ignored
                SyntaxToken precedingToken = token.GetPreviousToken();
                var         combinedTrivia = TriviaHelper.MergeTriviaLists(precedingToken.TrailingTrivia, token.LeadingTrivia);
                if (combinedTrivia.Count > 0 && !combinedTrivia.Last().IsKind(SyntaxKind.MultiLineCommentTrivia))
                {
                    hasPrecedingSpace = true;
                }
            }

            if (hasPrecedingSpace != requireBefore)
            {
                // colon should{ not}? be {preceded}{} by a space
                var properties = requireBefore ? TokenSpacingProperties.InsertPreceding : TokenSpacingProperties.RemovePreceding;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, requireBefore ? string.Empty : " not", "preceded", string.Empty));
            }

            if (missingFollowingSpace && checkRequireAfter)
            {
                // colon should{} be {followed}{} by a space
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), TokenSpacingProperties.InsertFollowing, string.Empty, "followed", string.Empty));
            }
        }
Ejemplo n.º 58
0
        private void AnalyzeTrailingTrivia(SyntaxTreeAnalysisContext context)
        {
            SourceText sourceText;

            if (!context.Tree.TryGetText(out sourceText))
            {
                return;
            }

            SyntaxNode root;

            if (!context.Tree.TryGetRoot(out root))
            {
                return;
            }

            var  emptyLines          = default(TextSpan);
            bool previousLineIsEmpty = false;
            int  i = 0;

            foreach (TextLine textLine in sourceText.Lines)
            {
                bool lineIsEmpty = false;

                if (textLine.Span.Length == 0)
                {
                    SyntaxTrivia endOfLine = root.FindTrivia(textLine.End);

                    if (endOfLine.IsKind(SyntaxKind.EndOfLineTrivia))
                    {
                        lineIsEmpty = true;

                        if (previousLineIsEmpty)
                        {
                            if (emptyLines.IsEmpty)
                            {
                                emptyLines = endOfLine.Span;
                            }
                            else
                            {
                                emptyLines = TextSpan.FromBounds(emptyLines.Start, endOfLine.Span.End);
                            }
                        }
                    }
                    else
                    {
                        emptyLines = default(TextSpan);
                    }
                }
                else
                {
                    if (!emptyLines.IsEmpty)
                    {
                        context.ReportDiagnostic(
                            DiagnosticDescriptors.RemoveRedundantEmptyLine,
                            Location.Create(context.Tree, emptyLines));
                    }

                    emptyLines = default(TextSpan);

                    int end = textLine.End - 1;

                    if (char.IsWhiteSpace(sourceText[end]))
                    {
                        int start = end;

                        while (start > textLine.Span.Start && char.IsWhiteSpace(sourceText[start - 1]))
                        {
                            start--;
                        }

                        TextSpan whitespace = TextSpan.FromBounds(start, end + 1);

                        if (root.FindTrivia(start).IsKind(SyntaxKind.WhitespaceTrivia))
                        {
                            if (previousLineIsEmpty && start == textLine.Start)
                            {
                                whitespace = TextSpan.FromBounds(
                                    sourceText.Lines[i - 1].End,
                                    whitespace.End);
                            }

                            context.ReportDiagnostic(
                                DiagnosticDescriptors.RemoveTrailingWhitespace,
                                Location.Create(context.Tree, whitespace));
                        }
                    }
                }

                previousLineIsEmpty = lineIsEmpty;
                i++;
            }
        }
Ejemplo n.º 59
0
        private static void HandleOpenParenToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            if (token.IsLastInLine())
            {
                // ignore open parenthesis when last on line.
                return;
            }

            var prevToken         = token.GetPreviousToken();
            var leadingTriviaList = TriviaHelper.MergeTriviaLists(prevToken.TrailingTrivia, token.LeadingTrivia);

            var isFirstOnLine = false;

            if (prevToken.GetLineSpan().EndLinePosition.Line < token.GetLineSpan().StartLinePosition.Line)
            {
                var done = false;
                for (var i = leadingTriviaList.Count - 1; !done && (i >= 0); i--)
                {
                    switch (leadingTriviaList[i].Kind())
                    {
                    case SyntaxKind.WhitespaceTrivia:
                        break;

                    case SyntaxKind.EndOfLineTrivia:
                        isFirstOnLine = true;
                        done          = true;
                        break;

                    default:
                        done = true;
                        break;
                    }
                }
            }

            bool haveLeadingSpace;
            bool partOfUnaryExpression;
            bool startOfIndexer;

            var prevTokenIsOpenParen = prevToken.IsKind(SyntaxKind.OpenParenToken);

            switch (token.Parent.Kind())
            {
            case SyntaxKind.IfStatement:
            case SyntaxKind.DoStatement:
            case SyntaxKind.WhileStatement:
            case SyntaxKind.ForStatement:
            case SyntaxKind.ForEachStatement:
            case SyntaxKind.SwitchStatement:
            case SyntaxKind.FixedStatement:
            case SyntaxKind.LockStatement:
            case SyntaxKind.UsingStatement:
            case SyntaxKind.CatchDeclaration:
            case SyntaxKind.CatchFilterClause:
                haveLeadingSpace = true;
                break;

            case SyntaxKind.ArgumentList:
            case SyntaxKind.AttributeArgumentList:
            case SyntaxKind.CheckedExpression:
            case SyntaxKind.UncheckedExpression:
            case SyntaxKind.ConstructorConstraint:
            case SyntaxKind.DefaultExpression:
            case SyntaxKind.SizeOfExpression:
            case SyntaxKind.TypeOfExpression:
                haveLeadingSpace = false;
                break;

            case SyntaxKind.ParenthesizedExpression:
                partOfUnaryExpression = prevToken.Parent is PrefixUnaryExpressionSyntax;
                startOfIndexer        = prevToken.IsKind(SyntaxKind.OpenBracketToken);
                var partOfCastExpression = prevToken.IsKind(SyntaxKind.CloseParenToken) && prevToken.Parent.IsKind(SyntaxKind.CastExpression);

                haveLeadingSpace = !partOfUnaryExpression && !startOfIndexer && !partOfCastExpression;
                break;

            case SyntaxKind.CastExpression:
                partOfUnaryExpression = prevToken.Parent is PrefixUnaryExpressionSyntax;
                startOfIndexer        = prevToken.IsKind(SyntaxKind.OpenBracketToken);
                var consecutiveCast     = prevToken.IsKind(SyntaxKind.CloseParenToken) && prevToken.Parent.IsKind(SyntaxKind.CastExpression);
                var partOfInterpolation = prevToken.IsKind(SyntaxKind.OpenBraceToken) && prevToken.Parent.IsKind(SyntaxKind.Interpolation);

                haveLeadingSpace = !partOfUnaryExpression && !startOfIndexer && !consecutiveCast && !partOfInterpolation;
                break;

            case SyntaxKind.ParameterList:
                var partOfLambdaExpression = token.Parent.Parent.IsKind(SyntaxKind.ParenthesizedLambdaExpression);
                haveLeadingSpace = partOfLambdaExpression;
                break;

            default:
                haveLeadingSpace = false;
                break;
            }

            // Ignore spacing before if another opening parenthesis is before this.
            // That way the first opening parenthesis will report any spacing errors.
            if (!prevTokenIsOpenParen)
            {
                var hasLeadingComment = (leadingTriviaList.Count > 0) && leadingTriviaList.Last().IsKind(SyntaxKind.MultiLineCommentTrivia);
                var hasLeadingSpace   = (leadingTriviaList.Count > 0) && leadingTriviaList.Last().IsKind(SyntaxKind.WhitespaceTrivia);

                if (!isFirstOnLine && !hasLeadingComment && (haveLeadingSpace != hasLeadingSpace))
                {
                    if (haveLeadingSpace)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(DescriptorPreceded, token.GetLocation(), OpenCloseSpacingCodeFixProvider.InsertPreceding));
                    }
                    else
                    {
                        context.ReportDiagnostic(Diagnostic.Create(DescriptorNotPreceded, token.GetLocation(), OpenCloseSpacingCodeFixProvider.RemovePreceding));
                    }
                }
            }

            if (token.IsFollowedByWhitespace())
            {
                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotFollowed, token.GetLocation(), OpenCloseSpacingCodeFixProvider.RemoveFollowing));
            }
        }
Ejemplo n.º 60
0
        private void HandleCloseBraceToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace;
            bool firstInLine;

            bool followedBySpace;
            bool lastInLine;
            bool precedesSpecialCharacter;

            firstInLine = token.HasLeadingTrivia || token.GetLocation()?.GetMappedLineSpan().StartLinePosition.Character == 0;
            if (firstInLine)
            {
                precededBySpace = true;
            }
            else
            {
                SyntaxToken precedingToken = token.GetPreviousToken();
                precededBySpace = precedingToken.HasTrailingTrivia;
            }

            followedBySpace = token.HasTrailingTrivia;
            lastInLine      = followedBySpace && token.TrailingTrivia.Any(SyntaxKind.EndOfLineTrivia);
            if (!followedBySpace && !lastInLine)
            {
                SyntaxToken nextToken = token.GetNextToken();
                precedesSpecialCharacter =
                    nextToken.IsKind(SyntaxKind.CloseParenToken) ||
                    nextToken.IsKind(SyntaxKind.CommaToken) ||
                    nextToken.IsKind(SyntaxKind.SemicolonToken);
            }
            else
            {
                precedesSpecialCharacter = false;
            }

            if (token.Parent is InterpolationSyntax)
            {
                // Don't report for interpolation string inlets
                return;
            }

            if (!firstInLine && !precededBySpace)
            {
                // Closing curly bracket must{} be {preceded} by a space.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "preceded"));
            }

            if (!lastInLine)
            {
                if (!precedesSpecialCharacter && !followedBySpace)
                {
                    // Closing curly bracket must{} be {followed} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), string.Empty, "followed"));
                }
                else if (precedesSpecialCharacter && followedBySpace)
                {
                    // Closing curly bracket must{ not} be {followed} by a space.
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), " not", "followed"));
                }
            }
        }