コード例 #1
0
        // TODO: Ideally, a load of static code analysis here, but just checking the first use would be a start.
        private void FirstUseOfUntrustedParameterShouldNotBeArgumentToTrustedParameter(SyntaxNodeAnalysisContext context)
        {
            var parameterSyntax = (ParameterSyntax)context.Node;
            var model           = context.SemanticModel;
            var parameter       = model.GetDeclaredSymbol(parameterSyntax);

            if (parameter.HasAttribute(TrustedAttributeName))
            {
                return;
            }
            var container = parameter.ContainingSymbol;

            if ((container as IMethodSymbol)?.MethodKind == MethodKind.AnonymousFunction)
            {
                // Be lenient for anonymous functions. Not entirely sure whether this is a good idea,
                // admittedly.
                return;
            }
            var firstUse = container.DeclaringSyntaxReferences
                           .SelectMany(syntaxRef => syntaxRef.GetSyntax().DescendantNodes())
                           .Select(node => ParameterUsage.ForNode(node, model, parameter))
                           .FirstOrDefault(usage => usage != null);

            if (firstUse?.CorrespondingParameter == null)
            {
                return;
            }
            if (firstUse.CorrespondingParameter.HasAttribute(TrustedAttributeName))
            {
                context.ReportDiagnostic(UntrustedParameterIsTrusted, firstUse.UsageNode, parameter.Name, container.Name);
            }
        }
コード例 #2
0
        /// <summary>
        /// Single method to have a look at how a parameter is used within a method (often stopping
        /// at the first usage) and then checking whether that usage is appropriate for the
        /// attributes applied to the parameter.
        /// </summary>
        private void UberCheckParameter(SyntaxNodeAnalysisContext context)
        {
            var parameterSyntax = (ParameterSyntax)context.Node;
            var model           = context.SemanticModel;
            var parameterSymbol = model.GetDeclaredSymbol(parameterSyntax);

            if (parameterSymbol.Type.IsValueType)
            {
                return;
            }

            bool notNull      = HasNotNullAttribute(parameterSymbol);
            var  container    = parameterSymbol.ContainingSymbol;
            var  methodSymbol = container as IMethodSymbol;

            if (methodSymbol?.MethodKind == MethodKind.AnonymousFunction)
            {
                // Be lenient for anonymous functions. Not entirely sure whether this is a good idea,
                // admittedly. Potentially check the attributes applied to the delegate type that the
                // anonymous function is being converted to.
                return;
            }

            if (container?.IsAbstract == true ||
                methodSymbol?.MethodKind == MethodKind.DelegateInvoke)
            {
                // Abstract members (including interface members) and delegates can't check their parameters
                return;
            }

            var firstUse = container.DeclaringSyntaxReferences
                           .SelectMany(syntaxRef => syntaxRef.GetSyntax().DescendantNodes())
                           .Select(node => ParameterUsage.ForNode(node, model, parameterSymbol))
                           .FirstOrDefault(usage => usage != null);

            if (firstUse == null)
            {
                // No "interesting" usage that could have been some other kind of check. (Could
                // be used in an assignment etc.)
                if (notNull)
                {
                    context.ReportDiagnostic(NotNullParameterIsNotChecked, parameterSyntax.Identifier, parameterSymbol.Name);
                }
                return;
            }
            // First use is parameter.Foo or parameter.Foo(). This might always be invalid... see how much
            // noise it causes. Also consider extension methods, where it's valid to be null.
            if (firstUse.CorrespondingParameter == null)
            {
                if (container.DeclaredAccessibility == Accessibility.Public && container.ContainingType.DeclaredAccessibility == Accessibility.Public)
                {
                    context.ReportDiagnostic(FirstNotNullParameterUseIsMemberAccess, firstUse.UsageNode);
                }
                return;
            }

            // Okay, it's an invocation (method, operator or whatever). It might be a CheckNotNull call, in which case we'll let the other
            // rule handle it.

            // TODO: Do we need to check that the right argument is being used here?
            if (IsCheckNotNull(firstUse.InvokedMember))
            {
                return;
            }

            // If the first usage is an equality check, let's assume it's being handled correctly. Examples:
            // - Checking inequality against non-null values (e.g. in xxx)
            // - Checking equality against the null literal (e.g. in Period.Compare)
            if (firstUse.InvokedMember.Name == "op_Equality" || firstUse.InvokedMember.Name == "op_Inequality")
            {
                return;
            }

            if (HasNotNullAttribute(firstUse.CorrespondingParameter))
            {
                // TODO: Consider the interplay of Trusted here.
                if (!notNull)
                {
                    context.ReportDiagnostic(ParameterImplicitlyNotNullCheckedWithoutAttribute, firstUse.UsageNode,
                                             parameterSymbol.Name);
                }
                if (firstUse.CorrespondingParameter.Name != parameterSymbol.Name)
                {
                    context.ReportDiagnostic(NotNullParameterCheckedWithWrongName, firstUse.UsageNode,
                                             parameterSymbol.Name, firstUse.CorrespondingParameter.Name);
                }
                return;
            }
            if (notNull)
            {
                // First usage doesn't check for nullity, despite this being a NotNull parameter.
                context.ReportDiagnostic(NotNullParameterIsNotChecked, parameterSyntax.Identifier, parameterSymbol.Name);
            }

            // TODO: Check later uses?
        }