//FIXME. make it less stupid static void parseInterfaces(ClassDef &Def, clang::Expr *Content, clang::Sema &Sema) { clang::Preprocessor &PP = Sema.getPreprocessor(); clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content); if (!Val) { PP.getDiagnostics().Report(Content->getExprLoc(), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Invalid Q_INTERFACES annotation")); return; } llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_INTERFACES")); clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()), Buf, PP.getSourceManager(), PP.getLangOpts()); clang::Token Tok; bool Append = false; bool Error = false; while (true) { Lex.LexFromRawLexer(Tok); if (Tok.is(clang::tok::eof)) break; if (Tok.is(clang::tok::raw_identifier)) PP.LookUpIdentifierInfo(Tok); if (Tok.is(clang::tok::identifier)) { if (Append) Def.Interfaces.back() += PP.getSpelling(Tok); else Def.Interfaces.push_back(PP.getSpelling(Tok)); Append = false; continue; } if (Append) { Error = true; break; } if (Tok.is(clang::tok::coloncolon)) { Def.Interfaces.back() += PP.getSpelling(Tok); Append = true; continue; } if (!Tok.is(clang::tok::colon)) { Error = true; break; } } if (Error || Append || !Tok.is(clang::tok::eof)) { PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "parse error in Q_INTERFACES")); } // TODO: check interface validity }
void MocASTConsumer::Initialize(clang::ASTContext& Ctx) { ctx = &Ctx; PPCallbacks = new MocPPCallbacks(ci.getPreprocessor(), Moc.Tags); ci.getPreprocessor().addPPCallbacks(maybe_unique(PPCallbacks)); // ci.getDiagnostics().setClient(new DiagnosticClient(), true); // We will enable this when we require Qt >= 5.6.1 and libclang >= 3.8 // Then we will be able to get rid of qobjectdefs-injected #if 0 std::string qtPredefinesBuffer; llvm::raw_string_ostream qtPredefines(qtPredefinesBuffer); clang::MacroBuilder builder(qtPredefines); builder.append("# 1 \"<moc-ng built-in>\" 1"); builder.defineMacro("QT_ANNOTATE_CLASS(type,...)", "static_assert(sizeof(#__VA_ARGS__),#type);"); builder.defineMacro("QT_ANNOTATE_CLASS2(type,a1,a2)", "static_assert(sizeof(#a1,#a2),#type);"); builder.defineMacro("QT_ANNOTATE_FUNCTION(a)", "__attribute__((annotate(#a)))"); builder.defineMacro("QT_ANNOTATE_ACCESS_SPECIFIER(a)", "__attribute__((annotate(#a)))"); builder.defineMacro("Q_CLASSINFO(name,value)", "static_assert(sizeof(name,value),\"qt_classinfo\");"); builder.defineMacro("Q_REVISION(v)", "__attribute__((annotate(\"qt_revision:\" QT_STRINGIFY2(v))))"); // prepend the Qt defines so the command line argument can override them. ci.getPreprocessor().setPredefines(qtPredefines.str() + ci.getPreprocessor().getPredefines()); #endif }
virtual void Initialize(clang::ASTContext& Ctx) override { annotator.setSourceMgr(Ctx.getSourceManager(), Ctx.getLangOpts()); annotator.setMangleContext(Ctx.createMangleContext()); ci.getPreprocessor().addPPCallbacks(maybe_unique(new PreprocessorCallback(annotator, ci.getPreprocessor()))); ci.getDiagnostics().setClient(new BrowserDiagnosticClient(annotator), true); }
static void parseEnums(ClassDef &Def, bool isFlag, clang::Expr *Content, clang::Sema &Sema) { clang::Preprocessor &PP = Sema.getPreprocessor(); clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content); if (!Val) { PP.getDiagnostics().Report(Content->getExprLoc(), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Invalid Q_ENUMS annotation")); return; } llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_ENUMS")); clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()), Buf, PP.getSourceManager(), PP.getLangOpts()); clang::CXXScopeSpec SS; clang::Token Tok, Next; Lex.LexFromRawLexer(Tok); for (; !Tok.is(clang::tok::eof); Tok = Next) { Lex.LexFromRawLexer(Next); clang::IdentifierInfo* II = nullptr; if (Tok.is(clang::tok::raw_identifier)) II = PP.LookUpIdentifierInfo(Tok); if (Tok.is(clang::tok::identifier)) { if (Next.is(clang::tok::coloncolon)) { if (Sema.ActOnCXXNestedNameSpecifier(Sema.getScopeForContext(Def.Record), *II, GetFromLiteral(Tok, Val, PP), GetFromLiteral(Next, Val, PP), {}, false, SS)) SS.SetInvalid({GetFromLiteral(Tok, Val, PP), GetFromLiteral(Next, Val, PP)}); Lex.LexFromRawLexer(Next); continue; } clang::LookupResult Found(Sema, II, GetFromLiteral(Tok, Val, PP), clang::Sema::LookupNestedNameSpecifierName); if (SS.isEmpty()) Sema.LookupQualifiedName(Found, Def.Record); else { clang::DeclContext* DC = Sema.computeDeclContext(SS); Sema.LookupQualifiedName(Found, DC ? DC : Def.Record); } llvm::StringRef Alias; clang::EnumDecl* R = Found.getAsSingle<clang::EnumDecl>(); if (!R) { if (clang::TypedefDecl *TD = Found.getAsSingle<clang::TypedefDecl>()) { const clang::EnumType* ET = TD->getUnderlyingType()->getAs<clang::EnumType>(); const clang::TemplateSpecializationType* TDR = TD->getUnderlyingType()->getAs<clang::TemplateSpecializationType>(); if(TDR && TDR->getNumArgs() == 1 && TDR->getTemplateName().getAsTemplateDecl()->getName() == "QFlags") ET = TDR->getArg(0).getAsType()->getAs<clang::EnumType>(); if (ET) { R = ET->getDecl(); if (TD->getIdentifier()) Alias = TD->getName(); } } } if (Found.empty() || !R) { // TODO: typo correction // This should be an error, but the official moc do not understand that as an error. PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, "no enum names %0")) << Found.getLookupName(); break; } if (R->getDeclContext() == Def.Record) { if (Alias.empty() && R->getIdentifier()) Alias = R->getName(); Def.addEnum(R, Alias.empty() ? R->getNameAsString() : std::string(Alias), isFlag); } else if (R->getDeclContext()->isRecord() && llvm::isa<clang::CXXRecordDecl>(R->getDeclContext())) { // TODO: check it is a QObject Def.addExtra(llvm::cast<clang::CXXRecordDecl>(R->getDeclContext())); } SS.clear(); continue; } else if (Tok.is(clang::tok::coloncolon)) { if (SS.isEmpty()) { SS.MakeGlobal(Sema.getASTContext(), GetFromLiteral(Tok, Val, PP)); continue; } } PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Invalid token in Q_ENUMS")); break; } }
static void parsePluginMetaData(ClassDef &Def, clang::Expr *Content, clang::Sema &Sema) { clang::Preprocessor &PP = Sema.getPreprocessor(); clang::StringLiteral *Val = llvm::dyn_cast<clang::StringLiteral>(Content); if (!Val) { PP.getDiagnostics().Report(Content->getExprLoc(), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Invalid Q_PLUGIN_METADATA annotation")); return; } llvm::MemoryBuffer* Buf = maybe_unique(llvm::MemoryBuffer::getMemBufferCopy(Val->getString(), "Q_PLUGIN_METADATA")); clang::Lexer Lex(CreateFileIDForMemBuffer(PP, Buf, Content->getExprLoc()), Buf, PP.getSourceManager(), PP.getLangOpts()); clang::Token Tok; Lex.LexFromRawLexer(Tok); while (Tok.is(clang::tok::raw_identifier)) { clang::IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok); if (II->getName() != "IID" && II->getName() != "FILE") { Lex.LexFromRawLexer(Tok); continue; } Lex.LexFromRawLexer(Tok); if (!Tok.is(clang::tok::string_literal)) { PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Expected string literal")); return; } llvm::SmallVector<clang::Token, 4> StrToks; do { StrToks.push_back(Tok); Lex.LexFromRawLexer(Tok); } while (Tok.is(clang::tok::string_literal)); #if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>4 clang::StringLiteralParser Literal(StrToks, PP); #else clang::StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP); #endif if (Literal.hadError) return; if (II->getName() == "IID") Def.Plugin.IID = Literal.GetString(); else { llvm::StringRef Filename = Literal.GetString(); const clang::DirectoryLookup *CurDir; const clang::FileEntry *File = PP.LookupFile( #if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>3 Val->getLocStart(), #endif Filename, false, nullptr, #if CLANG_VERSION_MAJOR!=3 || CLANG_VERSION_MINOR>5 nullptr, #endif CurDir, nullptr, nullptr, nullptr); if (!File) { PP.getDiagnostics().Report(GetFromLiteral(StrToks.front(), Val, PP), clang::diag::err_pp_file_not_found) << Filename; return; } const llvm::MemoryBuffer* JSonBuf = PP.getSourceManager().getMemoryBufferForFile(File); llvm::SourceMgr SM; llvm::yaml::Stream YAMLStream(JSonBuf->getBuffer(), SM); llvm::yaml::document_iterator I = YAMLStream.begin(); if (I == YAMLStream.end() || !I->getRoot() || !QBJS::Parse(I->getRoot(), Def.Plugin.MetaData)) { // FIXME PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Error pwhile parsing JSON")); return; } } } if (!Tok.is(clang::tok::eof)) { PP.getDiagnostics().Report(GetFromLiteral(Tok, Val, PP), PP.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "Parse error: Expected 'IID' or 'FILE'")); return; } }
void MocPPCallbacks::InjectQObjectDefs(clang::SourceLocation Loc) { #include "qobjectdefs-injected.h" auto Buf = maybe_unique(llvm::MemoryBuffer::getMemBuffer(Injected, "qobjectdefs-injected.moc")); Loc = PP.getSourceManager().getFileLoc(Loc); PP.EnterSourceFile( CreateFileIDForMemBuffer(PP, Buf, Loc), nullptr, Loc); }