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 "generator.h"
21#include "mocng.h"
22#include "qbjs.h"
23#include <string>
24#include <clang/AST/DeclCXX.h>
25#include <clang/AST/ASTContext.h>
26#include <clang/AST/DeclTemplate.h>
27#include <clang/Sema/Sema.h>
28
29#include <iostream>
30
31// Remove the decltype if possible
32static clang::QualType getDesugarType(const clang::QualType &QT) {
33 if (auto DL = QT->getAs<clang::DecltypeType>()) {
34 return DL->desugar();
35 }
36 return QT;
37}
38
39/* Wrapper for the change in the name in clang 3.5 */
40template <typename T> static auto getResultType(T *decl) -> decltype(decl->getResultType())
41{ return getDesugarType(decl->getResultType()); }
42template <typename T> static auto getResultType(T *decl) -> decltype(decl->getReturnType())
43{ return getDesugarType(decl->getReturnType()); }
44
45/**
46 * Return the type as writen in the file at the given SourceRange.
47 * May return an empty string if the type was expended from macros.
48 */
49static std::string TypeStringFromSourceRange(clang::SourceRange Range, const clang::SourceManager &SM)
50{
51 if (Range.isInvalid() || !Range.getBegin().isFileID())
52 return {};
53 clang::FileID FID = SM.getFileID(Range.getBegin());
54 if (FID != SM.getFileID(Range.getEnd()))
55 return {};
56 const llvm::MemoryBuffer *Buffer = SM.getBuffer(FID);
57 const char *Buf = Buffer->getBufferStart();
58 auto B = SM.getFileOffset(Range.getBegin());
59 auto E = SM.getFileOffset(Range.getEnd());
60 if (Buf[E] == '>') { // a type can be terminated be either a '>' or an identifier
61 E++;
62 } else {
63 while (std::isalnum(Buf[E]) || Buf[E] == '\\' || Buf[E] == '_') E++;
64 }
65 return std::string(Buf+B, Buf+E);
66}
67
68// Returns true if the last argument of this mehod is a 'QPrivateSignal'
69static bool HasPrivateSignal(const clang::CXXMethodDecl *MD) {
70 if (MD && MD->getNumParams()) {
71 clang::CXXRecordDecl* RD = MD->getParamDecl(MD->getNumParams()-1)->getType()->getAsCXXRecordDecl();
72 return RD && RD->getIdentifier() && RD->getName() == "QPrivateSignal";
73 }
74 return false;
75}
76
77// Executes the 'Functor' for each method, including clones
78template<typename T, typename F>
79static void ForEachMethod(const std::vector<T> &V, F && Functor) {
80 for(auto it : V) {
81 int Clones = it->getNumParams() - it->getMinRequiredArguments();
82 for (int C = 0; C <= Clones; ++C)
83 Functor(it, C);
84 }
85}
86
87// Count the number of method in the vector, including clones
88template<typename T>
89int CountMethod(const std::vector<T> &V) {
90 int R = 0;
91 ForEachMethod(V, [&](const clang::CXXMethodDecl*, int) { R++; });
92 return R;
93}
94
95// Count the total number of parametters in the vector
96template<typename T> int AggregateParameterCount(const std::vector<T>& V) {
97 int R = 0;
98 ForEachMethod(V, [&](const clang::CXXMethodDecl *M, int Clone) {
99 R += M->getNumParams() - Clone;
100 R += 1; // return value;
101 if (HasPrivateSignal(M))
102 R--;
103 });
104 return R;
105}
106
107// Generate the data in the data array for the function in the given vector.
108// ParamIndex is a reference to the index in which to store the parametters.
109template <typename T>
110void Generator::GenerateFunctions(const std::vector<T> &V, const char* TypeName, MethodFlags Type, int& ParamIndex)
111{
112 if (V.empty())
113 return;
114
115 OS << "\n // " << TypeName << ": name, argc, parameters, tag, flags\n";
116
117 ForEachMethod(V, [&](const clang::CXXMethodDecl *M, int Clone) {
118 unsigned int Flags = Type;
119 if (M->getAccess() == clang::AS_private)
120 Flags |= AccessPrivate;
121 else if (M->getAccess() == clang::AS_public)
122 Flags |= AccessPublic;
123 else if (M->getAccess() == clang::AS_protected)
124 Flags |= AccessProtected;
125
126 if (Clone)
127 Flags |= MethodCloned;
128
129 for (auto attr_it = M->specific_attr_begin<clang::AnnotateAttr>();
130 attr_it != M->specific_attr_end<clang::AnnotateAttr>();
131 ++attr_it) {
132 const clang::AnnotateAttr *A = *attr_it;
133 if (A->getAnnotation() == "qt_scriptable") {
134 Flags |= MethodScriptable;
135 } else if (A->getAnnotation().startswith("qt_revision:")) {
136 Flags |= MethodRevisioned;
137 } else if (A->getAnnotation() == "qt_moc_compat") {
138 Flags |= MethodCompatibility;
139 }
140 }
141
142 int argc = M->getNumParams() - Clone;
143 if (HasPrivateSignal(M))
144 argc--;
145
146 std::string tag = Moc->GetTag(M->getSourceRange().getBegin(), Ctx.getSourceManager());
147 OS << " " << StrIdx(M->getNameAsString()) << ", " << argc << ", " << ParamIndex << ", " << StrIdx(tag) << ", 0x";
148 OS.write_hex(Flags) << ",\n";
149 ParamIndex += 1 + argc * 2;
150 });
151}
152
153
154static bool IsIdentChar(char c) {
155 return (c=='_' || c=='$' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
156}
157
158//Generate the type information for the argument
159void Generator::GenerateTypeInfo(clang::QualType Type)
160{
161 if (Type->isVoidType()) {
162 OS << "QMetaType::Void";
163 return;
164 }
165
166 // remove const or const &
167 if (Type->isReferenceType() && Type.getNonReferenceType().isConstQualified())
168 Type = Type.getNonReferenceType();
169 Type.removeLocalConst();
170
171 const clang::TypedefType * TT = Type->getAs<clang::TypedefType>();
172 // Handle builtin types as QMetaType, but ignores typedef their name is likely not registered
173 // (FIXME: all the registered typedef such as uint and qint64 should go there.
174 if (Type->isBuiltinType() && (!TT)) {
175 const clang::BuiltinType * BT = Type->getAs<clang::BuiltinType>();
176 switch(+BT->getKind()) {
177#define BUILTIN(Type) \
178 case clang::BuiltinType::Type: \
179 OS << "QMetaType::" #Type; \
180 return;
181 BUILTIN(Bool)
182 BUILTIN(Int)
183 BUILTIN(UInt)
184 BUILTIN(LongLong)
185 BUILTIN(ULongLong)
186 BUILTIN(Double)
187 BUILTIN(Long)
188 BUILTIN(Short)
189 // Char?
190 BUILTIN(ULong)
191 BUILTIN(UShort)
192 BUILTIN(UChar)
193 BUILTIN(Float)
194 BUILTIN(SChar)
195#undef BUILTIN
196 }
197 }
198 // TODO: Find more QMetaType
199
200
201 clang::PrintingPolicy Policy = PrintPolicy;
202 Policy.SuppressScope = true;
203 std::string TypeString = getDesugarType(Type).getAsString(Policy);
204
205 // Remove the spaces;
206 int k = 0;
207 for (uint i = 0; i < TypeString.size(); ++i) {
208 char C = TypeString[i];
209 if (C == ' ') {
210 if (k == 0)
211 continue;
212 if (i+1 == TypeString.size())
213 continue;
214 char P = TypeString[k-1];
215 char N = TypeString[i+1];
216 if (!(IsIdentChar(P) && IsIdentChar(N))
217 && !(P == '>' && N == '>'))
218 continue;
219 }
220 TypeString[k++] = C;
221 }
222 TypeString.resize(k);
223
224 //adjust unsigned
225 uint UPos = 0;
226 while ((UPos = TypeString.find("unsigned ", UPos)) < TypeString.size()) {
227 const int L = sizeof("unsigned ") - 1; // don't include \0
228 llvm::StringRef R(&TypeString[UPos + L],
229 TypeString.size() - L);
230 if (R.startswith("int") || (R.startswith("long") &&
231 !R.startswith("long int") && !R.startswith("long long"))) {
232 TypeString.replace(UPos, L, "u");
233 }
234 UPos++;
235 }
236 OS << "0x80000000 | " << StrIdx(TypeString);
237}
238
239// Generate the data in the data array for the parametters of functions in the vector
240template <typename T>
241void Generator::GenerateFunctionParameters(const std::vector< T* >& V, const char* TypeName)
242{
243 if (V.empty())
244 return;
245
246 OS << "\n // " << TypeName << ": parameters\n";
247
248 ForEachMethod(V, [&](const clang::CXXMethodDecl *M, int Clone) {
249 int argc = M->getNumParams() - Clone;
250 if (HasPrivateSignal(M))
251 argc--;
252 OS << " ";
253 //Types
254 if (std::is_same<T, clang::CXXConstructorDecl>::value)
255 OS << "0x80000000 | " << StrIdx("");
256 else
257 GenerateTypeInfo(getResultType(M));
258 OS << ",";
259 for (int j = 0; j < argc; j++) {
260 OS << " ";
261 GenerateTypeInfo(M->getParamDecl(j)->getOriginalType());
262 OS << ",";
263 }
264
265 //Names
266 for (int j = 0; j < argc; j++) {
267 auto P = M->getParamDecl(j);
268 if (P->getIdentifier())
269 OS << " " << StrIdx(P->getName()) << ",";
270 else
271 OS << " " << StrIdx("") << ",";
272 }
273 OS << "\n";
274 });
275}
276
277// return true if a staticMetaObject is found in the bases
278static bool hasStaticMetaObject(clang::QualType T) {
279 auto RD = T->getAsCXXRecordDecl();
280 if (!RD)
281 return false;
282
283 for (auto it = RD->decls_begin(); it != RD->decls_end(); ++it) {
284 if (const clang::NamedDecl *Sub = llvm::dyn_cast<const clang::NamedDecl>(*it)) {
285 if (Sub->getIdentifier() && Sub->getName() == "staticMetaObject")
286 return true;
287 }
288 }
289
290 if (RD->getNumBases()) {
291 return hasStaticMetaObject(RD->bases_begin()->getType());
292 }
293 return false;
294}
295
296template <typename T>
297static void PrintTemplateParamName(llvm::raw_ostream &Out, const T *D, bool PrintPack = false)
298{
299 if (auto II = D->getIdentifier()) {
300 Out << II->getName();
301 } else {
302 Out << "T_" << D->getDepth() << "_" << D->getIndex();
303 }
304 if (PrintPack && D->isParameterPack()) {
305 Out << "...";
306 }
307}
308
309static void PrintTemplateParameters(llvm::raw_ostream &Out, clang::TemplateParameterList *List,
310 clang::PrintingPolicy &PrintPolicy)
311{
312 Out << "template <";
313 bool NeedComa = false;
314 for (clang::NamedDecl *Param : *List) {
315 if (NeedComa) Out << ", ";
316 NeedComa = true;
317 if (const auto *TTP = llvm::dyn_cast<clang::TemplateTypeParmDecl>(Param)) {
318 if (TTP->wasDeclaredWithTypename()) {
319 Out << "typename ";
320 } else {
321 Out << "class ";
322 }
323 if (TTP->isParameterPack())
324 Out << "...";
325 PrintTemplateParamName(Out, TTP);
326 } else if (const auto *NTTP = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(Param)) {
327 auto Type = NTTP->getType();
328 bool Pack = NTTP->isParameterPack();
329 if (auto *PET = Type->getAs<clang::PackExpansionType>()) {
330 Pack = true;
331 Type = PET->getPattern();
332 }
333 llvm::SmallString<25> Name;
334 {
335 llvm::raw_svector_ostream OS (Name);
336 PrintTemplateParamName(OS, NTTP);
337 }
338 Type.print(Out, PrintPolicy, (Pack ? "... " : "") + Name);
339 } else if (const auto *TTPD = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(Param)) {
340 PrintTemplateParameters(Out, TTPD->getTemplateParameters(), PrintPolicy);
341 Out << "class ";
342 if (TTPD->isParameterPack())
343 Out << "... ";
344 PrintTemplateParamName(Out, TTPD);
345 }
346 }
347 Out << "> ";
348}
349
350Generator::Generator(const ClassDef* CDef, llvm::raw_ostream& OS, clang::ASTContext& Ctx,
351 MocNg* Moc, llvm::raw_ostream *OS_TemplateHeader)
352 : Def(CDef), CDef(CDef), OS(OS), OS_TemplateHeader(OS_TemplateHeader ? *OS_TemplateHeader : OS),
353 Ctx(Ctx), PrintPolicy(Ctx.getPrintingPolicy()), Moc(Moc)
354{
355 PrintPolicy.SuppressTagKeyword = true;
356 PrintPolicy.SuppressUnwrittenScope = true;
357 PrintPolicy.AnonymousTagLocations = false;
358
359 HasTemplateHeader = OS_TemplateHeader && (&OS != OS_TemplateHeader);
360
361 {
362 llvm::raw_string_ostream QualNameS(QualName);
363 CDef->Record->printQualifiedName(QualNameS, PrintPolicy);
364 }
365
366 if (CDef->Record->getNumBases()) {
367 auto Base = CDef->Record->bases_begin()->getTypeSourceInfo();
368 // We need to try to get the type name as written. Because we don't want qualified name if
369 // it was not qualified. For example:
370 // namespace X { struct F; namespace Y { struct X; struct G : F { Q_OBJECT }; } }
371 // We don't want to use X::F because X would be the struct and not the namespace
372 BaseName = TypeStringFromSourceRange(Base->getTypeLoc().getSourceRange(),
373 Ctx.getSourceManager());
374 if (BaseName.empty()) {
375 BaseName = Base->getType().getAsString(PrintPolicy);
376 }
377 BaseHasStaticMetaObject = hasStaticMetaObject(Base->getType());
378 }
379
380 MethodCount = CountMethod(CDef->Signals) + CountMethod(CDef->Slots) + CountMethod(CDef->Methods) + CDef->PrivateSlotCount;
381
382 if (auto Tpl = CDef->Record->getDescribedClassTemplate()) {
383 llvm::raw_string_ostream TemplatePrefixStream(TemplatePrefix);
384 PrintTemplateParameters(TemplatePrefixStream, Tpl->getTemplateParameters(), PrintPolicy);
385 llvm::raw_string_ostream TemplatePostfixStream(QualName);
386 bool NeedComa = false;
387 TemplatePostfixStream << "<";
388 for (clang::NamedDecl *Param : *Tpl->getTemplateParameters()) {
389 if (NeedComa) TemplatePostfixStream << ", ";
390 NeedComa = true;
391 if (const auto *TTP = llvm::dyn_cast<clang::TemplateTypeParmDecl>(Param)) {
392 PrintTemplateParamName(TemplatePostfixStream, TTP, true);
393 } else if (const auto *NTTP = llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(Param)) {
394 PrintTemplateParamName(TemplatePostfixStream, NTTP, true);
395 } else if (const auto *TTPD = llvm::dyn_cast<clang::TemplateTemplateParmDecl>(Param)) {
396 PrintTemplateParamName(TemplatePostfixStream, TTPD, true);
397 }
398 }
399 TemplatePostfixStream << ">";
400 }
401}
402
403Generator::Generator(const NamespaceDef* NDef, llvm::raw_ostream& OS, clang::ASTContext& Ctx, MocNg* Moc)
404 : Def(NDef), CDef(nullptr), OS(OS), OS_TemplateHeader(OS), Ctx(Ctx),
405 PrintPolicy(Ctx.getPrintingPolicy()), Moc(Moc)
406{
407 PrintPolicy.SuppressTagKeyword = true;
408 PrintPolicy.SuppressUnwrittenScope = true;
409 PrintPolicy.AnonymousTagLocations = false;
410 HasTemplateHeader = false;
411
412 {
413 llvm::raw_string_ostream QualNameS(QualName);
414 NDef->Namespace->printQualifiedName(QualNameS, PrintPolicy);
415 }
416
417 MethodCount = 0;
418}
419
420
421void Generator::GenerateCode()
422{
423 // Build the data array
424 std::string QualifiedClassNameIdentifier = QualName;
425 if (CDef && CDef->Record->getDescribedClassTemplate()) {
426 auto pos = QualifiedClassNameIdentifier.find('<');
427 QualifiedClassNameIdentifier.resize(std::min(QualifiedClassNameIdentifier.size(), pos));
428 }
429 std::replace(QualifiedClassNameIdentifier.begin(), QualifiedClassNameIdentifier.end(), ':', '_');
430
431 int Index = MetaObjectPrivateFieldCount;
432
433 //Helper function which adds N to the index and return a value suitable to be placed in the array.
434 auto I = [&](int N) {
435 if (!N) return 0;
436 int R = Index;
437 Index += N;
438 return R;
439 };
440
441 llvm::StringRef Static;
442 if (!HasTemplateHeader) {
443 Static = "static ";
444 } else {
445 OS_TemplateHeader << "\nextern const uint qt_meta_data_" << QualifiedClassNameIdentifier << "[];\n";
446 }
447
448 OS << "\n" << Static << "const uint qt_meta_data_" << QualifiedClassNameIdentifier << "[] = {\n"
449 " " << OutputRevision << ", // revision\n"
450 " " << StrIdx(QualName) << ", // classname\n"
451 " " << Def->ClassInfo.size() << ", " << I(Def->ClassInfo.size() * 2) << ", //classinfo\n";
452
453 OS << " " << MethodCount << ", " << I(MethodCount * 5) << ", // methods \n";
454
455 if (CDef && CDef->RevisionMethodCount)
456 Index += MethodCount;
457
458 int ParamsIndex = Index;
459 if (CDef) {
460 int TotalParameterCount = AggregateParameterCount(CDef->Signals) + AggregateParameterCount(CDef->Slots)
461 + AggregateParameterCount(CDef->Methods) + AggregateParameterCount(CDef->Constructors);
462 for (const PrivateSlotDef &P : CDef->PrivateSlots)
463 TotalParameterCount += 1 + P.Args.size() * (1 + P.NumDefault) - (P.NumDefault * (P.NumDefault + 1) / 2);
464 Index += TotalParameterCount * 2 // type and parameter names
465 - MethodCount - CountMethod(CDef->Constructors); // return parameter don't have names
466 }
467
468 if (CDef)
469 OS << " " << CDef->Properties.size() << ", " << I(CDef->Properties.size() * 3) << ", // properties \n";
470 else
471 OS << " " << 0 << ", " << 0 << ", // properties \n";
472
473 if (CDef && CDef->NotifyCount)
474 Index += CDef->Properties.size();
475 if (CDef && CDef->RevisionPropertyCount)
476 Index += CDef->Properties.size();
477
478 OS << " " << Def->Enums.size() << ", " << I(Def->Enums.size() * 4) << ", // enums \n";
479 int EnumIndex = Index;
480 for (auto e : Def->Enums)
481 for (auto it = std::get<0>(e)->enumerator_begin() ; it != std::get<0>(e)->enumerator_end(); ++it)
482 Index += 2;
483
484 int ConstructorCount = CDef ? CountMethod(CDef->Constructors) : 0;
485 OS << " " << ConstructorCount << ", " << I(ConstructorCount * 5) << ", // constructors \n";
486
487 int flags = 0;
488 if (CDef && CDef->HasQGadget) {
489 // Ideally, all the classes could have that flag. But this broke classes generated
490 // by qdbusxml2cpp which generate code that require that we call qt_metacall for properties
491 flags |= PropertyAccessInStaticMetaCall;
492 }
493 OS << " " << flags << ", // flags \n";
494
495 OS << " " << (CDef ? CountMethod(CDef->Signals) : 0) << ", // signalCount \n";
496
497 if (Def->ClassInfo.size()) {
498 OS << "\n // classinfo: key, value\n";
499 for (const auto &I : Def->ClassInfo)
500 OS << " " << StrIdx(I.first) << ", " << StrIdx(I.second) << ",\n";
501 }
502
503 if (CDef) {
504 GenerateFunctions(CDef->Signals, "signals", MethodSignal, ParamsIndex);
505 GenerateFunctions(CDef->Slots, "slots", MethodSlot, ParamsIndex);
506 for (const PrivateSlotDef &P : CDef->PrivateSlots) {
507 for (int Clone = 0; Clone <= P.NumDefault; ++Clone) {
508 int argc = (P.Args.size() - Clone);
509 OS << " " << StrIdx(P.Name) << ", " << argc << ", " << ParamsIndex << ", 0, 0x";
510 unsigned int Flag = AccessPrivate | MethodSlot;
511 if (Clone) Flag |= MethodCloned;
512 OS.write_hex(Flag) << ",\n";
513 ParamsIndex += 1 + argc * 2;
514 }
515 }
516 GenerateFunctions(CDef->Methods, "methods", MethodMethod, ParamsIndex);
517
518
519 if (CDef->RevisionMethodCount) {
520 auto GenerateRevision = [&](const clang::CXXMethodDecl *M, int Clone) {
521 llvm::StringRef SubStr = "0";
522 for (auto attr_it = M->specific_attr_begin<clang::AnnotateAttr>();
523 attr_it != M->specific_attr_end<clang::AnnotateAttr>();
524 ++attr_it) {
525 const clang::AnnotateAttr *A = *attr_it;
526 if (A->getAnnotation().startswith("qt_revision:")) {
527 SubStr = A->getAnnotation().substr(sizeof("qt_revision:")-1);
528 }
529 }
530 OS << " " << SubStr << ",";
531 };
532 OS << "\n // method revisions\n ";
533 ForEachMethod(CDef->Signals, GenerateRevision);
534 OS << "\n ";
535 ForEachMethod(CDef->Slots, GenerateRevision);
536 //OS << "\n ";
537 for (const PrivateSlotDef &P : CDef->PrivateSlots) {
538 for (int Clone = 0; Clone <= P.NumDefault; ++Clone)
539 OS << " 0, ";
540 }
541 OS << "\n ";
542 ForEachMethod(CDef->Methods, GenerateRevision);
543 OS << "\n";
544 }
545
546 GenerateFunctionParameters(CDef->Signals, "signals");
547 GenerateFunctionParameters(CDef->Slots, "slots");
548 for (const PrivateSlotDef &P : CDef->PrivateSlots) {
549 for (int Clone = 0; Clone <= P.NumDefault; ++Clone) {
550 int argc = (P.Args.size() - Clone);
551 OS << " ";
552 if (P.ReturnType == "void") OS << "QMetaType::Void";
553 else OS << "0x80000000 | " << StrIdx(P.ReturnType);
554 for (int j = 0; j < argc; j++) {
555 OS << ", ";
556 if (P.Args[j] == "void") OS << "QMetaType::Void";
557 else OS << "0x80000000 | " << StrIdx(P.Args[j]);
558 }
559 //Names
560 for (int j = 0; j < argc; j++) {
561 OS << ", " << StrIdx("");
562 }
563 OS << ",\n";
564 }
565 }
566 GenerateFunctionParameters(CDef->Methods, "methods");
567 GenerateFunctionParameters(CDef->Constructors, "constructors");
568
569 GenerateProperties();
570 }
571
572 GenerateEnums(EnumIndex);
573
574 if (CDef) {
575 GenerateFunctions(CDef->Constructors, "constructors", MethodConstructor, ParamsIndex);
576 }
577
578 OS << "\n 0 // eod\n};\n";
579
580 // StringArray;
581
582 int TotalLen = 1;
583 for (const auto &S : Strings)
584 TotalLen += S.size() + 1;
585
586 OS_TemplateHeader << "struct qt_meta_stringdata_" << QualifiedClassNameIdentifier << "_t {\n"
587 " QByteArrayData data[" << Strings.size() << "];\n"
588 " char stringdata[" << TotalLen << "];\n"
589 "};\n";
590 if (HasTemplateHeader) {
591 OS_TemplateHeader << "extern const qt_meta_stringdata_" << QualifiedClassNameIdentifier
592 << "_t qt_meta_stringdata_"<< QualifiedClassNameIdentifier << ";\n";
593 }
594 OS << "#define QT_MOC_LITERAL(idx, ofs, len) \\\n"
595 " Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\\n"
596 " qptrdiff(offsetof(qt_meta_stringdata_"<< QualifiedClassNameIdentifier << "_t, stringdata) + ofs \\\n"
597 " - idx * sizeof(QByteArrayData)) \\\n"
598 " )\n"
599 << Static << "const qt_meta_stringdata_"<< QualifiedClassNameIdentifier << "_t qt_meta_stringdata_"<< QualifiedClassNameIdentifier << " = {\n"
600 " {\n";
601 int Idx = 0;
602 int LitteralIndex = 0;
603 for (const auto &S : Strings) {
604 if (LitteralIndex)
605 OS << ",\n";
606 OS << "QT_MOC_LITERAL("<< (LitteralIndex++) << ", " << Idx << ", " << S.size() << ")";
607 Idx += S.size() + 1;
608 }
609 OS << "\n },\n \"";
610 int Col = 0;
611 for (const auto &S : Strings) {
612 if (Col && Col + S.size() >= 72) {
613 OS << "\"\n \"";
614 Col = 0;
615 } else if (S.size() && ((S[0] >= '0' && S[0] <= '9') || S[0] == '?')) {
616 OS << "\"\"";
617 Col += 2;
618 }
619
620 // Can't use write_escaped because of the trigraph
621 for (unsigned i = 0, e = S.size(); i != e; ++i) {
622 unsigned char c = S[i];
623 switch (c) {
624 case '\\': OS << '\\' << '\\'; break;
625 case '\t': OS << '\\' << 't'; break;
626 case '\n': OS << '\\' << 'n'; break;
627 case '"': OS << '\\' << '"'; break;
628 case '?':
629 if (i != 0 && S[i-1] == '?') {
630 OS << '\\';
631 Col++;
632 }
633 OS << '?';
634 break;
635 default:
636 if (std::isprint(c)) {
637 OS << c;
638 break;
639 }
640 // Use 3 character octal sequence
641 OS << '\\' << char('0' + ((c >> 6) & 7)) << char('0' + ((c >> 3) & 7)) << char('0' + ((c >> 0) & 7));
642 Col += 3;
643 }
644 }
645
646 OS << "\\0";
647 Col += 2 + S.size();
648 }
649 OS << "\"\n};\n"
650 "#undef QT_MOC_LITERAL\n";
651
652 if (!Def->Extra.empty()) {
653 if (HasTemplateHeader)
654 OS_TemplateHeader << "extern const QMetaObject * const qt_meta_extradata_" << QualifiedClassNameIdentifier << "[];\n";
655 OS << Static << "const QMetaObject * const qt_meta_extradata_" << QualifiedClassNameIdentifier << "[] = {\n" ;
656 for (clang::CXXRecordDecl *E : Def->Extra)
657 //TODO: Check that extra is a QObject
658 OS << " &" << E->getQualifiedNameAsString() << "::staticMetaObject,\n";
659
660 OS << " 0\n};\n";
661
662 }
663
664 if (IsQtNamespace) {
665 OS_TemplateHeader << "\nconst QMetaObject QObject::staticQtMetaObject = {\n"
666 " { 0, qt_meta_stringdata_Qt.data, qt_meta_data_Qt, 0, 0, 0 }\n};\n";
667 return;
668 }
669
670 OS_TemplateHeader << "\n" << TemplatePrefix << "const QMetaObject " << QualName << "::staticMetaObject = {\n"
671 " { ";
672 if (BaseName.empty() || (CDef->HasQGadget && !BaseHasStaticMetaObject)) OS_TemplateHeader << "0";
673 else OS_TemplateHeader << "&" << BaseName << "::staticMetaObject";
674
675 OS_TemplateHeader << ", qt_meta_stringdata_"<< QualifiedClassNameIdentifier <<".data,\n"
676 " qt_meta_data_" << QualifiedClassNameIdentifier << ", ";
677
678 bool HasStaticMetaCall = CDef && (CDef->HasQObject || !CDef->Methods.empty() || !CDef->Properties.empty() || !CDef->Constructors.empty());
679 if (HasStaticMetaCall) OS_TemplateHeader << "qt_static_metacall, ";
680 else OS_TemplateHeader << "0, ";
681
682 if (!Def->Extra.empty()) OS_TemplateHeader << "qt_meta_extradata_" << QualifiedClassNameIdentifier << ", ";
683 else OS_TemplateHeader << "0, ";
684 OS_TemplateHeader << "0}\n};\n";
685
686 if (CDef && CDef->HasQObject) {
687 OS_TemplateHeader << TemplatePrefix << "const QMetaObject *" << QualName << "::metaObject() const\n{\n"
688 " return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;\n}\n";
689
690
691 OS_TemplateHeader << TemplatePrefix << "void *" << QualName << "::qt_metacast(const char *_clname)\n{\n"
692 " if (!_clname) return 0;\n"
693 " if (!strcmp(_clname, qt_meta_stringdata_" << QualifiedClassNameIdentifier << ".stringdata))\n"
694 " return static_cast<void*>(this);\n";
695
696 if (CDef->Record->getNumBases() > 1) {
697 for (auto BaseIt = CDef->Record->bases_begin()+1; BaseIt != CDef->Record->bases_end(); ++BaseIt) {
698 if (BaseIt->getAccessSpecifier() == clang::AS_private)
699 continue;
700 auto B = BaseIt->getType().getAsString(PrintPolicy);
701 OS_TemplateHeader << " if (!qstrcmp(_clname, \"" << B << "\"))\n"
702 " return static_cast< " << B << "*>(this);\n";
703 }
704 }
705
706 for (const auto &Itrf : CDef->Interfaces) {
707 OS_TemplateHeader << " if (!qstrcmp(_clname, qobject_interface_iid< " << Itrf << " *>()))\n"
708 " return static_cast< " << Itrf << " *>(this);\n";
709 }
710
711 if (BaseName.empty()) OS_TemplateHeader << " return 0;\n}\n";
712 else OS_TemplateHeader << " return "<< BaseName <<"::qt_metacast(_clname);\n"
713 "}\n";
714
715 GenerateMetaCall();
716 GenerateStaticMetaCall();
717
718 int SigIdx = 0;
719 for (const clang::CXXMethodDecl *MD : CDef->Signals) {
720 GenerateSignal(MD, SigIdx);
721 SigIdx += 1 + MD->getNumParams() - MD->getMinRequiredArguments();
722 }
723 } else if (HasStaticMetaCall) {
724 GenerateStaticMetaCall();
725 }
726
727 if (CDef && !CDef->Plugin.IID.empty()) {
728 OS << "\nQT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;\n"
729 "#ifdef QT_NO_DEBUG\n";
730 GeneratePluginMetaData(false);
731 OS << "#else\n";
732 GeneratePluginMetaData(true);
733 OS << "#endif\n";
734
735 OS << "QT_MOC_EXPORT_PLUGIN(" << QualName << ", " << CDef->Record->getName() << ")\n\n";
736 }
737}
738
739void Generator::GenerateMetaCall()
740{
741 OS_TemplateHeader << "\n" << TemplatePrefix << "int " << QualName
742 << "::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n";
743 if (!BaseName.empty()) {
744 OS_TemplateHeader << " _id = " << BaseName << "::qt_metacall(_c, _id, _a);\n";
745 if (MethodCount || CDef->Properties.size()) {
746 OS_TemplateHeader << " if (_id < 0)\n"
747 " return _id;\n";
748 };
749 }
750
751 if (MethodCount) {
752 OS_TemplateHeader <<
753 " if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {\n"
754 " if (_id < " << MethodCount << ")\n"
755 " qt_static_metacall(this, _c, _id, _a);\n"
756 " _id -= " << MethodCount << ";\n"
757 " }\n";
758 }
759
760 if (CDef->Properties.size()) {
761 bool needDesignable = false;
762 bool needScriptable = false;
763 bool needStored = false;
764 bool needEditable = false;
765 bool needUser = false;
766 for (const PropertyDef &p : CDef->Properties) {
767 auto IsFunction = [](const std::string &S) { return S.size() && S[S.size()-1] == ')'; };
768 needDesignable |= IsFunction(p.designable);
769 needScriptable |= IsFunction(p.scriptable);
770 needStored |= IsFunction(p.stored);
771 needEditable |= IsFunction(p.editable);
772 needUser |= IsFunction(p.user);
773 }
774
775 OS_TemplateHeader << " ";
776 if (MethodCount)
777 OS_TemplateHeader << "else ";
778
779 OS_TemplateHeader << " if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n"
780 " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {\n"
781 " if (_id < " << CDef->Properties.size() << ")\n"
782 " qt_static_metacall(this, _c, _id, _a);\n"
783 " _id -= " << CDef->Properties.size() << ";\n"
784 " }\n";
785
786 // Helper for all the QMetaObject::QueryProperty*
787 typedef std::string (PropertyDef::*Accessor);
788 auto HandleQueryPropertyAction = [&](bool Need, const char *Action, Accessor A) {
789 OS_TemplateHeader << " else ";
790 OS_TemplateHeader << "if (_c == QMetaObject::" << Action << ") {\n";
791 if (Need) {
792 OS_TemplateHeader << " switch (_id) {\n";
793 int I = 0;
794 for (const PropertyDef &p : CDef->Properties) {
795 OS_TemplateHeader << " case " << (I++) <<": ";
796 const std::string &S = (p.*A);
797 if (!S.empty() && S[S.size()-1] == ')')
798 OS_TemplateHeader << "*reinterpret_cast<bool*>(_a[0]) = " << S << "; ";
799 OS_TemplateHeader << "break;\n";
800 }
801 OS_TemplateHeader << " default: break;\n";
802 OS_TemplateHeader << " }";
803 }
804 OS_TemplateHeader << " _id -= " << CDef->Properties.size() << ";\n }";
805 };
806
807 HandleQueryPropertyAction(needDesignable, "QueryPropertyDesignable", &PropertyDef::designable);
808 HandleQueryPropertyAction(needScriptable, "QueryPropertyScriptable", &PropertyDef::scriptable);
809 HandleQueryPropertyAction(needStored, "QueryPropertyStored", &PropertyDef::stored);
810 HandleQueryPropertyAction(needEditable, "QueryPropertyEditable", &PropertyDef::editable);
811 HandleQueryPropertyAction(needUser, "QueryPropertyUser", &PropertyDef::user);
812
813 }
814 OS_TemplateHeader << "\n return _id;\n"
815 "}\n";
816}
817
818void Generator::GenerateStaticMetaCall()
819{
820 llvm::StringRef ClassName = CDef->Record->getName();
821 OS_TemplateHeader << "\n" << TemplatePrefix << "void " << QualName
822 << "::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)\n{\n ";
823 bool NeedElse = false;
824
825 if (!CDef->Constructors.empty()) {
826 OS_TemplateHeader << " if (_c == QMetaObject::CreateInstance) {\n"
827 " switch (_id) {\n";
828
829 llvm::StringRef resultType = CDef->HasQObject ? "QObject" : "void";
830
831 int CtorIndex = 0;
832 ForEachMethod(CDef->Constructors, [&](const clang::CXXConstructorDecl *MD, int C) {
833 OS_TemplateHeader << " case " << (CtorIndex++) << ": { " << resultType << " *_r = new " << ClassName << "(";
834
835 for (uint j = 0 ; j < MD->getNumParams() - C; ++j) {
836 if (j) OS_TemplateHeader << ",";
837 if (j == MD->getNumParams() - 1 && HasPrivateSignal(MD))
838 OS_TemplateHeader << "QPrivateSignal()";
839 else
840 OS_TemplateHeader << "*reinterpret_cast< " << Ctx.getPointerType(MD->getParamDecl(j)->getType().getNonReferenceType().getUnqualifiedType()).getAsString(PrintPolicy) << " >(_a[" << (j+1) << "])";
841 }
842 OS_TemplateHeader << ");\n if (_a[0]) *reinterpret_cast<" << resultType << "**>(_a[0]) = _r; } break;\n";
843 });
844 OS_TemplateHeader << " default: break;\n"
845 " }\n"
846 " }";
847
848 NeedElse = true;
849 }
850
851 if (MethodCount) {
852 if(NeedElse) OS_TemplateHeader << " else ";
853 NeedElse = true;
854 OS_TemplateHeader << "if (_c == QMetaObject::InvokeMetaMethod) {\n";
855 if (CDef->HasQObject) {
856// OS_TemplateHeader << " Q_ASSERT(staticMetaObject.cast(_o));\n";
857 OS_TemplateHeader << " " << ClassName <<" *_t = static_cast<" << ClassName << " *>(_o);\n";
858 } else {
859 OS_TemplateHeader << " " << ClassName <<" *_t = reinterpret_cast<" << ClassName << " *>(_o);\n";
860 }
861
862 OS_TemplateHeader << " switch(_id) {\n" ;
863 int MethodIndex = 0;
864 auto GenerateInvokeMethod = [&](const clang::CXXMethodDecl *MD, int Clone) {
865 if (!MD->getIdentifier())
866 return;
867
868 OS_TemplateHeader << " case " << MethodIndex << ": ";
869 MethodIndex++;
870
871 if (WorkaroundTests(ClassName, MD, OS))
872 return;
873
874 auto ReturnType = getResultType(MD);
875 // Original moc don't support reference as return type: see Moc::parseFunction
876 bool IsVoid = ReturnType->isVoidType() || ReturnType->isReferenceType();
877 // If we have a decltype, we need to use auto type deduction
878 bool AutoType = llvm::isa<clang::DecltypeType>(ReturnType) || llvm::isa<clang::AutoType>(ReturnType);
879 if (!IsVoid) {
880 OS_TemplateHeader << "{ ";
881 if (AutoType)
882 OS_TemplateHeader << "auto";
883 else
884 ReturnType.getUnqualifiedType().print(OS, PrintPolicy);
885 OS_TemplateHeader << " _r = ";
886 }
887
888 OS_TemplateHeader << "_t->" << MD->getName() << "(";
889
890 for (uint j = 0 ; j < MD->getNumParams() - Clone; ++j) {
891 if (j) OS_TemplateHeader << ",";
892 if (j == MD->getNumParams() - 1 && HasPrivateSignal(MD))
893 OS_TemplateHeader << "QPrivateSignal()";
894 else
895 OS_TemplateHeader << "*reinterpret_cast< " << Ctx.getPointerType(MD->getParamDecl(j)->getType().getNonReferenceType().getUnqualifiedType()).getAsString(PrintPolicy) << " >(_a[" << (j+1) << "])";
896 }
897 OS_TemplateHeader << ");";
898 if (!IsVoid) {
899 OS_TemplateHeader << "\n if (_a[0]) *reinterpret_cast< ";
900 if (AutoType)
901 OS_TemplateHeader << "decltype(&_r)";
902 else
903 Ctx.getPointerType(ReturnType.getNonReferenceType().getUnqualifiedType()).print(OS, PrintPolicy);
904 OS_TemplateHeader << " >(_a[0]) = qMove(_r); }";
905 }
906 OS_TemplateHeader << " break;\n";
907 };
908 ForEachMethod(CDef->Signals, GenerateInvokeMethod);
909 ForEachMethod(CDef->Slots, GenerateInvokeMethod);
910 for (const PrivateSlotDef &P : CDef->PrivateSlots) {
911 for (int Clone = 0; Clone <= P.NumDefault; ++Clone) {
912 OS_TemplateHeader << " case " << MethodIndex << ": ";
913 // Original moc don't support reference as return type: see Moc::parseFunction
914 bool IsVoid = P.ReturnType == "void" || P.ReturnType.empty() || P.ReturnType.back() == '&';
915 if (!IsVoid)
916 OS_TemplateHeader << "{ " << P.ReturnType << " _r = ";
917 OS_TemplateHeader << "_t->" << P.InPrivateClass << "->" << P.Name << "(";
918 for (uint j = 0 ; j < P.Args.size() - Clone; ++j) {
919 if (j) OS_TemplateHeader << ",";
920 OS_TemplateHeader << "*reinterpret_cast< " << P.Args[j] << " *>(_a[" << (j+1) << "])";
921 }
922 OS_TemplateHeader << ");";
923 if (!IsVoid) {
924 OS_TemplateHeader << "\n if (_a[0]) *reinterpret_cast< " << P.ReturnType << " *>(_a[0]) = _r; }";
925 }
926 OS_TemplateHeader << " break;\n";
927 MethodIndex++;
928 }
929 }
930 ForEachMethod(CDef->Methods, GenerateInvokeMethod);
931 OS_TemplateHeader << " default: break;\n"
932 " }\n"
933 " } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {\n"
934 " switch ((_id << 16) | *reinterpret_cast<int*>(_a[1])) {\n"
935 " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n";
936
937
938 MethodIndex = 0;
939 auto GenerateRegisterMethodArguments = [&](const clang::CXXMethodDecl *MD, int Clone) {
940 if (!MD->getIdentifier()) {
941 MethodIndex++;
942 return;
943 }
944 // RegisterT(getResultType(MD), (MethodIndex << 16));
945 int argc = MD->getNumParams() - Clone - (HasPrivateSignal(MD)?1:0);
946 for (int j = 0 ; j < argc ; ++j) {
947 auto Type = MD->getParamDecl(j)->getType();
948 if (!Moc->ShouldRegisterMetaType(Type))
949 break;
950 OS_TemplateHeader << " case 0x";
951 OS_TemplateHeader.write_hex((MethodIndex << 16) | j);
952 OS_TemplateHeader << ": *reinterpret_cast<int*>(_a[0]) = ";
953 OS_TemplateHeader << "QtPrivate::QMetaTypeIdHelper< " << Type.getNonReferenceType().getUnqualifiedType().getAsString(PrintPolicy)
954 << " >::qt_metatype_id(); break;\n";
955 }
956 MethodIndex++;
957 };
958
959 ForEachMethod(CDef->Signals, GenerateRegisterMethodArguments);
960 ForEachMethod(CDef->Slots, GenerateRegisterMethodArguments);
961 MethodIndex += CDef->PrivateSlotCount; // TODO: we should also register these types.
962 ForEachMethod(CDef->Methods, GenerateRegisterMethodArguments);
963
964 OS_TemplateHeader << " }\n }";
965
966 }
967 if (!CDef->Signals.empty()) {
968
969 int MethodIndex = 0;
970 OS_TemplateHeader << " else if (_c == QMetaObject::IndexOfMethod) {\n"
971 " int *result = reinterpret_cast<int *>(_a[0]);\n"
972 " void **func = reinterpret_cast<void **>(_a[1]);\n";
973
974 for (const clang::CXXMethodDecl *MD: CDef->Signals) {
975 int Idx = MethodIndex;
976 MethodIndex += MD->getNumParams() - MD->getMinRequiredArguments() + 1;
977 if (MD->isStatic() || !MD->getIdentifier())
978 continue;
979 OS_TemplateHeader << " {\n"
980 " typedef " << getResultType(MD).getAsString(PrintPolicy) << " (" << ClassName << "::*_t)(";
981 for (uint j = 0 ; j < MD->getNumParams(); ++j) {
982 if (j) OS_TemplateHeader << ",";
983 OS_TemplateHeader << MD->getParamDecl(j)->getType().getAsString(PrintPolicy);
984 }
985 if (MD->isConst()) OS_TemplateHeader << ") const;\n";
986 else OS_TemplateHeader << ");\n";
987
988 OS_TemplateHeader <<
989 " if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&"<< ClassName <<"::"<< MD->getName() <<")) {\n"
990 " *result = " << Idx << ";\n"
991 " }\n"
992 " }\n";
993 }
994 OS_TemplateHeader << " }";
995 }
996
997 if (!CDef->Properties.empty()) {
998 if(NeedElse) OS_TemplateHeader << " else ";
999 NeedElse = true;
1000
1001 bool needGet = false;
1002 //bool needTempVarForGet = false;
1003 bool needSet = false;
1004 bool needReset = false;
1005 for (const PropertyDef &p : CDef->Properties) {
1006 needGet |= !p.read.empty() || !p.member.empty();
1007 /*if (!p.read.empty())
1008 needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
1009 && p.gspec != PropertyDef::ReferenceSpec);*/
1010 needSet |= !p.write.empty() || (!p.member.empty() && !p.constant);
1011 needReset |= !p.reset.empty();
1012 }
1013
1014
1015 // Generate the code for QMetaObject::'Action'. calls 'Functor' to generate the code for
1016 // each properties
1017 auto HandlePropertyAction = [&](bool Need, const char *Action,
1018 const std::function<void(const PropertyDef &)> &Functor) {
1019 OS_TemplateHeader << "if (_c == QMetaObject::" << Action << ") {\n";
1020 if (Need) {
1021 if (CDef->HasQObject) {
1022 // OS_TemplateHeader << " Q_ASSERT(staticMetaObject.cast(_o));\n";
1023 OS_TemplateHeader << " " << ClassName <<" *_t = static_cast<" << ClassName << " *>(_o);\n";
1024 } else {
1025 OS_TemplateHeader << " " << ClassName <<" *_t = reinterpret_cast<" << ClassName << " *>(_o);\n";
1026 }
1027 OS_TemplateHeader << " switch (_id) {\n";
1028 int I = 0;
1029 for (const PropertyDef &p : CDef->Properties) {
1030 OS_TemplateHeader << " case " << (I++) <<": ";
1031 Functor(p);
1032 OS_TemplateHeader << "break;\n";
1033 }
1034 OS_TemplateHeader << " default: break;\n";
1035 OS_TemplateHeader << " }";
1036 }
1037 OS_TemplateHeader << " _id -= " << CDef->Properties.size() << ";\n }";
1038 };
1039
1040 HandlePropertyAction(needGet, "ReadProperty", [&](const PropertyDef &p) {
1041 if (p.read.empty() && p.member.empty())
1042 return;
1043
1044 std::string Prefix = "_t->";
1045 if (p.inPrivateClass.size()) {
1046 Prefix += p.inPrivateClass;
1047 Prefix += "->";
1048 }
1049
1050 //FIXME: enums case
1051 if (p.PointerHack) {
1052 OS_TemplateHeader << "_a[0] = const_cast<void*>(static_cast<const void*>(" << Prefix << p.read << "())); ";
1053 } else {
1054 OS_TemplateHeader << "*reinterpret_cast< " << p.type << "*>(_a[0]) = " << Prefix;
1055 if (!p.read.empty())
1056 OS_TemplateHeader << p.read << "(); ";
1057 else
1058 OS_TemplateHeader << p.member << "; ";
1059 }
1060 });
1061 OS_TemplateHeader << " else ";
1062 HandlePropertyAction(needSet, "WriteProperty", [&](const PropertyDef &p) {
1063 if (p.constant)
1064 return;
1065
1066 std::string Prefix = "_t->";
1067 if (p.inPrivateClass.size()) {
1068 Prefix += p.inPrivateClass;
1069 Prefix += "->";
1070 }
1071
1072 if (!p.write.empty()) {
1073 OS_TemplateHeader << Prefix << p.write << "(*reinterpret_cast< " << p.type << "*>(_a[0])); ";
1074 } else if (!p.member.empty()) {
1075 std::string M = Prefix + p.member;
1076 std::string A = "*reinterpret_cast< " + p.type + "*>(_a[0])";
1077 if (!p.notify.Str.empty()) {
1078 OS_TemplateHeader << "\n"
1079 " if (" << M << " != " << A << ") {\n"
1080 " " << M << " = " << A << ";\n"
1081 " Q_EMIT _t->" << p.notify.Str << "(";
1082 if (p.notify.MD && p.notify.MD->getMinRequiredArguments() > 0)
1083 OS_TemplateHeader << M;
1084 OS_TemplateHeader << ");\n"
1085 " } ";
1086 } else {
1087 OS_TemplateHeader << M << " = " << A << "; ";
1088 }
1089 }
1090 });
1091 OS_TemplateHeader << " else ";
1092 HandlePropertyAction(needReset, "ResetProperty", [&](const PropertyDef &p) {
1093 if (p.reset.empty() || p.reset[p.reset.size()-1] != ')')
1094 return;
1095 std::string Prefix = "_t->";
1096 if (p.inPrivateClass.size()) {
1097 Prefix += p.inPrivateClass;
1098 Prefix += "->";
1099 }
1100 OS_TemplateHeader << Prefix << p.reset << "; ";
1101 });
1102
1103 OS_TemplateHeader << "if (_c == QMetaObject::RegisterPropertyMetaType) {\n"
1104 " switch (_id) {\n"
1105 " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n";
1106
1107 //FIXME: optimize (group same properties, and don't generate for builtin
1108 int Idx = 0;
1109 for (const PropertyDef &P: CDef->Properties) {
1110 int OldIdx = Idx++;
1111 if (P.PossiblyForwardDeclared) {
1112 const auto &MTS = Moc->registered_meta_type;
1113 if (!std::any_of(MTS.begin(), MTS.end(), [&](const clang::Type*T){
1114 return clang::QualType(T,0).getAsString(PrintPolicy) == P.type;
1115 } ))
1116 continue;
1117 }
1118 OS_TemplateHeader << " case " << OldIdx << ": *reinterpret_cast<int*>(_a[0]) = QtPrivate::QMetaTypeIdHelper<"
1119 << P.type << " >::qt_metatype_id(); break;\n";
1120 }
1121 OS_TemplateHeader << " }\n";
1122 OS_TemplateHeader << " }\n";
1123 }
1124
1125
1126 OS_TemplateHeader << "\n Q_UNUSED(_o); Q_UNUSED(_id); Q_UNUSED(_c); Q_UNUSED(_a);";
1127 OS_TemplateHeader << "\n}\n";
1128}
1129
1130void Generator::GenerateSignal(const clang::CXXMethodDecl *MD, int Idx)
1131{
1132 if (MD->isPure())
1133 return;
1134
1135 clang::QualType ReturnType = getResultType(MD);
1136 // getResultType will desugar. So if we are still a decltype, it probably means this is type
1137 // dependant and therefore must be a literal decltype which we need to have in the proper scope
1138 bool TrailingReturn = llvm::isa<clang::DecltypeType>(ReturnType);
1139
1140 OS_TemplateHeader << "\n// SIGNAL " << Idx << "\n" << TemplatePrefix;
1141 if (TrailingReturn)
1142 OS_TemplateHeader << "auto ";
1143 else
1144 OS_TemplateHeader << ReturnType.getAsString(PrintPolicy) << " ";
1145 OS_TemplateHeader << QualName << "::" << MD->getName() + "(";
1146 for (uint j = 0 ; j < MD->getNumParams(); ++j) {
1147 if (j) OS_TemplateHeader << ",";
1148 OS_TemplateHeader << MD->getParamDecl(j)->getType().getAsString(PrintPolicy);
1149 OS_TemplateHeader << " _t" << (j+1);;
1150 }
1151 OS_TemplateHeader << ")";
1152 std::string This = "this";
1153 if (MD->isConst()) {
1154 OS_TemplateHeader << " const";
1155 This = "const_cast< " + CDef->Record->getNameAsString() + " *>(this)";
1156 }
1157 if (TrailingReturn)
1158 OS_TemplateHeader << " -> " << ReturnType.getAsString(PrintPolicy);
1159 OS_TemplateHeader << "\n{\n";
1160 bool IsVoid = ReturnType->isVoidType();
1161 unsigned int NumParam = MD->getNumParams();
1162 if (IsVoid && NumParam == 0) {
1163 OS_TemplateHeader << " QMetaObject::activate(" << This << ", &staticMetaObject, " << Idx << ", 0);\n";
1164 } else {
1165 std::string T = ReturnType.getNonReferenceType().getUnqualifiedType().getAsString(PrintPolicy);
1166 if (ReturnType->isPointerType()) {
1167 OS_TemplateHeader << " " << ReturnType.getAsString(PrintPolicy) << " _t0 = 0;\n";
1168 } else if (!IsVoid) {
1169 OS_TemplateHeader << " " << T << " _t0 = " << T << "();\n";
1170 }
1171 OS_TemplateHeader << " void *_a[] = { ";
1172 if (IsVoid) OS_TemplateHeader << "0";
1173 else OS_TemplateHeader << "&_t0";
1174
1175
1176 for (uint j = 0 ; j < NumParam; ++j) {
1177 if (MD->getParamDecl(j)->getType().isVolatileQualified())
1178 OS_TemplateHeader << ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t" << (j+1) << "))";
1179 else
1180 OS_TemplateHeader << ", const_cast<void*>(reinterpret_cast<const void*>(&_t" << (j+1) << "))";
1181 }
1182
1183 OS_TemplateHeader << " };\n"
1184 " QMetaObject::activate(" << This << ", &staticMetaObject, " << Idx << ", _a);\n";
1185
1186 if (!IsVoid)
1187 OS_TemplateHeader << " return _t0;\n";
1188 }
1189 OS_TemplateHeader <<"}\n";
1190}
1191
1192// Generate the data in the data array for the properties
1193void Generator::GenerateProperties()
1194{
1195 if (CDef->Properties.empty())
1196 return;
1197
1198 OS << "\n // properties: name, type, flags\n";
1199
1200 for (const PropertyDef &p : CDef->Properties) {
1201 unsigned int flags = Invalid;
1202 if (p.isEnum)
1203 flags |= EnumOrFlag;
1204 if (!p.member.empty() && !p.constant)
1205 flags |= Writable;
1206 if (!p.read.empty() || !p.member.empty())
1207 flags |= Readable;
1208 if (!p.write.empty()) {
1209 flags |= Writable;
1210
1211 llvm::StringRef W(p.write);
1212 if (W.startswith("set") && W[3] == char(toupper(p.name[0])) && W.substr(4) == &p.name[1])
1213 flags |= StdCppSet;
1214 }
1215 if (!p.reset.empty())
1216 flags |= Resettable;
1217 if (p.designable.empty())
1218 flags |= ResolveDesignable;
1219 else if (p.designable != "false")
1220 flags |= Designable;
1221 if (p.scriptable.empty())
1222 flags |= ResolveScriptable;
1223 else if (p.scriptable != "false")
1224 flags |= Scriptable;
1225 if (p.stored.empty())
1226 flags |= ResolveStored;
1227 else if (p.stored != "false")
1228 flags |= Stored;
1229 if (p.editable.empty())
1230 flags |= ResolveEditable;
1231 else if (p.editable != "false")
1232 flags |= Editable;
1233 if (p.user.empty())
1234 flags |= ResolveUser;
1235 else if (p.user != "false")
1236 flags |= User;
1237 if (!p.notify.Str.empty())
1238 flags |= Notify;
1239 if (p.revision > 0)
1240 flags |= Revisioned;
1241 if (p.constant)
1242 flags |= Constant;
1243 if (p.final)
1244 flags |= Final;
1245 OS << " " << StrIdx(p.name) << ", 0x80000000 | " << StrIdx(p.type) << ", 0x";
1246 OS.write_hex(flags) << ", // " << p.name << "\n";
1247 }
1248
1249 if(CDef->NotifyCount) {
1250 OS << "\n // properties: notify_signal_id\n";
1251 for (const PropertyDef &P : CDef->Properties) {
1252 if (P.notify.notifyId >= 0) {
1253 OS << " " << P.notify.notifyId << ",\n";
1254 } else if (!P.notify.Str.empty()) {
1255 OS << " 0x70000000 | " << StrIdx(P.notify.Str) << ",\n";
1256 } else {
1257 OS << " 0,\n";
1258 }
1259 }
1260 }
1261
1262 if(CDef->RevisionPropertyCount) {
1263 OS << "\n // properties: revision\n";
1264 for (const PropertyDef &P : CDef->Properties) {
1265 OS << " " << P.revision << ",\n";
1266 }
1267 }
1268}
1269
1270// Generate the data in the data array for the enum.
1271void Generator::GenerateEnums(int EnumIndex)
1272{
1273 if (Def->Enums.empty())
1274 return;
1275
1276 OS << "\n // enums: name, flags, count, data\n";
1277
1278 for (auto e : Def->Enums) {
1279 int Count = 0;
1280 for (auto it = std::get<0>(e)->enumerator_begin() ; it != std::get<0>(e)->enumerator_end(); ++it)
1281 Count++;
1282 unsigned flags = 0;
1283 if(std::get<2>(e))
1284 flags |= 0x1; // EnumIsFlag
1285 if(std::get<0>(e)->isScoped())
1286 flags |= 0x2; // EnumIsScoped
1287 OS << " " << StrIdx(std::get<1>(e)) << ", " << flags << ", " << Count << ", " << EnumIndex << ",\n";
1288 EnumIndex += Count*2;
1289 }
1290
1291 OS << "\n // enums data: key, valus\n";
1292 for (auto e : Def->Enums) {
1293 for (auto it = std::get<0>(e)->enumerator_begin() ; it != std::get<0>(e)->enumerator_end(); ++it) {
1294 clang::EnumConstantDecl *E = *it;
1295 OS << " " << StrIdx(E->getName()) << ", uint(" << QualName << "::";
1296 if (std::get<0>(e)->isScoped())
1297 OS << std::get<0>(e)->getName() << "::";
1298 OS << E->getName() <<"),\n";
1299 }
1300 }
1301}
1302
1303// Returns the index of a string in the string data.
1304// Register the string if it is not yet registered.
1305int Generator::StrIdx(llvm::StringRef Str)
1306{
1307 std::string S = Str;
1308 auto It = std::find(Strings.begin(), Strings.end(), S);
1309 if (It != Strings.end())
1310 return It - Strings.begin();
1311 Strings.push_back(std::move(S));
1312 return Strings.size() - 1;
1313}
1314
1315void Generator::GeneratePluginMetaData(bool Debug)
1316{
1317 QBJS::Value Data;
1318 Data.T = QBJS::Object;
1319 Data.Props["IID"] = CDef->Plugin.IID;
1320 Data.Props["className"] = CDef->Record->getNameAsString();
1321 Data.Props["version"] = double(QT_VERSION);
1322 Data.Props["MetaData"] = CDef->Plugin.MetaData;
1323 Data.Props["debug"] = Debug;
1324 for (const auto &It : MetaData) {
1325 QBJS::Value &Array = Data.Props[It.first];
1326 if (Array.T == QBJS::Undefined)
1327 Array.T = QBJS::Array;
1328 Array.Elems.push_back(std::string(It.second));
1329 }
1330 OS << "QT_PLUGIN_METADATA_SECTION\n"
1331 "static const unsigned char qt_pluginMetaData[] = {\n"
1332 " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',\n"
1333 " 'q', 'b', 'j', 's', 0x1, 0, 0, 0,\n ";
1334 QBJS::Stream JSON(OS);
1335 JSON << Data;
1336 OS << "\n};\n";
1337}
1338