diff --git a/.travis.yml b/.travis.yml index d57fc60..f31c480 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: python -sudo: required dist: xenial python: @@ -8,18 +7,16 @@ python: - "3.5" - "2.7" -matrix: - fast_finish: true jobs: include: - stage: format-check - python: - - "3.6" + python: "3.6" install: - pip install black script: - black --check --diff . + fast_finish: true # command to install dependencies install: diff --git a/CppHeaderParser/CppHeaderParser.py b/CppHeaderParser/CppHeaderParser.py index cb8fda2..db2cce5 100644 --- a/CppHeaderParser/CppHeaderParser.py +++ b/CppHeaderParser/CppHeaderParser.py @@ -1384,6 +1384,37 @@ def __init__(self, name, doxygen, location): set_location_info(self, location) +class _CppPreprocessorLiteral(dict): + """ Implementation for #pragmas, #defines and #includes, contains the + following keys: + + * ``value`` the value literal of the preprocessor item + * ``line_number`` line number at which the item was found + """ + + def __init__(self, macro, location): + self["value"] = re.split("[\t ]+", macro, 1)[1].strip() + set_location_info(self, location) + + def __str__(self): + return self["value"] + + +# Implementation is shared between CppPragma, CppDefine, CppInclude but they are +# distinct so that they may diverge if required without interface-breaking +# changes +class CppPragma(_CppPreprocessorLiteral): + pass + + +class CppDefine(_CppPreprocessorLiteral): + pass + + +class CppInclude(_CppPreprocessorLiteral): + pass + + C99_NONSTANDARD = { "int8": "signed char", "int16": "short int", @@ -1905,19 +1936,25 @@ def finalize_vars(self): # Take care of #defines and #pragmas etc trace_print("Processing precomp_macro_buf: %s" % self._precomp_macro_buf) - for m in self._precomp_macro_buf: + for m, location in self._precomp_macro_buf: macro = m.replace("\\n", "\n") ml = macro.lower() try: if ml.startswith("#define"): trace_print("Adding #define %s" % macro) - self.defines.append(re.split("[\t ]+", macro, 1)[1].strip()) + define = CppDefine(macro, location) + self.defines.append(define["value"]) + self.defines_detail.append(define) elif ml.startswith("#pragma"): trace_print("Adding #pragma %s" % macro) - self.pragmas.append(re.split("[\t ]+", macro, 1)[1].strip()) + pragma = CppPragma(macro, location) + self.pragmas_detail.append(pragma) + self.pragmas.append(pragma["value"]) elif ml.startswith("#include"): trace_print("Adding #include %s" % macro) - self.includes.append(re.split("[\t ]+", macro, 1)[1].strip()) + include = CppInclude(macro, location) + self.includes.append(include["value"]) + self.includes_detail.append(include) else: debug_print("Cant detect what to do with precomp macro '%s'", macro) except: @@ -2635,12 +2672,21 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs): #: List of #pragma directives found as strings self.pragmas = [] + #: List of pragmas with location information + self.pragmas_detail = [] + #: List of #define directives found self.defines = [] + #: List of #define directives found, with location information + self.defines_detail = [] + #: List of #include directives found self.includes = [] + #: List of #include directives found with location information + self.includes_detail = [] + #: Filenames encountered in #line directives while parsing self.headerFileNames = [] @@ -2814,7 +2860,7 @@ def __init__(self, headerFileName, argType="file", encoding=None, **kwargs): if tok.type in ("PRECOMP_MACRO", "PRECOMP_MACRO_CONT"): debug_print("PRECOMP: %s", tok) - self._precomp_macro_buf.append(tok.value) + self._precomp_macro_buf.append((tok.value, tok.location)) self.stack = [] self.stmtTokens = [] self.nameStack = [] diff --git a/test/test_CppHeaderParser.py b/test/test_CppHeaderParser.py index d3f54e7..99dc8cf 100644 --- a/test/test_CppHeaderParser.py +++ b/test/test_CppHeaderParser.py @@ -1869,15 +1869,27 @@ def setUp(self): def test_includes(self): self.assertEqual(self.cppHeader.includes, ["", '"../../debug.h"']) + self.assertEqual(self.cppHeader.includes_detail[0]["value"], "") + self.assertEqual(self.cppHeader.includes_detail[0]["line_number"], 2) + self.assertEqual(self.cppHeader.includes_detail[1]["value"], '"../../debug.h"') + self.assertEqual(self.cppHeader.includes_detail[1]["line_number"], 3) def test_pragmas(self): self.assertEqual(self.cppHeader.pragmas, ["once"]) + self.assertEqual(self.cppHeader.pragmas_detail[0]["value"], "once") + self.assertEqual(self.cppHeader.pragmas_detail[0]["line_number"], 7) def test_pragmas0(self): self.assertEqual(self.cppHeader.defines[0], "ONE 1") + self.assertEqual(self.cppHeader.defines_detail[0]["value"], "ONE 1") + self.assertEqual(self.cppHeader.defines_detail[0]["line_number"], 5) def test_pragmas1(self): self.assertEqual(self.cppHeader.defines[1], 'TWO_NUM_N_NAME "2 (TWO)"') + self.assertEqual( + self.cppHeader.defines_detail[1]["value"], 'TWO_NUM_N_NAME "2 (TWO)"' + ) + self.assertEqual(self.cppHeader.defines_detail[1]["line_number"], 6) def test_pragmas2(self): self.assertEqual(