Beispiel #1
0
        public void GetCompilationFailedResult_ReturnsCompilationResult_WithGroupedMessages()
        {
            // Arrange
            var viewPath = "Views/Home/Index";
            var generatedCodeFileName = "Generated Code";
            var fileProvider          = new TestFileProvider();

            fileProvider.AddFile(viewPath, "view-content");
            var options = new Mock <IOptions <RazorViewEngineOptions> >();

            options.SetupGet(o => o.Value)
            .Returns(new RazorViewEngineOptions
            {
                FileProvider = fileProvider
            });
            var compilationService = new RoslynCompilationService(
                GetApplicationEnvironment(),
                GetLoadContextAccessor(),
                GetLibraryExporter(),
                Mock.Of <ICompilerOptionsProvider>(),
                Mock.Of <IMvcRazorHost>(),
                options.Object);

            var assemblyName = "random-assembly-name";

            var diagnostics = new[]
            {
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-1"),
                    Location.Create(
                        viewPath,
                        new TextSpan(10, 5),
                        new LinePositionSpan(new LinePosition(10, 1), new LinePosition(10, 2)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-2"),
                    Location.Create(
                        assemblyName,
                        new TextSpan(1, 6),
                        new LinePositionSpan(new LinePosition(1, 2), new LinePosition(3, 4)))),
                Diagnostic.Create(
                    GetDiagnosticDescriptor("message-3"),
                    Location.Create(
                        viewPath,
                        new TextSpan(40, 50),
                        new LinePositionSpan(new LinePosition(30, 5), new LinePosition(40, 12)))),
            };

            // Act
            var compilationResult = compilationService.GetCompilationFailedResult(
                viewPath,
                "compilation-content",
                assemblyName,
                diagnostics);

            // Assert
            Assert.Collection(compilationResult.CompilationFailures,
                              failure =>
            {
                Assert.Equal(viewPath, failure.SourceFilePath);
                Assert.Equal("view-content", failure.SourceFileContent);
                Assert.Collection(failure.Messages,
                                  message =>
                {
                    Assert.Equal("message-1", message.Message);
                    Assert.Equal(viewPath, message.SourceFilePath);
                    Assert.Equal(11, message.StartLine);
                    Assert.Equal(2, message.StartColumn);
                    Assert.Equal(11, message.EndLine);
                    Assert.Equal(3, message.EndColumn);
                },
                                  message =>
                {
                    Assert.Equal("message-3", message.Message);
                    Assert.Equal(viewPath, message.SourceFilePath);
                    Assert.Equal(31, message.StartLine);
                    Assert.Equal(6, message.StartColumn);
                    Assert.Equal(41, message.EndLine);
                    Assert.Equal(13, message.EndColumn);
                });
            },
                              failure =>
            {
                Assert.Equal(generatedCodeFileName, failure.SourceFilePath);
                Assert.Equal("compilation-content", failure.SourceFileContent);
                Assert.Collection(failure.Messages,
                                  message =>
                {
                    Assert.Equal("message-2", message.Message);
                    Assert.Equal(assemblyName, message.SourceFilePath);
                    Assert.Equal(2, message.StartLine);
                    Assert.Equal(3, message.StartColumn);
                    Assert.Equal(4, message.EndLine);
                    Assert.Equal(5, message.EndColumn);
                });
            });
        }
        private void AnalyzeMagicNumberInvocationExpressions(SyntaxNodeAnalysisContext context)
        {
            var invocationExpressionSyntax = (InvocationExpressionSyntax)context.Node;

            if (!(invocationExpressionSyntax.Expression is MemberAccessExpressionSyntax MemberAccessExpressionSyntax))
            {
                return;
            }

            string methodName = MemberAccessExpressionSyntax.Name.ToString();
            //if (MemberAccessExpressionSyntax?.Name.ToString() != "AddIngredient")
            //    return;

            var argumentListSyntax = invocationExpressionSyntax.ArgumentList as ArgumentListSyntax;

            if (argumentListSyntax == null)
            {
                return;
            }
            int argumentCount = argumentListSyntax.Arguments.Count;


            //if (argumentCount != 1 && argumentCount != 2)
            //    return;

            var memberSymbol = context.SemanticModel.GetSymbolInfo(MemberAccessExpressionSyntax).Symbol as IMethodSymbol;

            if (memberSymbol == null)
            {
                return;
            }

            //if (argumentCount != memberSymbol.Parameters.Length) // < is fine, optional?
            //    return;

            string fullyQualifiedMethodName = memberSymbol.ToString();

            //   if (!memberSymbol.ToString().StartsWith("Terraria.ModLoader.ModRecipe.AddIngredient") ?? true) return;

            var parameterTypeNames = memberSymbol.Parameters.Select(p => p.Type.Name);

            // Find exact MethodParameterToIDTypeBinding related to this InvocationExpressionSyntax
            var methodParameterToIDTypeBinding = MethodParameterToIDTypeBindings.FirstOrDefault(x => x.fullMethodWithParameters == fullyQualifiedMethodName && x.parameterNames.SequenceEqual(parameterTypeNames) && x.appliesToVersion.HasFlag(tModLoaderVersion));

            if (methodParameterToIDTypeBinding == null)
            {
                return;
            }

            if (argumentCount < methodParameterToIDTypeBinding.parameterIndex) // IS this the bug? SetDefaults();
            {
                return;
            }

            // Check if parameter at index is literal number: SetDefaults(111, 2)
            if (!(argumentListSyntax.Arguments[methodParameterToIDTypeBinding.parameterIndex].Expression is LiteralExpressionSyntax parameter && parameter.IsKind(SyntaxKind.NumericLiteralExpression)))
            {
                return;
            }
            //if (!(memberSymbol.Parameters[methodParameterToIDTypeBinding.parameterIndex] is LiteralExpressionSyntax right && right.IsKind(SyntaxKind.NumericLiteralExpression)))
            //     return;

            //  methodParameterToIDTypeBinding.parameterIndex


            //if (p.Length != 2)
            //    return;

            //if (p[0].Type.Name != "Int32" || p[1].Type.Name != "Int32")
            //    return;

            Console.WriteLine();

            int rightValue = (int)parameter.Token.Value;

            if (methodParameterToIDTypeBinding.idDictionary.ContainsId(rightValue))
            //if (rightValue > 0 && rightValue < methodParameterToIDTypeBinding.idDictionary.Count /* ItemID.Count*/)
            {
                //string result = "ItemID." + ItemID.Search.GetName(rightValue);
                string result = $"{methodParameterToIDTypeBinding.idType}.{methodParameterToIDTypeBinding.idDictionary.GetName(rightValue)}"; // + ItemID.Search.GetName(rightValue);

                var builder = ImmutableDictionary.CreateBuilder <string, string>();
                builder["result"] = result;
                builder["idType"] = methodParameterToIDTypeBinding.idType;
                var properties = builder.ToImmutable();

                var diagnostic = Diagnostic.Create(ChangeMagicNumberToIDRule, parameter.GetLocation(), properties, rightValue, result);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeMagicNumberAssignmentExpressions(SyntaxNodeAnalysisContext context)
        {
            // Only support simple assignment: a = b
            var assignmentExpressionSyntax = (AssignmentExpressionSyntax)context.Node;

            if (!assignmentExpressionSyntax.IsKind(SyntaxKind.SimpleAssignmentExpression))
            {
                return;
            }

            // Check if right side is literal number: a = 123
            if (!(assignmentExpressionSyntax.Right is LiteralExpressionSyntax right && right.IsKind(SyntaxKind.NumericLiteralExpression)))
            {
                return;
            }

            ISymbol symbol;

            // Check if left is just a field: a = 123
            if (assignmentExpressionSyntax.Left is IdentifierNameSyntax identifierNameSyntax)
            {
                symbol = context.SemanticModel.GetSymbolInfo(identifierNameSyntax).Symbol;
            }
            // Check if left is accessing a member: a.b = 123
            else if (assignmentExpressionSyntax.Left is MemberAccessExpressionSyntax memberAccessExpressionSyntax)
            {
                symbol = context.SemanticModel.GetSymbolInfo(memberAccessExpressionSyntax).Symbol;
            }
            else
            {
                return;
            }

            // Check if left Type exists: item.b = 123
            if (symbol == null || symbol.ContainingType == null)
            {
                return;
            }

            if (!(symbol is IFieldSymbol fieldSymbol))
            {
                return;
            }

            string containingType = symbol.ContainingType.ToString();
            //if (!containingType.Equals("Terraria.Item"))
            //     return;

            string fieldName            = fieldSymbol.Name;
            var    FieldToIDTypeBinding = FieldToIDTypeBindings.FirstOrDefault(x => x.fullyQualifiedClassName == containingType && x.field == fieldName && x.appliesToVersion.HasFlag(tModLoaderVersion));

            if (FieldToIDTypeBinding == null)
            {
                return;
            }

            int rightValue = (int)right.Token.Value;

            if (FieldToIDTypeBinding.idDictionary.ContainsId(rightValue))
            //if (rightValue > 0 && rightValue < FieldToIDTypeBinding.idDictionary.Count /* ItemID.Count*/)
            {
                //string result = "ItemID." + ItemID.Search.GetName(rightValue);
                string result = $"{FieldToIDTypeBinding.idType}.{FieldToIDTypeBinding.idDictionary.GetName(rightValue)}"; // + ItemID.Search.GetName(rightValue);

                var builder = ImmutableDictionary.CreateBuilder <string, string>();
                builder["result"] = result;
                builder["idType"] = FieldToIDTypeBinding.idType;
                var properties = builder.ToImmutable();

                var diagnostic = Diagnostic.Create(ChangeMagicNumberToIDRule, right.GetLocation(), properties, rightValue, result);
                context.ReportDiagnostic(diagnostic);
            }
        }
Beispiel #4
0
        static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
        {
            var simpleLambda = nodeContext.Node as SimpleLambdaExpressionSyntax;
            var parenLambda  = nodeContext.Node as ParenthesizedLambdaExpressionSyntax;
            var anoMethod    = nodeContext.Node as AnonymousMethodExpressionSyntax;

            diagnostic = default(Diagnostic);
            if (nodeContext.IsFromGeneratedCode())
            {
                return(false);
            }
            var body = simpleLambda?.Body ?? parenLambda?.Body ?? anoMethod?.Block;

            if (body == null)
            {
                return(false);
            }

            var invocation = AnalyzeBody(body);

            if (invocation == null)
            {
                return(false);
            }
            if (!IsSimpleTarget(invocation.Expression))
            {
                return(false);
            }

            var symbolInfo = nodeContext.SemanticModel.GetSymbolInfo(invocation);
            var method     = symbolInfo.Symbol as IMethodSymbol;

            if (method == null)
            {
                return(false);
            }

            var memberAttributes = method.GetAttributes();

            if ((memberAttributes != null) && memberAttributes.Any(ad => (ad.AttributeClass != null) && (ad.AttributeClass.GetFullName() == "System.Diagnostics.ConditionalAttribute")))
            {
                return(false);
            }

            foreach (var param in method.Parameters)
            {
                if (param.RefKind == RefKind.Ref || param.RefKind == RefKind.Out || param.IsParams)
                {
                    return(false);
                }
            }

            IReadOnlyList <ParameterSyntax> lambdaParameters = parenLambda?.ParameterList?.Parameters ?? anoMethod?.ParameterList?.Parameters;

            if (simpleLambda != null)
            {
                lambdaParameters = new[] { simpleLambda.Parameter }
            }
            ;
            if (lambdaParameters == null)
            {
                lambdaParameters = new ParameterSyntax[] { }
            }
            ;

            var arguments = invocation.ArgumentList.Arguments;

            if (method.Parameters.Length != arguments.Count || lambdaParameters.Count != arguments.Count)
            {
                return(false);
            }

            for (int i = 0; i < arguments.Count && i < lambdaParameters.Count; i++)
            {
                //				var arg = UnpackImplicitIdentityOrReferenceConversion(arguments[i]) as LocalResolveResult;
                if (arguments[i].Expression.ToString() != lambdaParameters[i].Identifier.ToString())
                {
                    return(false);
                }
            }

            var returnConv = nodeContext.SemanticModel.GetConversion(invocation, nodeContext.CancellationToken);

            if (returnConv.IsExplicit || !(returnConv.IsIdentity || returnConv.IsReference))
            {
                return(false);
            }

            var validTypes = TypeGuessing.GetValidTypes(nodeContext.SemanticModel, nodeContext.Node, nodeContext.CancellationToken).ToList();

            // search for method group collisions
            foreach (var t in validTypes)
            {
                if (t.TypeKind != TypeKind.Delegate)
                {
                    continue;
                }
                var invokeMethod = t.GetDelegateInvokeMethod();

                foreach (var otherMethod in GetMethodGroup(method))
                {
                    if (otherMethod == method)
                    {
                        continue;
                    }
                    if (SignatureComparer.HaveSameSignature(otherMethod.GetParameters(), invokeMethod.Parameters))
                    {
                        return(false);
                    }
                }
            }

            bool isValidReturnType = false;

            foreach (var t in validTypes)
            {
                if (t.TypeKind != TypeKind.Delegate)
                {
                    continue;
                }
                var invokeMethod = t.GetDelegateInvokeMethod();
                isValidReturnType = method.ReturnType == invokeMethod.ReturnType || method.ReturnType.GetBaseTypes().Contains(invokeMethod.ReturnType);
                if (isValidReturnType)
                {
                    break;
                }
            }
            if (!isValidReturnType)
            {
                return(false);
            }

            if (method.ContainingType.TypeKind == TypeKind.Delegate)
            {
                if (!validTypes.Contains(method.ContainingType))
                {
                    return(false);
                }
            }

            // Method group used in an invocation expression might be ambiguos, keep the lambda instead
            if ((validTypes.Count > 1) && IsUsageInInvocation(nodeContext))
            {
                return(false);
            }

            diagnostic = Diagnostic.Create(
                descriptor,
                nodeContext.Node.GetLocation(),
                anoMethod != null ? GettextCatalog.GetString("Anonymous method can be simplified to method group") : GettextCatalog.GetString("Lambda expression can be simplified to method group")
                );
            return(true);
        }
Beispiel #5
0
        private void CheckFunctionNestingDepth(SyntaxNodeAnalysisContext context)
        {
            var walker = new NestingDepthWalker(Maximum, token => context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, token.GetLocation(), Maximum)));

            walker.SafeVisit(context.Node);
        }
        private static void CheckUsingDeclarations(SyntaxNodeAnalysisContext context, OrderingSettings orderingSettings, SyntaxList <UsingDirectiveSyntax> usingDirectives)
        {
            UsingDirectiveSyntax lastStaticUsingDirective       = null;
            UsingDirectiveSyntax lastSystemStaticUsingDirective = null;
            UsingDirectiveSyntax firstNonSystemUsing            = null;

            foreach (var usingDirective in usingDirectives)
            {
                if (usingDirective.IsPrecededByPreprocessorDirective())
                {
                    lastStaticUsingDirective       = null;
                    lastSystemStaticUsingDirective = null;
                    firstNonSystemUsing            = null;
                }

                if (usingDirective.StaticKeyword.IsKind(SyntaxKind.StaticKeyword))
                {
                    if (orderingSettings.SystemUsingDirectivesFirst && usingDirective.IsSystemUsingDirective())
                    {
                        if (firstNonSystemUsing != null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(
                                                         Descriptor,
                                                         firstNonSystemUsing.GetLocation(),
                                                         new[] { firstNonSystemUsing.Name.ToNormalizedString(), usingDirective.Name.ToNormalizedString() }));
                            return;
                        }

                        if (lastSystemStaticUsingDirective != null)
                        {
                            var firstName  = lastSystemStaticUsingDirective.Name;
                            var secondName = usingDirective.Name;

                            if (NameSyntaxHelpers.Compare(firstName, secondName) > 0)
                            {
                                context.ReportDiagnostic(Diagnostic.Create(
                                                             Descriptor,
                                                             lastSystemStaticUsingDirective.GetLocation(),
                                                             new[] { firstName.ToNormalizedString(), secondName.ToNormalizedString() }));
                                return;
                            }
                        }

                        lastSystemStaticUsingDirective = usingDirective;
                    }
                    else
                    {
                        if (lastStaticUsingDirective != null)
                        {
                            var firstName  = lastStaticUsingDirective.Name;
                            var secondName = usingDirective.Name;

                            if (NameSyntaxHelpers.Compare(firstName, secondName) > 0)
                            {
                                context.ReportDiagnostic(Diagnostic.Create(
                                                             Descriptor,
                                                             lastStaticUsingDirective.GetLocation(),
                                                             new[] { firstName.ToNormalizedString(), secondName.ToNormalizedString() }));
                                return;
                            }
                        }

                        lastStaticUsingDirective = usingDirective;
                        firstNonSystemUsing      = firstNonSystemUsing ?? usingDirective;
                    }
                }
            }
        }
        public override void Initialize(AnalysisContext analysisContext)
        {
            analysisContext.EnableConcurrentExecution();
            analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            analysisContext.RegisterOperationBlockStartAction(osContext =>
            {
                var method = osContext.OwningSymbol as IMethodSymbol;
                if (method == null)
                {
                    return;
                }

                osContext.RegisterOperationAction(opContext =>
                {
                    IOperation expression     = ((IExpressionStatementOperation)opContext.Operation).Operation;
                    DiagnosticDescriptor rule = null;
                    string targetMethodName   = null;
                    switch (expression.Kind)
                    {
                    case OperationKind.ObjectCreation:
                        IMethodSymbol ctor = ((IObjectCreationOperation)expression).Constructor;
                        if (ctor != null)
                        {
                            rule             = ObjectCreationRule;
                            targetMethodName = ctor.ContainingType.Name;
                        }
                        break;

                    case OperationKind.Invocation:
                        IInvocationOperation invocationExpression = ((IInvocationOperation)expression);
                        IMethodSymbol targetMethod = invocationExpression.TargetMethod;
                        if (targetMethod == null)
                        {
                            break;
                        }

                        if (IsStringCreatingMethod(targetMethod))
                        {
                            rule = StringCreationRule;
                        }
                        else if (IsTryParseMethod(targetMethod))
                        {
                            rule = TryParseRule;
                        }
                        else if (IsHResultOrErrorCodeReturningMethod(targetMethod))
                        {
                            rule = HResultOrErrorCodeRule;
                        }
                        else if (IsPureMethod(targetMethod, opContext.Compilation))
                        {
                            rule = PureMethodRule;
                        }

                        targetMethodName = targetMethod.Name;
                        break;
                    }

                    if (rule != null)
                    {
                        Diagnostic diagnostic = Diagnostic.Create(rule, expression.Syntax.GetLocation(), method.Name, targetMethodName);
                        opContext.ReportDiagnostic(diagnostic);
                    }
                }, OperationKind.ExpressionStatement);
            });
        }
        internal static void Run(SyntaxNodeAnalysisContext context, ExpressionSyntax token)
        {
            string id = token.ToFullString();

            if (string.IsNullOrWhiteSpace(id))
            {
                return;
            }

            BlockSyntax method = context.Node.FirstAncestorOrSelf <BlockSyntax>();

            if (method == null)
            {
                return;
            }

            try
            {
                if (token.IsKind(SyntaxKind.InvocationExpression))
                {
                    var    nodes = method.DescendantNodes();
                    string s     = string.Empty;

                    foreach (SyntaxNode n in nodes)
                    {
                        if (n.IsKind(SyntaxKind.ExpressionStatement) && id.Contains(n.GetFirstToken().Text) && n.ToFullString().Contains("Append("))
                        {
                            string rm = n.GetFirstToken().Text + ".Append(";
                            s += n.GetText().ToString().Replace(rm, "").Replace(@""")", "").Replace("\r\n", "").Replace(";", "") + " ";
                            s  = s.Replace("            \"", string.Empty);
                        }
                    }
                    s = Helper.BuildSqlStringFromIdString(context, s);
                    List <string> errorlist     = SqlParser.Parse(s);
                    string        errorlistText = String.Join("\r\n", errorlist);
                    var           diagnostic2   = Diagnostic.Create(RuleParam, context.Node.GetLocation(), errorlistText);

                    context.ReportDiagnostic(diagnostic2);
                    return;
                }
                var t = method.DescendantTokens().Where <SyntaxToken>(tk => tk.ValueText != null && tk.IsKind(SyntaxKind.IdentifierToken) && tk.ValueText == id).First <SyntaxToken>();

                if (string.IsNullOrWhiteSpace(t.ValueText))
                {
                    return;
                }

                string sql = t.GetNextToken().GetNextToken().Value.ToString();
                if (string.IsNullOrWhiteSpace(sql))
                {
                    return;
                }

                List <string> errors = SqlParser.Parse(sql);

                if (errors.Count == 0)
                {
                    var binaryExpressions = method.DescendantNodesAndSelf().OfType <BinaryExpressionSyntax>().First <BinaryExpressionSyntax>();

                    if (binaryExpressions != null)
                    {
                        BinaryExpressionDiagnostic.Run(context, binaryExpressions);
                        return;
                    }
                    return;
                }
                string errorText  = String.Join("\r\n", errors);
                var    diagnostic = Diagnostic.Create(RuleParam, t.GetNextToken().GetNextToken().GetLocation(), errorText);

                context.ReportDiagnostic(diagnostic);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("don't handle syntax yet: " + ex.Message);
            }
        }
        private static void HandleFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node;
            if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax))
            {
                return;
            }

            if (syntax.Modifiers.Any(SyntaxKind.ConstKeyword))
            {
                // this diagnostic does not apply to constant fields
                return;
            }

            if (syntax.Modifiers.Any(SyntaxKind.PublicKeyword)
                || syntax.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                // this diagnostic does not apply to public or internal read only fields
                return;
            }

            if (syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword)
                && syntax.Modifiers.Any(SyntaxKind.ProtectedKeyword))
            {
                // this diagnostic does not apply to non-private read only fields
                return;
            }

            if (syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword)
                && syntax.Modifiers.Any(SyntaxKind.StaticKeyword))
            {
                // this diagnostic does not apply to static read only fields
                return;
            }

            var variables = syntax.Declaration?.Variables;
            if (variables == null)
            {
                return;
            }

            foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value)
            {
                if (variableDeclarator == null)
                {
                    continue;
                }

                var identifier = variableDeclarator.Identifier;
                if (identifier.IsMissing)
                {
                    continue;
                }

                string name = identifier.ValueText;
                if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
                {
                    continue;
                }

                if (name[0] == '_')
                {
                    // `_foo` is handled by SA1309
                    continue;
                }

                // Field names must begin with lower-case letter
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation(), name));
            }
        }
        /// <summary>
        /// Analyze each line textually.
        /// </summary>
        /// <param name="context">Analysis context.</param>
        private static void AnalyzeLines(SyntaxTreeAnalysisContext context)
        {
            // Get the text for the file.
            var text = context.Tree.GetText(context.CancellationToken);

            // Gather non-CRLF lines.
            var nonCrlfLineEndings = new List <Location>();

            // Check each line.
            foreach (var line in text.Lines)
            {
                // Chech whether the line stays withint he 120 character limit.
                var lineText = line.ToString();
                int treshold;
                SyntaxHelper.GetTextLengthWith120Treshold(lineText, out treshold);
                if (treshold != -1)
                {
                    // Line exceeds 120 characters. Report the error.
                    var diagnostic = Diagnostic.Create(
                        KeepLinesWithin120Characters.Rule,
                        Location.Create(context.Tree,
                                        TextSpan.FromBounds(line.Span.Start + treshold, line.Span.End)));
                    context.ReportDiagnostic(diagnostic);
                }

                // Check whether there are space indenting.
                var match = SPACE_INDENT_REGEX.Match(lineText);
                if (match.Success)
                {
                    // Space indenting. REport error.
                    var start      = match.Groups["space"].Index;
                    var end        = start + match.Groups["space"].Length;
                    var diagnostic = Diagnostic.Create(
                        IndentWithTabs.Rule,
                        Location.Create(context.Tree,
                                        TextSpan.FromBounds(line.Start + start, line.Start + end)));
                    context.ReportDiagnostic(diagnostic);
                }

                // Check for trailing whitespace.
                var trailingMatch = TRAILING_WHITESPACE_REGEX.Match(lineText);
                if (trailingMatch.Success)
                {
                    // Trailing whitespace. Report error.
                    var diagnostic = Diagnostic.Create(
                        NoTrailingWhitespace.Rule,
                        Location.Create(context.Tree,
                                        TextSpan.FromBounds(
                                            line.Start + lineText.Length - trailingMatch.Length,
                                            line.End)));
                    context.ReportDiagnostic(diagnostic);
                }

                // Skip the line ending check if this is the last line.
                // The last "line" has no line ending.
                if (line.End == context.Tree.Length)
                {
                    continue;
                }

                // Ensure the line ends with CRLF.
                var expectedLineEndSpan = TextSpan.FromBounds(
                    line.EndIncludingLineBreak - 2,
                    line.EndIncludingLineBreak);
                var expectedLineEndText = line.Text.GetSubText(expectedLineEndSpan);
                var expectedLineEnd     = expectedLineEndText.ToString();
                if (expectedLineEnd != "\r\n")
                {
                    // Non-CRLF line ending.
                    var actualLineEndSpan = TextSpan.FromBounds(line.End, line.EndIncludingLineBreak);
                    nonCrlfLineEndings.Add(Location.Create(context.Tree, actualLineEndSpan));
                }
            }

            // If we had non-CRLF lines, report a diagnostic.
            // Do this only once per file to avoid spamming warnings.
            if (nonCrlfLineEndings.Count > 0)
            {
                // Non CRLF line endings. Report error.
                var firstLocation       = nonCrlfLineEndings.First();
                var additionalLocations = nonCrlfLineEndings.Skip(1);
                var diagnostic          = Diagnostic.Create(
                    UseWindowsLineEnding.Rule,
                    firstLocation, additionalLocations);
                context.ReportDiagnostic(diagnostic);
            }
        }
Beispiel #11
0
        private static void HandleFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            FieldDeclarationSyntax syntax = (FieldDeclarationSyntax)context.Node;

            if (NamedTypeHelpers.IsContainedInNativeMethodsClass(syntax))
            {
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.ReadOnlyKeyword))
            {
                // this analyzer only applies to readonly fields
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.PublicKeyword) &&
                !syntax.Modifiers.Any(SyntaxKind.ProtectedKeyword) &&
                !syntax.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                // this analyzer only applies to non-private fields
                return;
            }

            if (!syntax.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                // SA1307 is taken precedence here. SA1307 should be reported if the field is accessible.
                // So if SA1307 is enabled this diagnostic will only be reported for internal fields.
                if (!context.IsAnalyzerSuppressed(SA1307AccessibleFieldsMustBeginWithUpperCaseLetter.Descriptor))
                {
                    return;
                }
            }

            var variables = syntax.Declaration?.Variables;

            if (variables == null)
            {
                return;
            }

            foreach (VariableDeclaratorSyntax variableDeclarator in variables.Value)
            {
                if (variableDeclarator == null)
                {
                    continue;
                }

                var identifier = variableDeclarator.Identifier;
                if (identifier.IsMissing)
                {
                    continue;
                }

                string name = identifier.ValueText;
                if (string.IsNullOrEmpty(name) || !char.IsLower(name[0]))
                {
                    continue;
                }

                // Non-private readonly fields should begin with upper-case letter.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, identifier.GetLocation()));
            }
        }
        /// <summary>
        /// Analyses attributes.
        /// </summary>
        /// <param name="context">The context.</param>
        private static void AnalyzeAttributeArgumentLists(SyntaxNodeAnalysisContext context)
        {
            // Get the attribute list.
            var attributeList = ( AttributeArgumentListSyntax )context.Node;

            // We have two acceptable situations for argument lists:
            //  1) All the arguments are on the same line.
            //  2) All the arguments are on their own lines.
            List <int> lineNumbersPerAttribute = new List <int>();

            for (int attributeIndex = 0; attributeIndex < attributeList.Arguments.Count; ++attributeIndex)
            {
                // Get the attribute.
                var attribute = attributeList.Arguments[attributeIndex];

                // Get the attribute line number.
                int attributeLineNumber = attribute.GetLocation().GetLineSpan().EndLinePosition.Line;

                // Start checking only from the second attribute, as the first one is always correct.
                if (attributeIndex != 0)
                {
                    // Is the attribute on its own line, or on the same line as all the previous ones?
                    bool argumentOkay = false;
                    if (lineNumbersPerAttribute.All(existingLine => existingLine == attributeLineNumber))
                    {
                        // All attributes on the same line => Okay.
                        argumentOkay = true;
                    }
                    else
                    {
                        // The arguments should be on their own lines.

                        // Check if this attribute is on the next line than the previous one,
                        // and that all the previous attributes are also on their own lines.
                        bool previousLinesAreOkay = true;
                        for (int i = 1; i < lineNumbersPerAttribute.Count; ++i)
                        {
                            if (lineNumbersPerAttribute[i] != lineNumbersPerAttribute[i - 1] + 1)
                            {
                                previousLinesAreOkay = false;
                            }
                        }

                        // Check that the new attribute is own its line.
                        if (previousLinesAreOkay &&
                            lineNumbersPerAttribute.Last() + 1 == attributeLineNumber)
                        {
                            // This attribute is on the next line => Okay.
                            argumentOkay = true;
                        }
                    }

                    // Check if the checks went okay.
                    if (argumentOkay == false)
                    {
                        // Something wasn't as supposed. Report the results.
                        var diagnostic = Diagnostic.Create(
                            AttributesOnTheirOwnLines.Rule,
                            attribute.GetLocation());
                        context.ReportDiagnostic(diagnostic);
                    }
                }

                // Add to the list.
                lineNumbersPerAttribute.Add(attributeLineNumber);
            }
        }
        /// <summary>
        /// Analyze the statements in the block for continuation lines.
        /// </summary>
        /// <param name="context">Analysis context.</param>
        private static void AnalyzeBlocks(SyntaxNodeAnalysisContext context)
        {
            // Grab the block syntax node.
            var block = (BlockSyntax)context.Node;

            // Ensure braces are on their own lines.
            CheckBraceLines(
                context,
                block.Parent,
                block.OpenBraceToken,
                block.CloseBraceToken);

            // Check each statement for continuation lines.
            foreach (var statement in block.Statements)
            {
                // Skip the flow control statements. These are expected to be multi-line and
                // don't require double-indent.
                if (statement.IsKind(SyntaxKind.IfStatement) ||
                    statement.IsKind(SyntaxKind.ForEachStatement) ||
                    statement.IsKind(SyntaxKind.ForStatement) ||
                    statement.IsKind(SyntaxKind.DoStatement) ||
                    statement.IsKind(SyntaxKind.SwitchStatement) ||
                    statement.IsKind(SyntaxKind.WhileStatement) ||
                    statement.IsKind(SyntaxKind.LockStatement) ||
                    statement.IsKind(SyntaxKind.UncheckedStatement) ||
                    statement.IsKind(SyntaxKind.UsingStatement) ||
                    statement.IsKind(SyntaxKind.Block))
                {
                    // Flow control statement. Skip.
                    continue;
                }

                // There should be leading whitespace trivia. This includes the indent.
                if (!statement.HasLeadingTrivia)
                {
                    continue;
                }

                // If this is a single-line statement, skip it. There will be no continuation line.
                var lines = statement.ToString().Split('\n');
                if (lines.Length == 1)
                {
                    continue;
                }

                // If the second line is opening brace, it should signal to the user that this is a
                // continuation statement and we can skip the indent rules.
                var secondLine = lines[1];
                if (secondLine.Trim() == "{" || string.IsNullOrWhiteSpace(secondLine))
                {
                    continue;
                }

                // Get the whitespace preceding the statement.
                // There might be a lot of trivia preceding the statement. We're currently insterested only of
                // the whitespace on the last line.

                // First figure out where the last line begins from.
                var leadingTrivia    = statement.GetLeadingTrivia().ToList();
                var lastNewlineIndex = leadingTrivia.FindLastIndex(
                    trivia => trivia.IsKind(SyntaxKind.EndOfLineTrivia));
                int lastLineIndex = lastNewlineIndex == -1 ? 0 : lastNewlineIndex + 1;

                // Once we know where the last line starts, we can find the whitespace at the start of that line.
                var whitespaceOfLastLine = leadingTrivia.FindIndex(
                    lastLineIndex,
                    trivia => trivia.IsKind(SyntaxKind.WhitespaceTrivia));

                // Calculate the expected indent for the second line.
                var firstLineIndent = whitespaceOfLastLine == -1
                                                ? "" : leadingTrivia[whitespaceOfLastLine].ToString();
                int firstIndent      = SyntaxHelper.GetTextLength(firstLineIndent);
                var secondLineIndent = ALL_INDENT_REGEX.Match(secondLine).Value;
                int expectedIndent   = firstIndent + 8;

                // Check whether the second line fulfills the indent requirement.
                if (SyntaxHelper.GetTextLength(secondLineIndent) < expectedIndent)
                {
                    // Indent requirement not fulfilled. Report an issue.
                    var start      = statement.SpanStart + lines[0].Length + 1 + secondLineIndent.Length;
                    var end        = start + 1;
                    var diagnostic = Diagnostic.Create(
                        DoubleTabContinuationIndent.Rule,
                        Location.Create(statement.SyntaxTree, TextSpan.FromBounds(start, end)));
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
Beispiel #14
0
        private void Analyzer(SymbolAnalysisContext context)
        {
            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllModel))
            {
                return;
            }

            if (!(context.Symbol is INamedTypeSymbol namedTypeSymbol))
            {
                return;
            }

            // 筛选出含有UniqueId标签的类
            var attr = namedTypeSymbol.GetFirstAttribute(UniqueIdAttribute);

            if (attr == null)
            {
                return;
            }

            // 获取id 最小值最大值
            var minIdValue = attr.ConstructorArguments[0].Value;

            var maxIdValue = attr.ConstructorArguments[1].Value;

            if (minIdValue == null || maxIdValue == null)
            {
                return;
            }

            int minId = (int)minIdValue;

            int maxId = (int)maxIdValue;

            HashSet <int> IdSet = new HashSet <int>();

            foreach (var member in namedTypeSymbol.GetMembers())
            {
                if (member is IFieldSymbol {
                    IsConst: true, ConstantValue: int id
                } fieldSymbol)
                {
                    if (id < minId || id > maxId)
                    {
                        ReportDiagnostic(fieldSymbol, id, UniqueIdRangeAnaluzerRule.Rule);
                    }
                    else if (IdSet.Contains(id))
                    {
                        ReportDiagnostic(fieldSymbol, id, UniqueIdDuplicateAnalyzerRule.Rule);
                    }
                    else
                    {
                        IdSet.Add(id);
                    }
                }
            }


            void ReportDiagnostic(IFieldSymbol fieldSymbol, int idValue, DiagnosticDescriptor rule)
            {
                foreach (var syntaxReference in fieldSymbol.DeclaringSyntaxReferences)
                {
                    var        syntax     = syntaxReference.GetSyntax();
                    Diagnostic diagnostic = Diagnostic.Create(rule, syntax.GetLocation(), namedTypeSymbol.Name, fieldSymbol.Name, idValue.ToString());
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int kindIndex, SyntaxList <MemberDeclarationSyntax> members, ImmutableArray <SyntaxKind> order)
        {
            for (int i = 0; i < members.Count - 1; i++)
            {
                if (members[i + 1].IsKind(SyntaxKind.IncompleteMember))
                {
                    i++;
                    continue;
                }

                if (members[i].IsKind(SyntaxKind.IncompleteMember))
                {
                    continue;
                }

                bool compareKind = true;
                for (int j = 0; compareKind && j < kindIndex; j++)
                {
                    switch (elementOrder[j])
                    {
                    case OrderingTrait.Accessibility:
                        if (MemberOrderHelper.GetAccessLevelForOrdering(members[i + 1], members[i + 1].GetModifiers())
                            != MemberOrderHelper.GetAccessLevelForOrdering(members[i], members[i].GetModifiers()))
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Constant:
                    case OrderingTrait.Readonly:
                        // Only fields may be marked const or readonly, and all fields have the same kind.
                        continue;

                    case OrderingTrait.Static:
                        bool currentIsStatic = members[i].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        bool nextIsStatic    = members[i + 1].GetModifiers().Any(SyntaxKind.StaticKeyword);
                        if (currentIsStatic != nextIsStatic)
                        {
                            compareKind = false;
                        }

                        continue;

                    case OrderingTrait.Kind:
                    default:
                        continue;
                    }
                }

                if (!compareKind)
                {
                    continue;
                }

                var elementSyntaxKind = members[i].Kind();
                elementSyntaxKind = elementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : elementSyntaxKind;
                int index = order.IndexOf(elementSyntaxKind);

                var nextElementSyntaxKind = members[i + 1].Kind();
                nextElementSyntaxKind = nextElementSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : nextElementSyntaxKind;
                int nextIndex = order.IndexOf(nextElementSyntaxKind);

                if (index > nextIndex)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, NamedTypeHelpers.GetNameOrIdentifierLocation(members[i + 1]), MemberNames[nextElementSyntaxKind], MemberNames[elementSyntaxKind]));
                }
            }
        }
        private static void AnalyzeAttribute(SyntaxNodeAnalysisContext context)
        {
            var attributeInfo = SourceHelpers.GetSourceAttributeInformation(
                context,
                NUnitFrameworkConstants.FullNameOfTypeTestCaseSourceAttribute,
                NUnitFrameworkConstants.NameOfTestCaseSourceAttribute);

            if (attributeInfo is null)
            {
                return;
            }

            var attributeNode  = (AttributeSyntax)context.Node;
            var stringConstant = attributeInfo.SourceName;

            if (stringConstant is null && attributeNode.ArgumentList?.Arguments.Count == 1)
            {
                // The Type argument in this form represents the class that provides test cases.
                // It must have a default constructor and implement IEnumerable.
                var  sourceType = attributeInfo.SourceType;
                bool typeImplementsIEnumerable = sourceType.IsIEnumerable(out _);
                bool typeHasDefaultConstructor = sourceType.Constructors.Any(c => c.Parameters.IsEmpty);
                if (!typeImplementsIEnumerable)
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 sourceTypeNotIEnumerableDescriptor,
                                                 attributeNode.ArgumentList.Arguments[0].GetLocation(),
                                                 sourceType.Name));
                }
                else if (!typeHasDefaultConstructor)
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 sourceTypeNoDefaultConstructorDescriptor,
                                                 attributeNode.ArgumentList.Arguments[0].GetLocation(),
                                                 sourceType.Name));
                }

                return;
            }

            var syntaxNode = attributeInfo.SyntaxNode;

            if (syntaxNode is null || stringConstant is null)
            {
                return;
            }

            var symbol = SourceHelpers.GetMember(attributeInfo);

            if (symbol is null)
            {
                context.ReportDiagnostic(Diagnostic.Create(
                                             missingSourceDescriptor,
                                             syntaxNode.GetLocation(),
                                             stringConstant));
            }
            else
            {
                SourceHelpers.ReportToUseNameOfIfApplicable(
                    context,
                    syntaxNode,
                    attributeInfo,
                    symbol,
                    stringConstant,
                    considerNameOfDescriptor);

                if (!symbol.IsStatic)
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 sourceNotStaticDescriptor,
                                                 syntaxNode.GetLocation(),
                                                 stringConstant));
                }

                switch (symbol)
                {
                case IPropertySymbol property:
                    ReportIfSymbolNotIEnumerable(context, syntaxNode, property.Type);
                    ReportIfParametersSupplied(context, syntaxNode, attributeInfo.NumberOfMethodParameters, "properties");
                    break;

                case IFieldSymbol field:
                    ReportIfSymbolNotIEnumerable(context, syntaxNode, field.Type);
                    ReportIfParametersSupplied(context, syntaxNode, attributeInfo.NumberOfMethodParameters, "fields");
                    break;

                case IMethodSymbol method:
                    ReportIfSymbolNotIEnumerable(context, syntaxNode, method.ReturnType);

                    var methodParametersFromAttribute = attributeInfo.NumberOfMethodParameters ?? 0;
                    if (method.Parameters.Length != methodParametersFromAttribute)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(
                                                     mismatchInNumberOfParameters,
                                                     syntaxNode.GetLocation(),
                                                     methodParametersFromAttribute,
                                                     method.Parameters.Length));
                    }

                    break;
                }
            }
        }
        private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated())
            {
                return;
            }
            var objectCreation = context.Node as ObjectCreationExpressionSyntax;

            if (objectCreation == null)
            {
                return;
            }
            if (objectCreation.Parent == null)
            {
                return;
            }

            var        originalNode  = objectCreation;
            SyntaxNode topSyntaxNode = originalNode;

            while (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.ConditionalExpression, SyntaxKind.CastExpression))
            {
                topSyntaxNode = topSyntaxNode.Parent;
            }

            if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.ReturnStatement, SyntaxKind.UsingStatement, SyntaxKind.YieldReturnStatement))
            {
                return;
            }

            if (topSyntaxNode.Ancestors().Any(i => i.IsAnyKind(
                                                  SyntaxKind.ArrowExpressionClause,
                                                  SyntaxKind.ThisConstructorInitializer,
                                                  SyntaxKind.BaseConstructorInitializer,
                                                  SyntaxKind.ObjectCreationExpression)))
            {
                return;
            }

            var semanticModel = context.SemanticModel;
            var type          = semanticModel.GetSymbolInfo(originalNode.Type).Symbol as INamedTypeSymbol;

            if (type == null)
            {
                return;
            }
            if (!type.AllInterfaces.Any(i => i.ToString() == "System.IDisposable"))
            {
                return;
            }
            ISymbol         identitySymbol = null;
            StatementSyntax statement      = null;

            if (topSyntaxNode.Parent.IsKind(SyntaxKind.SimpleAssignmentExpression))
            {
                var assignmentExpression = (AssignmentExpressionSyntax)topSyntaxNode.Parent;
                identitySymbol = semanticModel.GetSymbolInfo(assignmentExpression.Left).Symbol;
                if (identitySymbol?.Kind != SymbolKind.Local)
                {
                    return;
                }
                if (assignmentExpression.FirstAncestorOrSelf <MethodDeclarationSyntax>() == null)
                {
                    return;
                }
                var usingStatement = assignmentExpression.Parent as UsingStatementSyntax;
                if (usingStatement != null)
                {
                    return;
                }
                statement = assignmentExpression.Parent as ExpressionStatementSyntax;
            }
            else if (topSyntaxNode.Parent.IsKind(SyntaxKind.EqualsValueClause) && topSyntaxNode.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator))
            {
                var variableDeclarator  = (VariableDeclaratorSyntax)topSyntaxNode.Parent.Parent;
                var variableDeclaration = variableDeclarator?.Parent as VariableDeclarationSyntax;
                identitySymbol = semanticModel.GetDeclaredSymbol(variableDeclarator);
                if (identitySymbol == null)
                {
                    return;
                }
                var usingStatement = variableDeclaration?.Parent as UsingStatementSyntax;
                if (usingStatement != null)
                {
                    return;
                }
                statement = variableDeclaration.Parent as LocalDeclarationStatementSyntax;
                if ((statement?.FirstAncestorOrSelf <MethodDeclarationSyntax>()) == null)
                {
                    return;
                }
            }
            else if (topSyntaxNode.Parent.IsAnyKind(SyntaxKind.SimpleLambdaExpression, SyntaxKind.ParenthesizedLambdaExpression))
            {
                var anonymousFunction = topSyntaxNode.Parent as AnonymousFunctionExpressionSyntax;
                var methodSymbol      = semanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol;
                if (!methodSymbol.ReturnsVoid)
                {
                    return;
                }
                var props = new Dictionary <string, string> {
                    { "typeName", type.Name }, { cantFix, "" }
                }.ToImmutableDictionary();
                context.ReportDiagnostic(Diagnostic.Create(Rule, originalNode.GetLocation(), props, type.Name.ToString()));
            }
            else
            {
                var props = new Dictionary <string, string> {
                    { "typeName", type.Name }
                }.ToImmutableDictionary();
                context.ReportDiagnostic(Diagnostic.Create(Rule, originalNode.GetLocation(), props, type.Name.ToString()));
                return;
            }
            if (statement != null && identitySymbol != null)
            {
                var isDisposeOrAssigned = IsDisposedOrAssigned(semanticModel, statement, (ILocalSymbol)identitySymbol);
                if (isDisposeOrAssigned)
                {
                    return;
                }
                var props = new Dictionary <string, string> {
                    { "typeName", type.Name }
                }.ToImmutableDictionary();
                context.ReportDiagnostic(Diagnostic.Create(Rule, originalNode.GetLocation(), props, type.Name.ToString()));
            }
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationStartAnalysisContext.Compilation);

                if (!wellKnownTypeProvider.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemSecurityCryptographySymmetricAlgorithm, out var symmetricAlgorithmTypeSymbol))
                {
                    return;
                }

                var rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    var owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;

                    // TODO: Handle case when exactly one of the below rules is configured to skip analysis.
                    if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                DefinitelyUseCreateEncryptorWithNonDefaultIVRule, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken) &&
                        owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartAnalysisContext.Options,
                                                                MaybeUseCreateEncryptorWithNonDefaultIVRule, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        var invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        var methodSymbol        = invocationOperation.TargetMethod;

                        if (methodSymbol.ContainingType.GetBaseTypesAndThis().Contains(symmetricAlgorithmTypeSymbol) &&
                            methodSymbol.Name == "CreateEncryptor")
                        {
                            if (methodSymbol.Parameters.Length == 0)
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add((invocationOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                                }
                            }
                            else
                            {
                                operationAnalysisContext.ReportDiagnostic(
                                    invocationOperation.CreateDiagnostic(
                                        DefinitelyUseCreateEncryptorWithNonDefaultIVRule));
                            }
                        }
                    },
                        OperationKind.Invocation);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                WellKnownTypeNames.SystemSecurityCryptographySymmetricAlgorithm,
                                ConstructorMapper,
                                PropertyMappers,
                                HazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    rootOperationsNeedingAnalysis.First().Item1.Syntax.SyntaxTree,
                                    compilationAnalysisContext.Compilation,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            DiagnosticDescriptor descriptor;
                            switch (kvp.Value)
                            {
                            case HazardousUsageEvaluationResult.Flagged:
                                descriptor = DefinitelyUseCreateEncryptorWithNonDefaultIVRule;
                                break;

                            case HazardousUsageEvaluationResult.MaybeFlagged:
                                descriptor = MaybeUseCreateEncryptorWithNonDefaultIVRule;
                                break;

                            default:
                                Debug.Fail($"Unhandled result value {kvp.Value}");
                                continue;
                            }

                            RoslynDebug.Assert(kvp.Key.Method != null);            // HazardousUsageEvaluations only for invocations.
                            compilationAnalysisContext.ReportDiagnostic(
                                Diagnostic.Create(
                                    descriptor,
                                    kvp.Key.Location,
                                    kvp.Key.Method.ToDisplayString(
                                        SymbolDisplayFormat.MinimallyQualifiedFormat)));
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free();
                        allResults?.Free();
                    }
                });
            });
        }
Beispiel #19
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();

            // Security analyzer - analyze and report diagnostics on generated code.
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationStartAnalysisContext) =>
            {
                if (!compilationStartAnalysisContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemWebHttpCookie,
                                                                                                  out INamedTypeSymbol? httpCookieSymbol))
                {
                    return;
                }

                PooledHashSet <(IOperation Operation, ISymbol ContainingSymbol)> rootOperationsNeedingAnalysis = PooledHashSet <(IOperation, ISymbol)> .GetInstance();

                compilationStartAnalysisContext.RegisterOperationBlockStartAction(
                    (OperationBlockStartAnalysisContext operationBlockStartAnalysisContext) =>
                {
                    ISymbol owningSymbol = operationBlockStartAnalysisContext.OwningSymbol;

                    if (operationBlockStartAnalysisContext.Options.IsConfiguredToSkipAnalysis(Rule, owningSymbol, operationBlockStartAnalysisContext.Compilation, operationBlockStartAnalysisContext.CancellationToken))
                    {
                        return;
                    }

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        ISimpleAssignmentOperation simpleAssignmentOperation =
                            (ISimpleAssignmentOperation)operationAnalysisContext.Operation;

                        if (simpleAssignmentOperation.Target is IPropertyReferenceOperation propertyReferenceOperation &&
                            httpCookieSymbol.Equals(propertyReferenceOperation.Property.ContainingType) &&
                            propertyReferenceOperation.Property.Name == "HttpOnly" &&
                            simpleAssignmentOperation.Value.ConstantValue.HasValue &&
                            simpleAssignmentOperation.Value.ConstantValue.Value.Equals(false))
                        {
                            operationAnalysisContext.ReportDiagnostic(
                                simpleAssignmentOperation.CreateDiagnostic(
                                    Rule));
                        }
                    },
                        OperationKind.SimpleAssignment);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IReturnOperation returnOperation = (IReturnOperation)operationAnalysisContext.Operation;

                        if (httpCookieSymbol.Equals(returnOperation.ReturnedValue?.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(
                                    (returnOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Return);

                    operationBlockStartAnalysisContext.RegisterOperationAction(
                        (OperationAnalysisContext operationAnalysisContext) =>
                    {
                        IArgumentOperation argumentOperation = (IArgumentOperation)operationAnalysisContext.Operation;

                        if (httpCookieSymbol.Equals(argumentOperation.Value.Type))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(
                                    (argumentOperation.GetRoot(), operationAnalysisContext.ContainingSymbol));
                            }
                        }
                    },
                        OperationKind.Argument);
                });

                compilationStartAnalysisContext.RegisterCompilationEndAction(
                    (CompilationAnalysisContext compilationAnalysisContext) =>
                {
                    PooledDictionary <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult>?allResults = null;

                    try
                    {
                        lock (rootOperationsNeedingAnalysis)
                        {
                            if (!rootOperationsNeedingAnalysis.Any())
                            {
                                return;
                            }

                            allResults = PropertySetAnalysis.BatchGetOrComputeHazardousUsages(
                                compilationAnalysisContext.Compilation,
                                rootOperationsNeedingAnalysis,
                                compilationAnalysisContext.Options,
                                WellKnownTypeNames.SystemWebHttpCookie,
                                ConstructorMapper,
                                PropertyMappers,
                                HazardousUsageEvaluators,
                                InterproceduralAnalysisConfiguration.Create(
                                    compilationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    rootOperationsNeedingAnalysis.First().Operation,
                                    compilationAnalysisContext.Compilation,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: compilationAnalysisContext.CancellationToken));
                        }

                        if (allResults == null)
                        {
                            return;
                        }

                        foreach (KeyValuePair <(Location Location, IMethodSymbol?Method), HazardousUsageEvaluationResult> kvp
                                 in allResults)
                        {
                            if (kvp.Value == HazardousUsageEvaluationResult.Flagged)
                            {
                                compilationAnalysisContext.ReportDiagnostic(
                                    Diagnostic.Create(
                                        Rule,
                                        kvp.Key.Location));
                            }
                        }
                    }
                    finally
                    {
                        rootOperationsNeedingAnalysis.Free(compilationAnalysisContext.CancellationToken);
                        allResults?.Free(compilationAnalysisContext.CancellationToken);
                    }
                });
            });
        }
Beispiel #20
0
        private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var root = context.Node as ExpressionSyntax;

            if (root == null)
            {
                return;
            }

            var invokedMethod = context.SemanticModel.GetSymbolInfo(root).Symbol;

            if (invokedMethod == null)
            {
                return;
            }

            // If not an offending method/member/field, ignore
            var offendingType = invokedMethod.ContainingSymbol.ToString();

            if (!m_offendingTypeSuggestions.ContainsKey(offendingType))
            {
                return;
            }

            // Check test for Isolated
            var containingMethod = root.FirstAncestorOrSelf <MethodDeclarationSyntax>();

            if (containingMethod == null)
            {
                return;
            }
            if (IsMarkedIsolated(context.SemanticModel.GetDeclaredSymbol(containingMethod)))
            {
                return;
            }

            // Check fixture for Isolated
            var containingClass = root.FirstAncestorOrSelf <ClassDeclarationSyntax>();

            if (containingClass == null)
            {
                return;
            }
            if (IsMarkedIsolated(context.SemanticModel.GetDeclaredSymbol(containingClass)))
            {
                return;
            }

            // Check assembly for Isolated
            var containingAssembly = context.SemanticModel.Compilation.Assembly;

            if (IsMarkedIsolated(containingAssembly))
            {
                return;
            }

            // Use of offending method in non-Isolated test; let's register a diagnostic
            var diagnostic = Diagnostic.Create(Rule, root.GetLocation(), offendingType, m_offendingTypeSuggestions[offendingType]);

            context.ReportDiagnostic(diagnostic);
        }
Beispiel #21
0
        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 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:
            case SyntaxKind.DoubleQuoteToken:
                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:
            case SyntaxKind.MinusGreaterThanToken:
                // allow a space for these cases, 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 = token.IsFirstInLine()
                    ? TokenSpacingProperties.RemovePreceding
                    : TokenSpacingProperties.RemoveImmediatePreceding;
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, " not", "preceded"));
            }

            if (!suppressFollowingSpaceError)
            {
                if (!precedesStickyCharacter && !followedBySpace && !lastInLine)
                {
                    // Closing parenthesis must{} 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 must{ not} be {followed} by a space.
                    var properties = TokenSpacingProperties.RemoveFollowing;
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, token.GetLocation(), properties, " not", "followed"));
                }
            }
        }
Beispiel #22
0
 public void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
 {
     context.ReportDiagnostic(Diagnostic.Create(s_syntaxDiagnosticDescriptor, context.Tree.GetRoot().GetFirstToken().GetLocation()));
 }
        private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol expressionTypeOpt)
        {
            var syntaxTree = context.Operation.Syntax.SyntaxTree;

            if (!IsSupported(syntaxTree.Options))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var throwExpressionOperation = (IThrowOperation)context.Operation;
            var throwStatementOperation  = throwExpressionOperation.Parent;

            if (throwStatementOperation.Kind != OperationKind.ExpressionStatement)
            {
                return;
            }

            var throwStatementSyntax = throwExpressionOperation.Syntax;
            var options   = context.Options;
            var optionSet = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferThrowExpression, throwStatementSyntax.Language);

            if (!option.Value)
            {
                return;
            }

            var compilation   = context.Compilation;
            var semanticModel = compilation.GetSemanticModel(throwStatementSyntax.SyntaxTree);
            var semanticFacts = GetSemanticFactsService();

            if (semanticFacts.IsInExpressionTree(semanticModel, throwStatementSyntax, expressionTypeOpt, cancellationToken))
            {
                return;
            }

            var ifOperation = GetContainingIfOperation(
                semanticModel, (IExpressionStatementOperation)throwStatementOperation, cancellationToken);

            // This throw statement isn't parented by an if-statement.  Nothing to
            // do here.
            if (ifOperation == null)
            {
                return;
            }

            if (ifOperation.WhenFalse != null)
            {
                // Can't offer this if the 'if-statement' has an 'else-clause'.
                return;
            }

            var containingBlock = GetOperation(
                semanticModel, ifOperation.Syntax.Parent, cancellationToken) as IBlockOperation;

            if (containingBlock == null)
            {
                return;
            }

            if (!TryDecomposeIfCondition(ifOperation, out var localOrParameter))
            {
                return;
            }

            if (!TryFindAssignmentExpression(containingBlock, ifOperation, localOrParameter,
                                             out var expressionStatement, out var assignmentExpression))
            {
                return;
            }

            // We found an assignment using this local/parameter.  Now, just make sure there
            // were no intervening accesses between the check and the assignment.
            if (ValueIsAccessed(
                    semanticModel, ifOperation, containingBlock,
                    localOrParameter, expressionStatement, assignmentExpression))
            {
                return;
            }

            // Ok, there were no intervening writes or accesses.  This check+assignment can be simplified.
            var allLocations = ImmutableArray.Create(
                ifOperation.Syntax.GetLocation(),
                throwExpressionOperation.Exception.Syntax.GetLocation(),
                assignmentExpression.Value.Syntax.GetLocation());

            var descriptor = GetDescriptorWithSeverity(option.Notification.Value);

            context.ReportDiagnostic(
                Diagnostic.Create(descriptor, throwStatementSyntax.GetLocation(), additionalLocations: allLocations));

            // Fade out the rest of the if that surrounds the 'throw' exception.

            var tokenBeforeThrow = throwStatementSyntax.GetFirstToken().GetPreviousToken();
            var tokenAfterThrow  = throwStatementSyntax.GetLastToken().GetNextToken();

            context.ReportDiagnostic(
                Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                  Location.Create(syntaxTree, TextSpan.FromBounds(
                                                      ifOperation.Syntax.SpanStart,
                                                      tokenBeforeThrow.Span.End)),
                                  additionalLocations: allLocations));

            if (ifOperation.Syntax.Span.End > tokenAfterThrow.Span.Start)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(UnnecessaryWithSuggestionDescriptor,
                                      Location.Create(syntaxTree, TextSpan.FromBounds(
                                                          tokenAfterThrow.Span.Start,
                                                          ifOperation.Syntax.Span.End)),
                                      additionalLocations: allLocations));
            }
        }
Beispiel #24
0
 public void AnalyzeNode(SyntaxNodeAnalysisContext context)
 {
     // Ensure only executable nodes are analyzed.
     Assert.NotEqual(SyntaxKind.MethodDeclaration, context.Node.Kind());
     context.ReportDiagnostic(Diagnostic.Create(Descriptor, context.Node.GetLocation()));
 }
        /// <summary>
        /// Logic for each method invocation (including constructor)
        /// The argument list is required because <code>InvocationExpressionSyntax</code> and
        /// <code>ObjectCreationExpressionSyntax</code> do not share a common interface.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="argList"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private VariableState VisitInvocationAndCreation(ExpressionSyntax node,
                                                         ArgumentListSyntax argList,
                                                         ExecutionState state,
                                                         VariableState?initialVariableState = null)
        {
            var symbol = state.GetSymbol(node);

            if (symbol == null)
            {
                return(new VariableState(node, VariableTaint.Unknown));
            }

            var behavior    = BehaviorRepo.GetMethodBehavior(symbol);
            var returnState = initialVariableState.HasValue && !symbol.IsStatic
                                  ? initialVariableState.Value
                                  : new VariableState(node,
                                                      behavior?.TaintFromArguments?.Any() == true ? VariableTaint.Safe
                                                                                                  : VariableTaint.Unknown);

            for (var i = 0; i < argList?.Arguments.Count; i++)
            {
                var argument      = argList.Arguments[i];
                var argumentState = VisitExpression(argument.GetExpression(), state);

                Logger.Log(symbol.ContainingType + "." + symbol.Name + " -> " + argumentState);

                if (behavior == null)
                {
                    continue;
                }

                //If the API is at risk
                if ((argumentState.Taint == VariableTaint.Tainted ||
                     argumentState.Taint == VariableTaint.Unknown) && //Tainted values
                    //If the current parameter can be injected.
                    Array.Exists(behavior.InjectablesArguments, element => element == i))
                {
                    var newRule    = LocaleUtil.GetDescriptor(behavior.LocaleInjection);
                    var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString());
                    state.AnalysisContext.ReportDiagnostic(diagnostic);
                }
                else if (argumentState.Taint == VariableTaint.Constant && //Hard coded value
                                                                          //If the current parameter is a password
                         Array.Exists(behavior.PasswordArguments, element => element == i))
                {
                    var newRule    = LocaleUtil.GetDescriptor(behavior.LocalePassword);
                    var diagnostic = Diagnostic.Create(newRule, node.GetLocation(), GetMethodName(node), (i + 1).ToNthString());
                    state.AnalysisContext.ReportDiagnostic(diagnostic);
                }
                else if (Array.Exists(behavior.TaintFromArguments, element => element == i))
                {
                    returnState = returnState.Merge(argumentState);
                }

                //TODO: taint all objects passed as arguments
            }

            //Additional analysis by extension
            foreach (var ext in Extensions)
            {
                ext.VisitInvocationAndCreation(node, argList, state);
            }

            return(returnState);
        }
Beispiel #26
0
 private void Analyze(SyntaxTreeAnalysisContext context)
 => context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.Create(context.Tree, TextSpan.FromBounds(1000, 2000))));
        private void AnalyzeRandNextEqualsExpressions(SyntaxNodeAnalysisContext context)
        {
            var binaryExpressionSyntax = (BinaryExpressionSyntax)context.Node;

            // Check if right side is literal number: a == 123
            if (!(binaryExpressionSyntax.Right is LiteralExpressionSyntax right && right.IsKind(SyntaxKind.NumericLiteralExpression)))
            {
                return;
            }

            ISymbol symbol;

            // Check if left is invoking a method: a.b() == 123
            if (binaryExpressionSyntax.Left is InvocationExpressionSyntax invocationExpressionSyntax)
            {
                symbol = context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol;
            }
            else
            {
                return;
            }

            // Check if left Type exists: item.b = 123
            if (symbol == null || symbol.ContainingType == null)
            {
                return;
            }

            if (!(symbol is IMethodSymbol methodSymbol))
            {
                return;
            }

            string containingType = symbol.ContainingType.ToString();

            string methodName = methodSymbol.Name;

            if (containingType != "Terraria.Utilities.UnifiedRandom" || methodName != "Next")
            {
                return;
            }

            if (methodSymbol.Parameters.Length != 1 || methodSymbol.Parameters[0].Type.Name != "Int32")
            {
                return;
            }

            //var argumentListSyntax = invocationExpressionSyntax.ArgumentList;

            //if (!(argumentListSyntax.Arguments[0].Expression is ExpressionSyntax argument))
            //    return;

            //if (!(argumentListSyntax.Arguments[0].Expression is LiteralExpressionSyntax parameter && parameter.IsKind(SyntaxKind.NumericLiteralExpression)))
            //    return;

            //int parameterValue = (int)parameter.Token.Value;

            //if (parameterValue != 0)
            //    return;

            string original = binaryExpressionSyntax.ToFullString();

            //string result = $"NextBool({argument.GetText()})";

            bool not = binaryExpressionSyntax.Kind() == SyntaxKind.NotEqualsExpression;

            var methodcall = invocationExpressionSyntax.Expression as MemberAccessExpressionSyntax;
            var nextBool   = invocationExpressionSyntax.ReplaceNode(methodcall.Name, SyntaxFactory.IdentifierName("NextBool"));

            nextBool = nextBool.WithoutTrailingTrivia();
            var notNextBool = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, nextBool);

            //var c = binaryExpressionSyntax.remove(binaryExpressionSyntax.OperatorToken, SyntaxRemoveOptions.KeepExteriorTrivia);
            //c = c.RemoveNode(binaryExpressionSyntax.);

            string result = not ? notNextBool.ToFullString() : nextBool.ToFullString();

            //invocationExpressionSyntax.ReplaceToken(invocationExpressionSyntax.Expression as MemberAccessException mem)

            var builder = ImmutableDictionary.CreateBuilder <string, string>();

            builder["result"] = result;
            var properties = builder.ToImmutable();

            // "The expression {0} should be changed to {1} for readability"
            var diagnostic = Diagnostic.Create(SimplifyUnifiedRandomRule, binaryExpressionSyntax.GetLocation(), properties, original, result);

            context.ReportDiagnostic(diagnostic);

            Console.WriteLine();
        }
Beispiel #28
0
        private static void Handle(SyntaxNodeAnalysisContext context)
        {
            if (!context.IsExcludedFromAnalysis() &&
                context.Node is InvocationExpressionSyntax invocation &&
                invocation.ArgumentList is ArgumentListSyntax argumentList)
            {
                if (TryGetX(context, out var member, out var name, out var flags, out var types))
                {
                    if (member.Match == FilterMatch.NoMatch)
                    {
                        if (member.ReflectedType?.IsSealed == true ||
                            member.ReflectedType?.IsStatic == true ||
                            member.ReflectedType?.TypeKind == TypeKind.Interface ||
                            member.GetX == KnownSymbol.Type.GetNestedType ||
                            member.GetX == KnownSymbol.Type.GetConstructor ||
                            member.TypeSource is TypeOfExpressionSyntax)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(REFL003MemberDoesNotExist.Descriptor, name.Argument.GetLocation(), member.ReflectedType, name.MetadataName));
                        }
                        else if (!IsNullCheckedAfter(invocation))
                        {
                            context.ReportDiagnostic(Diagnostic.Create(REFL009MemberCantBeFound.Descriptor, name.Argument.GetLocation(), name.MetadataName, member.ReflectedType));
                        }
                    }

                    if (member.Match == FilterMatch.Ambiguous)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL004AmbiguousMatch.Descriptor,
                                argumentList.GetLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(
                                    nameof(INamedTypeSymbol),
                                    member.ReflectedType?.QualifiedMetadataName())));
                    }

                    if (HasWrongFlags(member, flags, out var location, out var flagsText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL005WrongBindingFlags.Descriptor,
                                location,
                                ImmutableDictionary<string, string>.Empty.Add(nameof(ArgumentSyntax), flagsText),
                                $" Expected: {flagsText}."));
                    }

                    if (HasRedundantFlag(member, flags, out flagsText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL006RedundantBindingFlags.Descriptor,
                                flags.Argument.GetLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(nameof(ArgumentSyntax), flagsText),
                                $" Expected: {flagsText}."));
                    }

                    if (HasMissingFlags(member, flags, out location, out flagsText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL008MissingBindingFlags.Descriptor,
                                location,
                                ImmutableDictionary<string, string>.Empty.Add(nameof(ArgumentSyntax), flagsText),
                                $" Expected: {flagsText}."));
                    }

                    if (member.Match == FilterMatch.WrongMemberType)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL013MemberIsOfWrongType.Descriptor,
                                invocation.GetNameLocation(),
                                member.ReflectedType,
                                member.Symbol.Kind.ToString().ToLower(),
                                name.MetadataName));
                    }

                    if (IsPreferGetMemberThenAccessor(member, name, flags, types, context, out var callText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL014PreferGetMemberThenAccessor.Descriptor,
                                invocation.GetNameLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(
                                    nameof(ExpressionSyntax),
                                    callText),
                                callText));
                    }

                    if (member.Match == FilterMatch.UseContainingType)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL015UseContainingType.Descriptor,
                                TargetTypeLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(
                                    nameof(ISymbol.ContainingType),
                                    member.Symbol.ContainingType.ToString(context)),
                                member.Symbol.ContainingType.Name));
                    }

                    if (ShouldUseNameof(member, name, context, out location, out var nameText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL016UseNameof.Descriptor,
                                location,
                                ImmutableDictionary<string, string>.Empty.Add(nameof(NameSyntax), nameText)));
                    }

                    if (UsesNameOfWrongMember(member, name, context, out location, out nameText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL017DontUseNameofWrongMember.Descriptor,
                                location,
                                ImmutableDictionary<string, string>.Empty.Add(nameof(ExpressionSyntax), nameText),
                                nameText));
                    }

                    if (member.Match == FilterMatch.ExplicitImplementation)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL018ExplicitImplementation.Descriptor,
                                TargetTypeLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(
                                    nameof(ISymbol.ContainingType),
                                    member.Symbol.ContainingType.ToString(context)),
                                member.Symbol.Name));
                    }

                    if (member.Match == FilterMatch.WrongTypes)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL019NoMemberMatchesTheTypes.Descriptor,
                                types.Argument?.GetLocation() ?? invocation.GetNameLocation()));
                    }

                    if (HasMissingTypes(member, types, context, out var typeArrayText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL029MissingTypes.Descriptor,
                                argumentList.GetLocation(),
                                ImmutableDictionary<string, string>.Empty.Add(nameof(TypeSyntax), typeArrayText)));
                    }

                    if (ShouldUseSameTypeAsParameter(member, types, context, out location, out var typeText))
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL033UseSameTypeAsParameter.Descriptor,
                                location,
                                ImmutableDictionary<string, string>.Empty.Add(nameof(TypeSyntax), typeText),
                                typeText));
                    }

                    if (member.Match == FilterMatch.InSufficientFlags)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                REFL045InsufficientFlags.Descriptor,
                                flags.Argument?.GetLocation() ?? invocation.GetNameLocation()));
                    }
                }
            }

            Location TargetTypeLocation()
            {
                return invocation.Expression is MemberAccessExpressionSyntax explicitMemberAccess &&
                        explicitMemberAccess.Expression is TypeOfExpressionSyntax typeOf
                    ? typeOf.Type.GetLocation()
                    : invocation.Expression.GetLocation();
            }
        }
        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"));
            }
        }
Beispiel #30
0
 /// <summary>
 ///   Creates a diagnostic for <paramref name="location" /> using the <paramref name="messageArgs" /> to format the
 ///   diagnostic message.
 /// </summary>
 /// <param name="location">The location the diagnostic is emitted for.</param>
 /// <param name="messageArgs">The arguments for formatting the diagnostic message.</param>
 public Diagnostic CreateDiagnostic([NotNull] Location location, params object[] messageArgs)
 {
     return(Diagnostic.Create(Descriptor, location, messageArgs));
 }