예제 #1
0
        /// <summary>
        /// Given an operation, goes through all decendent operations and returns true if the symbol passed in
        /// is ever assigned a possibly null value as determined by nullable flow state. Returns
        /// null if no references are found, letting the caller determine what to do with that information
        /// </summary>
        public static bool?IsSymbolAssignedPossiblyNullValue(SemanticModel semanticModel, IOperation operation, ISymbol symbol)
        {
            var references = operation.DescendantsAndSelf()
                             .Where(o => IsSymbolReferencedByOperation(o, symbol));

            var hasReference = false;

            foreach (var reference in references)
            {
                hasReference = true;

                // foreach statements are handled special because the iterator is not assignable, so the elementtype
                // annotation is accurate for determining if the loop declaration has a reference that allows the symbol
                // to be null
                if (reference is IForEachLoopOperation forEachLoop)
                {
                    var foreachInfo = semanticModel.GetForEachStatementInfo((CommonForEachStatementSyntax)forEachLoop.Syntax);

                    if (foreachInfo.ElementType is null)
                    {
                        continue;
                    }

                    // Use NotAnnotated here to keep both Annotated and None (oblivious) treated the same, since
                    // this is directly looking at the annotation and not the flow state
                    if (foreachInfo.ElementType.NullableAnnotation != NullableAnnotation.NotAnnotated)
                    {
                        return(true);
                    }

                    continue;
                }

                var syntax = reference is IVariableDeclaratorOperation variableDeclarator
                    ? variableDeclarator.GetVariableInitializer() !.Value.Syntax
                    : reference.Syntax;

                var typeInfo = semanticModel.GetTypeInfo(syntax);

                if (typeInfo.Nullability.FlowState == NullableFlowState.MaybeNull)
                {
                    return(true);
                }
            }

            return(hasReference ? (bool?)false : null);
        }