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 "mocng.h"
21#include "propertyparser.h"
22#include "qbjs.h"
23
24#include <clang/Basic/Version.h>
25#include <clang/Lex/Preprocessor.h>
26#include <clang/Lex/LiteralSupport.h>
27#include <clang/Lex/LexDiagnostic.h>
28
29#include <clang/AST/DeclCXX.h>
30#include <clang/AST/DeclTemplate.h>
31#include <clang/AST/ASTContext.h>
32#include <clang/AST/Type.h>
33#include <clang/Sema/Sema.h>
34#include <clang/Sema/Lookup.h>
35#include <llvm/ADT/SmallVector.h>
36#include <llvm/Support/YAMLParser.h>
37#include <llvm/Support/SourceMgr.h>
38
39#include <iostream>
40
41static clang::SourceLocation GetFromLiteral(clang::Token Tok, clang::StringLiteral *Lit, clang::Preprocessor &PP) {
42 return Lit->getLocationOfByte(PP.getSourceManager().getFileOffset(Tok.getLocation()),
43 PP.getSourceManager(), PP.getLangOpts(), PP.getTargetInfo());
44}
45
46
47//FIXME. make it less stupid
48static void parseInterfaces(ClassDef &Def, clang::Expr *Content, clang::Sema &Sema) {
49 clang::Preprocessor &PP = Sema.getPreprocessor();
50 clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content);
51 if (!Val) {
52 PP.getDiagnostics().Report(Content->getExprLoc(),
53 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
54 "Invalid Q_INTERFACES annotation"));
55 return;
56 }
57
58 llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_INTERFACES"));
59 clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()),
60 Buf, PP.getSourceManager(), PP.getLangOpts());
61
62 clang::Token Tok;
63 bool Append = false;
64 bool Error = false;
65 while (true) {
66 Lex.LexFromRawLexer(Tok);
67
68 if (Tok.is(clang::tok::eof))
69 break;
70
71 if (Tok.is(clang::tok::raw_identifier))
72 PP.LookUpIdentifierInfo(Tok);
73
74 if (Tok.is(clang::tok::identifier)) {
75 if (Append)
76 Def.Interfaces.back() += PP.getSpelling(Tok);
77 else
78 Def.Interfaces.push_back(PP.getSpelling(Tok));
79 Append = false;
80 continue;
81 }
82
83 if (Append) {
84 Error = true;
85 break;
86 }
87
88 if (Tok.is(clang::tok::coloncolon)) {
89 Def.Interfaces.back() += PP.getSpelling(Tok);
90 Append = true;
91 continue;
92 }
93
94 if (!Tok.is(clang::tok::colon)) {
95 Error = true;
96 break;
97 }
98 }
99
100 if (Error || Append || !Tok.is(clang::tok::eof)) {
101 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
102 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
103 "parse error in Q_INTERFACES"));
104 }
105
106 // TODO: check interface validity
107}
108
109
110static void parsePluginMetaData(ClassDef &Def, clang::Expr *Content, clang::Sema &Sema) {
111 clang::Preprocessor &PP = Sema.getPreprocessor();
112 clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content);
113 if (!Val) {
114 PP.getDiagnostics().Report(Content->getExprLoc(),
115 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
116 "Invalid Q_PLUGIN_METADATA annotation"));
117 return;
118 }
119
120 llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_PLUGIN_METADATA"));
121 clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()),
122 Buf, PP.getSourceManager(), PP.getLangOpts());
123
124 clang::Token Tok;
125 Lex.LexFromRawLexer(Tok);
126 while (Tok.is(clang::tok::raw_identifier)) {
127 clang::IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok);
128 if (II->getName() != "IID" && II->getName() != "FILE") {
129 Lex.LexFromRawLexer(Tok);
130 continue;
131 }
132
133 Lex.LexFromRawLexer(Tok);
134 if (!Tok.is(clang::tok::string_literal)) {
135 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
136 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
137 "Expected string literal"));
138 return;
139 }
140
141 llvm::SmallVector<clang::Token, 4> StrToks;
142 do {
143 StrToks.push_back(Tok);
144 Lex.LexFromRawLexer(Tok);
145 } while (Tok.is(clang::tok::string_literal));
146#if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>4
147 clang::StringLiteralParser Literal(StrToks, PP);
148#else
149 clang::StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
150#endif
151 if (Literal.hadError)
152 return;
153
154 if (II->getName() == "IID")
155 Def.Plugin.IID = Literal.GetString();
156 else {
157 llvm::StringRef Filename = Literal.GetString();
158 const clang::DirectoryLookup *CurDir;
159 const clang::FileEntry *File = PP.LookupFile(
160#if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>3
161 Val->getLocStart(),
162#endif
163 Filename, false, nullptr,
164#if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>5
165 nullptr,
166#endif
167 CurDir, nullptr, nullptr, nullptr
168#if CLANG_VERSION_MAJOR >= 5
169 , nullptr
170#endif
171 );
172
173 if (!File) {
174 PP.getDiagnostics().Report(GetFromLiteral(StrToks.front(), Val, PP), clang::diag::err_pp_file_not_found)
175 << Filename;
176 return;
177 }
178 const llvm::MemoryBuffer* JSonBuf = PP.getSourceManager().getMemoryBufferForFile(File);
179 llvm::SourceMgr SM;
180 llvm::yaml::Stream YAMLStream(JSonBuf->getBuffer(), SM);
181 llvm::yaml::document_iterator I = YAMLStream.begin();
182 if (I == YAMLStream.end() || !I->getRoot() || !QBJS::Parse(I->getRoot(), Def.Plugin.MetaData)) {
183 // FIXME
184 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
185 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
186 "Error pwhile parsing JSON"));
187 return;
188 }
189 }
190 }
191
192 if (!Tok.is(clang::tok::eof)) {
193 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
194 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
195 "Parse error: Expected 'IID' or 'FILE'"));
196 return;
197 }
198
199}
200
201
202
203static void parseEnums(BaseDef &Def, clang::DeclContext *Context, bool isFlag, clang::Expr *Content, clang::Sema &Sema) {
204 clang::Preprocessor &PP = Sema.getPreprocessor();
205 clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content);
206 if (!Val) {
207 PP.getDiagnostics().Report(Content->getExprLoc(),
208 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
209 "Invalid Q_ENUMS annotation"));
210 return;
211 }
212
213 llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_ENUMS"));
214 clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()),
215 Buf, PP.getSourceManager(), PP.getLangOpts());
216
217 clang::CXXScopeSpec SS;
218 clang::Token Tok, Next;
219 Lex.LexFromRawLexer(Tok);
220 for (; !Tok.is(clang::tok::eof); Tok = Next) {
221 Lex.LexFromRawLexer(Next);
222 clang::IdentifierInfo* II = nullptr;
223 if (Tok.is(clang::tok::raw_identifier))
224 II = PP.LookUpIdentifierInfo(Tok);
225
226
227 if (Tok.is(clang::tok::identifier)) {
228
229 if (Next.is(clang::tok::coloncolon)) {
230 auto TokLoc = GetFromLiteral(Tok, Val, PP);
231 auto NextLoc = GetFromLiteral(Next, Val, PP);
232#if CLANG_VERSION_MAJOR >= 4
233 clang::Sema::NestedNameSpecInfo NameInfo(II, TokLoc, NextLoc);
234 if (Sema.ActOnCXXNestedNameSpecifier(Sema.getScopeForContext(Context),
235 NameInfo, false, SS))
236#else
237 if (Sema.ActOnCXXNestedNameSpecifier(Sema.getScopeForContext(Context), *II,
238 TokLoc, NextLoc, {}, false, SS))
239#endif
240 {
241 SS.SetInvalid({TokLoc, NextLoc});
242 }
243 Lex.LexFromRawLexer(Next);
244 continue;
245 }
246
247 clang::LookupResult Found(Sema, II, GetFromLiteral(Tok, Val, PP), clang::Sema::LookupNestedNameSpecifierName);
248 if (SS.isEmpty())
249 Sema.LookupQualifiedName(Found, Context);
250 else {
251 clang::DeclContext* DC = Sema.computeDeclContext(SS);
252 Sema.LookupQualifiedName(Found, DC ? DC : Context);
253 }
254
255 llvm::StringRef Alias;
256 clang::EnumDecl* R = Found.getAsSingle<clang::EnumDecl>();
257
258 if (!R) {
259 if (clang::TypedefDecl *TD = Found.getAsSingle<clang::TypedefDecl>()) {
260 const clang::EnumType* ET = TD->getUnderlyingType()->getAs<clang::EnumType>();
261 const clang::TemplateSpecializationType* TDR = TD->getUnderlyingType()->getAs<clang::TemplateSpecializationType>();
262 if(TDR && TDR->getNumArgs() == 1 && TDR->getTemplateName().getAsTemplateDecl()->getName() == "QFlags")
263 ET = TDR->getArg(0).getAsType()->getAs<clang::EnumType>();
264 if (ET) {
265 R = ET->getDecl();
266 if (TD->getIdentifier())
267 Alias = TD->getName();
268 }
269 }
270 }
271
272 if (Found.empty() || !R) {
273 // TODO: typo correction
274
275 // This should be an error, but the official moc do not understand that as an error.
276 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
277 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning,
278 "no enum names %0")) << Found.getLookupName();
279 break;
280 }
281 if (R->getDeclContext() == Context) {
282 if (Alias.empty() && R->getIdentifier())
283 Alias = R->getName();
284 Def.addEnum(R, Alias.empty() ? R->getNameAsString() : std::string(Alias), isFlag);
285 } else if (R->getDeclContext()->isRecord() && llvm::isa<clang::CXXRecordDecl>(R->getDeclContext())) {
286 // TODO: check it is a QObject
287 Def.addExtra(llvm::cast<clang::CXXRecordDecl>(R->getDeclContext()));
288 }
289 SS.clear();
290 continue;
291 } else if (Tok.is(clang::tok::coloncolon)) {
292 if (SS.isEmpty()) {
293 SS.MakeGlobal(Sema.getASTContext(), GetFromLiteral(Tok, Val, PP));
294 continue;
295 }
296 }
297
298 PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP),
299 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
300 "Invalid token in Q_ENUMS"));
301 break;
302 }
303
304
305}
306
307template<int N>
308static std::pair<clang::StringLiteral*, clang::StringLiteral *> ExtractLiterals(clang::Expr *E,
309 const clang::Preprocessor &PP,
310 const char *Keyword,
311 const char (&Error)[N]) {
312 clang::BinaryOperator* BO = llvm::dyn_cast<clang::BinaryOperator>(E);
313 clang::StringLiteral *Val1 = nullptr, *Val2 = nullptr;
314 if (!BO) {
315 PP.getDiagnostics().Report(E->getExprLoc(),
316 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
317 "Invalid %0 annotation")) << Keyword;
318 } else {
319 if (!(Val1 = llvm::dyn_cast<clang::StringLiteral>(BO->getLHS())))
320 PP.getDiagnostics().Report(BO->getLHS()->getExprLoc(),
321 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, Error));
322 if (!(Val2 = llvm::dyn_cast<clang::StringLiteral>(BO->getRHS())))
323 PP.getDiagnostics().Report(BO->getRHS()->getExprLoc(),
324 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, Error));
325 }
326 return {Val1, Val2};
327}
328
329static void parseClassInfo(BaseDef &Def, clang::Expr *SubExp, clang::Preprocessor &PP)
330{
331 clang::StringLiteral *Val1 = nullptr, *Val2 = nullptr;
332 std::tie(Val1, Val2) = ExtractLiterals(SubExp, PP, "Q_CLASSINFO",
333 "Expected string literal in Q_CLASSINFO");
334
335 if (Val1 && Val2) {
336 Def.ClassInfo.emplace_back(Val1->getString(), Val2->getString());
337 }
338}
339
340static bool IsAnnotationStaticAssert(clang::Decl *Decl, llvm::StringRef *Key, clang::Expr **SubExp) {
341 if (clang::StaticAssertDecl *S = llvm::dyn_cast<clang::StaticAssertDecl>(Decl)) {
342 if (auto *E = llvm::dyn_cast<clang::UnaryExprOrTypeTraitExpr>(S->getAssertExpr()))
343 if (clang::ParenExpr *PE = llvm::dyn_cast<clang::ParenExpr>(E->getArgumentExpr()))
344 {
345 *Key = S->getMessage()->getString();
346 *SubExp = PE->getSubExpr();
347 return true;
348 }
349 }
350 return false;
351}
352
353ClassDef MocNg::parseClass(clang::CXXRecordDecl* RD, clang::Sema& Sema)
354{
355 clang::Preprocessor &PP = Sema.getPreprocessor();
356 ClassDef Def;
357 Def.Record = RD;
358
359 for (auto it = RD->decls_begin(); it != RD->decls_end(); ++it) {
360 llvm::StringRef key;
361 clang::Expr *SubExp;
362 if (IsAnnotationStaticAssert(*it, &key, &SubExp)) {
363 if (key == "qt_property") {
364 clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(SubExp);
365 if (Val) {
366 PropertyParser Parser(Val->getString(),
367// Val->getStrTokenLoc(0),
368 Val->getLocationOfByte(0, PP.getSourceManager(), PP.getLangOpts(), PP.getTargetInfo()),
369 Sema, Def.Record);
370 Def.Properties.push_back(Parser.parseProperty());
371 Def.addExtra(Parser.Extra);
372 } else {
373 PP.getDiagnostics().Report((*it)->getLocation(),
374 PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error,
375 "Invalid Q_PROPERTY annotation"));
376 }
377 } else if (key == "qt_private_property") {
378 clang::StringLiteral *Val1 = nullptr, *Val2 = nullptr;
379 std::tie(Val1, Val2) = ExtractLiterals(SubExp, PP, "Q_PRIVATE_PROPERTY",
380 "Invalid Q_PRIVATE_PROPERTY annotation");
381
382 if (Val1 && Val2) {
383 PropertyParser Parser(Val2->getString(),
384 Val2->getLocationOfByte(0, PP.getSourceManager(), PP.getLangOpts(), PP.getTargetInfo()),
385 Sema, Def.Record);
386 PropertyDef P = Parser.parseProperty(true);
387 P.inPrivateClass = Val1->getString();
388 Def.Properties.push_back(std::move(P));
389 Def.addExtra(Parser.Extra);
390 }
391 } else if (key == "qt_private_slot") {
392 clang::StringLiteral *Val1 = nullptr, *Val2 = nullptr;
393 std::tie(Val1, Val2) = ExtractLiterals(SubExp, PP, "Q_PRIVATE_SLOT",
394 "Invalid Q_PRIVATE_SLOT annotation");
395 if (Val1 && Val2) {
396 PropertyParser Parser(Val2->getString(),
397 Val2->getLocationOfByte(0, PP.getSourceManager(), PP.getLangOpts(), PP.getTargetInfo()),
398 Sema, Def.Record);
399 PrivateSlotDef P = Parser.parsePrivateSlot();
400 P.InPrivateClass = Val1->getString();
401 if (!P.Name.empty()) {
402 Def.PrivateSlotCount += P.NumDefault + 1;
403 Def.PrivateSlots.push_back(std::move(P));
404 }
405 }
406 } else if (key == "qt_enums") {
407 parseEnums(Def, Def.Record, false, SubExp, Sema);
408 } else if (key == "qt_flags") {
409 parseEnums(Def, Def.Record, true, SubExp, Sema);
410 } else if (key == "qt_qobject") {
411 Def.HasQObject = true;
412 } else if (key == "qt_fake") {
413 Def.HasQGadget = false;
414 Def.HasQObject = false;
415 } else if (key == "qt_qgadget") {
416 Def.HasQGadget = true;
417 } else if (key == "qt_classinfo") {
418 parseClassInfo(Def, SubExp, PP);
419 } else if (key == "qt_interfaces") {
420 parseInterfaces(Def, SubExp, Sema);
421 } else if (key == "qt_plugin_metadata") {
422 parsePluginMetaData(Def, SubExp, Sema);
423 HasPlugin = true;
424 }
425 } else if (clang::CXXMethodDecl *M = llvm::dyn_cast<clang::CXXMethodDecl>(*it)) {
426 for (auto attr_it = M->specific_attr_begin<clang::AnnotateAttr>();
427 attr_it != M->specific_attr_end<clang::AnnotateAttr>();
428 ++attr_it) {
429
430 const clang::AnnotateAttr *A = *attr_it;
431 if (A->getAnnotation() == "qt_signal") {
432 Def.Signals.push_back(M);
433 } else if (A->getAnnotation() == "qt_slot") {
434 Def.Slots.push_back(M);
435 } else if (A->getAnnotation() == "qt_invokable" || A->getAnnotation() == "qt_scriptable" ) {
436 if (auto *C = llvm::dyn_cast<clang::CXXConstructorDecl>(M)) {
437 Def.Constructors.push_back(C);
438 } else {
439 Def.Methods.push_back(M);
440 }
441 } else if (A->getAnnotation().startswith("qt_revision:")) {
442 Def.RevisionMethodCount++;
443 }
444 }
445 }
446 }
447
448 //Check notify Signals
449 for (PropertyDef &P: Def.Properties) {
450 if (!P.notify.Str.empty()) {
451 int Idx = 0;
452 auto errorLevel = clang::DiagnosticsEngine::Error;
453 for (clang::CXXMethodDecl *MD : Def.Signals) {
454 if (MD->getName() == P.notify.Str) {
455 P.notify.notifyId = Idx;
456 P.notify.MD = MD;
457 break;
458 }
459 Idx += 1 + MD->getNumParams() - MD->getMinRequiredArguments();
460 }
461 if (P.notify.notifyId < 0 ) {
462 // Search in base classes
463 clang::CXXRecordDecl *Base = Def.Record;
464 do {
465 if (!Base->getNumBases())
466 break;
467 Base = Base->bases_begin()->getType()->getAsCXXRecordDecl();
468 if (!Base)
469 break;
470 for (auto it = Base->decls_begin(); it != Base->decls_end(); ++it) {
471 if (auto *MD = llvm::dyn_cast<clang::CXXMethodDecl>(*it)) {
472
473 if (MD->getIdentifier() && MD->getName() == P.notify.Str) {
474 // We found a possible match. Check if it is indeed a signal
475 if (std::any_of(MD->specific_attr_begin<clang::AnnotateAttr>(),
476 MD->specific_attr_end<clang::AnnotateAttr>(),
477 [&](const clang::AnnotateAttr *a) {
478 return a->getAnnotation() == "qt_signal";
479 })) {
480 P.notify.MD = MD;
481 break;
482 }
483 // Since the official moc let this compile and the runtime will show
484 // a warning, we just change the level to Warning.
485 // (required for tst_qmetaobject which tests that)
486 errorLevel = clang::DiagnosticsEngine::Warning;
487 }
488 }
489 }
490 } while(!P.notify.MD);
491 }
492 if (!P.notify.MD) {
493 PP.getDiagnostics().Report(P.notify.Loc,
494 PP.getDiagnostics().getCustomDiagID(errorLevel,
495 "NOTIFY signal '%0' of property '%1' does not exist in class %2"))
496 << P.notify.Str << P.name << Def.Record;
497 }
498 Def.NotifyCount++;
499 }
500
501 if (P.revision > 0)
502 Def.RevisionPropertyCount++;
503 }
504 return Def;
505}
506
507NamespaceDef MocNg::parseNamespace(clang::NamespaceDecl* ND, clang::Sema& Sema)
508{
509 NamespaceDef Def;
510 Def.Namespace = ND;
511 for (auto it = ND->decls_begin(); it != ND->decls_end(); ++it) {
512 llvm::StringRef key;
513 clang::Expr *SubExp;
514 if (IsAnnotationStaticAssert(*it, &key, &SubExp)) {
515 if (key == "qt_qnamespace") {
516 Def.hasQNamespace = true;
517 } else if (key == "qt_enums") {
518 parseEnums(Def, ND, false, SubExp, Sema);
519 } else if (key == "qt_flags") {
520 parseEnums(Def, ND, true, SubExp, Sema);
521 } else if (key == "qt_classinfo") {
522 parseClassInfo(Def, SubExp, Sema.getPreprocessor());
523 }
524 }
525 }
526 return Def;
527}
528
529std::string MocNg::GetTag(clang::SourceLocation DeclLoc, const clang::SourceManager &SM)
530{
531 clang::SourceLocation FileLoc = SM.getFileLoc(DeclLoc);
532 clang::FileID FID = SM.getFileID(FileLoc);
533 const llvm::MemoryBuffer *Buffer = SM.getBuffer(FID);
534 const char *B = Buffer->getBufferStart();
535 int Off = SM.getFileOffset(FileLoc);
536 int Orig = Off;
537 while (Off > 0 && B[Off] != ';' && B[Off]!=',' && B[Off] != '}' && B[Off] != ':' /*&& B[Off] != '\n'*/ ) {
538 Off--;
539 }
540
541 auto it_before = Tags.lower_bound(FileLoc.getLocWithOffset(Off - Orig));
542 auto it_after = Tags.upper_bound(FileLoc);
543 if (it_before != Tags.end() && it_after != Tags.begin() && it_before == (--it_after)) {
544 return it_before->second;
545 }
546 return {};
547}
548
549bool MocNg::ShouldRegisterMetaType(clang::QualType T)
550{
551 if (T->isVoidType() || (T->isReferenceType() && !T.getNonReferenceType().isConstQualified()))
552 return false;
553
554 if (registered_meta_type.count(T->getCanonicalTypeUnqualified().getTypePtr()))
555 return true;
556
557 T = T.getNonReferenceType();
558
559 if (T->isPointerType()) {
560 // registering pointer to forward declared type fails.
561 const clang::CXXRecordDecl* Pointee = T->getPointeeCXXRecordDecl();
562 if (Pointee && !Pointee->hasDefinition())
563 return false;
564 return true;
565 }
566
567 if (auto TD = llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(T->getAsCXXRecordDecl())) {
568 if (!TD->hasDefinition()) {
569 if (auto CTD = TD->getSpecializedTemplate()) {
570 if (CTD->getTemplatedDecl() && !CTD->getTemplatedDecl()->hasDefinition())
571 return false;
572 }
573 }
574 for (uint I = 0; I < TD->getTemplateArgs().size(); ++I) {
575 const auto &Arg = TD->getTemplateArgs().get(I);
576 if (Arg.getKind() == clang::TemplateArgument::Type) {
577 if (!ShouldRegisterMetaType(Arg.getAsType()))
578 return false;
579 }
580 }
581 }
582 return true;
583}
584