Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs (C#)

Code before:
        public abstract DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node);

        /// <summary>
        /// Gets await expression info.
        /// </summary>
        /// <param name="node">The node.</param>
        public abstract AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node);

        /// <summary>
        /// If the given node is within a preprocessing directive, gets the preprocessing symbol info for it.
        /// </summary>
        /// <param name="node">Preprocessing symbol identifier node.</param>
        public PreprocessingSymbolInfo GetPreprocessingSymbolInfo(IdentifierNameSyntax node)
        {
            CheckSyntaxNode(node);

            if (node.Ancestors().Any(n => isPreprocessorDirectiveAcceptingPreprocessingSymbols(n.Kind())))
            {
                bool isDefined = this.SyntaxTree.IsPreprocessorSymbolDefined(node.Identifier.ValueText, node.Identifier.SpanStart);
                return new PreprocessingSymbolInfo(new Symbols.PublicModel.PreprocessingSymbol(node.Identifier.ValueText), isDefined);
            }

            return PreprocessingSymbolInfo.None;

            static bool isPreprocessorDirectiveAcceptingPreprocessingSymbols(SyntaxKind kind)
                => kind is SyntaxKind.IfDirectiveTrivia or SyntaxKind.ElifDirectiveTrivia or SyntaxKind.DefineDirectiveTrivia or SyntaxKind.UndefDirectiveTrivia;
        }

        /// <summary>
        /// Options to control the internal working of GetSymbolInfoWorker. Not currently exposed
        /// to public clients, but could be if desired.
        /// </summary>
        [Flags]
        internal enum SymbolInfoOptions
        {
            /// <summary>
            /// When binding "C" new C(...), return the type C and do not return information about
            /// which constructor was bound to. Bind "new C(...)" to get information about which constructor
            /// was chosen.
            /// </summary>
            PreferTypeToConstructors = 0x1,

            /// <summary>
            /// When binding "C" new C(...), return the constructor of C that was bound to, if C unambiguously
            /// binds to a single type with at least one constructor. 
            /// </summary>
            PreferConstructorsToType = 0x2,

            /// <summary>
            /// When binding a name X that was declared with a "using X=OtherTypeOrNamespace", return OtherTypeOrNamespace.
            /// </summary>

Review comment (suggestion):
>SyntaxKind.DefineDirectiveTrivia or SyntaxKind.UndefDirectiveTrivia [](http://example.com/codeflow?start=93&length=67)

Are these using ```IdentifierNameSyntax``` to refer to preprocessing symbol? #Closed

Code after:
        /// <param name="node">The node.</param>
        public abstract AwaitExpressionInfo GetAwaitExpressionInfo(LocalDeclarationStatementSyntax node);

        /// <summary>
        /// Gets await expression info.
        /// </summary>
        /// <param name="node">The node.</param>
        public abstract AwaitExpressionInfo GetAwaitExpressionInfo(UsingStatementSyntax node);

        /// <summary>
        /// If the given node is within a preprocessing directive, gets the preprocessing symbol info for it.
        /// </summary>
        /// <param name="node">Preprocessing symbol identifier node.</param>
        public PreprocessingSymbolInfo GetPreprocessingSymbolInfo(IdentifierNameSyntax node)
        {
            CheckSyntaxNode(node);

            if (isPossiblePreprocessingSymbolReference(node))
            {
                bool isDefined = this.SyntaxTree.IsPreprocessorSymbolDefined(node.Identifier.ValueText, node.Identifier.SpanStart);
                return new PreprocessingSymbolInfo(new Symbols.PublicModel.PreprocessingSymbol(node.Identifier.ValueText), isDefined);
            }

            return PreprocessingSymbolInfo.None;

            bool isPossiblePreprocessingSymbolReference(IdentifierNameSyntax node)
            {
                var parentNode = node.Parent;
                while (parentNode is not null)
                {
                    var kind = parentNode.Kind();
                    switch (kind)
                    {
                        case SyntaxKind.IfDirectiveTrivia:
                            {
                                var parentIf = (IfDirectiveTriviaSyntax)parentNode;
                                return parentIf.Condition.FullSpan.Contains(node.FullSpan);
                            }
                        case SyntaxKind.ElifDirectiveTrivia:
                            {
                                var parentElif = (ElifDirectiveTriviaSyntax)parentNode;
                                return parentElif.Condition.FullSpan.Contains(node.FullSpan);
                            }
                    }

                    if (SyntaxFacts.IsPreprocessorDirective(kind))
                    {
                        return false;
                    }

                    parentNode = parentNode.Parent;