Skip to content

Exception parsing Constructor with conditional initializers #171

@bbczeuz

Description

@bbczeuz

Minimum crashing example

struct MyObject
{
    MyObject();
 private:
    int testing;
    void *output_file_handle_;
};  

MyObject::MyObject()
    : testing(0),
#if 1 
    output_file_handle_(nullptr)
#endif
{
}

Tested with:

user@host:~$ cppclean main.cpp 
Traceback (most recent call last):
  File "/home/user/.local/bin/cppclean", line 166, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/user/.local/bin/cppclean", line 139, in main
    entire_ast = list([_f for _f in builder.generate() if _f])
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/pipx/venvs/cppclean/lib/python3.12/site-packages/cpp/ast.py", line 675, in generate
    result = self._generate_one(token)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/pipx/venvs/cppclean/lib/python3.12/site-packages/cpp/ast.py", line 753, in _generate_one
    return self._get_method(temp_tokens, 0, None, False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/share/pipx/venvs/cppclean/lib/python3.12/site-packages/cpp/ast.py", line 1098, in _get_method
    member = member[0]
             ~~~~~~^^^
IndexError: list index out of range

Exception is thrown here:

        # Handle ctor initializers.
        # Supports C++11 method of direct initialization with braces.
        initializers = {}
        if token.name == ':':
            while token.name != ';' and token.name != '{':
                # skip preprocesors macros
1094            if token.name.startswith(('#if', '#elif', '#else', '#endif')):
1095                token = self._get_next_token()
1096                continue
1097            member, token = self.get_name()
1098            member = member[0]
                if token.name == '(' or token.name == '{':
                    end = '}' if token.name == '{' else ')'
                    initializers[member] = [
                        x for x in list(self._get_matching_char(token.name,
                                                                end))
                        if x.name != ',' and x.name != end]
                token = self._get_next_token()

On line 1097: member is empty; token is Token('#if 1', 133, 138)
It seems as the check on line 1094 fails.

Workaround

Adapt code so that all initializers are within the same preprocessor condition:

MyObject::MyObject()
#if SOME_CONDITION
    : testing(0), output_file_handle_(nullptr)
#endif
{
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions