Skip to content

Commit ab99f2f

Browse files
committed
Handle pcpp relative path quirk
1 parent e690838 commit ab99f2f

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

cxxheaderparser/preprocessor.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import io
6+
import re
67
import os
78
from os.path import relpath
89
import typing
@@ -36,7 +37,6 @@ def _filter_self(fname: str, fp: typing.TextIO) -> str:
3637
# isn't what a typical user of cxxheaderparser would want, so we strip out
3738
# the line directives and any content that isn't in our original file
3839

39-
# pcpp always emits line directives that match whatever is passed in to it
4040
line_ending = f'{fname}"\n'
4141

4242
new_output = io.StringIO()
@@ -100,6 +100,18 @@ def _preprocess_file(filename: str, content: str) -> str:
100100
if retain_all_content:
101101
return fp.read()
102102
else:
103+
# pcpp emits the #line directive using the filename you pass in
104+
# but will rewrite it if it's on the include path it uses. This
105+
# is copied from pcpp:
106+
abssource = os.path.abspath(filename)
107+
for rewrite in pp.rewrite_paths:
108+
temp = re.sub(rewrite[0], rewrite[1], abssource)
109+
if temp != abssource:
110+
filename = temp
111+
if os.sep != "/":
112+
filename = filename.replace(os.sep, "/")
113+
break
114+
103115
return _filter_self(filename, fp)
104116

105117
return _preprocess_file

tests/test_preprocessor.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import pathlib
23

34
from cxxheaderparser.options import ParserOptions
@@ -66,6 +67,46 @@ def test_preprocessor_omit_content(tmp_path: pathlib.Path) -> None:
6667
)
6768

6869

70+
def test_preprocessor_omit_content2(tmp_path: pathlib.Path) -> None:
71+
"""
72+
Ensure that content in other headers is omitted while handling pcpp
73+
relative path quirk
74+
"""
75+
h_content = '#include "t2.h"' "\n" "int x = X;\n"
76+
h2_content = "#define X 2\n" "int omitted = 1;\n"
77+
78+
tmp_path2 = tmp_path / "l1"
79+
tmp_path2.mkdir()
80+
81+
with open(tmp_path2 / "t1.h", "w") as fp:
82+
fp.write(h_content)
83+
84+
with open(tmp_path2 / "t2.h", "w") as fp:
85+
fp.write(h2_content)
86+
87+
options = ParserOptions(
88+
preprocessor=make_pcpp_preprocessor(include_paths=[str(tmp_path)])
89+
)
90+
91+
# Weirdness happens here
92+
os.chdir(tmp_path)
93+
data = parse_file(tmp_path2 / "t1.h", options=options)
94+
95+
assert data == ParsedData(
96+
namespace=NamespaceScope(
97+
variables=[
98+
Variable(
99+
name=PQName(segments=[NameSpecifier(name="x")]),
100+
type=Type(
101+
typename=PQName(segments=[FundamentalSpecifier(name="int")])
102+
),
103+
value=Value(tokens=[Token(value="2")]),
104+
)
105+
]
106+
)
107+
)
108+
109+
69110
def test_preprocessor_encoding(tmp_path: pathlib.Path) -> None:
70111
"""Ensure we can handle alternate encodings"""
71112
h_content = b"// \xa9 2023 someone\n" b'#include "t2.h"' b"\n" b"int x = X;\n"

0 commit comments

Comments
 (0)