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
23void 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
30void 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
47void 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
68bool 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
85void 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