C# Parser Fails (Root ERROR Node) with Conditionally Compiled Attribute When Member is Not in Same Conditional Block · Issue #376 · tree-sitter/tree-sitter-c-sharp · GitHub
Skip to content

C# Parser Fails (Root ERROR Node) with Conditionally Compiled Attribute When Member is Not in Same Conditional Block #376

Description

@pavlo-shchelkun

The tree-sitter-csharp parser fails and produces a root ERROR node when encountering a C# attribute that is conditionally compiled using #if/#endif, if the member (e.g., method, class) that the attribute applies to is not also enclosed within the same conditional compilation block.

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_attribute.cs
namespace TestNs
{
    public class TestClass
    {
#if SOME_CONDITION // This can be any valid preprocessor symbol
        [System.Obsolete("Conditional attribute")] // Attribute is conditional
#endif
        public void MyMethod() // Method is NOT conditional in the same block
        {
            // Method body
        }
    }
}

Observed Behavior:
When parsing the above code, the tree.root_node.type is ERROR and tree.root_node.has_error is True. The error seems to encompass a large portion of the file, starting very early if this pattern appears near the top of a declaration.

Expected Behavior:
The parser should correctly parse this valid C# construct, associating the conditional attribute with MyMethod if SOME_CONDITION were true (tree-sitter parses structure, not evaluating defines), or parsing MyMethod without the attribute if SOME_CONDITION were false. The root node should be compilation_unit and has_error should be False.

Note:
If the entire method declaration (including the attribute) is wrapped in the #if/#endif block, it parses correctly:

// This parses correctly:
namespace TestNs
{
    public class TestClass
    {
#if SOME_CONDITION
        [System.Obsolete("Conditional attribute")]
        public void MyMethod() 
        {
            // Method body
        }
#endif
    }
}

This suggests an issue with handling preprocessor directives that "interrupt" the expected contiguity between an attribute and the member it decorates. The grammar.js for tree-sitter-csharp often includes preprocessor directives in extras, which should theoretically allow them in many places, but this specific pattern seems to expose a limitation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions