Skip to content

C# Parser Fails (Root ERROR Node) with Nested Preprocessor Directives Conditionally Defining Method Parameters #377

@pavel-shchelkun-ilogos

Description

@pavel-shchelkun-ilogos

The tree-sitter-csharp parser fails and produces a root ERROR node when encountering nested C# preprocessor directives (#if ... #else ... #endif) that conditionally alter a method's signature, specifically its parameter list.

Environment:

  • py-tree-sitter version: 0.24.0
  • tree-sitter-language-pack version: 0.7.3
  • tree-sitter-csharp grammar version: 0.23.1
  • tree-sitter-embedded-template grammar version: 0.23.2
  • Operating System: macOS Sonoma 14.5

Minimal Reproducible Example:

// test_conditional_signature.cs
namespace TestNs
{
    public class TestClass
    {
#if OUTER_CONDITION // Outer preprocessor block
    #if INNER_CONDITION // Inner preprocessor block
        static void MyMethod() // Signature 1: no parameters
    #else
        static void MyMethod(int param) // Signature 2: with parameters
    #endif
        {
            // Common method body
        }
#endif
    }
}

Observed Behavior:
When parsing the above code, tree.root_node.type is ERROR and tree.root_node.has_error is True.

Expected Behavior:
The parser should correctly parse this valid C# construct, recognizing the method declaration with its conditionally defined parameter list. The root node should be compilation_unit and has_error should be False. Tree-sitter should parse the structure including both potential branches of the inner #if/#else.

Note:
If the method signature is not fragmented by inner preprocessor directives, it parses correctly. For example, if only one signature is used within the outer conditional block:

// This parses correctly:
namespace TestNs
{
    public class TestClass
    {
#if OUTER_CONDITION
        static void MyMethod(int param) 
        {
            // Common method body
        }
#endif
    }
}

This suggests an issue with the grammar's ability to handle preprocessor directives appearing within the syntactic structure of a method's parameter list definition. While preprocessor directives are often in extras, their interaction with the rules for parameter_list or method_declaration seems problematic in this nested scenario.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions