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