Example #1
0
        public NotNullMethodInfo VisitGetterMethod(SemanticModel model, IPropertySymbol propertySymbol, AccessorDeclarationSyntax getter)
        {
            var symbol = model.GetDeclaredSymbol(getter);

            if (symbol != null)
            {
                if (propertySymbol.HasNotNull() || symbol.HasNotNull())
                {
                    if (symbol.ReturnsVoid || IsValueType(symbol.ReturnType))
                    {
                        context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(getter.GetLocation(), true));
                        return(null);
                    }
                    if (getter.Body != null)
                    {
                        return(new NotNullMethodInfo(getter.GetLocation(), symbol, getter.Body));
                    }
                }
                else if (FindInheritedReference(model, symbol).HasNotNull())
                {
                    context.ReportDiagnostic(MainAnalyzer.CreateMissingAttribute(getter.GetLocation(), symbol.ToString()));
                }
            }
            return(null);
        }
Example #2
0
        // This is kinda duplicated in CodeBlockAnalyzer.GetAssignmentStatus
        private void CheckExpressionForNull(ISymbol symbol, ExpressionSyntax expression, MethodFlowAnalysis analysis = null)
        {
            var expressionValueType = expression.GetTypeOfValue(context.SemanticModel);

            if (expressionValueType == ValueType.NotNull)
            {
                // Argument cannot be null, so move to the next
                return;
            }
            if (expressionValueType == ValueType.Null)
            {
                context.ReportDiagnostic(MainAnalyzer.CreateReturnNull(expression.GetLocation(), symbol.ToString()));
                return;
            }
            if (analysis == null)
            {
                context.ReportDiagnostic(MainAnalyzer.CreateReturnNull(expression.GetLocation(), symbol.ToString()));
                return;
            }

            ExpressionStatus status = analysis.IsAlwaysAssigned(expression, expression);

            if (!status.IsAssigned())
            {
                context.ReportDiagnostic(MainAnalyzer.CreateReturnNull(expression.GetLocation(), symbol.ToString()));
            }
            if (status == ExpressionStatus.AssignedWithUnneededConstraint)
            {
                context.ReportDiagnostic(MainAnalyzer.CreateUnneededConstraint(expression.GetLocation(), symbol.ToString()));
            }
        }
Example #3
0
        public NotNullMethodInfo VisitMethod(SemanticModel model, MethodDeclarationSyntax method)
        {
            var symbol = model.GetDeclaredSymbol(method);

            if (symbol != null)
            {
                if (symbol.HasNotNull())
                {
                    if (symbol.ReturnsVoid || IsValueType(symbol.ReturnType))
                    {
                        context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(method.GetLocation(), true));
                        return(null);
                    }
                    if (method.Body != null)
                    {
                        return(new NotNullMethodInfo(method.GetLocation(), symbol, method.Body));
                    }
                }
                else if (FindInheritedReference(model, symbol).HasNotNull())
                {
                    context.ReportDiagnostic(MainAnalyzer.CreateMissingAttribute(method.GetLocation(), symbol.ToString()));
                }
            }
            return(null);
        }
Example #4
0
        public void Analyze(SemanticModel model)
        {
            var constructorFlowAnalyzer = new CtorFlowAnalyzer(model);
            var root    = model.SyntaxTree.GetRoot();
            var classes = root.DescendantNodes().OfType <ClassDeclarationSyntax>();

            foreach (var @class in classes)
            {
                var classSymbol = model.GetDeclaredSymbol(@class);
                if (classSymbol != null && classSymbol.HasNotNull())
                {
                    context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(@class.GetLocation(), false));
                }
                var members = GetTrackedMembers(model, @class);
                if (members.Item1.Count > 0)
                {
                    FlagUninitializedFields(@class, constructorFlowAnalyzer, members.Item1);
                }
                if (members.Item2.Count > 0)
                {
                    VerifyMethods(members.Item2);
                }
                if (members.Item3.Count > 0)
                {
                    VerifyExpressionBodies(members.Item3);
                }
            }
        }
Example #5
0
        private void FlagUninitializedFields(
            ClassDeclarationSyntax @class,
            CtorFlowAnalyzer constructorFlowAnalyzer,
            Dictionary <ISymbol, NotNullFieldInfo> fields)
        {
            var flowAnalysis = constructorFlowAnalyzer.AnalyzeDataFlow(@class, fields);

            foreach (var member in fields.Values)
            {
                var isInitialized = member.Initializer != null &&
                                    member.Initializer.Value.GetTypeOfValue(context.SemanticModel) == ValueType.NotNull;
                if (!isInitialized)
                {
                    if (flowAnalysis.Count == 0)
                    {
                        context.ReportDiagnostic(MainAnalyzer.CreateMemberNotInitialized(member.Location, member.Symbol));
                        continue;
                    }
                    foreach (var flow in flowAnalysis)
                    {
                        if (flow.UnassignedMembers.Contains(member))
                        {
                            context.ReportDiagnostic(MainAnalyzer.CreateMemberNotInitialized(flow.Constructor.GetLocation(), member.Symbol));
                        }
                    }
                }
            }
        }
Example #6
0
        private void ReportIfIsNotNullSymbol(ExpressionSyntax expression)
        {
            var target = expression.FindUnderlyingMember();

            if (target == null)
            {
                return;
            }
            if (target is ConditionalExpressionSyntax conditional)
            {
                ReportIfIsNotNullSymbol(conditional.WhenTrue);
                ReportIfIsNotNullSymbol(conditional.WhenFalse);
                return;
            }

            // Make sure the expression is always Not Null. This catches the case: ([NotNull]x as SomeType) which can be null.
            var expressionValue = expression.GetTypeOfValue(context.SemanticModel);

            switch (expressionValue)
            {
            case ValueType.NotNull:
            {
                var symbol = context.SemanticModel.GetSymbolInfo(target).Symbol;
                if (symbol.HasNotNullOrCheckNull())
                {
                    if (symbol is IParameterSymbol && expression.Parent.Parent is IfStatementSyntax ifStatement)
                    {
                        if (ifStatement.Statement is ThrowStatementSyntax)
                        {
                            return;
                        }
                        if (ifStatement.Statement is BlockSyntax block && block.ChildNodes().FirstOrDefault() is ThrowStatementSyntax)
                        {
                            return;
                        }
                    }
                    context.ReportDiagnostic(MainAnalyzer.CreateUnneededNullCheckError(expression.GetLocation(), symbol));
                }
                break;
            }

            case ValueType.MaybeNull:
            {
                var status = GetAssignmentStatus(expression, expression, ValueType.MaybeNull, AnalysisMode.Strict);
                if (status.IsAssigned())
                {
                    var symbol = context.SemanticModel.GetSymbolInfo(target).Symbol;
                    context.ReportDiagnostic(MainAnalyzer.CreateUnneededNullCheckError(expression.GetLocation(), symbol));
                }
                break;
            }
            }
        }
Example #7
0
        public void Analyze(SyntaxNode node)
        {
            needsConstraintChecking.Clear();
            this.Visit(node);

            foreach (var method in needsConstraintChecking.Values)
            {
                foreach (var violation in method.GetAssignmentsAfterConstraints())
                {
                    context.ReportDiagnostic(
                        MainAnalyzer.CreateAssignmentAfterConstraint(violation.Expression.GetLocation(), violation.Expression.ToString()));
                }
            }
        }
Example #8
0
        private void ReportIssue(ExpressionStatus status, Location location, string errorContext)
        {
            switch (status)
            {
            case ExpressionStatus.NotAssigned:
                context.ReportDiagnostic(MainAnalyzer.CreateNullAssignmentError(location, errorContext));
                break;

            case ExpressionStatus.ReassignedAfterCondition:
                context.ReportDiagnostic(MainAnalyzer.CreateAssignmentAfterCondition(location, errorContext));
                break;

            case ExpressionStatus.AssignedWithUnneededConstraint:
                context.ReportDiagnostic(MainAnalyzer.CreateUnneededConstraint(location, errorContext));
                break;
            }
        }
Example #9
0
 public NotNullExpressionBodyInfo VisitExpressionBody(SemanticModel model, IPropertySymbol propertySymbol, ExpressionSyntax expression, Location location)
 {
     if (propertySymbol.HasNotNull())
     {
         if (!propertySymbol.Type.IsReferenceType)
         {
             context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(location, true));
             return(null);
         }
         return(new NotNullExpressionBodyInfo(location, propertySymbol, expression));
     }
     else if (FindInheritedReference(model, propertySymbol).HasNotNull())
     {
         context.ReportDiagnostic(MainAnalyzer.CreateMissingAttribute(location, propertySymbol.ToString()));
     }
     return(null);
 }
Example #10
0
        public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
        {
            base.VisitAssignmentExpression(node);

            var valueType = node.Right.GetTypeOfValue(context.SemanticModel);

            if (valueType == ValueType.NotNull)
            {
                return;
            }
            var target = node.Left.FindUnderlyingMember();

            if (target == null)
            {
                return;
            }

            var symbol = context.SemanticModel.GetSymbolInfo(target).Symbol;

            if (!symbol.HasNotNullOrCheckNull())
            {
                return;
            }

            switch (GetAssignmentStatus(node.Right, node, valueType))
            {
            case ExpressionStatus.NotAssigned:
                context.ReportDiagnostic(MainAnalyzer.CreateNullAssignmentError(node.GetLocation(), symbol));
                break;

            case ExpressionStatus.ReassignedAfterCondition:
                context.ReportDiagnostic(MainAnalyzer.CreateAssignmentAfterCondition(node.GetLocation(), node.ToString()));
                break;

            case ExpressionStatus.AssignedWithUnneededConstraint:
                context.ReportDiagnostic(MainAnalyzer.CreateUnneededConstraint(node.GetLocation(), node.ToString()));
                break;
            }
        }
Example #11
0
        public override void VisitConstructorInitializer(ConstructorInitializerSyntax node)
        {
            base.VisitConstructorInitializer(node);

            var ctor = context.SemanticModel.GetSymbolInfo(node).Symbol as IMethodSymbol;

            if (ctor == null)
            {
                return;
            }
            CheckMethodInvocation(
                node,
                ctor,
                node.ArgumentList,
                (status, l, s) =>
            {
                if (status == ExpressionStatus.NotAssigned)
                {
                    context.ReportDiagnostic(MainAnalyzer.CreatePropagateNotNullInCtors(l, s));
                }
            });
        }
Example #12
0
        public override void VisitInvocationExpression(InvocationExpressionSyntax node)
        {
            base.VisitInvocationExpression(node);

            var methodDefinition = context.SemanticModel.GetSymbolInfo(node).Symbol as IMethodSymbol;

            if (methodDefinition == null)
            {
                return;
            }

            if (node.IsCheckAgainstNull(methodDefinition, out var target, out var valueType))
            {
                ReportIfIsNotNullSymbol(target);
            }

            if (methodDefinition.IsConstraintMethod())
            {
                if (node.IsConstraint(context.SemanticModel, out var expression))
                {
                    var symbol = context.SemanticModel.GetSymbolInfo(expression).Symbol;
                    if (symbol.HasNotNullOrCheckNull())
                    {
                        context.ReportDiagnostic(MainAnalyzer.CreateUnneededConstraint(node.GetLocation(), symbol.ToString()));
                    }
                }
                else
                {
                    context.ReportDiagnostic(MainAnalyzer.CreateInvalidConstraintError(node.GetLocation()));
                }
            }
            CheckMethodInvocation(
                node,
                methodDefinition,
                node.ArgumentList,
                (status, location, error) => ReportIssue(status, location, error));
        }
Example #13
0
        private void CheckMethodInvocation(
            SyntaxNode node,
            IMethodSymbol methodDefinition,
            ArgumentListSyntax argumentList,
            Action <ExpressionStatus, Location, string> reportAction)
        {
            try
            {
                if (argumentList == null)
                {
                    // Is object initializer
                    return;
                }
                ImmutableArray <IParameterSymbol> parameters;
                List <ExpressionSyntax>           arguments;
                // Extension method
                if (methodDefinition.ReducedFrom != null)
                {
                    var invocation            = ((InvocationExpressionSyntax)node).Expression;
                    ExpressionSyntax firstArg = null;
                    // TODO: handle extension methods on other things like MemberBindingExpressionSyntax
                    if (invocation is MemberAccessExpressionSyntax access)
                    {
                        firstArg = access.Expression;
                    }

                    if (firstArg != null)
                    {
                        parameters = methodDefinition.ReducedFrom.Parameters;
                        arguments  = new[] { firstArg }.Concat(argumentList.Arguments.Select(i => i.Expression)).ToList();
                    }
                    else
                    {
                        parameters = methodDefinition.Parameters;
                        arguments  = argumentList.Arguments.Select(i => i.Expression).ToList();
                    }
                }
                else
                {
                    parameters = methodDefinition.Parameters;
                    arguments  = argumentList.Arguments.Select(i => i.Expression).ToList();
                }

                if (parameters.Length != arguments.Count)
                {
                    // Compiler error
                    return;
                }

                var parameterEnumerator = parameters.GetEnumerator();
                foreach (var arg in arguments)
                {
                    parameterEnumerator.MoveNext();
                    if (parameterEnumerator.Current.IsParams)
                    {
                        // Ignore for 'params' parameter
                        return;
                    }
                    if (parameterEnumerator.Current.RefKind == RefKind.Ref)
                    {
                        var argSymbol = context.SemanticModel.GetSymbolInfo(arg).Symbol;
                        if (argSymbol.HasNotNullOrCheckNull())
                        {
                            context.ReportDiagnostic(MainAnalyzer.CreateNotNullAsRefParameter(arg.GetLocation(), arg.ToString()));
                            continue;
                        }
                    }
                    if (!parameterEnumerator.Current.HasNotNullOrCheckNull())
                    {
                        // Only check [NotNull] parameters
                        continue;
                    }
                    var status = GetAssignmentStatus(arg, node, arg.GetTypeOfValue(context.SemanticModel));
                    reportAction(status, arg.GetLocation(), $"{methodDefinition.Name}({arg})");
                }
            }
            catch (Exception ex)
            {
                throw new ParseFailedException(node.GetLocation(), $"{ex.Message} --> Parse failed on: {methodDefinition.GetFullName()}", ex);
            }
        }
Example #14
0
        GetTrackedMembers(SemanticModel model, ClassDeclarationSyntax type)
        {
            var trackedFields           = new Dictionary <ISymbol, NotNullFieldInfo>();
            var trackedMethods          = new Dictionary <IMethodSymbol, NotNullMethodInfo>();
            var trackedExpressionBodies = new Dictionary <ISymbol, NotNullExpressionBodyInfo>();

            foreach (var member in type.ChildNodes()
                     .Where(i => i is PropertyDeclarationSyntax || i is FieldDeclarationSyntax || i is MethodDeclarationSyntax))
            {
                var property = member as PropertyDeclarationSyntax;
                if (property != null)
                {
                    var symbol = model.GetDeclaredSymbol(property);
                    if (symbol == null)
                    {
                        throw new ParseFailedException(member.GetLocation(), "Parse failed on: " + property);
                    }
                    if (!property.IsAutoProperty())
                    {
                        if (property.ExpressionBody?.Expression != null)
                        {
                            var info = VisitExpressionBody(model, symbol, property.ExpressionBody.Expression, property.GetLocation());
                            if (info != null)
                            {
                                trackedExpressionBodies.Add(info.Symbol, info);
                            }
                        }
                        else
                        {
                            var getter = property.AccessorList?.Accessors.FirstOrDefault(i => i.Kind() == SyntaxKind.GetAccessorDeclaration);
                            if (getter != null)
                            {
                                var info = VisitGetterMethod(model, symbol, getter);
                                if (info != null)
                                {
                                    trackedMethods.Add(info.Symbol, info);
                                }
                            }
                        }
                        // Is computed property, so we don't need to worry about the ctor setting it.
                        continue;
                    }
                    if (symbol.HasNotNull())
                    {
                        if (symbol.SetMethod != null || IsValueType(symbol.Type))
                        {
                            context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(member.GetLocation(), IsValueType(symbol.Type)));
                            continue;
                        }
                        trackedFields.Add(symbol, new NotNullFieldInfo(member.GetLocation(), symbol, property.Initializer));
                    }
                    else if (FindInheritedReference(model, symbol).HasNotNull())
                    {
                        context.ReportDiagnostic(MainAnalyzer.CreateMissingAttribute(member.GetLocation(), symbol.ToString()));
                    }
                }

                var field = member as FieldDeclarationSyntax;
                if (field != null)
                {
                    var declaration = field.Declaration.Variables.First();
                    var symbol      = model.GetDeclaredSymbol(declaration) as IFieldSymbol;
                    if (symbol == null)
                    {
                        throw new ParseFailedException(member.GetLocation(), "Parse failed on: " + declaration);
                    }
                    if (symbol.HasNotNull())
                    {
                        if (!symbol.IsReadOnlyOrConst() || IsValueType(symbol.Type))
                        {
                            context.ReportDiagnostic(MainAnalyzer.CreateBadAttributeUsageError(member.GetLocation(), IsValueType(symbol.Type)));
                            continue;
                        }
                        trackedFields.Add(symbol, new NotNullFieldInfo(member.GetLocation(), symbol, declaration.Initializer));
                    }
                }

                if (member is MethodDeclarationSyntax method)
                {
                    var info = VisitMethod(model, method);
                    if (info != null)
                    {
                        trackedMethods.Add(info.Symbol, info);
                    }
                }
            }
#if PORTABLE
            return(new Tuple <Dictionary <ISymbol, NotNullFieldInfo>, Dictionary <IMethodSymbol, NotNullMethodInfo>, Dictionary <ISymbol, NotNullExpressionBodyInfo> >(trackedFields, trackedMethods, trackedExpressionBodies));
#else
            return(trackedFields, trackedMethods, trackedExpressionBodies);
#endif
        }