|
9 | 9 | #include <clang/Frontend/ASTUnit.h> |
10 | 10 | #include <clang/Frontend/CompilerInstance.h> |
11 | 11 | #include <clang/Frontend/TextDiagnosticPrinter.h> |
| 12 | +#include <clang/Lex/MacroInfo.h> |
| 13 | +#include <clang/Lex/Preprocessor.h> |
12 | 14 |
|
| 15 | +#include <algorithm> |
13 | 16 | #include <filesystem> |
14 | 17 | #include <utility> |
15 | 18 |
|
@@ -66,6 +69,69 @@ class AstCanopyDiagnosticsConsumer : public DiagnosticConsumer { |
66 | 69 | } |
67 | 70 | }; |
68 | 71 |
|
| 72 | +bool filename_is_retained(const std::string &file_name, |
| 73 | + const std::vector<std::string> &files_to_retain) { |
| 74 | + return std::any_of(files_to_retain.begin(), files_to_retain.end(), |
| 75 | + [&file_name](const std::string &file_to_retain) { |
| 76 | + return file_name == file_to_retain; |
| 77 | + }); |
| 78 | +} |
| 79 | + |
| 80 | +std::string replacement_text_from_macro_info(const MacroInfo ¯o_info, |
| 81 | + const Preprocessor &preprocessor) { |
| 82 | + std::string replacement_text; |
| 83 | + for (const Token &token : macro_info.tokens()) { |
| 84 | + bool invalid = false; |
| 85 | + std::string spelling = preprocessor.getSpelling(token, &invalid); |
| 86 | + if (invalid) { |
| 87 | + continue; |
| 88 | + } |
| 89 | + |
| 90 | + if (!replacement_text.empty()) { |
| 91 | + replacement_text += " "; |
| 92 | + } |
| 93 | + replacement_text += spelling; |
| 94 | + } |
| 95 | + return replacement_text; |
| 96 | +} |
| 97 | + |
| 98 | +void collect_macro_defines_from_ast( |
| 99 | + ASTUnit *ast, const std::vector<std::string> &files_to_retain, |
| 100 | + Declarations *decls) { |
| 101 | + decls->macro_defines.clear(); |
| 102 | + |
| 103 | + Preprocessor &preprocessor = ast->getPreprocessor(); |
| 104 | + const SourceManager &source_manager = ast->getSourceManager(); |
| 105 | + |
| 106 | + for (const auto &entry : preprocessor.getIdentifierTable()) { |
| 107 | + const IdentifierInfo *identifier_info = entry.second; |
| 108 | + if (!identifier_info) { |
| 109 | + continue; |
| 110 | + } |
| 111 | + |
| 112 | + MacroDefinition macro_definition = |
| 113 | + preprocessor.getMacroDefinition(identifier_info); |
| 114 | + const MacroInfo *macro_info = macro_definition.getMacroInfo(); |
| 115 | + if (!macro_info || macro_info->isFunctionLike()) { |
| 116 | + continue; |
| 117 | + } |
| 118 | + |
| 119 | + SourceLocation spelling_location = |
| 120 | + source_manager.getSpellingLoc(macro_info->getDefinitionLoc()); |
| 121 | + if (!spelling_location.isValid()) { |
| 122 | + continue; |
| 123 | + } |
| 124 | + |
| 125 | + std::string file_name = source_manager.getFilename(spelling_location).str(); |
| 126 | + if (!filename_is_retained(file_name, files_to_retain)) { |
| 127 | + continue; |
| 128 | + } |
| 129 | + |
| 130 | + decls->macro_defines[identifier_info->getName().str()] = |
| 131 | + replacement_text_from_macro_info(*macro_info, preprocessor); |
| 132 | + } |
| 133 | +} |
| 134 | + |
69 | 135 | /** |
70 | 136 | * @brief Return the source filename of the declaration. |
71 | 137 | */ |
@@ -215,6 +281,7 @@ parse_declarations_from_command_line(std::vector<std::string> options, |
215 | 281 | &ctsd_callback); |
216 | 282 |
|
217 | 283 | finder.matchAST(ast->getASTContext()); |
| 284 | + detail::collect_macro_defines_from_ast(ast.get(), files_to_retain, &decls); |
218 | 285 |
|
219 | 286 | #ifndef NDEBUG |
220 | 287 | std::cout << "Records: " << decls.records.size() << std::endl; |
|
0 commit comments