From c770efcb89749fd58e28b14d90132ba1593da52a Mon Sep 17 00:00:00 2001 From: Renaud Durlin Date: Wed, 2 Oct 2013 21:48:39 +0200 Subject: [PATCH 1/2] Fix parsing of functions arguments when the argument is not named --- cpp/ast.py | 5 ++++- test/baz.h | 2 +- test_ast.py | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cpp/ast.py b/cpp/ast.py index 9216ca8..a89d265 100644 --- a/cpp/ast.py +++ b/cpp/ast.py @@ -597,8 +597,11 @@ def add_parameter(): if default: del default[0] # Remove flag. end = type_modifiers[-1].end + needs_name_removed = \ + not (len(type_modifiers) == 1 or (len(type_modifiers) == 2 and + type_modifiers[0].name == 'const')) name, type_name, templated_types, modifiers, _, __ = \ - self.declaration_to_parts(type_modifiers, True) + self.declaration_to_parts(type_modifiers, needs_name_removed) parameter_type = Type(first_token.start, first_token.end, type_name, templated_types, modifiers, reference, pointer, array) diff --git a/test/baz.h b/test/baz.h index 46ec50a..ac4bed6 100644 --- a/test/baz.h +++ b/test/baz.h @@ -2,4 +2,4 @@ #include "typedef.h" void fct(Bar& bar); -void fct(Type& t); +void fct(Type&); diff --git a/test_ast.py b/test_ast.py index d2c961b..ab8fce8 100755 --- a/test_ast.py +++ b/test_ast.py @@ -480,6 +480,22 @@ class AstBuilderIntegrationTest(unittest.TestCase): """ + def test_function_one_argument_with_name(self): + for argument in ('Foo f', 'const Foo f', 'Foo& f', 'const Foo& f'): + code = 'void fct(%s);' % argument + nodes = list(MakeBuilder(code).generate()) + self.assertEqual(1, len(nodes)) + self.assertEqual(1, len(nodes[0].parameters)) + self.assertEqual('f', nodes[0].parameters[0].name) + + def test_function_one_argument_with_no_name(self): + for argument in ('Foo', 'const Foo', 'Foo&', 'const Foo&'): + code = 'void fct(%s);' % argument + nodes = list(MakeBuilder(code).generate()) + self.assertEqual(1, len(nodes)) + self.assertEqual(1, len(nodes[0].parameters)) + self.assertEqual(None, nodes[0].parameters[0].name) + def test_no_argument(self): nodes = list(MakeBuilder('FOO();').generate()) self.assertEqual(1, len(nodes)) From 1364718bd81a688d8608850bafdf624a77ce2a5f Mon Sep 17 00:00:00 2001 From: Renaud Durlin Date: Wed, 2 Oct 2013 21:56:40 +0200 Subject: [PATCH 2/2] Be more robust when parsing function. Insert a dummy ';' token instead of asserting (the missing ';' can happen when dealing with macro) --- cpp/ast.py | 22 ++++++++++++++-------- test/macro1.h | 1 + test/macro2.h | 2 ++ test/macro3.h | 5 +++++ 4 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 test/macro1.h create mode 100644 test/macro2.h create mode 100644 test/macro3.h diff --git a/cpp/ast.py b/cpp/ast.py index a89d265..6d9b5a8 100644 --- a/cpp/ast.py +++ b/cpp/ast.py @@ -1032,31 +1032,37 @@ def _get_method(self, return_type_and_name, modifiers, templated_types, parameters = list(self._get_parameters()) del parameters[-1] # Remove trailing ')'. - token = self._get_next_token() - while token.token_type == tokenize.NAME: - modifier_token = token + try: token = self._get_next_token() - if modifier_token.name == 'const': + except: + token = tokenize.Token(tokenize.SYNTAX, ';', 0, 0) + while token.token_type == tokenize.NAME: + if token.name == 'const': modifiers |= FUNCTION_CONST - elif modifier_token.name == '__attribute__': + token = self._get_next_token() + elif token.name == '__attribute__': # TODO(nnorwitz): handle more __attribute__ details. modifiers |= FUNCTION_ATTRIBUTE + token = self._get_next_token() assert token.name == '(', token # Consume everything between the (parens). list(self._get_matching_char('(', ')')) token = self._get_next_token() - elif modifier_token.name == 'throw': + elif token.name == 'throw': modifiers |= FUNCTION_THROW + token = self._get_next_token() assert token.name == '(', token # Consume everything between the (parens). list(self._get_matching_char('(', ')')) token = self._get_next_token() - elif modifier_token.name == modifier_token.name.upper(): + elif token.name == token.name.upper(): # HACK(nnorwitz): assume that all upper-case names # are some macro we aren't expanding. modifiers |= FUNCTION_UNKNOWN_ANNOTATION + token = self._get_next_token() else: - self.handle_error('unexpected token', modifier_token) + self._add_back_token(token) + token = tokenize.Token(tokenize.SYNTAX, ';', 0, 0) if token.token_type != tokenize.SYNTAX: raise ParseError(token) diff --git a/test/macro1.h b/test/macro1.h new file mode 100644 index 0000000..0e6e918 --- /dev/null +++ b/test/macro1.h @@ -0,0 +1 @@ +MyMacro(Get) diff --git a/test/macro2.h b/test/macro2.h new file mode 100644 index 0000000..ddf6698 --- /dev/null +++ b/test/macro2.h @@ -0,0 +1,2 @@ +MyMacro(Get) +MyMacro(Set) diff --git a/test/macro3.h b/test/macro3.h new file mode 100644 index 0000000..87ebbb0 --- /dev/null +++ b/test/macro3.h @@ -0,0 +1,5 @@ +MyMacro(NS, Name) + +namespace NS { + +}