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 "mocastconsumer.h"
22#include "clangversionabstraction.h"
23#include <clang/AST/ASTContext.h>
24#include <clang/AST/DeclCXX.h>
25#include <clang/AST/DeclTemplate.h>
26#include <clang/Sema/Sema.h>
27#include <clang/Basic/MacroBuilder.h>
28
29
30void MocASTConsumer::Initialize(clang::ASTContext& Ctx) {
31 ctx = &Ctx;
32 PPCallbacks = new MocPPCallbacks(ci.getPreprocessor(), Moc.Tags);
33 ci.getPreprocessor().addPPCallbacks(maybe_unique(PPCallbacks));
34// ci.getDiagnostics().setClient(new DiagnosticClient(), true);
35
36 // We will enable this when we require Qt >= 5.6.1 and libclang >= 3.8
37 // Then we will be able to get rid of qobjectdefs-injected
38#if 0
39 std::string qtPredefinesBuffer;
40 llvm::raw_string_ostream qtPredefines(qtPredefinesBuffer);
41 clang::MacroBuilder builder(qtPredefines);
42 builder.append("# 1 \"<moc-ng built-in>\" 1");
43 builder.defineMacro("QT_ANNOTATE_CLASS(type,...)", "static_assert(sizeof(#__VA_ARGS__),#type);");
44 builder.defineMacro("QT_ANNOTATE_CLASS2(type,a1,a2)", "static_assert(sizeof(#a1,#a2),#type);");
45 builder.defineMacro("QT_ANNOTATE_FUNCTION(a)", "__attribute__((annotate(#a)))");
46 builder.defineMacro("QT_ANNOTATE_ACCESS_SPECIFIER(a)", "__attribute__((annotate(#a)))");
47 builder.defineMacro("Q_CLASSINFO(name,value)", "static_assert(sizeof(name,value),\"qt_classinfo\");");
48 builder.defineMacro("Q_REVISION(v)", "__attribute__((annotate(\"qt_revision:\" QT_STRINGIFY2(v))))");
49 // prepend the Qt defines so the command line argument can override them.
50 ci.getPreprocessor().setPredefines(qtPredefines.str() + ci.getPreprocessor().getPredefines());
51#endif
52}
53
54
55void MocASTConsumer::HandleTagDeclDefinition(clang::TagDecl* D)
56{
57 clang::CXXRecordDecl *RD = llvm::dyn_cast<clang::CXXRecordDecl>(D);
58 if (!RD)
59 return;
60
61 if (!shouldParseDecl(D))
62 return;
63
64 clang::ClassTemplateSpecializationDecl* TD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(RD);
65 if (TD && TD->getIdentifier() && TD->getName() == "QMetaTypeId" && TD->getTemplateArgs().size() == 1) {
66 Moc.registered_meta_type.insert(TD->getTemplateArgs().get(0).getAsType()->getCanonicalTypeUnqualified().getTypePtr());
67 }
68
69 if (TD) {
70 // Do not parse class for class template specialization
71 return;
72 }
73
74
75 /*if (!(PPCallbacks->seenQ_OBJECT.isValid() &&
76 ctx->getSourceManager().isBeforeInTranslationUnit(D->getSourceRange().getBegin(),
77 PPCallbacks->seenQ_OBJECT) &&
78 ctx->getSourceManager().isBeforeInTranslationUnit(PPCallbacks->seenQ_OBJECT,
79 D->getSourceRange().getEnd())
80 ))
81 return;
82
83 PPCallbacks->seenQ_OBJECT = {};*/
84
85 ClassDef Def = Moc.parseClass(RD, ci.getSema());
86 if (Def.HasQObject || Def.HasQGadget) {
87 objects.push_back(std::move(Def));
88 ci.getPreprocessor().enableIncrementalProcessing();
89 }
90}
91
92bool MocASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef D)
93{
94 for (clang::Decl *Decl : D) {
95 if (clang::NamespaceDecl *NS = llvm::dyn_cast<clang::NamespaceDecl>(Decl)) {
96 if (!shouldParseDecl(Decl))
97 continue;
98 HandleNamespaceDefinition(NS);
99 }
100 }
101 return clang::ASTConsumer::HandleTopLevelDecl(D);
102}
103
104template<typename T>
105static void operator+=(std::vector<T> &v1, const std::vector<T> &v2)
106{
107 v1.insert(v1.end(), v2.begin(), v2.end());
108}
109
110void MocASTConsumer::HandleNamespaceDefinition(clang::NamespaceDecl* D)
111{
112 // Try to find Q_NAMESPACE
113 NamespaceDef Def = Moc.parseNamespace(D, ci.getSema());
114 if (Def.hasQNamespace) {
115 auto Canonical = D->getCanonicalDecl();
116 auto it = std::find_if(namespaces.begin(), namespaces.end(), [&](const NamespaceDef &d)
117 { return d.Namespace && d.Namespace->getCanonicalDecl() == Canonical; });
118 if (it == namespaces.end()) {
119 namespaces.push_back(std::move(Def));
120 } else {
121 // merge the two.
122 it->Enums += Def.Enums;
123 it->Extra += Def.Extra;
124 it->ClassInfo += Def.ClassInfo;
125 }
126 ci.getPreprocessor().enableIncrementalProcessing();
127 }
128 for (auto it = D->decls_begin(); it != D->decls_end(); ++it) {
129 if (clang::NamespaceDecl *NS = llvm::dyn_cast<clang::NamespaceDecl>(*it))
130 HandleNamespaceDefinition(NS);
131 }
132}
133
134