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

Code before:
        /// <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 (isPreprocessingSymbolIdentifierContainer(node.Parent))
            {
                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 isPreprocessingSymbolIdentifierContainer(SyntaxNode parentNode)
            {
                if (parentNode is null)
                {
                    return false;
                }

                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;
                }

Review comment (suggestion):
>SyntaxNode parentNode [](http://example.com/codeflow?start=58&length=21)

Consider passing ```IdentifierNameSyntax node``` instead and using a loop through the `Parent` chain instead of a recursion. #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;