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 "mocppcallbacks.h" |
21 | #include "clangversionabstraction.h" |
22 | |
23 | void MocPPCallbacks::InjectQObjectDefs(clang::SourceLocation Loc) { |
24 | #include "qobjectdefs-injected.h" |
25 | auto Buf = maybe_unique(llvm::MemoryBuffer::getMemBuffer(Injected, "qobjectdefs-injected.moc" )); |
26 | Loc = PP.getSourceManager().getFileLoc(Loc); |
27 | PP.EnterSourceFile( CreateFileIDForMemBuffer(PP, Buf, Loc), nullptr, Loc); |
28 | } |
29 | |
30 | void MocPPCallbacks::EnterMainFile(llvm::StringRef Name) |
31 | { |
32 | if (Name.endswith("global/qnamespace.h" )) { |
33 | // qnamsepace.h is a bit special because it contains all the Qt namespace enums |
34 | // but all the Q_ENUMS are within a Q_MOC_RUN scope, which also do all sort of things. |
35 | |
36 | clang::MacroInfo *MI = PP.AllocateMacroInfo({}); |
37 | MI->setIsBuiltinMacro(); |
38 | #if CLANG_VERSION_MAJOR != 3 || CLANG_VERSION_MINOR > 2 |
39 | PP.appendDefMacroDirective(PP.getIdentifierInfo("Q_MOC_RUN" ), MI); |
40 | #else |
41 | PP.setMacroInfo(PP.getIdentifierInfo("Q_MOC_RUN" ), MI); |
42 | #endif |
43 | InjectQObjectDefs({}); |
44 | } |
45 | } |
46 | |
47 | void MocPPCallbacks::FileChanged(clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason, clang::SrcMgr::CharacteristicKind FileType, clang::FileID PrevFID) { |
48 | |
49 | clang::SourceManager &SM = PP.getSourceManager(); |
50 | IsInMainFile = (SM.getFileID(SM.getFileLoc(Loc)) == SM.getMainFileID()); |
51 | |
52 | if (IsInMainFile && Reason == EnterFile) { |
53 | EnterMainFile(SM.getFilename(Loc)); |
54 | } |
55 | |
56 | if (Reason != ExitFile) |
57 | return; |
58 | auto F = PP.getSourceManager().getFileEntryForID(PrevFID); |
59 | if (!F) |
60 | return; |
61 | |
62 | llvm::StringRef name = F->getName(); |
63 | if (name.endswith("qobjectdefs.h" )) { |
64 | InjectQObjectDefs(Loc); |
65 | } |
66 | } |
67 | |
68 | bool MocPPCallbacks::FileNotFound(llvm::StringRef FileName, llvm::SmallVectorImpl< char >& RecoveryPath) { |
69 | if (FileName.endswith(".moc" ) || FileName.endswith("_moc.cpp" ) || FileName.startswith("moc_" )) { |
70 | if (!PP.GetSuppressIncludeNotFoundError()) { |
71 | PP.SetSuppressIncludeNotFoundError(true); |
72 | IncludeNotFoundSupressed = true; |
73 | } |
74 | } else { |
75 | if (IncludeNotFoundSupressed) { |
76 | PP.SetSuppressIncludeNotFoundError(false); |
77 | IncludeNotFoundSupressed = false; |
78 | } else { |
79 | ShouldWarnHeaderNotFound = true; |
80 | } |
81 | } |
82 | return false; |
83 | } |
84 | |
85 | void MocPPCallbacks::InclusionDirective(clang::SourceLocation HashLoc, const clang::Token& IncludeTok, |
86 | llvm::StringRef FileName, bool IsAngled, |
87 | clang::CharSourceRange FilenameRange, |
88 | const clang::FileEntry* File, llvm::StringRef SearchPath, |
89 | llvm::StringRef RelativePath, const clang::Module* Imported |
90 | #if CLANG_VERSION_MAJOR >= 7 |
91 | , clang::SrcMgr::CharacteristicKind |
92 | #endif |
93 | ) |
94 | { |
95 | if (!File && ShouldWarnHeaderNotFound) { |
96 | /* This happens when we are not running as a plugin |
97 | * We want to transform the "include not found" error in a warning. |
98 | */ |
99 | PP.getDiagnostics().Report(FilenameRange.getBegin(), |
100 | PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, |
101 | "'%0' file not found" )) |
102 | << FileName << FilenameRange; |
103 | } |
104 | ShouldWarnHeaderNotFound = false; |
105 | } |
106 | |