1 | /**************************************************************************** |
2 | * Copyright (C) 2013-2016 Woboq GmbH |
3 | * Olivier Goffart <contact at woboq.com> |
4 | * https://woboq.com/ |
5 | * |
6 | * This program is free software: you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation, either version 3 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include <clang/Lex/Preprocessor.h> |
21 | #include <clang/Basic/Version.h> |
22 | #include <set> |
23 | |
24 | class MocPPCallbacks : public clang::PPCallbacks { |
25 | clang::Preprocessor &PP; |
26 | |
27 | bool IncludeNotFoundSupressed = false; |
28 | bool = false; |
29 | bool InQMOCRUN = false; |
30 | std::set<std::string> PossibleTags; |
31 | std::map<clang::SourceLocation, std::string> &Tags; |
32 | |
33 | public: |
34 | |
35 | MocPPCallbacks(clang::Preprocessor &PP, std::map<clang::SourceLocation, std::string> &Tags) : PP(PP), Tags(Tags) {} |
36 | |
37 | bool IsInMainFile = false; |
38 | void InjectQObjectDefs(clang::SourceLocation Loc); |
39 | void EnterMainFile(clang::StringRef Name); |
40 | |
41 | protected: |
42 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR >= 7 |
43 | typedef const clang::MacroDefinition &MacroParam; |
44 | typedef const clang::MacroDirective *MacroParam2; |
45 | #elif CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
46 | typedef const clang::MacroDirective *MacroParam; |
47 | typedef const clang::MacroDirective *MacroParam2; |
48 | #else |
49 | typedef const clang::MacroInfo *MacroParam; |
50 | typedef MacroParam MacroParam2; |
51 | #endif |
52 | |
53 | |
54 | void MacroUndefined(const clang::Token& MacroNameTok, MacroParam |
55 | #if CLANG_VERSION_MAJOR >= 5 |
56 | , const clang::MacroDirective * |
57 | #endif |
58 | ) override { |
59 | //Workaround to get moc's test to compile |
60 | if (MacroNameTok.getIdentifierInfo()->getName() == "QT_NO_KEYWORDS" ) { |
61 | //re-inject qobjectdefs |
62 | InjectQObjectDefs(MacroNameTok.getLocation()); |
63 | } |
64 | } |
65 | |
66 | void FileChanged(clang::SourceLocation Loc, FileChangeReason Reason, clang::SrcMgr::CharacteristicKind FileType, |
67 | clang::FileID PrevFID) override; |
68 | bool FileNotFound(llvm::StringRef FileName, llvm::SmallVectorImpl< char >& RecoveryPath) override; |
69 | void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token& IncludeTok, |
70 | llvm::StringRef FileName, bool IsAngled, clang::CharSourceRange FilenameRange, |
71 | const clang::FileEntry* File, llvm::StringRef SearchPath, llvm::StringRef RelativePath, |
72 | const clang::Module* Imported |
73 | #if CLANG_VERSION_MAJOR >= 7 |
74 | , clang::SrcMgr::CharacteristicKind |
75 | #endif |
76 | ) override; |
77 | |
78 | void Defined(const clang::Token& MacroNameTok |
79 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
80 | ,MacroParam = {} |
81 | #endif |
82 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 3 |
83 | , clang::SourceRange = {} |
84 | #endif |
85 | ) override { |
86 | if (MacroNameTok.getIdentifierInfo()->getName() != "Q_MOC_RUN" ) |
87 | return; |
88 | auto F = PP.getSourceManager().getFileEntryForID(PP.getSourceManager().getFileID(MacroNameTok.getLocation())); |
89 | if (!F) return; |
90 | llvm::StringRef name = F->getName(); |
91 | if (name.endswith("qobjectdefs.h" ) || name.endswith("qglobal.h" )) |
92 | return; |
93 | InQMOCRUN = true; |
94 | } |
95 | void Ifdef(clang::SourceLocation Loc, const clang::Token& MacroNameTok |
96 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
97 | ,MacroParam |
98 | #endif |
99 | ) override { Defined(MacroNameTok); } |
100 | void Ifndef(clang::SourceLocation Loc, const clang::Token& MacroNameTok |
101 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
102 | ,MacroParam |
103 | #endif |
104 | ) override { Defined(MacroNameTok); } |
105 | |
106 | void Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) override { |
107 | InQMOCRUN = false; |
108 | //TODO: handle embedded Ifs |
109 | } |
110 | |
111 | void MacroDefined(const clang::Token& MacroNameTok, MacroParam2) override { |
112 | if (!InQMOCRUN) |
113 | return; |
114 | PossibleTags.insert(MacroNameTok.getIdentifierInfo()->getName()); |
115 | } |
116 | |
117 | |
118 | void MacroExpands(const clang::Token& MacroNameTok, MacroParam, clang::SourceRange Range |
119 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
120 | , const clang::MacroArgs * |
121 | #endif |
122 | ) override { |
123 | if (InQMOCRUN) return; |
124 | if (PossibleTags.count(MacroNameTok.getIdentifierInfo()->getName())) { |
125 | clang::SourceLocation FileLoc = PP.getSourceManager().getFileLoc(MacroNameTok.getLocation()); |
126 | Tags.insert({FileLoc, MacroNameTok.getIdentifierInfo()->getName()}); |
127 | } |
128 | } |
129 | |
130 | }; |
131 | |