-
Notifications
You must be signed in to change notification settings - Fork 5
Introduce clang_utils.py, compilation_database.py and related changes #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3e1d46f
[clang_utils.py] Introduce clang_utils.py to get checks from cindex.py
diivm 8f07af2
changes coming from clang_utils.py
diivm f0edede
[pytest.yml] bump clang to v12 and ubuntu to 20.04
diivm 838ac87
[compilation_database.py] add compilation_database.py
diivm 6f4c13e
update compilation db logic
diivm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| import inspect | ||
| import clang.cindex as clang | ||
|
|
||
|
|
||
| def getmembers_static(object, predicate=None): | ||
| """ | ||
| Return all members of an object as (name, value) pairs sorted by name via `getattr_static`. | ||
| Optionally, only return members that satisfy a given predicate. | ||
|
|
||
|
|
||
| - A static version of `get_members` function at: | ||
| https://github.com/python/cpython/blob/3.9/Lib/inspect.py#L326-L368 | ||
| https://github.com/python/cpython/blob/14ba761078b5ae83519e34d66ab883743912c45b/Lib/inspect.py#L444-L486 | ||
| - `getmembers` function (from the inspect module) triggers execution instead of doing static analysis. | ||
| - This leads to errors, particularly on properties of classes in cindex.py, which causes segmentation errors or raises an Exception if a particular condition is not satisfied. | ||
| - To curb this, we fetch the members statically. We define a custom function based on the one in the inspect module. | ||
| """ | ||
|
|
||
| results = [] | ||
| names = dir(object) | ||
| # :dd any DynamicClassAttributes to the list of names if object is a class; | ||
| # this may result in duplicate entries if, for example, a virtual | ||
| # attribute with the same name as a DynamicClassAttribute exists | ||
| try: | ||
| base_members = filter( | ||
| lambda k, v: isinstance(v, types.DynamicClassAttribute), | ||
| object.__bases__.__dict__.items(), | ||
| ) | ||
| names.extend(base_members) | ||
| except AttributeError: | ||
| pass | ||
| for key in names: | ||
| value = inspect.getattr_static(object, key) | ||
| if not predicate or predicate(value): | ||
| results.append((key, value)) | ||
| results.sort(key=lambda pair: pair[0]) | ||
| return results | ||
|
|
||
|
|
||
| class ClangUtils: | ||
| """ | ||
| Clang's cindex class utilities. | ||
|
|
||
| Supports the following objects: | ||
| CursorKind: | ||
| https://github.com/llvm/llvm-project/blob/release/12.x/clang/bindings/python/clang/cindex.py#L657 | ||
| https://github.com/llvm/llvm-project/blob/1acd9a1a29ac30044ecefb6613485d5d168f66ca/clang/bindings/python/clang/cindex.py#L657 | ||
| - A CursorKind describes the kind of entity that a cursor points to. | ||
| Cursor: | ||
| https://github.com/llvm/llvm-project/blob/release/12.x/clang/bindings/python/clang/cindex.py#L1415 | ||
| https://github.com/llvm/llvm-project/blob/1acd9a1a29ac30044ecefb6613485d5d168f66ca/clang/bindings/python/clang/cindex.py#L1415 | ||
| - The Cursor class represents a reference to an element within the AST. It acts as a kind of iterator. | ||
| Type: | ||
| https://github.com/llvm/llvm-project/blob/release/12.x/clang/bindings/python/clang/cindex.py#L2180 | ||
| https://github.com/llvm/llvm-project/blob/1acd9a1a29ac30044ecefb6613485d5d168f66ca/clang/bindings/python/clang/cindex.py#L2180 | ||
| - The Type class represents the type of an element in the abstract syntax tree. | ||
| """ | ||
|
|
||
| def __init__(self, object): | ||
| if not ( | ||
| isinstance(object, clang.CursorKind) | ||
| or isinstance(object, clang.Cursor) | ||
| or isinstance(object, clang.Type) | ||
| ): | ||
| raise NotImplementedError(f"Not implemented for {object}") | ||
|
|
||
| self.check_functions_dict = {} | ||
| self.get_functions_dict = {} | ||
| self.properties_dict = {} | ||
|
|
||
| # A list to ignore the functions/properties that causes segmentation errors. | ||
| ignore_list = [ | ||
| "mangled_name", | ||
| "get_address_space", | ||
| "get_typedef_name", | ||
| "tls_kind", | ||
| ] | ||
|
|
||
| # populate dicts | ||
| valid_entries = filter( | ||
| lambda entry: entry[0] not in ignore_list, getmembers_static(object) | ||
| ) | ||
| for name, func in valid_entries: | ||
| if inspect.isfunction(func): # if function | ||
| try: # cindex.py's functions raise exceptions internally | ||
| if name.startswith("is_"): | ||
| self.check_functions_dict[name] = func(object) | ||
| if name.startswith("get_"): | ||
| self.get_functions_dict[name] = func(object) | ||
| except: | ||
| continue | ||
| elif isinstance(func, property): # else, property | ||
| try: # cindex.py's property functions raise exceptions internally | ||
| self.properties_dict[name] = getattr(object, name) | ||
| except: | ||
| continue | ||
|
|
||
| def get_check_functions_dict(self): | ||
| """ | ||
| Returns: `check_functions_dict`: | ||
| - functions that begin with "is_" i.e., checking functions | ||
| - {function_name, function_result} | ||
| """ | ||
| return self.check_functions_dict | ||
|
|
||
| def get_get_functions_dict(self): | ||
| """ | ||
| Returns: `get_functions_dict`: | ||
| - functions that begin with "get_" i.e., getter functions | ||
| - {function_name, function_result} | ||
| """ | ||
| return self.get_functions_dict | ||
|
|
||
| def get_properties_dict(self): | ||
| """ | ||
| Returns: properties_dict | ||
| - Properties | ||
| - {property_name, property} | ||
| """ | ||
| return self.properties_dict |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import clang.cindex as clang | ||
|
|
||
|
|
||
| class CompilationDatabase: | ||
| """ | ||
| Build a compilation database from a given directory | ||
| """ | ||
|
|
||
| def __init__(self, compilation_database_path): | ||
| self.compilation_database = clang.CompilationDatabase.fromDirectory( | ||
| buildDir=compilation_database_path | ||
| ) | ||
|
|
||
| def get_compilation_arguments(self, filename=None): | ||
| """ | ||
| Returns the compilation commands extracted from the compilation database | ||
| Parameters: | ||
| - compilation_database_path: The path to `compile_commands.json` | ||
| - filename (optional): To get compilaton commands of a file | ||
| Returns: | ||
| - compilation_arguments (dict): {filename: compiler arguments} | ||
| """ | ||
|
|
||
| if filename: | ||
| # Get compilation commands from the compilation database for the given file | ||
| compilation_commands = self.compilation_database.getCompileCommands( | ||
| filename=filename | ||
| ) | ||
| else: | ||
| # Get all compilation commands from the compilation database | ||
| compilation_commands = self.compilation_database.getAllCompileCommands() | ||
|
|
||
| # {file: compiler arguments} | ||
| compilation_arguments = { | ||
| command.filename: list(command.arguments)[1:-1] | ||
| for command in compilation_commands | ||
| } | ||
| return compilation_arguments | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filename required here? Shouldn't the db path in L9 solve this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filename for the cpp file to be parsed, to get that file's compiler args from the compilation database.
If none, it will return the compiler args for all the files in the compilation db.