Skip to content

Commit

Permalink
parser: set clang -x<language> option at the low level
Browse files Browse the repository at this point in the history
Have a single point of truth for setting the clang -x<language> option,
to unify parsing across the extension, tests, and cli.

Choose the language primarily based on the domain, and secondarily based
on the filename extension to differentiate headers. Using "-header" is
necessary for some cases such as "#pragma once", where plain "-xc" or
"-xc++" would interpret the file as a main file.

This unconditionally bypasses libclang automatic detection. The user and
tests can still override the parser selected language, as the user
provided clang_args are appended.

Fixes: #208
  • Loading branch information
jnikula committed Nov 9, 2023
1 parent 7227ca7 commit 15147ad
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 8 deletions.
4 changes: 1 addition & 3 deletions src/hawkmoth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ def __display_parser_diagnostics(self, errors):
location=(self.env.docname, self.lineno))

def __get_clang_args(self):
# Always pass `-xc++` to the compiler on 'cpp' domain as the first
# option so that the user can override it.
clang_args = ['-xc++'] if self._domain == 'cpp' else []
clang_args = []

clang_args.extend(self.env.config.hawkmoth_clang.copy())

Expand Down
20 changes: 19 additions & 1 deletion src/hawkmoth/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,18 @@ def _parse_undocumented_block(domain, comments, errors, cursor, nest):

return ret

def _language_option(filename, domain):
"""Return clang -x<language> option depending on domain and filename."""
if domain == 'cpp':
language = '-xc++'
else:
language = '-xc'

if os.path.splitext(filename)[1] in ['.h', '.H', '.hh', '.hpp', '.hxx']:
language += '-header'

return language

# Parse a file and return a tree of docstring.Docstring objects.
def parse(filename, domain=None, clang_args=None):
# Empty root comment with just children
Expand All @@ -813,8 +825,14 @@ def parse(filename, domain=None, clang_args=None):
errors = []
index = Index.create()

# Note: Preserve the passed in clang_args in RootDocstring, as it's used for
# filtering by the callers
full_args = [_language_option(filename, domain)]
if clang_args:
full_args.extend(clang_args)

try:
tu = index.parse(filename, args=clang_args,
tu = index.parse(filename, args=full_args,
options=TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD |
TranslationUnit.PARSE_SKIP_FUNCTION_BODIES)
except TranslationUnitLoadError as e:
Expand Down
5 changes: 1 addition & 4 deletions test/testenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ def get_directive_string(self):
return directive_str

def get_clang_args(self):
# Default to compile as C++ if the test is for the C++ domain so that we
# can use C sources for C++ tests. The yaml may override this in cases
# where we want to force a mismatch.
clang_args = ['-xc++'] if self.domain == 'cpp' else ['-xc']
clang_args = []

clang_args.extend(_clang_include_args.copy())

Expand Down

0 comments on commit 15147ad

Please sign in to comment.