Skip to content

Exception parsing Constructor with conditional initializers #171

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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