From de4d06defed5cb5d0b65ff2bf45d9a285d1c5eaf Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Sat, 2 Sep 2023 21:03:15 -0400 Subject: [PATCH] Fix preprocessor option to retain content --- cxxheaderparser/preprocessor.py | 15 ++++------- tests/test_preprocessor.py | 45 ++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/cxxheaderparser/preprocessor.py b/cxxheaderparser/preprocessor.py index a89c4b1..f732ef2 100644 --- a/cxxheaderparser/preprocessor.py +++ b/cxxheaderparser/preprocessor.py @@ -3,6 +3,7 @@ Contains optional preprocessor support via pcpp """ import io +import os from os.path import relpath import typing from .options import PreprocessorFunction @@ -17,7 +18,7 @@ class PreprocessorError(Exception): class _CustomPreprocessor(Preprocessor): def __init__(self): Preprocessor.__init__(self) - self.errors = [] + self.errors: typing.List[str] = [] def on_error(self, file, line, msg): self.errors.append(f"{file}:{line} error: {msg}") @@ -34,21 +35,15 @@ def _filter_self(fname: str, fp: typing.TextIO) -> str: # isn't what a typical user of cxxheaderparser would want, so we strip out # the line directives and any content that isn't in our original file - # Compute the filename to match based on how pcpp does it - try: - relfname = relpath(fname) - except Exception: - relfname = fname - relfname = relfname.replace("\\", "/") - - relfname += '"\n' + # pcpp always emits line directives that match whatever is passed in to it + line_ending = f'{fname}"\n' new_output = io.StringIO() keep = True for line in fp: if line.startswith("#line"): - keep = line.endswith(relfname) + keep = line.endswith(line_ending) if keep: new_output.write(line) diff --git a/tests/test_preprocessor.py b/tests/test_preprocessor.py index 35ed0ab..8e9ae02 100644 --- a/tests/test_preprocessor.py +++ b/tests/test_preprocessor.py @@ -1,7 +1,17 @@ +import pathlib + from cxxheaderparser.options import ParserOptions from cxxheaderparser.preprocessor import make_pcpp_preprocessor -from cxxheaderparser.simple import NamespaceScope, ParsedData, parse_string -from cxxheaderparser.types import FundamentalSpecifier, NameSpecifier, PQName, Token, Type, Value, Variable +from cxxheaderparser.simple import NamespaceScope, ParsedData, parse_file, parse_string +from cxxheaderparser.types import ( + FundamentalSpecifier, + NameSpecifier, + PQName, + Token, + Type, + Value, + Variable, +) def test_basic_preprocessor() -> None: @@ -24,4 +34,33 @@ def test_basic_preprocessor() -> None: ) ] ) - ) \ No newline at end of file + ) + + +def test_preprocessor_omit_content(tmp_path: pathlib.Path) -> None: + """Ensure that content in other headers is omitted""" + h_content = '#include "t2.h"' "\n" "int x = X;\n" + h2_content = "#define X 2\n" "int omitted = 1;\n" + + with open(tmp_path / "t1.h", "w") as fp: + fp.write(h_content) + + with open(tmp_path / "t2.h", "w") as fp: + fp.write(h2_content) + + options = ParserOptions(preprocessor=make_pcpp_preprocessor()) + data = parse_file(tmp_path / "t1.h", options=options) + + assert data == ParsedData( + namespace=NamespaceScope( + variables=[ + Variable( + name=PQName(segments=[NameSpecifier(name="x")]), + type=Type( + typename=PQName(segments=[FundamentalSpecifier(name="int")]) + ), + value=Value(tokens=[Token(value="2")]), + ) + ] + ) + )