private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
    {
      var methodNode = (MethodDeclarationSyntax)context.Node;
      var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
      var typeSymbol = methodSymbol.ContainingType;

      if (typeSymbol.IsStereotype() && methodSymbol.IsDataPortalOperation() &&
        methodSymbol.DeclaredAccessibility == Accessibility.Public)
      {
        if(typeSymbol.TypeKind == TypeKind.Interface)
        {
          context.ReportDiagnostic(Diagnostic.Create(
            IsOperationMethodPublicAnalyzer.makeNonPublicForInterfaceRule,
            methodNode.Identifier.GetLocation()));
        }
        else
        {
          var properties = new Dictionary<string, string>()
          {
            [IsOperationMethodPublicAnalyzerConstants.IsSealed] = typeSymbol.IsSealed.ToString()
          }.ToImmutableDictionary();

          context.ReportDiagnostic(Diagnostic.Create(IsOperationMethodPublicAnalyzer.makeNonPublicRule,
            methodNode.Identifier.GetLocation(), properties));
        }
      }
    }
        private static void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            AttributeSyntax attribute = (AttributeSyntax)context.Node;
            var model = context.SemanticModel;
            var attributeSymbol = model.GetSymbolInfo(attribute).Symbol?.ContainingSymbol;
            // TODO: Write a convenience method to do this properly, with namespace as well...
            if (attributeSymbol?.Name != "ReadWriteForEfficiencyAttribute")
            {
                return;
            }
            // ReadWriteForEfficiency can only be applied to fields, so the grandparent node must
            // be a field declaration syntax.
            var fieldDeclaration = (FieldDeclarationSyntax)attribute.Parent.Parent;
            foreach (var individualField in fieldDeclaration.Declaration.Variables)
            {
                var fieldSymbol = model.GetDeclaredSymbol(individualField);
                if (fieldSymbol.DeclaredAccessibility != Accessibility.Private)
                {
                    context.ReportDiagnostic(ReadWriteForEfficiencyNotPrivate, individualField, fieldSymbol.Name);
                }

                var invalidAssignments = fieldSymbol.ContainingType.DeclaringSyntaxReferences
                    .SelectMany(reference => reference.GetSyntax().DescendantNodes())
                    .OfType<AssignmentExpressionSyntax>()
                    .Where(n => IsAssignmentOutsideConstructor(n, fieldSymbol, model));
                foreach (var invalidAssignment in invalidAssignments)
                {
                    context.ReportDiagnostic(ReadWriteForEfficiencyAssignmentOutsideConstructor,
                        invalidAssignment, fieldSymbol.Name);
                }
            }
        }
Example #3
0
        private void AnalyzeIfBlock(SyntaxNodeAnalysisContext context)
        {
            var statement = context.Node as IfStatementSyntax;

            var thenClause = statement.Statement;

            if (!(thenClause is BlockSyntax))
            {
                // create the diagnostic:
                var location = thenClause.GetLocation();
                var diagnostic = Diagnostic.Create(Rule, location, "true clause");
                context.ReportDiagnostic(diagnostic);
            }

            // check the else clause:
            var elseStatement = statement.Else;
            if (elseStatement != null)
            {
                if (!(elseStatement.Statement is BlockSyntax))
                {
                    var location = elseStatement.Statement.GetLocation();
                    var diagnostic = Diagnostic.Create(Rule, location, "false (else) clause");
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
 public void AnalyzeNode(SyntaxNodeAnalysisContext context)
 {
     var classDecl = (ClassDeclarationSyntax)context.Node;
     var location = classDecl.Identifier.GetLocation();
     context.ReportDiagnostic(Diagnostic.Create(Decsciptor1, location));
     context.ReportDiagnostic(Diagnostic.Create(Decsciptor2, location));
 }
        private void AnalyzeIfOrElseStatement(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            IfStatementSyntax ifStatement = context.Node as IfStatementSyntax;

            // Is this an if statement followed directly by a call with no braces?
            if ((ifStatement != null) &&
                (ifStatement.Statement != null) &&
                (ifStatement.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location loc = ifStatement.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "if");
                context.ReportDiagnostic(diagnostic);
            }

            // Is this an else clause followed by a call with no braces?
            ElseClauseSyntax elseSyntax = context.Node as ElseClauseSyntax;
            if ((elseSyntax != null) &&
                (elseSyntax.Statement != null ) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.IfStatement) == false) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location loc = elseSyntax.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "else");
                context.ReportDiagnostic(diagnostic);
            }
        }
        private static void Analyzer(SyntaxNodeAnalysisContext context)
        {
            var documentationNode = (DocumentationCommentTriviaSyntax)context.Node;
            var method = GetMethodFromXmlDocumentation(documentationNode);
            if (method == null) return;
            var methodParameters = method.ParameterList.Parameters;
            var xElementsWitAttrs = documentationNode.Content.OfType<XmlElementSyntax>()
                                    .Where(xEle => xEle.StartTag?.Name?.LocalName.ValueText == "param")
                                    .SelectMany(xEle => xEle.StartTag.Attributes, (xEle, attr) => attr as XmlNameAttributeSyntax)
                                    .Where(attr => attr != null);

            var keys = methodParameters.Select(parameter => parameter.Identifier.ValueText)
                .Union(xElementsWitAttrs.Select(x => x.Identifier?.Identifier.ValueText))
                .ToImmutableHashSet();

            var parameterWithDocParameter = (from key in keys
                                            where key != null
                                            let Parameter = methodParameters.FirstOrDefault(p => p.Identifier.ValueText == key)
                                            let DocParameter = xElementsWitAttrs.FirstOrDefault(p => p.Identifier?.Identifier.ValueText == key)
                                            select new { Parameter, DocParameter });

            if (parameterWithDocParameter.Any(p => p.Parameter == null))
            {
                var properties = new Dictionary<string, string> {["kind"] = "nonexistentParam" }.ToImmutableDictionary();
                var diagnostic = Diagnostic.Create(Rule, documentationNode.GetLocation(), properties);
                context.ReportDiagnostic(diagnostic);
            }

            if (parameterWithDocParameter.Any(p => p.DocParameter == null))
            {
                var properties = new Dictionary<string, string> { ["kind"] = "missingDoc" }.ToImmutableDictionary();
                var diagnostic = Diagnostic.Create(Rule, documentationNode.GetLocation(), properties);
                context.ReportDiagnostic(diagnostic);
            }
        }
        static void AnalyzeField(SyntaxNodeAnalysisContext nodeContext)
        {
            var node = nodeContext.Node as FieldDeclarationSyntax;
            if (node?.Declaration?.Variables == null)
                return;
            if (node.Modifiers.Any(m => m.IsKind(SyntaxKind.ConstKeyword)))
                return;
            var type = nodeContext.SemanticModel.GetTypeInfo(node.Declaration.Type).Type;
            if (type == null)
                return;
            foreach (var v in node.Declaration.Variables)
            {
                var initializer = v.Initializer?.Value;
                if (initializer == null)
                    continue;

                if (initializer.IsKind(SyntaxKind.DefaultExpression))
                {
                    //var defaultExpr = (DefaultExpressionSyntax)initializer;
                    //var defaultType = nodeContext.SemanticModel.GetTypeInfo(defaultExpr.Type).Type;
                    //if (defaultType == type) {
                    nodeContext.ReportDiagnostic(Diagnostic.Create(descriptor, v.Initializer.GetLocation()));
                    //}
                    continue;
                }

                var constValue = nodeContext.SemanticModel.GetConstantValue(initializer);
                if (!constValue.HasValue)
                    continue;
                if (IsDefaultValue(type, constValue.Value))
                {
                    nodeContext.ReportDiagnostic(Diagnostic.Create(descriptor, v.Initializer.GetLocation()));
                }
            }
        }
 private static void Analyzer(SyntaxNodeAnalysisContext context)
 {
     if (context.IsGenerated()) return;
     var ifStatement = context.Node as IfStatementSyntax;
     if (ifStatement == null) return;
     if (ifStatement.Else == null) return;
     var blockIf = ifStatement.Statement as BlockSyntax;
     var blockElse = ifStatement.Else.Statement as BlockSyntax;
     if ((blockIf == null || blockIf.Statements.Count == 1) &&
         (blockElse == null || blockElse.Statements.Count == 1))
     {
         var statementInsideIf = ifStatement.Statement is BlockSyntax ? ((BlockSyntax)ifStatement.Statement).Statements.Single() : ifStatement.Statement;
         var elseStatement = ifStatement.Else;
         var statementInsideElse = elseStatement.Statement is BlockSyntax ? ((BlockSyntax)elseStatement.Statement).Statements.Single() : elseStatement.Statement;
         if (statementInsideIf is ReturnStatementSyntax && statementInsideElse is ReturnStatementSyntax)
         {
             var diagnostic = Diagnostic.Create(RuleForIfWithReturn, ifStatement.IfKeyword.GetLocation(), "You can use a ternary operator.");
             context.ReportDiagnostic(diagnostic);
             return;
         }
         var expressionInsideIf = statementInsideIf as ExpressionStatementSyntax;
         var expressionInsideElse = statementInsideElse as ExpressionStatementSyntax;
         if (expressionInsideIf != null && expressionInsideIf.Expression.IsKind(SyntaxKind.SimpleAssignmentExpression) && expressionInsideElse != null && expressionInsideElse.Expression.IsKind(SyntaxKind.SimpleAssignmentExpression))
         {
             var assignmentExpressionInsideIf = (AssignmentExpressionSyntax)expressionInsideIf.Expression;
             var assignmentExpressionInsideElse = (AssignmentExpressionSyntax)expressionInsideElse.Expression;
             var variableIdentifierInsideIf = assignmentExpressionInsideIf.Left as IdentifierNameSyntax;
             var variableIdentifierInsideElse = assignmentExpressionInsideElse.Left as IdentifierNameSyntax;
             if (variableIdentifierInsideIf == null || variableIdentifierInsideElse == null
                 || variableIdentifierInsideIf.Identifier.Text != variableIdentifierInsideElse.Identifier.Text) return;
             var diagnostic = Diagnostic.Create(RuleForIfWithAssignment, ifStatement.IfKeyword.GetLocation(), "You can use a ternary operator.");
             context.ReportDiagnostic(diagnostic);
         }
     }
 }
        public void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            var ifStatementSyntax = (IfStatementSyntax)context.Node;

            if (ifStatementSyntax.Else != null)
            {
                SyntaxNode ifExpression = GetStatementSingle(ifStatementSyntax.Statement);

                SyntaxNode elseExpression = GetStatementSingle(ifStatementSyntax.Else.Statement);

                if (ifExpression != null && elseExpression != null)
                {
                    if (ifExpression is ReturnStatementSyntax && elseExpression is ReturnStatementSyntax)
                        context.ReportDiagnostic(Diagnostic.Create(Rule, ifStatementSyntax.GetLocation()));
                    else if (ifExpression is ExpressionStatementSyntax && elseExpression is ExpressionStatementSyntax)
                    {
                        ExpressionSyntax ifExpressionStatement = ((ExpressionStatementSyntax)ifExpression).Expression;
                        ExpressionSyntax elseExpressionStatement = ((ExpressionStatementSyntax)elseExpression).Expression;

                        if (ifExpressionStatement.IsKind(SyntaxKind.SimpleAssignmentExpression) &&
                            elseExpressionStatement.IsKind(SyntaxKind.SimpleAssignmentExpression))
                        {
                            var ifAssignmentVariable = ((BinaryExpressionSyntax)ifExpressionStatement).Left as IdentifierNameSyntax;
                            var elseAssignmentVariable = ((BinaryExpressionSyntax)elseExpressionStatement).Left as IdentifierNameSyntax;

                            if (ifAssignmentVariable != null && elseAssignmentVariable != null &&
                               ifAssignmentVariable.Identifier.Text == elseAssignmentVariable.Identifier.Text)
                                context.ReportDiagnostic(Diagnostic.Create(Rule, ifStatementSyntax.GetLocation()));
                        }
                    }
                }
            }
        }
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {

            var equalsExpression = (BinaryExpressionSyntax)context.Node;

            var left = context.SemanticModel.GetTypeInfo(equalsExpression.Left);
            var right = context.SemanticModel.GetTypeInfo(equalsExpression.Right);

            if (
                left.IsLite() && right.IsEntity() ||
                left.IsEntity() && right.IsLite())
            {
                context.ReportDiagnostic(Diagnostic.Create(RuleLiteEntity, equalsExpression.GetLocation()));
            }
            else if (
                left.IsLite() && right.IsLite())
            {
                var tLeft = left.GetLiteEntityType();
                var tRight = right.GetLiteEntityType();

                if (tLeft != null && 
                    tRight != null &&
                    !tLeft.IsAbstract &&
                    !tRight.IsAbstract &&
                    !tLeft.GetBaseTypesAndThis().Contains(tRight) &&
                    !tRight.GetBaseTypesAndThis().Contains(tLeft))
                {
                    context.ReportDiagnostic(Diagnostic.Create(RuleEntityTypes, equalsExpression.GetLocation(), tLeft.Name, tRight.Name));
                }
            }
        }
 public static void ReportLSPViolatingExceptionIfThrown(SyntaxNodeAnalysisContext context,
                                                        INamedTypeSymbol exceptionType,
                                                        DiagnosticDescriptor rule)
 {
     var throwStatement = context.Node as ThrowStatementSyntax;
     throwStatement.Expression.DescendantNodesAndTokens()
                   .Where(t => t.IsKind(SyntaxKind.IdentifierName) || t.IsKind(SyntaxKind.IdentifierToken))
                   .TryFirst()
                   .Match()
                   .Some().Where(t => t.IsNode).Do(t =>
                   {
                       var identifier = t.AsNode() as IdentifierNameSyntax;
                       var identifierType = context.SemanticModel.GetSymbolInfo(identifier);
                       if (identifierType.Symbol.Equals(exceptionType))
                       {
                           context.ReportDiagnostic(Diagnostic.Create(rule, identifier.GetLocation()));
                       }
                   })
                   .Some().Do(t =>
                   {
                       var identifier = t.Parent as IdentifierNameSyntax;
                       var identiferType = context.SemanticModel.GetTypeInfo(identifier).Type;
                       if (identiferType.Equals(exceptionType))
                       {
                           context.ReportDiagnostic(Diagnostic.Create(rule, identifier.GetLocation()));
                       }
                   })
                   .None().Do(() => { })
                   .Exec();
 }
        private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated()) return;
            var method = (MethodDeclarationSyntax)context.Node;
            if (method.Identifier.ToString().EndsWith("Async")) return;
            if (method.Modifiers.Any(SyntaxKind.NewKeyword, SyntaxKind.OverrideKeyword)) return;

            var errorMessage = method.Identifier.ToString() + "Async";
            var diag = Diagnostic.Create(Rule, method.Identifier.GetLocation(), errorMessage);

            if (method.Modifiers.Any(SyntaxKind.AsyncKeyword))
            {
                context.ReportDiagnostic(diag);
                return;
            }
            var returnType = context.SemanticModel.GetSymbolInfo(method.ReturnType).Symbol as INamedTypeSymbol;
            if (returnType == null) return;

            if (returnType.ToString() == "System.Threading.Tasks.Task" ||
                (returnType.IsGenericType && returnType.ConstructedFrom.ToString() == "System.Threading.Tasks.Task<TResult>"))
            {
                context.ReportDiagnostic(diag);
            }

        }
		private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
		{
			var classDeclaration = context.Node as ClassDeclarationSyntax;
			
			var dupeExports = classDeclaration.GetAttributes("Export")
				.GroupBy(x => x.ArgumentList.Arguments.First().ToString())
				.Where(x => 1 < x.Count())
				.Select(x => x.Key.ToString())
				.ToArray();

			if (dupeExports.Any())
				context.ReportDiagnostic(Diagnostic.Create(
					DuplicateExportAttributeRule,
					classDeclaration.GetLocation(),
					string.Join(", ", dupeExports)));


			var dupeMetadatas = classDeclaration.GetAttributes("ExportMetadata")
				.GroupBy(x => x.ArgumentList.Arguments.First().ToString())
				.Where(x => 1 < x.Count())
				.Select(x => x.Key.ToString().Replace("\"", ""))
				.ToArray();

			if (dupeMetadatas.Any())
				context.ReportDiagnostic(Diagnostic.Create(
					DuplicateExportMetadataAttributeRule,
					classDeclaration.GetLocation(),
					string.Join(", ", dupeMetadatas)));
		}
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            var symbol = context.SemanticModel.GetSymbolInfo(context.Node).Symbol;

            var methodLambda = symbol as IMethodSymbol;

            if (methodLambda != null && methodLambda.IsAsync)
            {
                var type = context.SemanticModel.GetTypeInfo(context.Node);
                if (this.CheckIfVoidReturningDelegateType(type.ConvertedType))
                {
                    // check if the lambda is being assigned to a variable.  This has a code fix.
                    var parent = context.Node.Parent;

                    while (parent != null && !(parent is InvocationExpressionSyntax))
                    {
                        if (parent is VariableDeclarationSyntax)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(Rule2, parent.GetLocation()));
                            return;
                        }

                        parent = parent.Parent;
                    }

                    // if not, add the normal diagnostic
                    context.ReportDiagnostic(Diagnostic.Create(Rule1, context.Node.GetLocation()));
                    return;
                }
            }

            return;
        }
        private static void Analyze(SyntaxNodeAnalysisContext context)
        {
            var model = context.SemanticModel;

            var classDeclaration = context.Node as ClassDeclarationSyntax;
            if (classDeclaration == null) return;

            var declaredSymbol = model.GetDeclaredSymbol(classDeclaration);
            if (declaredSymbol == null) return;
            if (declaredSymbol.IsAbstract) return;

            var hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.Hub<T>");
            if (hub == null) return;

            var hubAttribute = declaredSymbol.GetAttributes().FindAttribute("PhotonWire.Server.HubAttribute");
            if (hubAttribute == null)
            {
                // if type == hub, needs attribute
                context.ReportDiagnostic(Diagnostic.Create(HubNeedsHubAttribute, classDeclaration.GetLocation()));
                return;
            }

            var methods = declaredSymbol.GetMembers()
                .OfType<IMethodSymbol>()
                .Where(x => x.MethodKind == MethodKind.Ordinary)
                .Where(x => x.DeclaredAccessibility == Accessibility.Public)
                .Where(x => !x.IsStatic)
                .ToArray();

            // all member needs OperationAttribute
            var attrs = methods.Select(x => x.GetAttributes().FindAttribute("PhotonWire.Server.OperationAttribute")).ToArray();

            var set = new HashSet<byte>();
            for (int i = 0; i < methods.Length; i++)
            {
                var m = methods[i];
                var a = attrs[i];

                if (a == null)
                {
                    // attr needs OperationAttribute;
                    context.ReportDiagnostic(Diagnostic.Create(MethodNeedsOperationAttribute, m.Locations[0]));
                    continue;
                }

                if (a.ConstructorArguments.Length != 1) continue;
                var id = (byte)a.ConstructorArguments[0].Value;
                if (!set.Add(id))
                {
                    // Report Diagnostics
                    var location = Location.Create(a.ApplicationSyntaxReference.SyntaxTree, a.ApplicationSyntaxReference.Span);
                    context.ReportDiagnostic(Diagnostic.Create(OperationIdMustBeUniqueAttribute, location, id));
                }
            }

            var clientType = hub.TypeArguments[0];
            VerifyClient(context, declaredSymbol, clientType);
        }
        private void AnalyzeMethodInvocation(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax)context.Node;

            var symbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol;

            if (symbol != null && FormatHelper.IsFormattableCall(symbol, context.SemanticModel))
            {
                var parsedFormat = FormatHelper.ParseFormatMethodInvocation(invocation, symbol, context.SemanticModel);
                if (!parsedFormat.IsValid)
                {
                    context.ReportDiagnostic(Diagnostic.Create(InvalidFormatRule, parsedFormat.FormatArgument.GetLocation()));
                }
                else
                {
                    // Special corner case: if param args is an expression that provides object or object[]
                    // then giving up the analysis!
                    int actualArgumentsLength = parsedFormat.Args.Length;

                    if (parsedFormat.Args.Length == 1)
                    {
                        ITypeSymbol expressionType = GetExpressionType(parsedFormat.Args[0], context.SemanticModel);
                        if (expressionType?.Equals(context.SemanticModel.GetClrType(typeof (object))) == true ||
                            IsArrayOfObjects(expressionType, context.SemanticModel))
                        {
                            // Giving up all the checks! Can't deal with them!
                            return;
                        }
                    }

                    // Checking for non-existed indices in a format string
                    var missedArguments = parsedFormat.UsedIndices.Where(i => i < 0 || i >= actualArgumentsLength).ToList();
                    if (missedArguments.Count != 0)
                    {
                        context.ReportDiagnostic(Diagnostic
                            .Create(
                                NonExistingIndexRule, parsedFormat.FormatArgument.GetLocation(),
                                string.Join(", ", missedArguments)));
                    }

                    // TODO: unused parameters should have warnings on the parameters themselves not on the string format!
                    var excessiveArguments =
                        Enumerable.Range(0, actualArgumentsLength)
                            .Where(i => !parsedFormat.UsedIndices.Contains(i))
                            .Select(i => parsedFormat.Args[i])
                            .ToList();

                    foreach (var excessiveArg in excessiveArguments)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                ExcessiveArgumentRule, excessiveArg.GetLocation(), excessiveArg));
                    }
                }
            }
        }
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            var method = context.SemanticModel.GetEnclosingSymbol(context.Node.SpanStart) as IMethodSymbol;

            if (method != null && method.IsAsync)
            {
                var invokeMethod = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IMethodSymbol;

                if (invokeMethod != null && !invokeMethod.IsExtensionMethod)
                {
                    // Checks if the Wait method is called within an async method then creates the diagnostic.
                    if (invokeMethod.OriginalDefinition.Name.Equals("Wait"))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
                        return;
                    }

                    // Checks if the WaitAny method is called within an async method then creates the diagnostic.
                    if (invokeMethod.OriginalDefinition.Name.Equals("WaitAny"))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
                        return;
                    }

                    // Checks if the WaitAll method is called within an async method then creates the diagnostic.
                    if (invokeMethod.OriginalDefinition.Name.Equals("WaitAll"))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
                        return;
                    }

                    // Checks if the Sleep method is called within an async method then creates the diagnostic.
                    if (invokeMethod.OriginalDefinition.Name.Equals("Sleep"))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
                        return;
                    }

                    // Checks if the GetResult method is called within an async method then creates the diagnostic.     
                    if (invokeMethod.OriginalDefinition.Name.Equals("GetResult"))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.Parent.GetLocation()));
                        return;
                    }
                }

                var property = context.SemanticModel.GetSymbolInfo(context.Node).Symbol as IPropertySymbol;

                // Checks if the Result property is called within an async method then creates the diagnostic.
                if (property != null && property.OriginalDefinition.Name.Equals("Result"))
                {
                    context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
                    return;
                }
            }
        }
        private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated()) return;
            var objectCreation = context.Node as ObjectCreationExpressionSyntax;
            if (objectCreation == null) return;
            if (objectCreation?.Parent is UsingStatementSyntax) return;
            if (objectCreation?.Parent is ReturnStatementSyntax) return;
            if (objectCreation.Ancestors().Any(i => i.IsAnyKind(
                SyntaxKind.ThisConstructorInitializer,
                SyntaxKind.BaseConstructorInitializer,
                SyntaxKind.ObjectCreationExpression))) return;

            var semanticModel = context.SemanticModel;
            var type = semanticModel.GetSymbolInfo(objectCreation.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 (objectCreation.Parent.IsKind(SyntaxKind.SimpleAssignmentExpression))
            {
                var assignmentExpression = (AssignmentExpressionSyntax)objectCreation.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 (objectCreation.Parent.IsKind(SyntaxKind.EqualsValueClause) && objectCreation.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator))
            {
                var variableDeclarator = (VariableDeclaratorSyntax)objectCreation.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
            {
                var props = new Dictionary<string, string> { { "typeName", type.Name } }.ToImmutableDictionary();
                context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.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, objectCreation.GetLocation(), props, type.Name.ToString()));
            }
        }
        private void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
        {
            var isExpression = context.Node as BinaryExpressionSyntax;

            var isIdentifierExpression = isExpression?.Left as IdentifierNameSyntax;
            if (isIdentifierExpression == null)
            {
                return;
            }
            var isIdentifier = isIdentifierExpression.Identifier.ValueText;

            var ifExpression = isExpression.AncestorsAndSelf().OfType<IfStatementSyntax>().FirstOrDefault();
            if (ifExpression == null)
            {
                return;
            }

            var asExpressions = ifExpression.Statement.DescendantNodes().OfType<BinaryExpressionSyntax>().Where(x => x.OperatorToken.Kind() == SyntaxKind.AsKeyword);
            foreach (var asExpression in asExpressions)
            {
                var asIdentifier = asExpression.Left as IdentifierNameSyntax;
                if (asIdentifier == null)
                {
                    continue;
                }

                if (!string.Equals(asIdentifier.Identifier.ValueText, isIdentifier))
                {
                    continue;
                }

                context.ReportDiagnostic(Diagnostic.Create(Rule, isExpression.GetLocation(), isIdentifier));
            }

            var castExpressions = ifExpression.Statement.DescendantNodes().OfType<CastExpressionSyntax>().ToArray();
            foreach (var castExpression in castExpressions)
            {
                var castIdentifier = castExpression.Expression as IdentifierNameSyntax;
                if (castIdentifier == null)
                {
                    continue;
                }

                if (!string.Equals(castIdentifier.Identifier.ValueText, isIdentifier))
                {
                    continue;
                }

                context.ReportDiagnostic(Diagnostic.Create(Rule, isExpression.GetLocation(), isIdentifier));
            }
        }
        // Called when Roslyn encounters a catch clause.
        private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var catchBlock = (CatchClauseSyntax)context.Node;

            if (catchBlock.Declaration == null || catchBlock.Declaration.CatchIsTooGeneric(context.SemanticModel))
            {
                var usages = context.SemanticModel.GetExceptionIdentifierUsages(catchBlock);

                    bool wasObserved =
                    usages.
                        Select(id => id.Identifier)
                        .Any(u => u.Parent is ArgumentSyntax || // Exception object was used directly
                                  u.Parent is AssignmentExpressionSyntax || // Was saved to field or local
                                  // For instance in Console.WriteLine($"e = {e}");
                                  u.Parent is InterpolationSyntax ||
                                  // or Inner exception, Message or other properties were used
                                  u.Parent is MemberAccessExpressionSyntax);

                if (wasObserved)
                {
                    // Exception was observed!
                    return;
                }

                StatementSyntax syntax = catchBlock.Block;
                var controlFlow = context.SemanticModel.AnalyzeControlFlow(syntax);

                // Warn for every exit points
                foreach (SyntaxNode @return in controlFlow.ExitPoints)
                {
                    // Due to some very weird behavior, return statement would be an exit point of the method
                    // even if the return statement is unreachable (for instance, because throw statement is preceding it);
                    // So analyzing control flow once more and emitting a warning only when the endpoint is reachable!
                    var localFlow = context.SemanticModel.AnalyzeControlFlow(@return);

                    if (localFlow.Succeeded && localFlow.StartPointIsReachable)
                    {
                        // Block is empty, create and report diagnostic warning.
                        var diagnostic = Diagnostic.Create(Rule, @return.GetLocation(), @return.WithoutTrivia().GetText());
                        context.ReportDiagnostic(diagnostic);
                    }
                }

                // EndPoint (end of the block) is not a exit point. Should be covered separately!
                if (controlFlow.EndPointIsReachable)
                {
                    var diagnostic = Diagnostic.Create(Rule, catchBlock.Block.CloseBraceToken.GetLocation(), catchBlock.Block.CloseBraceToken.ValueText);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
    private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)
    {
      var hasPublicNoArgumentConstructor = false;
      var hasNonPublicNoArgumentConstructor = false;
      var classNode = (ClassDeclarationSyntax)context.Node;
      var classSymbol = context.SemanticModel.GetDeclaredSymbol(classNode);

      if (classSymbol.IsStereotype() && !(classSymbol?.IsAbstract).Value)
      {
        foreach (var constructor in classSymbol?.Constructors)
        {
          if (!constructor.IsStatic)
          {
            if (constructor.DeclaredAccessibility == Accessibility.Public)
            {
              if (constructor.Parameters.Length == 0)
              {
                hasPublicNoArgumentConstructor = true;
              }
              else if(classSymbol.IsEditableStereotype())
              {
                foreach (var location in constructor.Locations)
                {
                  context.ReportDiagnostic(Diagnostic.Create(
                    CheckConstructorsAnalyzer.constructorHasParametersRule,
                    location));
                }
              }
            }
            else if (constructor.Parameters.Length == 0)
            {
              hasNonPublicNoArgumentConstructor = true;
            }
          }
        }

        if (!hasPublicNoArgumentConstructor)
        {
          var properties = new Dictionary<string, string>()
          {
            [PublicNoArgumentConstructorIsMissingConstants.HasNonPublicNoArgumentConstructor] = hasNonPublicNoArgumentConstructor.ToString()
          }.ToImmutableDictionary();

          context.ReportDiagnostic(Diagnostic.Create(
            CheckConstructorsAnalyzer.publicNoArgumentConstructorIsMissingRule,
            classNode.Identifier.GetLocation(), properties));
        }
      }
    }
        private void HandleXmlElement(SyntaxNodeAnalysisContext context)
        {
            var xmlElementSyntax = context.Node as XmlElementSyntax;

            if (xmlElementSyntax != null)
            {
                if (xmlElementSyntax.StartTag.LessThanToken.IsMissing)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.StartTag.GetLocation(), "XML element start tag is missing a '<'."));
                }

                if (xmlElementSyntax.StartTag.GreaterThanToken.IsMissing)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.StartTag.GetLocation(), "XML element start tag is missing a '>'."));
                }

                if (xmlElementSyntax.EndTag.IsMissing)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.StartTag.GetLocation(), $"The XML tag '{xmlElementSyntax.StartTag.Name}' is not closed."));
                }
                else
                {
                    if (xmlElementSyntax.EndTag.LessThanSlashToken.IsMissing)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.EndTag.GetLocation(), "XML element end tag is missing a '</'."));
                    }

                    if (xmlElementSyntax.EndTag.GreaterThanToken.IsMissing)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.EndTag.GetLocation(), "XML element end tag is missing a '>'."));
                    }

                    if (xmlElementSyntax.StartTag.Name.ToString() != xmlElementSyntax.EndTag.Name.ToString())
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, xmlElementSyntax.StartTag.GetLocation(), new[] { xmlElementSyntax.EndTag.GetLocation() }, $"The '{xmlElementSyntax.StartTag.Name}' start tag does not match the end tag of '{xmlElementSyntax.EndTag.Name}'."));
                    }
                }

                IEnumerable<SyntaxTrivia> skippedTokens = xmlElementSyntax.StartTag.DescendantTrivia()
                    .Concat(xmlElementSyntax.EndTag.DescendantTrivia())
                    .Where(trivia => trivia.IsKind(SyntaxKind.SkippedTokensTrivia));

                foreach (var item in skippedTokens)
                {
                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, item.GetLocation(), "Invalid token."));
                }
            }
        }
        private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated()) return;
            var objectCreationExpression = (ObjectCreationExpressionSyntax)context.Node;

            var type = objectCreationExpression.Type;
            var typeSymbol = context.SemanticModel.GetSymbolInfo(type).Symbol as ITypeSymbol;
            if (!typeSymbol?.ToString().EndsWith("System.ArgumentException") ?? true) return;

            var argumentList = objectCreationExpression.ArgumentList as ArgumentListSyntax;
            if ((argumentList?.Arguments.Count ?? 0) < 2) return;

            var paramNameLiteral = argumentList.Arguments[1].Expression as LiteralExpressionSyntax;
            if (paramNameLiteral == null) return;

            var paramNameOpt = context.SemanticModel.GetConstantValue(paramNameLiteral);
            if (!paramNameOpt.HasValue) return;

            var paramName = paramNameOpt.Value as string;

            IList<string> parameters;
            if (IsParamNameCompatibleWithCreatingContext(objectCreationExpression, paramName, out parameters)) return;
            var props = parameters.ToImmutableDictionary(p => $"param{p}", p => p);
            var diagnostic = Diagnostic.Create(Rule, paramNameLiteral.GetLocation(), props.ToImmutableDictionary(), paramName);
            context.ReportDiagnostic(diagnostic);
        }
        private static void HandleDocumentation(SyntaxNodeAnalysisContext context)
        {
            var documentationTrivia = context.Node as DocumentationCommentTriviaSyntax;

            if (documentationTrivia != null)
            {
                var summaryElement = documentationTrivia.Content.GetFirstXmlElement(XmlCommentHelper.SummaryXmlTag) as XmlElementSyntax;

                if (summaryElement != null)
                {
                    var textElement = summaryElement.Content.FirstOrDefault() as XmlTextSyntax;

                    if (textElement != null)
                    {
                        string text = XmlCommentHelper.GetText(textElement, true);

                        if (!string.IsNullOrEmpty(text))
                        {
                            if (text.TrimStart().StartsWith(DefaultText, StringComparison.Ordinal))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptor, summaryElement.GetLocation()));
                            }
                        }
                    }
                }
            }
        }
        private static void HandleBlock(SyntaxNodeAnalysisContext context)
        {
            BlockSyntax block = context.Node as BlockSyntax;

            if (block != null && block.Statements.Any())
            {
                var previousStatement = block.Statements[0];
                FileLinePositionSpan previousStatementLocation = previousStatement.GetLineSpan();
                FileLinePositionSpan currentStatementLocation;

                for (int i = 1; i < block.Statements.Count; i++)
                {
                    var currentStatement = block.Statements[i];
                    currentStatementLocation = currentStatement.GetLineSpan();

                    if (previousStatementLocation.EndLinePosition.Line
                        == currentStatementLocation.StartLinePosition.Line
                        && !IsLastTokenMissing(previousStatement))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, block.Statements[i].GetLocation()));
                    }

                    previousStatementLocation = currentStatementLocation;
                    previousStatement = currentStatement;
                }
            }
        }
        private void AnalyzeRegexCreation(SyntaxNodeAnalysisContext context)
        {
            var objectCreation = (ObjectCreationExpressionSyntax) context.Node;

            var type = context.SemanticModel.GetSymbolInfo(objectCreation.Type).Symbol as ITypeSymbol;
            if (type == null || !type.Equals(context.SemanticModel.GetClrType(typeof(Regex))))
            {
                return;
            }

            var pattern = objectCreation.ArgumentList.Arguments[0].Expression.GetLiteral(context.SemanticModel);
            if (pattern == null)
            {
                return;
            }

            try
            {
                var regex = new Regex(pattern, RegexOptions.None, Timeout);
            }
            catch (ArgumentException e)
            {
                context.ReportDiagnostic(Diagnostic.Create(InvalidRegexRule, objectCreation.ArgumentList.Arguments[0].GetLocation(), e.Message));
            }
        }
 private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context, Compilation compilation)
 {
     if (context.IsGenerated()) return;
     var methodInvokeSyntax = context.Node as InvocationExpressionSyntax;
     var childNodes = methodInvokeSyntax.ChildNodes();
     var methodCaller = childNodes.OfType<MemberAccessExpressionSyntax>().FirstOrDefault();
     if (methodCaller == null) return;
     var argumentsCount = CountArguments(childNodes);
     var classSymbol = GetCallerClassSymbol(context.SemanticModel, methodCaller.Expression);
     if (classSymbol == null || !classSymbol.MightContainExtensionMethods) return;
     var methodSymbol = GetCallerMethodSymbol(context.SemanticModel, methodCaller.Name, argumentsCount);
     if (methodSymbol == null || !methodSymbol.IsExtensionMethod) return;
     if (ContainsDynamicArgument(context.SemanticModel, childNodes)) return;
     ExpressionSyntax invocationStatement;
     if (methodInvokeSyntax.Parent.IsNotKind(SyntaxKind.ArrowExpressionClause))
     {
         invocationStatement = (methodInvokeSyntax.FirstAncestorOrSelfThatIsAStatement() as ExpressionStatementSyntax).Expression;
     }
     else
     {
         invocationStatement = methodInvokeSyntax.FirstAncestorOrSelfOfType<ArrowExpressionClauseSyntax>().Expression;
     }
     if (invocationStatement == null) return;
     if (IsSelectingADifferentMethod(childNodes, methodCaller.Name, context.Node.SyntaxTree, methodSymbol, invocationStatement, compilation)) return;
     context.ReportDiagnostic(Diagnostic.Create(Rule, methodCaller.GetLocation(), methodSymbol.Name, classSymbol.Name));
 }
Example #28
0
        private static void AnalyzeTell(SyntaxNodeAnalysisContext context)
        {
            var invocationExpr = (InvocationExpressionSyntax)context.Node;

            // technically this should be a MemberAccessExpression, since it's invoked as a method off of IActorRef / ICanTell
            var memberAccessExpr = invocationExpr.Expression as MemberAccessExpressionSyntax;
            if (memberAccessExpr?.Name.ToString() != TargetMethodName) return;

            // need to verify that this `Tell` method is actually `ICanTell.Tell`
            var memberSymbol = context.SemanticModel.GetSymbolInfo(memberAccessExpr).Symbol as IMethodSymbol;

            var memberIsICanTell = (memberSymbol?.ToString().StartsWith(ICanTellMethodFQN) ?? false) || (memberSymbol?.ToString().StartsWith(IActorRefTellMethodFQN) ?? false);
            var memberIsActorRefExtension = memberSymbol?.ToString().StartsWith(ActorRefImplicitSenderTellFQN) ?? false;
            if (!memberIsICanTell && !memberIsActorRefExtension) return;

            // need to get the first argument being passed to the `Tell` method
            var argumentList = invocationExpr.ArgumentList as ArgumentListSyntax;
            if ((argumentList?.Arguments.Count ?? 0) < 1) return;

            // ReSharper disable once PossibleNullReferenceException //already validated as not null above
            var messageArgument =
                context.SemanticModel.GetSymbolInfo(memberIsICanTell ? argumentList.Arguments[0].Expression : argumentList.Arguments[1].Expression).Symbol;
            var allInterfaces = ((messageArgument as INamedTypeSymbol)?.Interfaces ?? ImmutableArray<INamedTypeSymbol>.Empty).Concat(messageArgument?.ContainingType.Interfaces ?? ImmutableArray<INamedTypeSymbol>.Empty).ToImmutableArray();
            if (allInterfaces.Any(y => y.ToString().StartsWith(ISystemMsgFQN)))
            {
                // found an ISystemMessage being passed into a Tell method
                var diagnostic = Diagnostic.Create(Rule, argumentList.GetLocation(), messageArgument.ToString(), DiagnosticSeverity.Error);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated()) return;
            var lambda = context.Node as ExpressionSyntax;

            var invocation = GetInvocationIfAny(lambda);
            if (invocation == null || invocation.ArgumentList.Arguments.Count == 0) return;

            var lambdaParameters = BuildParameters(lambda);
            if (!MatchArguments(lambdaParameters, invocation.ArgumentList)) return;

            var root = lambda.SyntaxTree.GetRoot();
            var newRoot = root.ReplaceNode(lambda, invocation.Expression as ExpressionSyntax);

            var semanticNode = GetNodeRootForAnalysis(lambda);
            var newSemanticNode = newRoot.DescendantNodesAndSelf()
                .Where(x => x.SpanStart == semanticNode.SpanStart && x.Span.OverlapsWith(context.Node.Span))
                .LastOrDefault(x => x.Kind() == semanticNode.Kind());

            if (newSemanticNode == null || ReplacementChangesSemantics(semanticNode, newSemanticNode, context.SemanticModel)) return;

            var diagnostic = Diagnostic.Create(
                Rule,
                context.Node.GetLocation(),
                invocation.Expression.ToString());
            context.ReportDiagnostic(diagnostic);
        }
Example #30
0
        private static void Analyzer(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGenerated()) return;
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            var memberExpresion = invocationExpression.Expression as MemberAccessExpressionSyntax;
            if (memberExpresion?.Name?.ToString() != "Match") return;

            var memberSymbol = context.SemanticModel.GetSymbolInfo(memberExpresion).Symbol;
            if (memberSymbol?.ToString() != "System.Text.RegularExpressions.Regex.Match(string, string)") return;

            var argumentList = invocationExpression.ArgumentList as ArgumentListSyntax;
            if ((argumentList?.Arguments.Count ?? 0) != 2) return;

            var regexLiteral = argumentList.Arguments[1].Expression as LiteralExpressionSyntax;
            if (regexLiteral == null) return;

            var regexOpt = context.SemanticModel.GetConstantValue(regexLiteral);

            var regex = regexOpt.Value as string;

            try
            {
                System.Text.RegularExpressions.Regex.Match("", regex);
            }
            catch (ArgumentException e)
            {
                var diag = Diagnostic.Create(Rule, regexLiteral.GetLocation(), e.Message);
                context.ReportDiagnostic(diag);
            }
        }
Example #31
0
 internal void ReportDiagnostic(Location location, string className, string methodName)
 {
     if (_context != null)
     {
         var diagnostic = Diagnostic.Create(this.GetDiagnosticDescriptor(), location, className, methodName);
         _context?.ReportDiagnostic(diagnostic);
     }
 }
 private static void ReportSA1624(SyntaxNodeAnalysisContext context, Location diagnosticLocation, ImmutableDictionary <string, string> .Builder diagnosticProperties, string accessor, string expectedStartingText, string startingTextToRemove)
 {
     diagnosticProperties.Add(ExpectedTextKey, expectedStartingText);
     diagnosticProperties.Add(TextToRemoveKey, startingTextToRemove);
     context.ReportDiagnostic(Diagnostic.Create(SA1624Descriptor, diagnosticLocation, diagnosticProperties.ToImmutable(), accessor, expectedStartingText));
 }
Example #33
0
        private static void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context)
        {
            var objectCreation = context.Node as ObjectCreationExpressionSyntax;

            if (objectCreation == null)
            {
                return;
            }
            var semanticModel = context.SemanticModel;
            var type          = semanticModel.GetSymbolInfo(objectCreation.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 (objectCreation.Parent.IsKind(SyntaxKind.SimpleAssignmentExpression))
            {
                var assignmentExpression = (AssignmentExpressionSyntax)objectCreation.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 (objectCreation.Parent.IsKind(SyntaxKind.EqualsValueClause) && objectCreation.Parent.Parent.IsKind(SyntaxKind.VariableDeclarator))
            {
                var variableDeclarator  = (VariableDeclaratorSyntax)objectCreation.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
            {
                context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation(), type.Name.ToString()));
                return;
            }
            if (statement != null && identitySymbol != null)
            {
                var isDisposeOrAssigned = IsDisposedOrAssigned(semanticModel, statement, (ILocalSymbol)identitySymbol);
                if (isDisposeOrAssigned)
                {
                    return;
                }
                context.ReportDiagnostic(Diagnostic.Create(Rule, objectCreation.GetLocation(), type.Name.ToString()));
            }
        }
Example #34
0
        private void LookForIllegalIAmImmutableImplementations(SyntaxNodeAnalysisContext context)
        {
            var classDeclaration = context.Node as ClassDeclarationSyntax;

            if (classDeclaration == null)
            {
                return;
            }

            // Only bother looking this up (which is relatively expensive) if we know that we have to
            var classImplementIAmImmutable = new Lazy <bool>(() => CommonAnalyser.ImplementsIAmImmutable(context.SemanticModel.GetDeclaredSymbol(classDeclaration)));
            var publicMutableFields        = classDeclaration.ChildNodes()
                                             .OfType <FieldDeclarationSyntax>()
                                             .Where(field => field.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword)))
                                             .Where(field => !field.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.ReadOnlyKeyword)));

            foreach (var publicMutableField in publicMutableFields)
            {
                if (classImplementIAmImmutable.Value)
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 MayNotHavePublicNonReadOnlyFieldsRule,
                                                 publicMutableField.GetLocation(),
                                                 string.Join(", ", publicMutableField.Declaration.Variables.Select(variable => variable.Identifier.Text))
                                                 ));
                }
            }

            // When the "With" methods updates create new instances, the existing instance is cloned and the target property updated - the constructor is not called on the
            // new instance, which means that any validation in there is bypassed. I don't think that there's sufficient information available at runtime (in JavaScript) to
            // create a new instance by calling the constructor instead of using this approach so, instead, validation is not allowed in the constructor - only "CtorSet"
            // calls are acceptable with an optional "Validate" call that may appear at the end of the constructor. If this "Validate" method exists then it will be called
            // after each "With" call in order to allow validation to be performed after each property update. The "Validate" method must have no parameters but may have
            // any accessibility (private probably makes most sense).
            var constructorsThatShouldUseValidateMethodIfClassImplementsIAmImmutable = new List <ConstructorDeclarationSyntax>();
            var instanceConstructors = classDeclaration.ChildNodes()
                                       .OfType <ConstructorDeclarationSyntax>()
                                       .Where(constructor => (constructor.Body != null)) // If the code is in an invalid state then the Body property might be null - safe to ignore
                                       .Where(constructor => !constructor.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword));

            foreach (var instanceConstructor in instanceConstructors)
            {
                var constructorShouldUseValidateMethodIfClassImplementsIAmImmutable = false;
                var constructorChildNodes = instanceConstructor.Body.ChildNodes().ToArray();
                foreach (var node in constructorChildNodes.Select((childNode, i) => new { Node = childNode, IsLastNode = i == (constructorChildNodes.Length - 1) }))
                {
                    var expressionStatement = node.Node as ExpressionStatementSyntax;
                    if (expressionStatement == null)
                    {
                        constructorShouldUseValidateMethodIfClassImplementsIAmImmutable = true;
                        break;
                    }
                    var invocation = expressionStatement.Expression as InvocationExpressionSyntax;
                    if (invocation != null)
                    {
                        if (InvocationIsCtorSetCall(invocation, context) || (node.IsLastNode && InvocationIsAllowableValidateCall(invocation, context)))
                        {
                            continue;
                        }
                    }
                    constructorShouldUseValidateMethodIfClassImplementsIAmImmutable = true;
                }
                if (constructorShouldUseValidateMethodIfClassImplementsIAmImmutable)
                {
                    constructorsThatShouldUseValidateMethodIfClassImplementsIAmImmutable.Add(instanceConstructor);
                }
            }
            if (constructorsThatShouldUseValidateMethodIfClassImplementsIAmImmutable.Any())
            {
                if (classImplementIAmImmutable.Value)
                {
                    foreach (var constructorThatShouldUseValidateMethod in constructorsThatShouldUseValidateMethodIfClassImplementsIAmImmutable)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(
                                                     ConstructorWithLogicOtherThanCtorSetCallsShouldUseValidateMethod,
                                                     constructorThatShouldUseValidateMethod.GetLocation()
                                                     ));
                    }
                }
            }

            // If there is a Validate method that should be called and this constructor isn't calling it then warn
            if (HasValidateMethodThatThisClassMustCall(classDeclaration))
            {
                var constructorsThatNeedToWarnAreNotCallingValidate = instanceConstructors
                                                                      .Except(constructorsThatShouldUseValidateMethodIfClassImplementsIAmImmutable) // Don't warn about any constructors that are already being identified as needing attention
                                                                      .Where(instanceConstructor =>
                                                                                                                                                    // If this constructors calls another of the constructor overloads then don't warn (only warn about constructors that DON'T call another overload)
                                                                             (instanceConstructor.Initializer == null) || (instanceConstructor.Initializer.Kind() != SyntaxKind.ThisConstructorInitializer)
                                                                             )
                                                                      .Where(instanceConstructor =>
                                                                             !instanceConstructor.Body.ChildNodes()
                                                                             .OfType <ExpressionStatementSyntax>()
                                                                             .Select(expressionStatement => expressionStatement.Expression as InvocationExpressionSyntax)
                                                                             .Where(invocation => (invocation != null) && InvocationIsAllowableValidateCall(invocation, context))
                                                                             .Any()
                                                                             );
                if (constructorsThatNeedToWarnAreNotCallingValidate.Any() && classImplementIAmImmutable.Value)
                {
                    foreach (var constructorThatShouldUseValidateMethod in constructorsThatNeedToWarnAreNotCallingValidate)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(
                                                     ConstructorDoesNotCallValidateMethod,
                                                     constructorThatShouldUseValidateMethod.GetLocation(),
                                                     classDeclaration.Identifier.Text
                                                     ));
                    }
                }
            }

            // This is likely to be the most expensive work (since it requires lookup of other symbols elsewhere in the solution, whereas the
            // logic below only look at code in the current file) so only perform it when required (leave it as null until we absolutely need
            // to know whether the current class implements IAmImmutable or not)
            foreach (var property in classDeclaration.ChildNodes().OfType <PropertyDeclarationSyntax>())
            {
                if (property.ExplicitInterfaceSpecifier != null)
                {
                    // Since CtorSet and With can not target properties that are not directly accessible through a reference to the
                    // IAmImmutable-implementing type (because "_ => _.Name" is acceptable as a property retriever but not something
                    // like "_ => ((IWhatever)_).Name") if a property is explicitly implemented for a base interface then the rules
                    // below need not be applied to it.
                    continue;
                }

                // If property.ExpressionBody is an ArrowExpressionClauseSyntax then it's C# 6 syntax for a read-only property that returns
                // a value (which is different to a readonly auto-property, which introduces a backing field behind the scenes, this syntax
                // doesn't introduce a new backing field, it returns an expression). In this case, there won't be an AccessorList (it will
                // be null).
                Diagnostic errorIfAny;
                if (property.ExpressionBody is ArrowExpressionClauseSyntax)
                {
                    errorIfAny = Diagnostic.Create(
                        MustHaveSettersOnPropertiesWithGettersAccessRule,
                        property.GetLocation(),
                        property.Identifier.Text
                        );
                }
                else
                {
                    var getterIfDefined = property.AccessorList.Accessors.FirstOrDefault(a => a.Kind() == SyntaxKind.GetAccessorDeclaration);
                    var setterIfDefined = property.AccessorList.Accessors.FirstOrDefault(a => a.Kind() == SyntaxKind.SetAccessorDeclaration);
                    if ((getterIfDefined != null) && (setterIfDefined == null))
                    {
                        // If getterIfDefined is non-null but has a null Body then it's an auto-property getter, in which case not having
                        // a setter is allowed since it means that it's a read-only auto-property (for which Bridge will create a property
                        // setter for in the JavaScript)
                        if (getterIfDefined.Body != null)
                        {
                            errorIfAny = Diagnostic.Create(
                                MustHaveSettersOnPropertiesWithGettersAccessRule,
                                property.GetLocation(),
                                property.Identifier.Text
                                );
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if ((getterIfDefined != null) && CommonAnalyser.HasDisallowedAttribute(Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(context.SemanticModel, getterIfDefined)))
                    {
                        errorIfAny = Diagnostic.Create(
                            MayNotHaveBridgeAttributesOnPropertiesWithGettersAccessRule,
                            getterIfDefined.GetLocation(),
                            property.Identifier.Text
                            );
                    }
                    else if ((setterIfDefined != null) && CommonAnalyser.HasDisallowedAttribute(Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(context.SemanticModel, setterIfDefined)))
                    {
                        errorIfAny = Diagnostic.Create(
                            MayNotHaveBridgeAttributesOnPropertiesWithGettersAccessRule,
                            setterIfDefined.GetLocation(),
                            property.Identifier.Text
                            );
                    }
                    else if ((setterIfDefined != null) && IsPublic(property) && !IsPrivateOrProtected(setterIfDefined))
                    {
                        errorIfAny = Diagnostic.Create(
                            MayNotHavePublicSettersRule,
                            setterIfDefined.GetLocation(),
                            property.Identifier.Text
                            );
                    }
                    else
                    {
                        continue;
                    }
                }

                // Enountered a potential error if the current class implements IAmImmutable - so find out whether it does or not (if it
                // doesn't then no further work is required and we can exit the entire process early)
                if (!classImplementIAmImmutable.Value)
                {
                    return;
                }
                context.ReportDiagnostic(errorIfAny);
            }
        }
Example #35
0
        private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol referenceEqualsMethod)
        {
            var cancellationToken = context.CancellationToken;

            var semanticModel = context.SemanticModel;
            var syntaxTree    = semanticModel.SyntaxTree;

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

            var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CodeStyleOptions.PreferIsNullCheckOverReferenceEqualityMethod, semanticModel.Language);

            if (!option.Value)
            {
                return;
            }

            var invocation  = context.Node;
            var syntaxFacts = GetSyntaxFactsService();

            var expression = syntaxFacts.GetExpressionOfInvocationExpression(invocation);
            var nameNode   = syntaxFacts.IsIdentifierName(expression)
                ? expression
                : syntaxFacts.IsSimpleMemberAccessExpression(expression)
                    ? syntaxFacts.GetNameOfMemberAccessExpression(expression)
                    : null;

            if (!syntaxFacts.IsIdentifierName(nameNode))
            {
                return;
            }

            syntaxFacts.GetNameAndArityOfSimpleName(nameNode, out var name, out _);
            if (!syntaxFacts.StringComparer.Equals(name, nameof(ReferenceEquals)))
            {
                return;
            }

            var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(invocation);

            if (arguments.Count != 2)
            {
                return;
            }

            if (!MatchesPattern(syntaxFacts, arguments[0], arguments[1]) &&
                !MatchesPattern(syntaxFacts, arguments[1], arguments[0]))
            {
                return;
            }

            var symbol = semanticModel.GetSymbolInfo(invocation, cancellationToken).Symbol;

            if (!referenceEqualsMethod.Equals(symbol))
            {
                return;
            }

            var properties = ImmutableDictionary <string, string> .Empty.Add(
                UseIsNullConstants.Kind, UseIsNullConstants.ReferenceEqualsKey);

            var genericParameterSymbol = GetGenericParameterSymbol(syntaxFacts, semanticModel, arguments[0], arguments[1], cancellationToken);

            if (genericParameterSymbol != null)
            {
                if (genericParameterSymbol.HasValueTypeConstraint)
                {
                    // 'is null' would generate error CS0403: Cannot convert null to type parameter 'T' because it could be a non-nullable value type. Consider using 'default(T)' instead.
                    // '== null' would generate error CS0019: Operator '==' cannot be applied to operands of type 'T' and '<null>'
                    // 'Is Nothing' would generate error BC30020: 'Is' operator does not accept operands of type 'T'. Operands must be reference or nullable types.
                    return;
                }

                if (!genericParameterSymbol.HasReferenceTypeConstraint)
                {
                    // Needs special casing for C# as long as
                    // https://github.com/dotnet/csharplang/issues/1284
                    // is not implemented.
                    properties = properties.Add(AbstractUseIsNullCheckForReferenceEqualsCodeFixProvider.UnconstrainedGeneric, "");
                }
            }

            var additionalLocations = ImmutableArray.Create(invocation.GetLocation());

            var negated = syntaxFacts.IsLogicalNotExpression(invocation.Parent);

            if (negated)
            {
                properties = properties.Add(AbstractUseIsNullCheckForReferenceEqualsCodeFixProvider.Negated, "");
            }

            var severity = option.Notification.Severity;

            context.ReportDiagnostic(
                DiagnosticHelper.Create(
                    Descriptor, nameNode.GetLocation(),
                    severity,
                    additionalLocations, properties));
        }
            private void AnalyzeNodeForXmlTextReaderDerivedTypeMethodDecl(SyntaxNodeAnalysisContext context)
            {
                SyntaxNode    node  = context.Node;
                SemanticModel model = context.SemanticModel;

                if (!(SyntaxNodeHelper.GetDeclaredSymbol(node, model) is IMethodSymbol methodSymbol) ||
                    !((!Equals(methodSymbol.ContainingType, _xmlTypes.XmlTextReader)) && methodSymbol.ContainingType.DerivesFrom(_xmlTypes.XmlTextReader, baseTypesOnly: true)))
                {
                    return;
                }

                // If the default value are not secure, the AnalyzeNodeForXmlTextReaderDerivedTypeConstructorDecl would be skipped,
                // therefoer we need to check constructor for any insecure settings.
                // Otherwise, we skip checking constructors
                if (_isFrameworkSecure && methodSymbol.MethodKind == MethodKind.Constructor)
                {
                    return;
                }

                bool hasSetXmlResolver         = false;
                bool hasSetInsecureXmlResolver = true;
                bool isDtdProcessingSet        = false;
                bool isDtdProcessingEnabled    = true;

                List <Location> locs = null;

                IEnumerable <SyntaxNode> assignments = _syntaxNodeHelper.GetDescendantAssignmentExpressionNodes(node);

                foreach (SyntaxNode assignment in assignments)
                {
                    bool ret;

                    ret = IsAssigningIntendedValueToPropertyDerivedFromType(assignment,
                                                                            model,
                                                                            (s) =>
                    {
                        return(SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverProperty(s, _xmlTypes));
                    },
                                                                            (n) =>
                    {
                        return(!(SyntaxNodeHelper.NodeHasConstantValueNull(n, model) ||
                                 SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(n).Type, _xmlTypes)));
                    },
                                                                            out bool isTargetProperty
                                                                            );

                    if (isTargetProperty)
                    {
                        hasSetXmlResolver          = true;
                        hasSetInsecureXmlResolver &= ret; // use 'AND' to avoid false positives (but imcrease false negative rate)
                        if (ret)
                        {
                            if (locs == null)
                            {
                                locs = new List <Location>();
                            }
                            locs.Add(assignment.GetLocation());
                        }
                        continue;
                    }

                    ret = IsAssigningIntendedValueToPropertyDerivedFromType(assignment,
                                                                            model,
                                                                            (s) =>
                    {
                        return(SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingProperty(s, _xmlTypes));
                    },
                                                                            (n) =>
                    {
                        return(SyntaxNodeHelper.GetSymbol(n, model).MatchFieldByName(_xmlTypes.DtdProcessing, SecurityMemberNames.Parse));
                    },
                                                                            out isTargetProperty);

                    if (isTargetProperty)
                    {
                        isDtdProcessingSet      = true;
                        isDtdProcessingEnabled &= ret; // use 'AND' to avoid false positives (but imcrease false negative rate)
                        if (ret)
                        {
                            if (locs == null)
                            {
                                locs = new List <Location>();
                            }
                            locs.Add(assignment.GetLocation());
                        }
                    }
                }

                // neither XmlResolver nor DtdProcessing is explicitly set
                if (!(hasSetXmlResolver || isDtdProcessingSet))
                {
                    return;
                }
                // explicitly set XmlResolver and/or DtdProcessing to secure value
                else if (!hasSetInsecureXmlResolver || !isDtdProcessingEnabled)
                {
                    return;
                }
                // didn't explicitly set either one of XmlResolver and DtdProcessing to secure value
                // but explicitly set XmlResolver and/or DtdProcessing to insecure value
                else
                {
                    DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessingInApiDesign;
                    // TODO: Only first location is shown in error, maybe we want to report on method instead?
                    //       Or on each insecure assignment?
                    context.ReportDiagnostic(
                        CreateDiagnostic(
                            locs,
                            rule,
                            SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                nameof(MicrosoftNetFrameworkAnalyzersResources.XmlTextReaderDerivedClassSetInsecureSettingsInMethodMessage),
                                methodSymbol.Name
                                )
                            )
                        );
                }
            }
        private void ProcessDiagnostics(
            SyntaxNodeAnalysisContext context,
            IEnumerator <Diagnostic> diagnostics,
            Location location,
            ISymbol fieldOrProperty,
            string fieldOrPropertyName
            )
        {
            var hasDiagnostics = diagnostics.MoveNext();

            bool hasUnauditedAnnotation = Attributes.Statics.Unaudited.IsDefined(fieldOrProperty);
            bool hasAuditedAnnotation   = Attributes.Statics.Audited.IsDefined(fieldOrProperty);

            if (hasAuditedAnnotation && hasUnauditedAnnotation)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(
                        Diagnostics.ConflictingStaticAnnotation,
                        location
                        )
                    );

                // Bail out here because it's unclear which of the remaining
                // diagnostics for this field/property should apply.
                return;
            }

            bool hasAnnotations = hasAuditedAnnotation || hasUnauditedAnnotation;

            // Unnecessary annotations clutter the code base. Because
            // Statics.Audited and Statics.Unaudited enable things to build
            // that shouldn't otherwise we would like to keep the list of
            // annotations small and this covers the easy case. This also
            // provides assurance that we don't start marking things as safe
            // that we previously wouldn't due to an analyzer change (the
            // existing Statics.Audited and Statics.Unaudited serve as test
            // cases in a way.)
            if (hasAnnotations && !hasDiagnostics)
            {
                context.ReportDiagnostic(
                    Diagnostic.Create(
                        Diagnostics.UnnecessaryStaticAnnotation,
                        location,
                        ImmutableDictionary <string, string> .Empty,
                        hasAuditedAnnotation ? "Statics.Audited" : "Statics.Unaudited",
                        fieldOrPropertyName
                        )
                    );

                // this bail-out isn't important because !hasDiagnostics
                return;
            }

            if (hasAnnotations)
            {
                // the annotations supress remaining diagnostics
                return;
            }

            while (hasDiagnostics)
            {
                context.ReportDiagnostic(diagnostics.Current);
                hasDiagnostics = diagnostics.MoveNext();
            }
        }
        /// <inheritdoc/>
        protected override void HandleXmlElement(SyntaxNodeAnalysisContext context, StyleCopSettings settings, bool needsComment, IEnumerable <XmlNodeSyntax> syntaxList, params Location[] diagnosticLocations)
        {
            var node       = context.Node;
            var identifier = GetIdentifier(node);

            bool supportedIdentifier = identifier != null;

            if (!supportedIdentifier)
            {
                return;
            }

            var parameterList = GetParameters(node)?.ToImmutableArray();

            bool hasNoParameters = !parameterList?.Any() ?? false;

            if (hasNoParameters)
            {
                return;
            }

            var parentParameters = parameterList.Value;

            var index = 0;

            foreach (var syntax in syntaxList)
            {
                var nameAttributeSyntax = XmlCommentHelper.GetFirstAttributeOrDefault <XmlNameAttributeSyntax>(syntax);
                var nameAttributeText   = nameAttributeSyntax?.Identifier?.Identifier.ValueText;

                // Make sure we ignore violations that should be reported by SA1613 instead.
                if (string.IsNullOrWhiteSpace(nameAttributeText))
                {
                    return;
                }

                var location = nameAttributeSyntax.Identifier.Identifier.GetLocation();

                var parentParameter = parentParameters.FirstOrDefault(s => s.Identifier.ValueText == nameAttributeText);
                if (parentParameter == null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(MissingParameterDescriptor, location, nameAttributeText));
                }
                else
                {
                    if (!needsComment)
                    {
                        // Parameter documentation is allowed to be omitted, so skip parameters for which there is no
                        // documentation.
                        while (index < parentParameters.Length && parentParameters[index] != parentParameter)
                        {
                            index++;
                        }
                    }

                    if (parentParameters.Length <= index || parentParameters[index] != parentParameter)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                OrderDescriptor,
                                location,
                                nameAttributeText,
                                parentParameters.IndexOf(parentParameter) + 1));
                    }
                }

                index++;
            }
        }
        private static void HandleIdentifierNameImpl(SyntaxNodeAnalysisContext context, SimpleNameSyntax nameExpression)
        {
            if (nameExpression == null)
            {
                return;
            }

            if (!HasThis(nameExpression))
            {
                return;
            }

            SymbolInfo symbolInfo = context.SemanticModel.GetSymbolInfo(nameExpression, context.CancellationToken);
            ImmutableArray <ISymbol> symbolsToAnalyze;

            if (symbolInfo.Symbol != null)
            {
                symbolsToAnalyze = ImmutableArray.Create(symbolInfo.Symbol);
            }
            else if (symbolInfo.CandidateReason == CandidateReason.MemberGroup)
            {
                // analyze the complete set of candidates, and use 'this.' if it applies to all
                symbolsToAnalyze = symbolInfo.CandidateSymbols;
            }
            else
            {
                return;
            }

            foreach (ISymbol symbol in symbolsToAnalyze)
            {
                if (symbol is ITypeSymbol)
                {
                    return;
                }

                if (symbol.IsStatic)
                {
                    return;
                }

                if (!(symbol.ContainingSymbol is ITypeSymbol))
                {
                    // covers local variables, parameters, etc.
                    return;
                }

                if (symbol is IMethodSymbol methodSymbol)
                {
                    switch (methodSymbol.MethodKind)
                    {
                    case MethodKind.Constructor:
                    case MethodKindEx.LocalFunction:
                        return;

                    default:
                        break;
                    }
                }

                // This is a workaround for:
                // - https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1501
                // - https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2093
                // and can be removed when the underlying bug in roslyn is resolved
                if (nameExpression.Parent is MemberAccessExpressionSyntax)
                {
                    var memberAccessSymbol = context.SemanticModel.GetSymbolInfo(nameExpression.Parent, context.CancellationToken).Symbol;

                    switch (memberAccessSymbol?.Kind)
                    {
                    case null:
                        break;

                    case SymbolKind.Field:
                    case SymbolKind.Method:
                    case SymbolKind.Property:
                        if (memberAccessSymbol.IsStatic && (memberAccessSymbol.ContainingType.Name == symbol.Name))
                        {
                            return;
                        }

                        break;
                    }
                }

                // End of workaround
            }

            // Prefix local calls with this
            context.ReportDiagnostic(Diagnostic.Create(Descriptor, nameExpression.GetLocation()));
        }
        private void AnalyzeCoalesceExpression(SyntaxNodeAnalysisContext context)
        {
            var cancellationToken = context.CancellationToken;
            var semanticModel     = context.SemanticModel;
            var options           = (CSharpParseOptions)semanticModel.SyntaxTree.Options;

            if (options.LanguageVersion < LanguageVersion.CSharp8)
            {
                return;
            }

            var coalesceExpression = (BinaryExpressionSyntax)context.Node;

            var option = context.GetOption(CodeStyleOptions2.PreferCompoundAssignment, coalesceExpression.Language);

            // Bail immediately if the user has disabled this feature.
            if (!option.Value)
            {
                return;
            }

            var coalesceLeft  = coalesceExpression.Left;
            var coalesceRight = coalesceExpression.Right;

            if (!(coalesceRight is ParenthesizedExpressionSyntax parenthesizedExpr))
            {
                return;
            }

            if (!(parenthesizedExpr.Expression is AssignmentExpressionSyntax assignment))
            {
                return;
            }

            if (assignment.Kind() != SyntaxKind.SimpleAssignmentExpression)
            {
                return;
            }

            // have    x ?? (y = z)
            // ensure that 'x' and 'y' are suitably equivalent.
            var syntaxFacts = CSharpSyntaxFacts.Instance;

            if (!syntaxFacts.AreEquivalent(coalesceLeft, assignment.Left))
            {
                return;
            }

            // Syntactically looks promising.  But we can only safely do this if 'expr'
            // is side-effect-free since we will be changing the number of times it is
            // executed from twice to once.
            if (!UseCompoundAssignmentUtilities.IsSideEffectFree(
                    syntaxFacts, coalesceLeft, semanticModel, cancellationToken))
            {
                return;
            }

            // Good match.
            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         coalesceExpression.OperatorToken.GetLocation(),
                                         option.Notification.Severity,
                                         additionalLocations: ImmutableArray.Create(coalesceExpression.GetLocation()),
                                         properties: null));
        }
        private void AnalyzeSyntax(
            SyntaxNodeAnalysisContext context,
            INamedTypeSymbol?expressionTypeOpt,
            IMethodSymbol?referenceEqualsMethodOpt)
        {
            var conditionalExpression = (TConditionalExpressionSyntax)context.Node;

            if (!ShouldAnalyze(conditionalExpression.SyntaxTree.Options))
            {
                return;
            }

            var option = context.GetOption(CodeStyleOptions.PreferNullPropagation, conditionalExpression.Language);

            if (!option.Value)
            {
                return;
            }

            var syntaxFacts = GetSyntaxFacts();

            syntaxFacts.GetPartsOfConditionalExpression(
                conditionalExpression, out var conditionNode, out var whenTrueNode, out var whenFalseNode);

            conditionNode = syntaxFacts.WalkDownParentheses(conditionNode);

            var conditionIsNegated = false;

            if (syntaxFacts.IsLogicalNotExpression(conditionNode))
            {
                conditionIsNegated = true;
                conditionNode      = syntaxFacts.WalkDownParentheses(
                    syntaxFacts.GetOperandOfPrefixUnaryExpression(conditionNode));
            }

            if (!TryAnalyzeCondition(
                    context, syntaxFacts, referenceEqualsMethodOpt, conditionNode,
                    out var conditionPartToCheck, out var isEquals))
            {
                return;
            }

            if (conditionIsNegated)
            {
                isEquals = !isEquals;
            }

            // Needs to be of the form:
            //      x == null ? null : ...    or
            //      x != null ? ...  : null;
            if (isEquals && !syntaxFacts.IsNullLiteralExpression(whenTrueNode))
            {
                return;
            }

            if (!isEquals && !syntaxFacts.IsNullLiteralExpression(whenFalseNode))
            {
                return;
            }

            var whenPartToCheck = isEquals ? whenFalseNode : whenTrueNode;

            var semanticModel = context.SemanticModel;
            var whenPartMatch = GetWhenPartMatch(syntaxFacts, semanticModel, conditionPartToCheck, whenPartToCheck);

            if (whenPartMatch == null)
            {
                return;
            }

            // ?. is not available in expression-trees.  Disallow the fix in that case.

            var type = semanticModel.GetTypeInfo(conditionalExpression).Type;

            if (type?.IsValueType == true)
            {
                if (!(type is INamedTypeSymbol namedType) || namedType.ConstructedFrom.SpecialType != SpecialType.System_Nullable_T)
                {
                    // User has something like:  If(str is nothing, nothing, str.Length)
                    // In this case, converting to str?.Length changes the type of this from
                    // int to int?
                    return;
                }
                // But for a nullable type, such as  If(c is nothing, nothing, c.nullable)
                // converting to c?.nullable doesn't affect the type
            }

            if (IsInExpressionTree(semanticModel, conditionNode, expressionTypeOpt, context.CancellationToken))
            {
                return;
            }

            var locations = ImmutableArray.Create(
                conditionalExpression.GetLocation(),
                conditionPartToCheck.GetLocation(),
                whenPartToCheck.GetLocation());

            var properties         = ImmutableDictionary <string, string> .Empty;
            var whenPartIsNullable = semanticModel.GetTypeInfo(whenPartMatch).Type?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T;

            if (whenPartIsNullable)
            {
                properties = properties.Add(UseNullPropagationConstants.WhenPartIsNullable, "");
            }

            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         conditionalExpression.GetLocation(),
                                         option.Notification.Severity,
                                         locations,
                                         properties));
        }
Example #42
0
        private void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var styleOption = context.GetAnalyzerOptions().PreferSimplifiedBooleanExpressions;

            if (!styleOption.Value)
            {
                // Bail immediately if the user has disabled this feature.
                return;
            }

            var semanticModel         = context.SemanticModel;
            var cancellationToken     = context.CancellationToken;
            var conditionalExpression = (TConditionalExpressionSyntax)context.Node;

            SyntaxFacts.GetPartsOfConditionalExpression(
                conditionalExpression, out var conditionNode, out var whenTrueNode, out var whenFalseNode);
            var condition = (TExpressionSyntax)conditionNode;
            var whenTrue  = (TExpressionSyntax)whenTrueNode;
            var whenFalse = (TExpressionSyntax)whenFalseNode;

            // Only offer when everything is a basic boolean type.  That way we don't have to worry
            // about any sort of subtle cases with implicit or bool conversions.
            if (!IsSimpleBooleanType(condition) ||
                !IsSimpleBooleanType(whenTrue) ||
                !IsSimpleBooleanType(whenFalse))
            {
                return;
            }

            var whenTrue_isTrue  = IsTrue(whenTrue);
            var whenTrue_isFalse = IsFalse(whenTrue);

            var whenFalse_isTrue  = IsTrue(whenFalse);
            var whenFalse_isFalse = IsFalse(whenFalse);

            if (whenTrue_isTrue && whenFalse_isFalse)
            {
                // c ? true : false     =>      c
                ReportDiagnostic(s_takeCondition);
            }
            else if (whenTrue_isFalse && whenFalse_isTrue)
            {
                // c ? false : true     =>      !c
                ReportDiagnostic(s_negateCondition);
            }
            else if (whenTrue_isFalse && whenFalse_isFalse)
            {
                // c ? false : false      =>      c && false
                // Note: this is a slight optimization over the when `c ? false : wf`
                // case below.  It allows to generate `c && false` instead of `!c && false`
                ReportDiagnostic(s_takeConditionAndWhenFalse);
            }
            else if (whenTrue_isTrue)
            {
                // c ? true : wf        =>      c || wf
                ReportDiagnostic(s_takeConditionOrWhenFalse);
            }
            else if (whenTrue_isFalse)
            {
                // c ? false : wf       =>      !c && wf
                ReportDiagnostic(s_negateConditionAndWhenFalse);
            }
            else if (whenFalse_isTrue)
            {
                // c ? wt : true        =>      !c or wt
                ReportDiagnostic(s_negateConditionOrWhenTrue);
            }
            else if (whenFalse_isFalse)
            {
                // c ? wt : false       =>      c && wt
                ReportDiagnostic(s_takeConditionAndWhenTrue);
            }

            return;

            // local functions

            void ReportDiagnostic(ImmutableDictionary <string, string?> properties)
            => context.ReportDiagnostic(DiagnosticHelper.Create(
                                            Descriptor,
                                            conditionalExpression.GetLocation(),
                                            styleOption.Notification.Severity,
                                            additionalLocations: null,
                                            properties));

            bool IsSimpleBooleanType(TExpressionSyntax node)
            {
                var typeInfo   = semanticModel.GetTypeInfo(node, cancellationToken);
                var conversion = GetConversion(semanticModel, node, cancellationToken);

                return
                    (conversion.MethodSymbol == null &&
                     typeInfo.Type?.SpecialType == SpecialType.System_Boolean &&
                     typeInfo.ConvertedType?.SpecialType == SpecialType.System_Boolean);
            }

            bool IsTrue(TExpressionSyntax node) => IsBoolValue(node, true);
            bool IsFalse(TExpressionSyntax node) => IsBoolValue(node, false);

            bool IsBoolValue(TExpressionSyntax node, bool value)
            {
                var constantValue = semanticModel.GetConstantValue(node, cancellationToken);

                return(constantValue.HasValue && constantValue.Value is bool b && b == value);
            }
        }
Example #43
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()));
 }
Example #44
0
        internal static void Analyze(SyntaxNodeAnalysisContext context, MemberInvocationExpressionInfo invocationInfo)
        {
            if (!ValidateMethodNameAndArgumentCount())
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            if (!semanticModel.TryGetMethodInfo(invocationInfo.InvocationExpression, out MethodInfo methodInfo, cancellationToken))
            {
                return;
            }

            if (!methodInfo.IsPublicStaticRegexMethod())
            {
                return;
            }

            SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

            if (!ValidateArgument(arguments[1]))
            {
                return;
            }

            if (methodInfo.Name == "Replace")
            {
                if (arguments.Count == 4 &&
                    !ValidateArgument(arguments[3]))
                {
                    return;
                }
            }
            else if (arguments.Count == 3 &&
                     !ValidateArgument(arguments[2]))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod, invocationInfo.Name);

            bool ValidateMethodNameAndArgumentCount()
            {
                switch (invocationInfo.NameText)
                {
                case "IsMatch":
                case "Match":
                case "Matches":
                case "Split":
                {
                    int count = invocationInfo.Arguments.Count;

                    return(count >= 2 &&
                           count <= 3);
                }

                case "Replace":
                {
                    int count = invocationInfo.Arguments.Count;

                    return(count >= 3 &&
                           count <= 4);
                }
                }

                return(false);
            }

            bool ValidateArgument(ArgumentSyntax argument)
            {
                ExpressionSyntax expression = argument.Expression;

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

                if (expression.WalkDownParentheses() is LiteralExpressionSyntax)
                {
                    return(true);
                }

                if (!semanticModel.GetConstantValue(expression, cancellationToken).HasValue)
                {
                    return(false);
                }

                ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken);

                Debug.Assert(symbol != null);

                if (symbol == null)
                {
                    return(true);
                }

                switch (symbol.Kind)
                {
                case SymbolKind.Field:
                {
                    return(((IFieldSymbol)symbol).HasConstantValue);
                }

                case SymbolKind.Method:
                {
                    if (((IMethodSymbol)symbol).MethodKind != MethodKind.BuiltinOperator)
                    {
                        return(false);
                    }

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, cancellationToken);

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

                    return(typeSymbol.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Text_RegularExpressions_RegexOptions)));
                }

                default:
                {
                    return(false);
                }
                }
            }
        }
        private static void ReportAtLastLabel([NotNull] SwitchSectionSyntax switchSection, SyntaxNodeAnalysisContext context)
        {
            SwitchLabelSyntax lastLabel = switchSection.Labels.Last();

            context.ReportDiagnostic(Diagnostic.Create(Rule, lastLabel.Keyword.GetLocation()));
        }
        /// <inheritdoc/>
        protected override void HandleCompleteDocumentation(SyntaxNodeAnalysisContext context, bool needsComment, XElement completeDocumentation, params Location[] diagnosticLocations)
        {
            var node       = context.Node;
            var identifier = GetIdentifier(node);

            bool supportedIdentifier = identifier != null;

            if (!supportedIdentifier)
            {
                return;
            }

            var identifierLocation = identifier.Value.GetLocation();
            var parameterList      = GetParameters(node)?.ToImmutableArray();

            bool hasNoParameters = !parameterList?.Any() ?? false;

            if (hasNoParameters)
            {
                return;
            }

            // We are working with an <include> element
            var xmlParamTags = completeDocumentation.Nodes()
                               .OfType <XElement>()
                               .Where(e => e.Name == XmlCommentHelper.ParamXmlTag);

            var parentParameters = parameterList.Value;

            var index = 0;

            foreach (var paramTag in xmlParamTags)
            {
                var nameAttributeText = paramTag.Attributes().FirstOrDefault(a => a.Name == "name")?.Value;

                // Make sure we ignore violations that should be reported by SA1613 instead.
                if (string.IsNullOrWhiteSpace(nameAttributeText))
                {
                    return;
                }

                var parentParameter = parentParameters.FirstOrDefault(s => s.Identifier.ValueText == nameAttributeText);
                if (parentParameter == null)
                {
                    context.ReportDiagnostic(Diagnostic.Create(MissingParameterDescriptor, identifierLocation, nameAttributeText));
                }
                else
                {
                    if (!needsComment)
                    {
                        // Parameter documentation is allowed to be omitted, so skip parameters for which there is no
                        // documentation.
                        while (index < parentParameters.Length && parentParameters[index] != parentParameter)
                        {
                            index++;
                        }
                    }

                    if (parentParameters.Length <= index || parentParameters[index] != parentParameter)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                OrderDescriptor,
                                identifierLocation,
                                nameAttributeText,
                                parentParameters.IndexOf(parentParameter) + 1));
                    }
                }

                index++;
            }
        }
        private static void HandleMemberList(SyntaxNodeAnalysisContext context, ImmutableArray <OrderingTrait> elementOrder, int accessibilityIndex, SyntaxList <MemberDeclarationSyntax> members, AccessLevel defaultAccessLevel)
        {
            MemberDeclarationSyntax previousMember = null;
            var  previousSyntaxKind  = SyntaxKind.None;
            var  previousAccessLevel = AccessLevel.NotSpecified;
            bool previousIsConst     = false;
            bool previousIsReadonly  = false;
            bool previousIsStatic    = false;

            foreach (var member in members)
            {
                var currentSyntaxKind = member.Kind();
                currentSyntaxKind = currentSyntaxKind == SyntaxKind.EventFieldDeclaration ? SyntaxKind.EventDeclaration : currentSyntaxKind;

                // if the SyntaxKind of this member (e.g. SyntaxKind.IncompleteMember) will not
                // be handled, skip early.
                if (!MemberKinds.Contains(currentSyntaxKind))
                {
                    continue;
                }

                var         modifiers          = member.GetModifiers();
                AccessLevel currentAccessLevel = MemberOrderHelper.GetAccessLevelForOrdering(member, modifiers);
                bool        currentIsConst     = modifiers.Any(SyntaxKind.ConstKeyword);
                bool        currentIsReadonly  = modifiers.Any(SyntaxKind.ReadOnlyKeyword);
                bool        currentIsStatic    = modifiers.Any(SyntaxKind.StaticKeyword);

                if (previousAccessLevel != AccessLevel.NotSpecified)
                {
                    bool compareAccessLevel = true;
                    for (int j = 0; compareAccessLevel && j < accessibilityIndex; j++)
                    {
                        switch (elementOrder[j])
                        {
                        case OrderingTrait.Kind:
                            if (previousSyntaxKind != currentSyntaxKind)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Constant:
                            if (previousIsConst != currentIsConst)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Readonly:
                            if (previousIsReadonly != currentIsReadonly)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Static:
                            if (previousIsStatic != currentIsStatic)
                            {
                                compareAccessLevel = false;
                            }

                            continue;

                        case OrderingTrait.Accessibility:
                        default:
                            continue;
                        }
                    }

                    if (compareAccessLevel && currentAccessLevel > previousAccessLevel)
                    {
                        context.ReportDiagnostic(
                            Diagnostic.Create(
                                Descriptor,
                                NamedTypeHelpers.GetNameOrIdentifierLocation(member),
                                AccessLevelHelper.GetName(currentAccessLevel),
                                AccessLevelHelper.GetName(previousAccessLevel)));
                    }
                }

                previousMember      = member;
                previousSyntaxKind  = currentSyntaxKind;
                previousAccessLevel = currentAccessLevel;
                previousIsConst     = currentIsConst;
                previousIsReadonly  = currentIsReadonly;
                previousIsStatic    = currentIsStatic;
            }
        }
Example #48
0
            private void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
            {
                var           invocation    = context.Node as TInvocationExpressionSyntax;
                SemanticModel semanticModel = context.SemanticModel;

                ISymbol symbol = semanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol;

                if (symbol == null || symbol.Kind != SymbolKind.Method || !symbol.Name.StartsWith("Register", StringComparison.Ordinal))
                {
                    return;
                }

                var method = (IMethodSymbol)symbol;

                NoteRegisterActionInvocation(method, invocation, semanticModel, context.CancellationToken);

                bool isRegisterSymbolAction         = IsRegisterAction(RegisterSymbolActionName, method, _analysisContext, _compilationStartAnalysisContext);
                bool isRegisterSyntaxNodeAction     = IsRegisterAction(RegisterSyntaxNodeActionName, method, _analysisContext, _compilationStartAnalysisContext, _codeBlockStartAnalysisContext);
                bool isRegisterCodeBlockStartAction = IsRegisterAction(RegisterCodeBlockStartActionName, method, _analysisContext, _compilationStartAnalysisContext);
                bool isRegisterOperationAction      = IsRegisterAction(RegisterOperationActionName, method, _analysisContext, _compilationStartAnalysisContext, _operationBlockStartAnalysisContext);

                if (isRegisterSymbolAction || isRegisterSyntaxNodeAction || isRegisterOperationAction)
                {
                    if (method.Parameters.Length == 2 && method.Parameters[1].IsParams)
                    {
                        IEnumerable <SyntaxNode> arguments = GetArgumentExpressions(invocation);
                        if (arguments != null)
                        {
                            int argumentCount = arguments.Count();
                            if (argumentCount >= 1)
                            {
                                ITypeSymbol type = semanticModel.GetTypeInfo(arguments.First(), context.CancellationToken).ConvertedType;
                                if (type == null || type.Name.Equals(nameof(Action), StringComparison.Ordinal))
                                {
                                    if (argumentCount == 1)
                                    {
                                        DiagnosticDescriptor rule;
                                        if (isRegisterSymbolAction)
                                        {
                                            rule = MissingSymbolKindArgumentRule;
                                        }
                                        else if (isRegisterOperationAction)
                                        {
                                            rule = MissingOperationKindArgumentRule;
                                        }
                                        else
                                        {
                                            rule = MissingSyntaxKindArgumentRule;
                                        }

                                        SyntaxNode invocationExpression = GetInvocationExpression(invocation);
                                        Diagnostic diagnostic           = Diagnostic.Create(rule, invocationExpression.GetLocation());
                                        context.ReportDiagnostic(diagnostic);
                                    }
                                    else if (isRegisterSymbolAction)
                                    {
                                        foreach (SyntaxNode argument in arguments.Skip(1))
                                        {
                                            symbol = semanticModel.GetSymbolInfo(argument, context.CancellationToken).Symbol;
                                            if (symbol != null &&
                                                symbol.Kind == SymbolKind.Field &&
                                                _symbolKind.Equals(symbol.ContainingType) &&
                                                !s_supportedSymbolKinds.Contains(symbol.Name))
                                            {
                                                Diagnostic diagnostic = Diagnostic.Create(UnsupportedSymbolKindArgumentRule, argument.GetLocation(), symbol.Name);
                                                context.ReportDiagnostic(diagnostic);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (method.TypeParameters.Length > 0 &&
                    (isRegisterSyntaxNodeAction || isRegisterCodeBlockStartAction))
                {
                    ITypeSymbol typeArgument = null;
                    if (method.TypeParameters.Length == 1)
                    {
                        if (method.TypeParameters[0].Name == TLanguageKindEnumName)
                        {
                            typeArgument = method.TypeArguments[0];
                        }
                    }
                    else
                    {
                        ITypeParameterSymbol typeParam = method.TypeParameters.SingleOrDefault(t => t.Name == TLanguageKindEnumName);
                        if (typeParam != null)
                        {
                            int index = method.TypeParameters.IndexOf(typeParam);
                            typeArgument = method.TypeArguments[index];
                        }
                    }

                    if (typeArgument != null &&
                        typeArgument.TypeKind != TypeKind.TypeParameter &&
                        typeArgument.TypeKind != TypeKind.Error &&
                        !IsSyntaxKind(typeArgument))
                    {
                        Location location = typeArgument.Locations[0];
                        if (!location.IsInSource)
                        {
                            SyntaxNode invocationExpression = GetInvocationExpression(invocation);
                            location = invocationExpression.GetLocation();
                        }

                        Diagnostic diagnostic = Diagnostic.Create(InvalidSyntaxKindTypeArgumentRule, location, typeArgument.Name, TLanguageKindEnumName, method.Name);
                        context.ReportDiagnostic(diagnostic);
                    }
                }
            }
Example #49
0
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            switch (context.Node)
            {
            case MemberAccessExpressionSyntax memberAccessSyntax:
            {
                if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol &&
                    symbol.ContainingAssembly != context.Compilation.Assembly)
                {
                    var containingType = symbol.ContainingType;

                    if (HasInternalAttribute(symbol))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), $"{containingType}.{symbol.Name}"));
                        return;
                    }

                    if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(_descriptor, memberAccessSyntax.Name.GetLocation(), containingType));
                        return;
                    }
                }
                return;
            }

            case ObjectCreationExpressionSyntax creationSyntax:
            {
                if (context.SemanticModel.GetSymbolInfo(context.Node, context.CancellationToken).Symbol is ISymbol symbol &&
                    symbol.ContainingAssembly != context.Compilation.Assembly)
                {
                    var containingType = symbol.ContainingType;

                    if (HasInternalAttribute(symbol))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.GetLocation(), containingType));
                        return;
                    }

                    if (IsInInternalNamespace(containingType) || HasInternalAttribute(containingType))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(_descriptor, creationSyntax.Type.GetLocation(), containingType));
                        return;
                    }
                }

                return;
            }

            case ClassDeclarationSyntax declarationSyntax:
            {
                if (context.SemanticModel.GetDeclaredSymbol(declarationSyntax)?.BaseType is ISymbol symbol &&
                    symbol.ContainingAssembly != context.Compilation.Assembly &&
                    (IsInInternalNamespace(symbol) || HasInternalAttribute(symbol)) &&
                    declarationSyntax.BaseList?.Types.Count > 0)
                {
                    context.ReportDiagnostic(Diagnostic.Create(_descriptor, declarationSyntax.BaseList.Types[0].GetLocation(), symbol));
                }

                return;
            }
            }
        }
Example #50
0
 /// <summary>
 /// Analyzes null checks like: obj = obj1 ?? obj2;
 /// </summary>
 private void AnalyzeNullCheck_CoalesceExpression(SyntaxNodeAnalysisContext context)
 {
     context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
 }
            private void AnalyzeNodeForXmlTextReaderDerivedTypeConstructorDecl(SyntaxNodeAnalysisContext context)
            {
                SyntaxNode    node  = context.Node;
                SemanticModel model = context.SemanticModel;

                if (!(SyntaxNodeHelper.GetDeclaredSymbol(node, model) is IMethodSymbol methodSymbol) ||
                    methodSymbol.MethodKind != MethodKind.Constructor ||
                    !((!Equals(methodSymbol.ContainingType, _xmlTypes.XmlTextReader)) && methodSymbol.ContainingType.DerivesFrom(_xmlTypes.XmlTextReader, baseTypesOnly: true)))
                {
                    return;
                }

                bool hasSetSecureXmlResolver = false;
                bool isDtdProcessingDisabled = false;

                IEnumerable <SyntaxNode> assignments = _syntaxNodeHelper.GetDescendantAssignmentExpressionNodes(node);

                foreach (SyntaxNode assignment in assignments)
                {
                    bool isTargetProperty = false;

                    hasSetSecureXmlResolver = hasSetSecureXmlResolver || IsAssigningIntendedValueToPropertyDerivedFromType(assignment,
                                                                                                                           model,
                                                                                                                           (s) =>
                    {
                        return(SecurityDiagnosticHelpers.IsXmlTextReaderXmlResolverProperty(s, _xmlTypes));
                    },
                                                                                                                           (n) =>
                    {
                        return(SyntaxNodeHelper.NodeHasConstantValueNull(n, model) ||
                               SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(n).Type, _xmlTypes));
                    },
                                                                                                                           out isTargetProperty);

                    if (isTargetProperty)
                    {
                        continue;
                    }

                    isDtdProcessingDisabled = isDtdProcessingDisabled || IsAssigningIntendedValueToPropertyDerivedFromType(assignment,
                                                                                                                           model,
                                                                                                                           (s) =>
                    {
                        return(SecurityDiagnosticHelpers.IsXmlTextReaderDtdProcessingProperty(s, _xmlTypes));
                    },
                                                                                                                           (n) =>
                    {
                        return(!SyntaxNodeHelper.GetSymbol(n, model).MatchFieldByName(_xmlTypes.DtdProcessing, SecurityMemberNames.Parse));
                    },
                                                                                                                           out isTargetProperty);

                    if (hasSetSecureXmlResolver && isDtdProcessingDisabled)
                    {
                        return;
                    }
                }

                DiagnosticDescriptor rule = RuleDoNotUseInsecureDtdProcessingInApiDesign;

                context.ReportDiagnostic(
                    CreateDiagnostic(
                        methodSymbol.Locations,
                        rule,
                        SecurityDiagnosticHelpers.GetLocalizableResourceString(
                            nameof(MicrosoftNetFrameworkAnalyzersResources.XmlTextReaderDerivedClassConstructorNoSecureSettingsMessage),
                            SecurityDiagnosticHelpers.GetNonEmptyParentName(node, model, context.CancellationToken)
                            )
                        )
                    );
            }
    private void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
    {
        if (context.Node is not InvocationExpressionSyntax invocation || !context.Node.IsKind(SyntaxKind.InvocationExpression))
        {
            return;
        }

        if (invocation.Expression is not MemberAccessExpressionSyntax memberAccess)
        {
            return;
        }

        if (invocation.ArgumentList.Arguments.Count != 1)
        {
            return;
        }

        // Filter out everything except FromError
        if (memberAccess.Name.Identifier.Text != "FromError")
        {
            return;
        }

        // Filter out everything except Result and Result<T>
        if (memberAccess.Expression is not SimpleNameSyntax memberAccessName)
        {
            return;
        }

        if (memberAccessName.Identifier.Text != "Result")
        {
            return;
        }

        // Okay, we're looking at a Result[<>].FromError(something) call...
        var argument = invocation.ArgumentList.Arguments.Single();

        if (argument.Expression is not MemberAccessExpressionSyntax argumentMemberAccess)
        {
            return;
        }

        if (argumentMemberAccess.Name.Identifier.Text != "Error")
        {
            return;
        }

        if (argumentMemberAccess.Expression is not SimpleNameSyntax argumentMemberAccessName)
        {
            return;
        }

        // Suspicious! Let's compare types...
        var argumentTypeInfo   = context.SemanticModel.GetTypeInfo(argumentMemberAccessName);
        var expressionTypeInfo = context.SemanticModel.GetTypeInfo(memberAccessName);

        if (!argumentTypeInfo.Equals(expressionTypeInfo))
        {
            return;
        }

        // Bad!
        context.ReportDiagnostic
        (
            Diagnostic.Create
            (
                descriptor: Descriptors.REM0001RedundantFromErrorCall,
                invocation.GetLocation(),
                messageArgs: argumentMemberAccessName.Identifier.Text
            )
        );
    }
            private void AnalyzeNodeForXslCompiledTransformLoad(SyntaxNodeAnalysisContext context)
            {
                SyntaxNode    node         = context.Node;
                SemanticModel model        = context.SemanticModel;
                IMethodSymbol methodSymbol = _syntaxNodeHelper.GetCalleeMethodSymbol(node, model);

                if (SecurityDiagnosticHelpers.IsXslCompiledTransformLoad(methodSymbol, _xmlTypes))
                {
                    bool isSecureResolver;
                    bool isSecureSettings;
                    bool isSetInBlock;

                    int xmlResolverIndex  = SecurityDiagnosticHelpers.GetXmlResolverParameterIndex(methodSymbol, _xmlTypes);
                    int xsltSettingsIndex = SecurityDiagnosticHelpers.GetXsltSettingsParameterIndex(methodSymbol, _xmlTypes);

                    // Overloads with no XmlResolver and XstlSettings specified are secure since they all have folowing behavior:
                    //  1. An XmlUrlResolver with no user credentials is used to process any xsl:import or xsl:include elements.
                    //  2. The document() function is disabled.
                    //  3. Embedded scripts are not supported.
                    if (xmlResolverIndex >= 0 &&
                        xsltSettingsIndex >= 0)
                    {
                        IEnumerable <SyntaxNode> argumentExpressionNodes = _syntaxNodeHelper.GetInvocationArgumentExpressionNodes(node);
                        SyntaxNode resolverNode = argumentExpressionNodes.ElementAt(xmlResolverIndex);

                        isSecureResolver = SyntaxNodeHelper.NodeHasConstantValueNull(resolverNode, model) ||
                                           SecurityDiagnosticHelpers.IsXmlSecureResolverType(model.GetTypeInfo(resolverNode).Type, _xmlTypes);


                        SyntaxNode settingsNode   = argumentExpressionNodes.ElementAt(xsltSettingsIndex);
                        ISymbol    settingsSymbol = SyntaxNodeHelper.GetSymbol(settingsNode, model);

                        // 1. pass null or XsltSettings.Default as XsltSetting : secure
                        if (settingsSymbol == null || SecurityDiagnosticHelpers.IsXsltSettingsDefaultProperty(settingsSymbol as IPropertySymbol, _xmlTypes))
                        {
                            isSetInBlock     = true;
                            isSecureSettings = true;
                        }
                        // 2. XsltSettings.TrustedXslt : insecure
                        else if (SecurityDiagnosticHelpers.IsXsltSettingsTrustedXsltProperty(settingsSymbol as IPropertySymbol, _xmlTypes))
                        {
                            isSetInBlock     = true;
                            isSecureSettings = false;
                        }
                        // 3. check xsltSettingsEnvironments, if IsScriptDisabled && IsDocumentFunctionDisabled then secure, else insecure
                        else if (_xsltSettingsEnvironments.TryGetValue(settingsSymbol, out XsltSettingsEnvironment env))
                        {
                            isSetInBlock     = false;
                            isSecureSettings = env.IsDocumentFunctionDisabled && env.IsScriptDisabled;
                        }
                        //4. symbol for settings is not found => passed in without any change => assume insecure
                        else
                        {
                            isSetInBlock     = true;
                            isSecureSettings = false;
                        }

                        if (!isSecureSettings && !isSecureResolver)
                        {
                            LocalizableResourceString message = SecurityDiagnosticHelpers.GetLocalizableResourceString(
                                isSetInBlock ? nameof(MicrosoftNetFrameworkAnalyzersResources.XslCompiledTransformLoadInsecureConstructedMessage) :
                                nameof(MicrosoftNetFrameworkAnalyzersResources.XslCompiledTransformLoadInsecureInputMessage),
                                SecurityDiagnosticHelpers.GetNonEmptyParentName(node, model, context.CancellationToken)
                                );

                            context.ReportDiagnostic(
                                Diagnostic.Create(
                                    RuleDoNotUseInsecureXSLTScriptExecution,
                                    node.GetLocation(),
                                    message
                                    )
                                );
                        }
                    }
                }
            }
        private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext, INamedTypeSymbol expressionTypeOpt)
        {
            var options           = syntaxContext.Options;
            var syntaxTree        = syntaxContext.Node.SyntaxTree;
            var cancellationToken = syntaxContext.CancellationToken;
            var optionSet         = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var styleOption = optionSet.GetOption(CSharpCodeStyleOptions.PreferLocalOverAnonymousFunction);

            if (!styleOption.Value)
            {
                // Bail immediately if the user has disabled this feature.
                return;
            }

            // Local functions are only available in C# 7.0 and above.  Don't offer this refactoring
            // in projects targetting a lesser version.
            if (((CSharpParseOptions)syntaxTree.Options).LanguageVersion < LanguageVersion.CSharp7)
            {
                return;
            }

            var severity          = styleOption.Notification.Value;
            var anonymousFunction = (AnonymousFunctionExpressionSyntax)syntaxContext.Node;

            var semanticModel = syntaxContext.SemanticModel;

            if (!CheckForPattern(semanticModel, anonymousFunction, cancellationToken,
                                 out var localDeclaration))
            {
                return;
            }

            if (localDeclaration.Declaration.Variables.Count != 1)
            {
                return;
            }

            if (!(localDeclaration.Parent is BlockSyntax block))
            {
                return;
            }

            var local = semanticModel.GetDeclaredSymbol(localDeclaration.Declaration.Variables[0], cancellationToken);

            if (local == null)
            {
                return;
            }

            var delegateType = semanticModel.GetTypeInfo(anonymousFunction, cancellationToken).ConvertedType as INamedTypeSymbol;

            if (!delegateType.IsDelegateType() ||
                delegateType.DelegateInvokeMethod == null)
            {
                return;
            }

            if (!CanReplaceAnonymousWithLocalFunction(semanticModel, expressionTypeOpt, local, block, anonymousFunction, cancellationToken))
            {
                return;
            }

            // Looks good!
            var additionalLocations = ImmutableArray.Create(
                localDeclaration.GetLocation(),
                anonymousFunction.GetLocation());

            if (severity != DiagnosticSeverity.Hidden)
            {
                // If the diagnostic is not hidden, then just place the user visible part
                // on the local being initialized with the lambda.
                syntaxContext.ReportDiagnostic(Diagnostic.Create(
                                                   GetDescriptorWithSeverity(severity),
                                                   localDeclaration.Declaration.Variables[0].Identifier.GetLocation(),
                                                   additionalLocations));
            }
            else
            {
                // If the diagnostic is hidden, place it on the entire construct.
                syntaxContext.ReportDiagnostic(Diagnostic.Create(
                                                   GetDescriptorWithSeverity(severity),
                                                   localDeclaration.GetLocation(),
                                                   additionalLocations));

                var anonymousFunctionStatement = anonymousFunction.GetAncestor <StatementSyntax>();
                if (localDeclaration != anonymousFunctionStatement)
                {
                    syntaxContext.ReportDiagnostic(Diagnostic.Create(
                                                       GetDescriptorWithSeverity(severity),
                                                       anonymousFunctionStatement.GetLocation(),
                                                       additionalLocations));
                }
            }
        }
Example #55
0
        private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            var expr = invocationExpression.Expression;

            var checkArgs = string.Empty;

            if (expr is MemberBindingExpressionSyntax mbes)
            {
                var mbesName = mbes.Name.ToString();

                if (mbesName == "RecordGeneralError")
                {
                    checkArgs = mbesName;
                }
                else if (mbesName == "RecordNotice")
                {
                    checkArgs = mbesName;
                }
                else if (mbesName == "RecordInfo")
                {
                    checkArgs = mbesName;
                }
                else if (mbesName == "RecordFeatureUsage")
                {
                    checkArgs = mbesName;
                }
                else if (mbesName == "RecordError")
                {
                    checkArgs = mbesName;
                }
            }
            else if (expr is MemberAccessExpressionSyntax maes)
            {
                var maesName = maes.Name.ToString();

                if (maesName == "RecordGeneralError")
                {
                    checkArgs = maesName;
                }
                else if (maesName == "RecordNotice")
                {
                    checkArgs = maesName;
                }
                else if (maesName == "RecordInfo")
                {
                    checkArgs = maesName;
                }
                else if (maesName == "RecordFeatureUsage")
                {
                    checkArgs = maesName;
                }
                else if (maesName == "RecordError")
                {
                    checkArgs = maesName;
                }
            }

            if (!string.IsNullOrWhiteSpace(checkArgs))
            {
                var arg = invocationExpression.ArgumentList.Arguments.FirstOrDefault();

                if (arg != null)
                {
                    if (arg.Expression is LiteralExpressionSyntax ||
                        arg.Expression.ToString().StartsWith("\""))
                    {
                        var diagnostic = Diagnostic.Create(Rule, arg.GetLocation(), checkArgs);

                        context.ReportDiagnostic(diagnostic);
                    }
                }
            }
        }
        private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (TConditionalExpressionSyntax)context.Node;

            var optionSet = context.Options.GetOptionSet();
            var option    = optionSet.GetOption(CodeStyleOptions.PreferCoalesceExpression, conditionalExpression.Language);

            if (!option.Value)
            {
                return;
            }

            var syntaxFacts = this.GetSyntaxFactsService();

            SyntaxNode conditionNode, whenTrueNodeHigh, whenFalseNodeHigh;

            syntaxFacts.GetPartsOfConditionalExpression(
                conditionalExpression, out conditionNode, out whenTrueNodeHigh, out whenFalseNodeHigh);

            conditionNode = syntaxFacts.WalkDownParentheses(conditionNode);
            var whenTrueNodeLow  = syntaxFacts.WalkDownParentheses(whenTrueNodeHigh);
            var whenFalseNodeLow = syntaxFacts.WalkDownParentheses(whenFalseNodeHigh);

            var notHasValueExpression = false;

            if (syntaxFacts.IsLogicalNotExpression(conditionNode))
            {
                notHasValueExpression = true;
                conditionNode         = syntaxFacts.GetOperandOfPrefixUnaryExpression(conditionNode);
            }

            var conditionMemberAccess = conditionNode as TMemberAccessExpression;

            if (conditionMemberAccess == null)
            {
                return;
            }

            SyntaxNode conditionExpression, conditionSimpleName;

            syntaxFacts.GetPartsOfMemberAccessExpression(conditionMemberAccess, out conditionExpression, out conditionSimpleName);

            string conditionName; int unused;

            syntaxFacts.GetNameAndArityOfSimpleName(conditionSimpleName, out conditionName, out unused);

            if (conditionName != nameof(Nullable <int> .HasValue))
            {
                return;
            }

            var whenPartToCheck      = notHasValueExpression ? whenFalseNodeLow : whenTrueNodeLow;
            var whenPartMemberAccess = whenPartToCheck as TMemberAccessExpression;

            if (whenPartMemberAccess == null)
            {
                return;
            }

            SyntaxNode whenPartExpression, whenPartSimpleName;

            syntaxFacts.GetPartsOfMemberAccessExpression(whenPartMemberAccess, out whenPartExpression, out whenPartSimpleName);

            string whenPartName;

            syntaxFacts.GetNameAndArityOfSimpleName(whenPartSimpleName, out whenPartName, out unused);

            if (whenPartName != nameof(Nullable <int> .Value))
            {
                return;
            }

            if (!syntaxFacts.AreEquivalent(conditionExpression, whenPartExpression))
            {
                return;
            }

            // Syntactically this looks like something we can simplify.  Make sure we're
            // actually looking at something Nullable (and not some type that uses a similar
            // syntactic pattern).
            var semanticModel = context.SemanticModel;
            var nullableType  = semanticModel.Compilation.GetTypeByMetadataName("System.Nullable`1");

            if (nullableType == null)
            {
                return;
            }

            var cancellationToken = context.CancellationToken;
            var type = semanticModel.GetTypeInfo(conditionExpression, cancellationToken);

            if (!nullableType.Equals(type.Type?.OriginalDefinition))
            {
                return;
            }

            var whenPartToKeep = notHasValueExpression ? whenTrueNodeHigh : whenFalseNodeHigh;
            var locations      = ImmutableArray.Create(
                conditionalExpression.GetLocation(),
                conditionExpression.GetLocation(),
                whenPartToKeep.GetLocation());

            context.ReportDiagnostic(Diagnostic.Create(
                                         this.CreateDescriptorWithSeverity(option.Notification.Value),
                                         conditionalExpression.GetLocation(),
                                         locations));
        }
Example #57
0
        /// <summary>
        /// Check if xml comment exists.
        /// </summary>
        /// <param name="syntaxNodeAnalysisContext">The systax node analysis context.</param>
        private void CheckEvent(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext)
        {
            var node = syntaxNodeAnalysisContext.Node as EventDeclarationSyntax;

            if (node == null)
            {
                return;
            }

            // if inside of an interface declaration do nothing
            if (node.Parent is InterfaceDeclarationSyntax)
            {
                return;
            }

            var xmlTrivia = node.GetLeadingTrivia()
                            .Select(i => i.GetStructure())
                            .OfType <DocumentationCommentTriviaSyntax>()
                            .FirstOrDefault();

            if (xmlTrivia != null)
            {
                var hasSummary = xmlTrivia.ChildNodes()
                                 .OfType <XmlElementSyntax>()
                                 .Any(i => i.StartTag.Name.ToString().Equals(Constants.Summary));

                if (hasSummary)
                {
                    return;
                }
            }

            if (node.Modifiers.Any(SyntaxKind.PublicKeyword))
            {
                syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5001, node.Identifier.GetLocation(), Constants.Public, DiagnosticId5001));
                return;
            }

            if (node.Modifiers.Any(SyntaxKind.PrivateKeyword))
            {
                syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5005, node.Identifier.GetLocation(), Constants.Private, DiagnosticId5005));
                return;
            }

            if (node.Modifiers.Any(SyntaxKind.InternalKeyword))
            {
                if (node.Modifiers.Any(SyntaxKind.ProtectedKeyword))
                {
                    syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5003, node.Identifier.GetLocation(), Constants.InternalProtected, DiagnosticId5003));
                }
                else
                {
                    syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5002, node.Identifier.GetLocation(), Constants.Internal, DiagnosticId5002));
                }

                return;
            }

            if (node.Modifiers.Any(SyntaxKind.ProtectedKeyword))
            {
                syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5004, node.Identifier.GetLocation(), Constants.Protected, DiagnosticId5004));
                return;
            }

            if (node.Parent is NamespaceDeclarationSyntax)
            {
                syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5002, node.Identifier.GetLocation(), Constants.Internal, DiagnosticId5002));
                return;
            }

            syntaxNodeAnalysisContext.ReportDiagnostic(Diagnostic.Create(Rule5005, node.Identifier.GetLocation(), Constants.Private, DiagnosticId5005));
        }
Example #58
0
        private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
        {
            var options           = syntaxContext.Options;
            var syntaxTree        = syntaxContext.Node.SyntaxTree;
            var cancellationToken = syntaxContext.CancellationToken;
            var optionSet         = options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var styleOption = optionSet.GetOption(CSharpCodeStyleOptions.PreferPatternMatchingOverIsWithCastCheck);

            if (!styleOption.Value)
            {
                // Bail immediately if the user has disabled this feature.
                return;
            }

            var severity = styleOption.Notification.Value;

            var isExpression = (BinaryExpressionSyntax)syntaxContext.Node;

            // "x is Type y" is only available in C# 7.0 and above.  Don't offer this refactoring
            // in projects targetting a lesser version.
            if (((CSharpParseOptions)isExpression.SyntaxTree.Options).LanguageVersion < LanguageVersion.CSharp7)
            {
                return;
            }

            // The is check has to be in an if check: "if (x is Type)
            if (!isExpression.Parent.IsKind(SyntaxKind.IfStatement))
            {
                return;
            }

            var ifStatement = (IfStatementSyntax)isExpression.Parent;

            if (!ifStatement.Statement.IsKind(SyntaxKind.Block))
            {
                return;
            }

            var ifBlock = (BlockSyntax)ifStatement.Statement;

            if (ifBlock.Statements.Count == 0)
            {
                return;
            }

            var firstStatement = ifBlock.Statements[0];

            if (!firstStatement.IsKind(SyntaxKind.LocalDeclarationStatement))
            {
                return;
            }

            var localDeclarationStatement = (LocalDeclarationStatementSyntax)firstStatement;

            if (localDeclarationStatement.Declaration.Variables.Count != 1)
            {
                return;
            }

            var declarator = localDeclarationStatement.Declaration.Variables[0];

            if (declarator.Initializer == null)
            {
                return;
            }

            var declaratorValue = declarator.Initializer.Value.WalkDownParentheses();

            if (!declaratorValue.IsKind(SyntaxKind.CastExpression))
            {
                return;
            }

            var castExpression = (CastExpressionSyntax)declaratorValue;

            if (!SyntaxFactory.AreEquivalent(isExpression.Left.WalkDownParentheses(), castExpression.Expression.WalkDownParentheses(), topLevel: false) ||
                !SyntaxFactory.AreEquivalent(isExpression.Right.WalkDownParentheses(), castExpression.Type, topLevel: false))
            {
                return;
            }

            // It's of the form:
            //
            //     if (expr is Type)
            //     {
            //         var v = (Type)expr;
            //     }

            // Make sure that moving 'v' to the outer scope won't cause any conflicts.

            var ifStatementScope = ifStatement.Parent.IsKind(SyntaxKind.Block)
                ? ifStatement.Parent
                : ifStatement;

            if (ContainsVariableDeclaration(ifStatementScope, declarator))
            {
                // can't switch to using a pattern here as it would cause a scoping
                // problem.
                //
                // TODO(cyrusn): Consider allowing the user to do this, but giving
                // them an error preview.
                return;
            }

            var semanticModel = syntaxContext.SemanticModel;
            var localSymbol   = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator);
            var isType        = semanticModel.GetTypeInfo(castExpression.Type).Type;

            if (!localSymbol.Type.Equals(isType))
            {
                // we have something like:
                //
                //      if (x is DerivedType)
                //      {
                //          BaseType b = (DerivedType)x;
                //      }
                //
                // It's not necessarily safe to convert this to:
                //
                //      if (x is DerivedType b) { ... }
                //
                // That's because there may be later code that wants to do something like assign a
                // 'BaseType' into 'b'.  As we've now claimed that it must be DerivedType, that
                // won't work.  This might also cause unintended changes like changing overload
                // resolution.  So, we conservatively do not offer the change in a situation like this.
                return;
            }

            // Looks good!
            var additionalLocations = ImmutableArray.Create(
                ifStatement.GetLocation(),
                localDeclarationStatement.GetLocation());

            // Put a diagnostic with the appropriate severity on the declaration-statement itself.
            syntaxContext.ReportDiagnostic(Diagnostic.Create(
                                               GetDescriptorWithSeverity(severity),
                                               localDeclarationStatement.GetLocation(),
                                               additionalLocations));
        }
Example #59
0
        public static void ReportDiagnostic(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right,
            bool fadeOut)
        {
            if (!binaryExpression.SpanContainsDirectives())
            {
                context.ReportDiagnostic(DiagnosticDescriptors.SimplifyBooleanComparison, binaryExpression);

                if (fadeOut)
                {
                    context.ReportToken(FadeOutDescriptor, binaryExpression.OperatorToken);

                    switch (binaryExpression.Kind())
                    {
                    case SyntaxKind.EqualsExpression:
                    {
                        if (left.IsKind(SyntaxKind.FalseLiteralExpression))
                        {
                            context.ReportNode(FadeOutDescriptor, left);

                            if (right.IsKind(SyntaxKind.LogicalNotExpression))
                            {
                                context.ReportToken(FadeOutDescriptor, ((PrefixUnaryExpressionSyntax)right).OperatorToken);
                            }
                        }
                        else if (right.IsKind(SyntaxKind.FalseLiteralExpression))
                        {
                            context.ReportNode(FadeOutDescriptor, right);

                            if (left.IsKind(SyntaxKind.LogicalNotExpression))
                            {
                                context.ReportToken(FadeOutDescriptor, ((PrefixUnaryExpressionSyntax)left).OperatorToken);
                            }
                        }

                        break;
                    }

                    case SyntaxKind.NotEqualsExpression:
                    {
                        if (left.IsKind(SyntaxKind.TrueLiteralExpression))
                        {
                            context.ReportNode(FadeOutDescriptor, left);

                            if (right.IsKind(SyntaxKind.LogicalNotExpression))
                            {
                                context.ReportToken(FadeOutDescriptor, ((PrefixUnaryExpressionSyntax)right).OperatorToken);
                            }
                        }
                        else if (right.IsKind(SyntaxKind.TrueLiteralExpression))
                        {
                            context.ReportNode(FadeOutDescriptor, right);

                            if (left.IsKind(SyntaxKind.LogicalNotExpression))
                            {
                                context.ReportToken(FadeOutDescriptor, ((PrefixUnaryExpressionSyntax)left).OperatorToken);
                            }
                        }

                        break;
                    }
                    }
                }
            }
        }
        private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
        {
            var outermostUsing = (UsingStatementSyntax)context.Node;

            var syntaxTree = context.Node.SyntaxTree;
            var options    = (CSharpParseOptions)syntaxTree.Options;

            if (options.LanguageVersion < LanguageVersion.CSharp8)
            {
                return;
            }

            if (!(outermostUsing.Parent is BlockSyntax parentBlock))
            {
                // Don't offer on a using statement that is parented by another using statement.
                // We'll just offer on the topmost using statement.
                return;
            }

            var innermostUsing = outermostUsing;

            // Check that all the immediately nested usings are convertible as well.
            // We don't want take a sequence of nested-using and only convert some of them.
            for (var current = outermostUsing; current != null; current = current.Statement as UsingStatementSyntax)
            {
                innermostUsing = current;
                if (current.Declaration == null)
                {
                    return;
                }
            }

            // Verify that changing this using-statement into a using-declaration will not
            // change semantics.
            if (!PreservesSemantics(parentBlock, outermostUsing, innermostUsing))
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            // Converting a using-statement to a using-variable-declaration will cause the using's
            // variables to now be pushed up to the parent block's scope. This is also true for any
            // local variables in the innermost using's block. These may then collide with other
            // variables in the block, causing an error.  Check for that and bail if this happens.
            if (CausesVariableCollision(
                    context.SemanticModel, parentBlock,
                    outermostUsing, innermostUsing, cancellationToken))
            {
                return;
            }

            var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();

            if (optionSet == null)
            {
                return;
            }

            var option = optionSet.GetOption(CSharpCodeStyleOptions.PreferSimpleUsingStatement);

            if (!option.Value)
            {
                return;
            }

            // Good to go!
            context.ReportDiagnostic(DiagnosticHelper.Create(
                                         Descriptor,
                                         outermostUsing.UsingKeyword.GetLocation(),
                                         option.Notification.Severity,
                                         additionalLocations: ImmutableArray.Create(outermostUsing.GetLocation()),
                                         properties: null));
        }