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 |
32 | static 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 */ |
40 | template <typename T> static auto getResultType(T *decl) -> decltype(decl->getResultType()) |
41 | { return getDesugarType(decl->getResultType()); } |
42 | template <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 | */ |
49 | static 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' |
69 | static 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 |
78 | template<typename T, typename F> |
79 | static 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 |
88 | template<typename T> |
89 | int 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 |
96 | template<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. |
109 | template <typename T> |
110 | void 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 | |
154 | static 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 |
159 | void 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 |
240 | template <typename T> |
241 | void 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 |
278 | static 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 | |
296 | template <typename T> |
297 | static 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 | |
309 | static 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 | |
350 | Generator::Generator(const ClassDef* CDef, llvm::raw_ostream& OS, clang::ASTContext& Ctx, |
351 | MocNg* Moc, llvm::raw_ostream *) |
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 | |
403 | Generator::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 | |
421 | void 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 | |
739 | void 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 | |
818 | void 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 | |
1130 | void 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 |
1193 | void 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. |
1271 | void 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. |
1305 | int 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 | |
1315 | void 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 | |