diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Frontend')
43 files changed, 29049 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp new file mode 100644 index 0000000..7b8ebf9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -0,0 +1,464 @@ +//===--- ASTConsumers.cpp - ASTConsumer implementations -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumer Implementations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/DocumentXML.h" +#include "clang/Frontend/PathDiagnosticClients.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "llvm/Module.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +/// ASTPrinter - Pretty-printer and dumper of ASTs + +namespace { + class ASTPrinter : public ASTConsumer { + llvm::raw_ostream &Out; + bool Dump; + + public: + ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false) + : Out(o? *o : llvm::errs()), Dump(Dump) { } + + virtual void HandleTranslationUnit(ASTContext &Context) { + PrintingPolicy Policy = Context.PrintingPolicy; + Policy.Dump = Dump; + Context.getTranslationUnitDecl()->print(Out, Policy); + } + }; +} // end anonymous namespace + +ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) { + return new ASTPrinter(out); +} + +//===----------------------------------------------------------------------===// +/// ASTPrinterXML - XML-printer of ASTs + +namespace { + class ASTPrinterXML : public ASTConsumer { + DocumentXML Doc; + + public: + ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {} + + void Initialize(ASTContext &Context) { + Doc.initialize(Context); + } + + virtual void HandleTranslationUnit(ASTContext &Ctx) { + Doc.addSubNode("TranslationUnit"); + for (DeclContext::decl_iterator + D = Ctx.getTranslationUnitDecl()->decls_begin(), + DEnd = Ctx.getTranslationUnitDecl()->decls_end(); + D != DEnd; + ++D) + Doc.PrintDecl(*D); + Doc.toParent(); + Doc.finalize(); + } + }; +} // end anonymous namespace + + +ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) { + return new ASTPrinterXML(out ? *out : llvm::outs()); +} + +ASTConsumer *clang::CreateASTDumper() { + return new ASTPrinter(0, true); +} + +//===----------------------------------------------------------------------===// +/// ASTViewer - AST Visualization + +namespace { + class ASTViewer : public ASTConsumer { + ASTContext *Context; + public: + void Initialize(ASTContext &Context) { + this->Context = &Context; + } + + virtual void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + } + + void HandleTopLevelSingleDecl(Decl *D); + }; +} + +void ASTViewer::HandleTopLevelSingleDecl(Decl *D) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + FD->print(llvm::errs()); + + if (Stmt *Body = FD->getBody()) { + llvm::errs() << '\n'; + Body->viewAST(); + llvm::errs() << '\n'; + } + return; + } + + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + MD->print(llvm::errs()); + + if (MD->getBody()) { + llvm::errs() << '\n'; + MD->getBody()->viewAST(); + llvm::errs() << '\n'; + } + } +} + + +ASTConsumer *clang::CreateASTViewer() { return new ASTViewer(); } + +//===----------------------------------------------------------------------===// +/// DeclContextPrinter - Decl and DeclContext Visualization + +namespace { + +class DeclContextPrinter : public ASTConsumer { + llvm::raw_ostream& Out; +public: + DeclContextPrinter() : Out(llvm::errs()) {} + + void HandleTranslationUnit(ASTContext &C) { + PrintDeclContext(C.getTranslationUnitDecl(), 4); + } + + void PrintDeclContext(const DeclContext* DC, unsigned Indentation); +}; +} // end anonymous namespace + +void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, + unsigned Indentation) { + // Print DeclContext name. + switch (DC->getDeclKind()) { + case Decl::TranslationUnit: + Out << "[translation unit] " << DC; + break; + case Decl::Namespace: { + Out << "[namespace] "; + const NamespaceDecl* ND = cast<NamespaceDecl>(DC); + Out << ND; + break; + } + case Decl::Enum: { + const EnumDecl* ED = cast<EnumDecl>(DC); + if (ED->isDefinition()) + Out << "[enum] "; + else + Out << "<enum> "; + Out << ED; + break; + } + case Decl::Record: { + const RecordDecl* RD = cast<RecordDecl>(DC); + if (RD->isDefinition()) + Out << "[struct] "; + else + Out << "<struct> "; + Out << RD; + break; + } + case Decl::CXXRecord: { + const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC); + if (RD->isDefinition()) + Out << "[class] "; + else + Out << "<class> "; + Out << RD << ' ' << DC; + break; + } + case Decl::ObjCMethod: + Out << "[objc method]"; + break; + case Decl::ObjCInterface: + Out << "[objc interface]"; + break; + case Decl::ObjCCategory: + Out << "[objc category]"; + break; + case Decl::ObjCProtocol: + Out << "[objc protocol]"; + break; + case Decl::ObjCImplementation: + Out << "[objc implementation]"; + break; + case Decl::ObjCCategoryImpl: + Out << "[objc categoryimpl]"; + break; + case Decl::LinkageSpec: + Out << "[linkage spec]"; + break; + case Decl::Block: + Out << "[block]"; + break; + case Decl::Function: { + const FunctionDecl* FD = cast<FunctionDecl>(DC); + if (FD->isThisDeclarationADefinition()) + Out << "[function] "; + else + Out << "<function> "; + Out << FD; + // Print the parameters. + Out << "("; + bool PrintComma = false; + for (FunctionDecl::param_const_iterator I = FD->param_begin(), + E = FD->param_end(); I != E; ++I) { + if (PrintComma) + Out << ", "; + else + PrintComma = true; + Out << *I; + } + Out << ")"; + break; + } + case Decl::CXXMethod: { + const CXXMethodDecl* D = cast<CXXMethodDecl>(DC); + if (D->isOutOfLine()) + Out << "[c++ method] "; + else if (D->isImplicit()) + Out << "(c++ method) "; + else + Out << "<c++ method> "; + Out << D; + // Print the parameters. + Out << "("; + bool PrintComma = false; + for (FunctionDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); I != E; ++I) { + if (PrintComma) + Out << ", "; + else + PrintComma = true; + Out << *I; + } + Out << ")"; + + // Check the semantic DeclContext. + const DeclContext* SemaDC = D->getDeclContext(); + const DeclContext* LexicalDC = D->getLexicalDeclContext(); + if (SemaDC != LexicalDC) + Out << " [[" << SemaDC << "]]"; + + break; + } + case Decl::CXXConstructor: { + const CXXConstructorDecl* D = cast<CXXConstructorDecl>(DC); + if (D->isOutOfLine()) + Out << "[c++ ctor] "; + else if (D->isImplicit()) + Out << "(c++ ctor) "; + else + Out << "<c++ ctor> "; + Out << D; + // Print the parameters. + Out << "("; + bool PrintComma = false; + for (FunctionDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); I != E; ++I) { + if (PrintComma) + Out << ", "; + else + PrintComma = true; + Out << *I; + } + Out << ")"; + + // Check the semantic DC. + const DeclContext* SemaDC = D->getDeclContext(); + const DeclContext* LexicalDC = D->getLexicalDeclContext(); + if (SemaDC != LexicalDC) + Out << " [[" << SemaDC << "]]"; + break; + } + case Decl::CXXDestructor: { + const CXXDestructorDecl* D = cast<CXXDestructorDecl>(DC); + if (D->isOutOfLine()) + Out << "[c++ dtor] "; + else if (D->isImplicit()) + Out << "(c++ dtor) "; + else + Out << "<c++ dtor> "; + Out << D; + // Check the semantic DC. + const DeclContext* SemaDC = D->getDeclContext(); + const DeclContext* LexicalDC = D->getLexicalDeclContext(); + if (SemaDC != LexicalDC) + Out << " [[" << SemaDC << "]]"; + break; + } + case Decl::CXXConversion: { + const CXXConversionDecl* D = cast<CXXConversionDecl>(DC); + if (D->isOutOfLine()) + Out << "[c++ conversion] "; + else if (D->isImplicit()) + Out << "(c++ conversion) "; + else + Out << "<c++ conversion> "; + Out << D; + // Check the semantic DC. + const DeclContext* SemaDC = D->getDeclContext(); + const DeclContext* LexicalDC = D->getLexicalDeclContext(); + if (SemaDC != LexicalDC) + Out << " [[" << SemaDC << "]]"; + break; + } + + default: + assert(0 && "a decl that inherits DeclContext isn't handled"); + } + + Out << "\n"; + + // Print decls in the DeclContext. + for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + I != E; ++I) { + for (unsigned i = 0; i < Indentation; ++i) + Out << " "; + + Decl::Kind DK = I->getKind(); + switch (DK) { + case Decl::Namespace: + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ObjCMethod: + case Decl::ObjCInterface: + case Decl::ObjCCategory: + case Decl::ObjCProtocol: + case Decl::ObjCImplementation: + case Decl::ObjCCategoryImpl: + case Decl::LinkageSpec: + case Decl::Block: + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + { + DeclContext* DC = cast<DeclContext>(*I); + PrintDeclContext(DC, Indentation+2); + break; + } + case Decl::Field: { + FieldDecl* FD = cast<FieldDecl>(*I); + Out << "<field> " << FD << '\n'; + break; + } + case Decl::Typedef: { + TypedefDecl* TD = cast<TypedefDecl>(*I); + Out << "<typedef> " << TD << '\n'; + break; + } + case Decl::EnumConstant: { + EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I); + Out << "<enum constant> " << ECD << '\n'; + break; + } + case Decl::Var: { + VarDecl* VD = cast<VarDecl>(*I); + Out << "<var> " << VD << '\n'; + break; + } + case Decl::ImplicitParam: { + ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I); + Out << "<implicit parameter> " << IPD << '\n'; + break; + } + case Decl::ParmVar: { + ParmVarDecl* PVD = cast<ParmVarDecl>(*I); + Out << "<parameter> " << PVD << '\n'; + break; + } + case Decl::ObjCProperty: { + ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); + Out << "<objc property> " << OPD << '\n'; + break; + } + case Decl::FunctionTemplate: { + FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); + Out << "<function template> " << FTD << '\n'; + break; + } + case Decl::FileScopeAsm: { + Out << "<file-scope asm>\n"; + break; + } + case Decl::UsingDirective: { + Out << "<using directive>\n"; + break; + } + case Decl::NamespaceAlias: { + NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I); + Out << "<namespace alias> " << NAD << '\n'; + break; + } + case Decl::ClassTemplate: { + ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); + Out << "<class template> " << CTD << '\n'; + break; + } + default: + Out << "DeclKind: " << DK << '"' << *I << "\"\n"; + assert(0 && "decl unhandled"); + } + } +} +ASTConsumer *clang::CreateDeclContextPrinter() { + return new DeclContextPrinter(); +} + +//===----------------------------------------------------------------------===// +/// InheritanceViewer - C++ Inheritance Visualization + +namespace { +class InheritanceViewer : public ASTConsumer { + const std::string clsname; +public: + InheritanceViewer(const std::string& cname) : clsname(cname) {} + + void HandleTranslationUnit(ASTContext &C) { + for (ASTContext::type_iterator I=C.types_begin(),E=C.types_end(); I!=E; ++I) + if (RecordType *T = dyn_cast<RecordType>(*I)) { + if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(T->getDecl())) { + // FIXME: This lookup needs to be generalized to handle namespaces and + // (when we support them) templates. + if (D->getNameAsString() == clsname) { + D->viewInheritance(C); + } + } + } + } +}; +} + +ASTConsumer *clang::CreateInheritanceViewer(const std::string& clsname) { + return new InheritanceViewer(clsname); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp new file mode 100644 index 0000000..b0faf0a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp @@ -0,0 +1,104 @@ +//===-- ASTMerge.cpp - AST Merging Frontent Action --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/ASTImporter.h" +#include "clang/Basic/Diagnostic.h" + +using namespace clang; + +ASTConsumer *ASTMergeAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return AdaptedAction->CreateASTConsumer(CI, InFile); +} + +bool ASTMergeAction::BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename) { + // FIXME: This is a hack. We need a better way to communicate the + // AST file, compiler instance, and file name than member variables + // of FrontendAction. + AdaptedAction->setCurrentFile(getCurrentFile(), takeCurrentASTUnit()); + AdaptedAction->setCompilerInstance(&CI); + return AdaptedAction->BeginSourceFileAction(CI, Filename); +} + +void ASTMergeAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + CI.getDiagnostics().getClient()->BeginSourceFile( + CI.getASTContext().getLangOptions()); + CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, + &CI.getASTContext()); + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); + for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { + ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], Diags, false); + if (!Unit) + continue; + + ASTImporter Importer(CI.getDiagnostics(), + CI.getASTContext(), + CI.getFileManager(), + Unit->getASTContext(), + Unit->getFileManager()); + + TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); + for (DeclContext::decl_iterator D = TU->decls_begin(), + DEnd = TU->decls_end(); + D != DEnd; ++D) { + // Don't re-import __va_list_tag, __builtin_va_list. + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (IdentifierInfo *II = ND->getIdentifier()) + if (II->isStr("__va_list_tag") || II->isStr("__builtin_va_list")) + continue; + + Importer.Import(*D); + } + + delete Unit; + } + + AdaptedAction->ExecuteAction(); + CI.getDiagnostics().getClient()->EndSourceFile(); +} + +void ASTMergeAction::EndSourceFileAction() { + return AdaptedAction->EndSourceFileAction(); +} + +ASTMergeAction::ASTMergeAction(FrontendAction *AdaptedAction, + std::string *ASTFiles, unsigned NumASTFiles) + : AdaptedAction(AdaptedAction), ASTFiles(ASTFiles, ASTFiles + NumASTFiles) { + assert(AdaptedAction && "ASTMergeAction needs an action to adapt"); +} + +ASTMergeAction::~ASTMergeAction() { + delete AdaptedAction; +} + +bool ASTMergeAction::usesPreprocessorOnly() const { + return AdaptedAction->usesPreprocessorOnly(); +} + +bool ASTMergeAction::usesCompleteTranslationUnit() { + return AdaptedAction->usesCompleteTranslationUnit(); +} + +bool ASTMergeAction::hasPCHSupport() const { + return AdaptedAction->hasPCHSupport(); +} + +bool ASTMergeAction::hasASTSupport() const { + return AdaptedAction->hasASTSupport(); +} + +bool ASTMergeAction::hasCodeCompletionSupport() const { + return AdaptedAction->hasCodeCompletionSupport(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp new file mode 100644 index 0000000..4730bdc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -0,0 +1,459 @@ +//===--- ASTUnit.cpp - ASTUnit utility ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTUnit Implementation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/PCHReader.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Tool.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +using namespace clang; + +ASTUnit::ASTUnit(bool _MainFileIsAST) + : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { } + +ASTUnit::~ASTUnit() { + ConcurrencyCheckValue = CheckLocked; + for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) + TemporaryFiles[I].eraseFromDisk(); +} + +namespace { + +/// \brief Gathers information from PCHReader that will be used to initialize +/// a Preprocessor. +class PCHInfoCollector : public PCHReaderListener { + LangOptions &LangOpt; + HeaderSearch &HSI; + std::string &TargetTriple; + std::string &Predefines; + unsigned &Counter; + + unsigned NumHeaderInfos; + +public: + PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, + std::string &TargetTriple, std::string &Predefines, + unsigned &Counter) + : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), + Predefines(Predefines), Counter(Counter), NumHeaderInfos(0) {} + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + LangOpt = LangOpts; + return false; + } + + virtual bool ReadTargetTriple(llvm::StringRef Triple) { + TargetTriple = Triple; + return false; + } + + virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef, + FileID PCHBufferID, + llvm::StringRef OriginalFileName, + std::string &SuggestedPredefines) { + Predefines = PCHPredef; + return false; + } + + virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) { + HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); + } + + virtual void ReadCounter(unsigned Value) { + Counter = Value; + } +}; + +class StoredDiagnosticClient : public DiagnosticClient { + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags; + +public: + explicit StoredDiagnosticClient( + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + : StoredDiags(StoredDiags) { } + + virtual void HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info); +}; + +/// \brief RAII object that optionally captures diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + Diagnostic &Diags; + StoredDiagnosticClient Client; + DiagnosticClient *PreviousClient; + +public: + CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, + llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags) + : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient()) + { + if (RequestCapture || Diags.getClient() == 0) + Diags.setClient(&Client); + } + + ~CaptureDroppedDiagnostics() { + Diags.setClient(PreviousClient); + } +}; + +} // anonymous namespace + +void StoredDiagnosticClient::HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) { + StoredDiags.push_back(StoredDiagnostic(Level, Info)); +} + +const std::string &ASTUnit::getOriginalSourceFileName() { + return OriginalSourceFile; +} + +const std::string &ASTUnit::getPCHFileName() { + assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); + return static_cast<PCHReader *>(Ctx->getExternalSource())->getFileName(); +} + +ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + bool OnlyLocalDecls, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles, + bool CaptureDiagnostics) { + llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); + + if (!Diags.getPtr()) { + // No diagnostics engine was provided, so create our own diagnostics object + // with the default options. + DiagnosticOptions DiagOpts; + Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + } + + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->Diagnostics = Diags; + AST->FileMgr.reset(new FileManager); + AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics())); + AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); + + // If requested, capture diagnostics in the ASTUnit. + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(), + AST->StoredDiagnostics); + + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + RemappedFiles[I].second->getBufferSize(), + 0); + if (!FromFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + delete RemappedFiles[I].second; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, + RemappedFiles[I].second); + } + + // Gather Info for preprocessor construction later on. + + LangOptions LangInfo; + HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); + std::string TargetTriple; + std::string Predefines; + unsigned Counter; + + llvm::OwningPtr<PCHReader> Reader; + llvm::OwningPtr<ExternalASTSource> Source; + + Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), + AST->getDiagnostics())); + Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, + Predefines, Counter)); + + switch (Reader->ReadPCH(Filename)) { + case PCHReader::Success: + break; + + case PCHReader::Failure: + case PCHReader::IgnorePCH: + AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); + return NULL; + } + + AST->OriginalSourceFile = Reader->getOriginalSourceFile(); + + // PCH loaded successfully. Now create the preprocessor. + + // Get information about the target being compiled for. + // + // FIXME: This is broken, we should store the TargetOptions in the PCH. + TargetOptions TargetOpts; + TargetOpts.ABI = ""; + TargetOpts.CPU = ""; + TargetOpts.Features.clear(); + TargetOpts.Triple = TargetTriple; + AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(), + TargetOpts)); + AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo, + *AST->Target.get(), + AST->getSourceManager(), HeaderInfo)); + Preprocessor &PP = *AST->PP.get(); + + PP.setPredefines(Reader->getSuggestedPredefines()); + PP.setCounterValue(Counter); + Reader->setPreprocessor(PP); + + // Create and initialize the ASTContext. + + AST->Ctx.reset(new ASTContext(LangInfo, + AST->getSourceManager(), + *AST->Target.get(), + PP.getIdentifierTable(), + PP.getSelectorTable(), + PP.getBuiltinInfo(), + /* FreeMemory = */ false, + /* size_reserve = */0)); + ASTContext &Context = *AST->Ctx.get(); + + Reader->InitializeContext(Context); + + // Attach the PCH reader to the AST context as an external AST + // source, so that declarations will be deserialized from the + // PCH file as needed. + Source.reset(Reader.take()); + Context.setExternalSource(Source); + + return AST.take(); +} + +namespace { + +class TopLevelDeclTrackerConsumer : public ASTConsumer { + ASTUnit &Unit; + +public: + TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} + + void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { + Decl *D = *it; + // FIXME: Currently ObjC method declarations are incorrectly being + // reported as top-level declarations, even though their DeclContext + // is the containing ObjC @interface/@implementation. This is a + // fundamental problem in the parser right now. + if (isa<ObjCMethodDecl>(D)) + continue; + Unit.getTopLevelDecls().push_back(D); + } + } +}; + +class TopLevelDeclTrackerAction : public ASTFrontendAction { +public: + ASTUnit &Unit; + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new TopLevelDeclTrackerConsumer(Unit); + } + +public: + TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} + + virtual bool hasCodeCompletionSupport() const { return false; } +}; + +} + +ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + bool OnlyLocalDecls, + bool CaptureDiagnostics) { + // Create the compiler instance to use for building the AST. + CompilerInstance Clang; + llvm::OwningPtr<ASTUnit> AST; + llvm::OwningPtr<TopLevelDeclTrackerAction> Act; + + if (!Diags.getPtr()) { + // No diagnostics engine was provided, so create our own diagnostics object + // with the default options. + DiagnosticOptions DiagOpts; + Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + } + + Clang.setInvocation(CI); + + Clang.setDiagnostics(Diags.getPtr()); + Clang.setDiagnosticClient(Diags->getClient()); + + // Create the target instance. + Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), + Clang.getTargetOpts())); + if (!Clang.hasTarget()) { + Clang.takeDiagnosticClient(); + return 0; + } + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + + assert(Clang.getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST && + "FIXME: AST inputs not yet supported here!"); + + // Create the AST unit. + AST.reset(new ASTUnit(false)); + AST->Diagnostics = Diags; + AST->FileMgr.reset(new FileManager); + AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics())); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + + // Capture any diagnostics that would otherwise be dropped. + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, + Clang.getDiagnostics(), + AST->StoredDiagnostics); + + // Create a file manager object to provide access to and cache the filesystem. + Clang.setFileManager(&AST->getFileManager()); + + // Create the source manager. + Clang.setSourceManager(&AST->getSourceManager()); + + // Create the preprocessor. + Clang.createPreprocessor(); + + Act.reset(new TopLevelDeclTrackerAction(*AST)); + if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + /*IsAST=*/false)) + goto error; + + Act->Execute(); + + // Steal the created target, context, and preprocessor, and take back the + // source and file managers. + AST->Ctx.reset(Clang.takeASTContext()); + AST->PP.reset(Clang.takePreprocessor()); + Clang.takeSourceManager(); + Clang.takeFileManager(); + AST->Target.reset(Clang.takeTarget()); + + Act->EndSourceFile(); + + Clang.takeDiagnosticClient(); + Clang.takeInvocation(); + + AST->Invocation.reset(Clang.takeInvocation()); + return AST.take(); + +error: + Clang.takeSourceManager(); + Clang.takeFileManager(); + Clang.takeDiagnosticClient(); + return 0; +} + +ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags, + llvm::StringRef ResourceFilesPath, + bool OnlyLocalDecls, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles, + bool CaptureDiagnostics) { + if (!Diags.getPtr()) { + // No diagnostics engine was provided, so create our own diagnostics object + // with the default options. + DiagnosticOptions DiagOpts; + Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + } + + llvm::SmallVector<const char *, 16> Args; + Args.push_back("<clang>"); // FIXME: Remove dummy argument. + Args.insert(Args.end(), ArgBegin, ArgEnd); + + // FIXME: Find a cleaner way to force the driver into restricted modes. We + // also want to force it to use clang. + Args.push_back("-fsyntax-only"); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), + "a.out", false, false, *Diags); + + // Don't check that inputs exist, they have been remapped. + TheDriver.setCheckInputsExist(false); + + llvm::OwningPtr<driver::Compilation> C( + TheDriver.BuildCompilation(Args.size(), Args.data())); + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } + + const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags->Report(diag::err_fe_expected_clang_command); + return 0; + } + + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation); + CompilerInvocation::CreateFromArgs(*CI, + const_cast<const char **>(CCArgs.data()), + const_cast<const char **>(CCArgs.data()) + + CCArgs.size(), + *Diags); + + // Override any files that need remapping + for (unsigned I = 0; I != NumRemappedFiles; ++I) + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + + CI->getFrontendOpts().DisableFree = true; + return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, + CaptureDiagnostics); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/AnalysisConsumer.cpp new file mode 100644 index 0000000..6a47279 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/AnalysisConsumer.cpp @@ -0,0 +1,587 @@ +//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// "Meta" ASTConsumer for running different source analyses. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/AnalysisConsumer.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ParentMap.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/CFG.h" +#include "clang/Checker/Checkers/LocalCheckers.h" +#include "clang/Checker/ManagerRegistry.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Checker/PathSensitive/GRTransferFuncs.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/PathDiagnosticClients.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +#include "llvm/ADT/OwningPtr.h" + +using namespace clang; + +static ExplodedNode::Auditor* CreateUbiViz(); + +//===----------------------------------------------------------------------===// +// Special PathDiagnosticClients. +//===----------------------------------------------------------------------===// + +static PathDiagnosticClient* +CreatePlistHTMLDiagnosticClient(const std::string& prefix, + const Preprocessor &PP) { + llvm::sys::Path F(prefix); + PathDiagnosticClient *PD = CreateHTMLDiagnosticClient(F.getDirname(), PP); + return CreatePlistDiagnosticClient(prefix, PP, PD); +} + +//===----------------------------------------------------------------------===// +// AnalysisConsumer declaration. +//===----------------------------------------------------------------------===// + +namespace { + +class AnalysisConsumer : public ASTConsumer { +public: + typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); + typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, + TranslationUnitDecl &TU); + +private: + typedef std::vector<CodeAction> Actions; + typedef std::vector<TUAction> TUActions; + + Actions FunctionActions; + Actions ObjCMethodActions; + Actions ObjCImplementationActions; + Actions CXXMethodActions; + TUActions TranslationUnitActions; // Remove this. + +public: + ASTContext* Ctx; + const Preprocessor &PP; + const std::string OutDir; + AnalyzerOptions Opts; + bool declDisplayed; + + + // PD is owned by AnalysisManager. + PathDiagnosticClient *PD; + + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + llvm::OwningPtr<AnalysisManager> Mgr; + + AnalysisConsumer(const Preprocessor& pp, + const std::string& outdir, + const AnalyzerOptions& opts) + : Ctx(0), PP(pp), OutDir(outdir), + Opts(opts), declDisplayed(false), PD(0) { + DigestAnalyzerOptions(); + } + + void DigestAnalyzerOptions() { + // Create the PathDiagnosticClient. + if (!OutDir.empty()) { + switch (Opts.AnalysisDiagOpt) { + default: +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ + case PD_##NAME: PD = CREATEFN(OutDir, PP); break; +#include "clang/Frontend/Analyses.def" + } + } + + // Create the analyzer component creators. + if (ManagerRegistry::StoreMgrCreator != 0) { + CreateStoreMgr = ManagerRegistry::StoreMgrCreator; + } + else { + switch (Opts.AnalysisStoreOpt) { + default: + assert(0 && "Unknown store manager."); +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ + case NAME##Model: CreateStoreMgr = CREATEFN; break; +#include "clang/Frontend/Analyses.def" + } + } + + if (ManagerRegistry::ConstraintMgrCreator != 0) + CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator; + else { + switch (Opts.AnalysisConstraintsOpt) { + default: + assert(0 && "Unknown store manager."); +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ + case NAME##Model: CreateConstraintMgr = CREATEFN; break; +#include "clang/Frontend/Analyses.def" + } + } + } + + void DisplayFunction(const Decl *D) { + if (!Opts.AnalyzerDisplayProgress || declDisplayed) + return; + + declDisplayed = true; + SourceManager &SM = Mgr->getASTContext().getSourceManager(); + PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); + llvm::errs() << "ANALYZE: " << Loc.getFilename(); + + if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { + const NamedDecl *ND = cast<NamedDecl>(D); + llvm::errs() << ' ' << ND << '\n'; + } + else if (isa<BlockDecl>(D)) { + llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" + << Loc.getColumn() << '\n'; + } + } + + void addCodeAction(CodeAction action) { + FunctionActions.push_back(action); + ObjCMethodActions.push_back(action); + CXXMethodActions.push_back(action); + } + + void addTranslationUnitAction(TUAction action) { + TranslationUnitActions.push_back(action); + } + + void addObjCImplementationAction(CodeAction action) { + ObjCImplementationActions.push_back(action); + } + + virtual void Initialize(ASTContext &Context) { + Ctx = &Context; + Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), + PP.getLangOptions(), PD, + CreateStoreMgr, CreateConstraintMgr, + Opts.MaxNodes, Opts.MaxLoop, + Opts.VisualizeEGDot, Opts.VisualizeEGUbi, + Opts.PurgeDead, Opts.EagerlyAssume, + Opts.TrimGraph, Opts.InlineCall)); + } + + virtual void HandleTranslationUnit(ASTContext &C); + void HandleCode(Decl *D, Stmt* Body, Actions& actions); +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// AnalysisConsumer implementation. +//===----------------------------------------------------------------------===// + +void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { + + TranslationUnitDecl *TU = C.getTranslationUnitDecl(); + + for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end(); + I != E; ++I) { + Decl *D = *I; + + switch (D->getKind()) { + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: + case Decl::Function: { + FunctionDecl* FD = cast<FunctionDecl>(D); + + if (FD->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) + break; + HandleCode(FD, FD->getBody(), FunctionActions); + } + break; + } + + case Decl::ObjCMethod: { + ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); + + if (MD->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) + break; + HandleCode(MD, MD->getBody(), ObjCMethodActions); + } + break; + } + + case Decl::ObjCImplementation: { + ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); + HandleCode(ID, 0, ObjCImplementationActions); + + for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), + ME = ID->meth_end(); MI != ME; ++MI) { + if ((*MI)->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) + break; + HandleCode(*MI, (*MI)->getBody(), ObjCMethodActions); + } + } + break; + } + + default: + break; + } + } + + for (TUActions::iterator I = TranslationUnitActions.begin(), + E = TranslationUnitActions.end(); I != E; ++I) { + (*I)(*this, *Mgr, *TU); + } + + // Explicitly destroy the PathDiagnosticClient. This will flush its output. + // FIXME: This should be replaced with something that doesn't rely on + // side-effects in PathDiagnosticClient's destructor. This is required when + // used with option -disable-free. + Mgr.reset(NULL); +} + +static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { + if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) + WL.push_back(BD); + + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I!=E; ++I) + if (DeclContext *DC = dyn_cast<DeclContext>(*I)) + FindBlocks(DC, WL); +} + +void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { + + // Don't run the actions if an error has occured with parsing the file. + Diagnostic &Diags = PP.getDiagnostics(); + if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) + return; + + // Don't run the actions on declarations in header files unless + // otherwise specified. + if (!Opts.AnalyzeAll && + !Ctx->getSourceManager().isFromMainFile(D->getLocation())) + return; + + // Clear the AnalysisManager of old AnalysisContexts. + Mgr->ClearContexts(); + + // Dispatch on the actions. + llvm::SmallVector<Decl*, 10> WL; + WL.push_back(D); + + if (Body && Opts.AnalyzeNestedBlocks) + FindBlocks(cast<DeclContext>(D), WL); + + for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) + for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); + WI != WE; ++WI) + (*I)(*this, *Mgr, *WI); +} + +//===----------------------------------------------------------------------===// +// Analyses +//===----------------------------------------------------------------------===// + +static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + if (LiveVariables *L = mgr.getLiveVariables(D)) { + BugReporter BR(mgr); + CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); + } +} + +static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + if (CFG* c = mgr.getCFG(D)) { + CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); + } +} + + +static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D, + GRTransferFuncs* tf) { + + llvm::OwningPtr<GRTransferFuncs> TF(tf); + + // Construct the analysis engine. We first query for the LiveVariables + // information to see if the CFG is valid. + // FIXME: Inter-procedural analysis will need to handle invalid CFGs. + if (!mgr.getLiveVariables(D)) + return; + GRExprEngine Eng(mgr, TF.take()); + + if (C.Opts.EnableExperimentalInternalChecks) + RegisterExperimentalInternalChecks(Eng); + + RegisterAppleChecks(Eng, *D); + + if (C.Opts.EnableExperimentalChecks) + RegisterExperimentalChecks(Eng); + + // Set the graph auditor. + llvm::OwningPtr<ExplodedNode::Auditor> Auditor; + if (mgr.shouldVisualizeUbigraph()) { + Auditor.reset(CreateUbiViz()); + ExplodedNode::SetAuditor(Auditor.get()); + } + + // Execute the worklist algorithm. + Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes()); + + // Release the auditor (if any) so that it doesn't monitor the graph + // created BugReporter. + ExplodedNode::SetAuditor(0); + + // Visualize the exploded graph. + if (mgr.shouldVisualizeGraphviz()) + Eng.ViewGraph(mgr.shouldTrimGraph()); + + // Display warnings. + Eng.getBugReporter().FlushReports(); +} + +static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D, bool GCEnabled) { + + GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), + GCEnabled, + mgr.getLangOptions()); + + ActionGRExprEngine(C, mgr, D, TF); +} + +static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + + switch (mgr.getLangOptions().getGCMode()) { + default: + assert (false && "Invalid GC mode."); + case LangOptions::NonGC: + ActionObjCMemCheckerAux(C, mgr, D, false); + break; + + case LangOptions::GCOnly: + ActionObjCMemCheckerAux(C, mgr, D, true); + break; + + case LangOptions::HybridGC: + ActionObjCMemCheckerAux(C, mgr, D, false); + ActionObjCMemCheckerAux(C, mgr, D, true); + break; + } +} + +static void ActionDisplayLiveVariables(AnalysisConsumer &C, + AnalysisManager& mgr, Decl *D) { + if (LiveVariables* L = mgr.getLiveVariables(D)) { + L->dumpBlockLiveness(mgr.getSourceManager()); + } +} + +static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + cfg->dump(mgr.getLangOptions()); + } +} + +static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { + if (CFG *cfg = mgr.getCFG(D)) { + cfg->viewCFG(mgr.getLangOptions()); + } +} + +static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, + AnalysisManager &mgr, Decl *D) { + BugReporter BR(mgr); + CheckSecuritySyntaxOnly(D, BR); +} + +static void ActionLLVMConventionChecker(AnalysisConsumer &C, + AnalysisManager &mgr, + TranslationUnitDecl &TU) { + BugReporter BR(mgr); + CheckLLVMConventions(TU, BR); +} + +static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) + return; + BugReporter BR(mgr); + CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); +} + +static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + BugReporter BR(mgr); + CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); +} + +static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D) { + BugReporter BR(mgr); + CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); +} + +static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, + Decl *D) { + BugReporter BR(mgr); + CheckSizeofPointer(D, BR); +} + +//===----------------------------------------------------------------------===// +// AnalysisConsumer creation. +//===----------------------------------------------------------------------===// + +ASTConsumer* clang::CreateAnalysisConsumer(const Preprocessor& pp, + const std::string& OutDir, + const AnalyzerOptions& Opts) { + llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); + + for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) + switch (Opts.AnalysisList[i]) { +#define ANALYSIS(NAME, CMD, DESC, SCOPE)\ + case NAME:\ + C->add ## SCOPE ## Action(&Action ## NAME);\ + break; +#include "clang/Frontend/Analyses.def" + default: break; + } + + // Last, disable the effects of '-Werror' when using the AnalysisConsumer. + pp.getDiagnostics().setWarningsAsErrors(false); + + return C.take(); +} + +//===----------------------------------------------------------------------===// +// Ubigraph Visualization. FIXME: Move to separate file. +//===----------------------------------------------------------------------===// + +namespace { + +class UbigraphViz : public ExplodedNode::Auditor { + llvm::OwningPtr<llvm::raw_ostream> Out; + llvm::sys::Path Dir, Filename; + unsigned Cntr; + + typedef llvm::DenseMap<void*,unsigned> VMap; + VMap M; + +public: + UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, + llvm::sys::Path& filename); + + ~UbigraphViz(); + + virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst); +}; + +} // end anonymous namespace + +static ExplodedNode::Auditor* CreateUbiViz() { + std::string ErrMsg; + + llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); + if (!ErrMsg.empty()) + return 0; + + llvm::sys::Path Filename = Dir; + Filename.appendComponent("llvm_ubi"); + Filename.makeUnique(true,&ErrMsg); + + if (!ErrMsg.empty()) + return 0; + + llvm::errs() << "Writing '" << Filename.str() << "'.\n"; + + llvm::OwningPtr<llvm::raw_fd_ostream> Stream; + Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg)); + + if (!ErrMsg.empty()) + return 0; + + return new UbigraphViz(Stream.take(), Dir, Filename); +} + +void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { + + assert (Src != Dst && "Self-edges are not allowed."); + + // Lookup the Src. If it is a new node, it's a root. + VMap::iterator SrcI= M.find(Src); + unsigned SrcID; + + if (SrcI == M.end()) { + M[Src] = SrcID = Cntr++; + *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; + } + else + SrcID = SrcI->second; + + // Lookup the Dst. + VMap::iterator DstI= M.find(Dst); + unsigned DstID; + + if (DstI == M.end()) { + M[Dst] = DstID = Cntr++; + *Out << "('vertex', " << DstID << ")\n"; + } + else { + // We have hit DstID before. Change its style to reflect a cache hit. + DstID = DstI->second; + *Out << "('change_vertex_style', " << DstID << ", 1)\n"; + } + + // Add the edge. + *Out << "('edge', " << SrcID << ", " << DstID + << ", ('arrow','true'), ('oriented', 'true'))\n"; +} + +UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, + llvm::sys::Path& filename) + : Out(out), Dir(dir), Filename(filename), Cntr(0) { + + *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; + *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," + " ('size', '1.5'))\n"; +} + +UbigraphViz::~UbigraphViz() { + Out.reset(0); + llvm::errs() << "Running 'ubiviz' program... "; + std::string ErrMsg; + llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz"); + std::vector<const char*> args; + args.push_back(Ubiviz.c_str()); + args.push_back(Filename.c_str()); + args.push_back(0); + + if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) { + llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; + } + + // Delete the directory. + Dir.eraseFromDisk(true); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp new file mode 100644 index 0000000..ae150c6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/BoostConAction.cpp @@ -0,0 +1,39 @@ +//===-- BoostConAction.cpp - BoostCon Workshop Action -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include <cstdio> +#include <iostream> +using namespace clang; + +namespace { + class BoostConASTConsumer : public ASTConsumer, + public RecursiveASTVisitor<BoostConASTConsumer> { + public: + /// HandleTranslationUnit - This method is called when the ASTs for entire + /// translation unit have been parsed. + virtual void HandleTranslationUnit(ASTContext &Ctx); + + bool VisitCXXRecordDecl(CXXRecordDecl *D) { + std::cout << D->getNameAsString() << std::endl; + return false; + } + }; +} + +ASTConsumer *BoostConAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new BoostConASTConsumer(); +} + +void BoostConASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { + fprintf(stderr, "Welcome to BoostCon!\n"); + Visit(Ctx.getTranslationUnitDecl()); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt new file mode 100644 index 0000000..01592d1 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CMakeLists.txt @@ -0,0 +1,59 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangFrontend + ASTConsumers.cpp + ASTMerge.cpp + ASTUnit.cpp + AnalysisConsumer.cpp + BoostConAction.cpp + CacheTokens.cpp + CodeGenAction.cpp + CompilerInstance.cpp + CompilerInvocation.cpp + DeclXML.cpp + DependencyFile.cpp + DiagChecker.cpp + DocumentXML.cpp + FixItRewriter.cpp + FrontendAction.cpp + FrontendActions.cpp + FrontendOptions.cpp + GeneratePCH.cpp + HTMLDiagnostics.cpp + HTMLPrint.cpp + InitHeaderSearch.cpp + InitPreprocessor.cpp + LangStandards.cpp + PCHReader.cpp + PCHReaderDecl.cpp + PCHReaderStmt.cpp + PCHWriter.cpp + PCHWriterDecl.cpp + PCHWriterStmt.cpp + PlistDiagnostics.cpp + PrintParserCallbacks.cpp + PrintPreprocessedOutput.cpp + RewriteMacros.cpp + RewriteObjC.cpp + RewriteTest.cpp + StmtXML.cpp + TextDiagnosticBuffer.cpp + TextDiagnosticPrinter.cpp + TypeXML.cpp + VerifyDiagnosticsClient.cpp + Warnings.cpp + ) + +IF(MSVC) + get_target_property(NON_ANSI_COMPILE_FLAGS clangFrontend COMPILE_FLAGS) + string(REPLACE /Za + "" NON_ANSI_COMPILE_FLAGS + ${NON_ANSI_COMPILE_FLAGS}) + set_target_properties(clangFrontend PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) +ENDIF(MSVC) + +add_dependencies(clangFrontend + ClangDiagnosticFrontend + ClangDiagnosticLex + ClangDiagnosticSema + ClangStmtNodes) diff --git a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp new file mode 100644 index 0000000..a5fcebe --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp @@ -0,0 +1,649 @@ +//===--- CacheTokens.cpp - Caching of lexer tokens for PTH support --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides a possible implementation of PTH support for Clang that is +// based on caching lexed tokens and identifiers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" + +// FIXME: put this somewhere else? +#ifndef S_ISDIR +#define S_ISDIR(x) (((x)&_S_IFDIR)!=0) +#endif + +using namespace clang; +using namespace clang::io; + +//===----------------------------------------------------------------------===// +// PTH-specific stuff. +//===----------------------------------------------------------------------===// + +namespace { +class PTHEntry { + Offset TokenData, PPCondData; + +public: + PTHEntry() {} + + PTHEntry(Offset td, Offset ppcd) + : TokenData(td), PPCondData(ppcd) {} + + Offset getTokenOffset() const { return TokenData; } + Offset getPPCondTableOffset() const { return PPCondData; } +}; + + +class PTHEntryKeyVariant { + union { const FileEntry* FE; const char* Path; }; + enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind; + struct stat *StatBuf; +public: + PTHEntryKeyVariant(const FileEntry *fe) + : FE(fe), Kind(IsFE), StatBuf(0) {} + + PTHEntryKeyVariant(struct stat* statbuf, const char* path) + : Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {} + + explicit PTHEntryKeyVariant(const char* path) + : Path(path), Kind(IsNoExist), StatBuf(0) {} + + bool isFile() const { return Kind == IsFE; } + + llvm::StringRef getString() const { + return Kind == IsFE ? FE->getName() : Path; + } + + unsigned getKind() const { return (unsigned) Kind; } + + void EmitData(llvm::raw_ostream& Out) { + switch (Kind) { + case IsFE: + // Emit stat information. + ::Emit32(Out, FE->getInode()); + ::Emit32(Out, FE->getDevice()); + ::Emit16(Out, FE->getFileMode()); + ::Emit64(Out, FE->getModificationTime()); + ::Emit64(Out, FE->getSize()); + break; + case IsDE: + // Emit stat information. + ::Emit32(Out, (uint32_t) StatBuf->st_ino); + ::Emit32(Out, (uint32_t) StatBuf->st_dev); + ::Emit16(Out, (uint16_t) StatBuf->st_mode); + ::Emit64(Out, (uint64_t) StatBuf->st_mtime); + ::Emit64(Out, (uint64_t) StatBuf->st_size); + delete StatBuf; + break; + default: + break; + } + } + + unsigned getRepresentationLength() const { + return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8; + } +}; + +class FileEntryPTHEntryInfo { +public: + typedef PTHEntryKeyVariant key_type; + typedef key_type key_type_ref; + + typedef PTHEntry data_type; + typedef const PTHEntry& data_type_ref; + + static unsigned ComputeHash(PTHEntryKeyVariant V) { + return llvm::HashString(V.getString()); + } + + static std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + const PTHEntry& E) { + + unsigned n = V.getString().size() + 1 + 1; + ::Emit16(Out, n); + + unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0); + ::Emit8(Out, m); + + return std::make_pair(n, m); + } + + static void EmitKey(llvm::raw_ostream& Out, PTHEntryKeyVariant V, unsigned n){ + // Emit the entry kind. + ::Emit8(Out, (unsigned) V.getKind()); + // Emit the string. + Out.write(V.getString().data(), n - 1); + } + + static void EmitData(llvm::raw_ostream& Out, PTHEntryKeyVariant V, + const PTHEntry& E, unsigned) { + + + // For file entries emit the offsets into the PTH file for token data + // and the preprocessor blocks table. + if (V.isFile()) { + ::Emit32(Out, E.getTokenOffset()); + ::Emit32(Out, E.getPPCondTableOffset()); + } + + // Emit any other data associated with the key (i.e., stat information). + V.EmitData(Out); + } +}; + +class OffsetOpt { + bool valid; + Offset off; +public: + OffsetOpt() : valid(false) {} + bool hasOffset() const { return valid; } + Offset getOffset() const { assert(valid); return off; } + void setOffset(Offset o) { off = o; valid = true; } +}; +} // end anonymous namespace + +typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap; + +namespace { +class PTHWriter { + typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap; + typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy; + + IDMap IM; + llvm::raw_fd_ostream& Out; + Preprocessor& PP; + uint32_t idcount; + PTHMap PM; + CachedStrsTy CachedStrs; + Offset CurStrOffset; + std::vector<llvm::StringMapEntry<OffsetOpt>*> StrEntries; + + //// Get the persistent id for the given IdentifierInfo*. + uint32_t ResolveID(const IdentifierInfo* II); + + /// Emit a token to the PTH file. + void EmitToken(const Token& T); + + void Emit8(uint32_t V) { ::Emit8(Out, V); } + + void Emit16(uint32_t V) { ::Emit16(Out, V); } + + void Emit24(uint32_t V) { ::Emit24(Out, V); } + + void Emit32(uint32_t V) { ::Emit32(Out, V); } + + void EmitBuf(const char *Ptr, unsigned NumBytes) { + Out.write(Ptr, NumBytes); + } + + void EmitString(llvm::StringRef V) { + ::Emit16(Out, V.size()); + EmitBuf(V.data(), V.size()); + } + + /// EmitIdentifierTable - Emits two tables to the PTH file. The first is + /// a hashtable mapping from identifier strings to persistent IDs. + /// The second is a straight table mapping from persistent IDs to string data + /// (the keys of the first table). + std::pair<Offset, Offset> EmitIdentifierTable(); + + /// EmitFileTable - Emit a table mapping from file name strings to PTH + /// token data. + Offset EmitFileTable() { return PM.Emit(Out); } + + PTHEntry LexTokens(Lexer& L); + Offset EmitCachedSpellings(); + +public: + PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp) + : Out(out), PP(pp), idcount(0), CurStrOffset(0) {} + + PTHMap &getPM() { return PM; } + void GeneratePTH(const std::string &MainFile); +}; +} // end anonymous namespace + +uint32_t PTHWriter::ResolveID(const IdentifierInfo* II) { + // Null IdentifierInfo's map to the persistent ID 0. + if (!II) + return 0; + + IDMap::iterator I = IM.find(II); + if (I != IM.end()) + return I->second; // We've already added 1. + + IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL. + return idcount; +} + +void PTHWriter::EmitToken(const Token& T) { + // Emit the token kind, flags, and length. + Emit32(((uint32_t) T.getKind()) | ((((uint32_t) T.getFlags())) << 8)| + (((uint32_t) T.getLength()) << 16)); + + if (!T.isLiteral()) { + Emit32(ResolveID(T.getIdentifierInfo())); + } else { + // We cache *un-cleaned* spellings. This gives us 100% fidelity with the + // source code. + const char* s = T.getLiteralData(); + unsigned len = T.getLength(); + + // Get the string entry. + llvm::StringMapEntry<OffsetOpt> *E = &CachedStrs.GetOrCreateValue(s, s+len); + + // If this is a new string entry, bump the PTH offset. + if (!E->getValue().hasOffset()) { + E->getValue().setOffset(CurStrOffset); + StrEntries.push_back(E); + CurStrOffset += len + 1; + } + + // Emit the relative offset into the PTH file for the spelling string. + Emit32(E->getValue().getOffset()); + } + + // Emit the offset into the original source file of this token so that we + // can reconstruct its SourceLocation. + Emit32(PP.getSourceManager().getFileOffset(T.getLocation())); +} + +PTHEntry PTHWriter::LexTokens(Lexer& L) { + // Pad 0's so that we emit tokens to a 4-byte alignment. + // This speed up reading them back in. + Pad(Out, 4); + Offset TokenOff = (Offset) Out.tell(); + + // Keep track of matching '#if' ... '#endif'. + typedef std::vector<std::pair<Offset, unsigned> > PPCondTable; + PPCondTable PPCond; + std::vector<unsigned> PPStartCond; + bool ParsingPreprocessorDirective = false; + Token Tok; + + do { + L.LexFromRawLexer(Tok); + NextToken: + + if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) && + ParsingPreprocessorDirective) { + // Insert an eom token into the token cache. It has the same + // position as the next token that is not on the same line as the + // preprocessor directive. Observe that we continue processing + // 'Tok' when we exit this branch. + Token Tmp = Tok; + Tmp.setKind(tok::eom); + Tmp.clearFlag(Token::StartOfLine); + Tmp.setIdentifierInfo(0); + EmitToken(Tmp); + ParsingPreprocessorDirective = false; + } + + if (Tok.is(tok::identifier)) { + PP.LookUpIdentifierInfo(Tok); + EmitToken(Tok); + continue; + } + + if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { + // Special processing for #include. Store the '#' token and lex + // the next token. + assert(!ParsingPreprocessorDirective); + Offset HashOff = (Offset) Out.tell(); + EmitToken(Tok); + + // Get the next token. + L.LexFromRawLexer(Tok); + + // If we see the start of line, then we had a null directive "#". + if (Tok.isAtStartOfLine()) + goto NextToken; + + // Did we see 'include'/'import'/'include_next'? + if (Tok.isNot(tok::identifier)) { + EmitToken(Tok); + continue; + } + + IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok); + tok::PPKeywordKind K = II->getPPKeywordID(); + + ParsingPreprocessorDirective = true; + + switch (K) { + case tok::pp_not_keyword: + // Invalid directives "#foo" can occur in #if 0 blocks etc, just pass + // them through. + default: + break; + + case tok::pp_include: + case tok::pp_import: + case tok::pp_include_next: { + // Save the 'include' token. + EmitToken(Tok); + // Lex the next token as an include string. + L.setParsingPreprocessorDirective(true); + L.LexIncludeFilename(Tok); + L.setParsingPreprocessorDirective(false); + assert(!Tok.isAtStartOfLine()); + if (Tok.is(tok::identifier)) + PP.LookUpIdentifierInfo(Tok); + + break; + } + case tok::pp_if: + case tok::pp_ifdef: + case tok::pp_ifndef: { + // Add an entry for '#if' and friends. We initially set the target + // index to 0. This will get backpatched when we hit #endif. + PPStartCond.push_back(PPCond.size()); + PPCond.push_back(std::make_pair(HashOff, 0U)); + break; + } + case tok::pp_endif: { + // Add an entry for '#endif'. We set the target table index to itself. + // This will later be set to zero when emitting to the PTH file. We + // use 0 for uninitialized indices because that is easier to debug. + unsigned index = PPCond.size(); + // Backpatch the opening '#if' entry. + assert(!PPStartCond.empty()); + assert(PPCond.size() > PPStartCond.back()); + assert(PPCond[PPStartCond.back()].second == 0); + PPCond[PPStartCond.back()].second = index; + PPStartCond.pop_back(); + // Add the new entry to PPCond. + PPCond.push_back(std::make_pair(HashOff, index)); + EmitToken(Tok); + + // Some files have gibberish on the same line as '#endif'. + // Discard these tokens. + do + L.LexFromRawLexer(Tok); + while (Tok.isNot(tok::eof) && !Tok.isAtStartOfLine()); + // We have the next token in hand. + // Don't immediately lex the next one. + goto NextToken; + } + case tok::pp_elif: + case tok::pp_else: { + // Add an entry for #elif or #else. + // This serves as both a closing and opening of a conditional block. + // This means that its entry will get backpatched later. + unsigned index = PPCond.size(); + // Backpatch the previous '#if' entry. + assert(!PPStartCond.empty()); + assert(PPCond.size() > PPStartCond.back()); + assert(PPCond[PPStartCond.back()].second == 0); + PPCond[PPStartCond.back()].second = index; + PPStartCond.pop_back(); + // Now add '#elif' as a new block opening. + PPCond.push_back(std::make_pair(HashOff, 0U)); + PPStartCond.push_back(index); + break; + } + } + } + + EmitToken(Tok); + } + while (Tok.isNot(tok::eof)); + + assert(PPStartCond.empty() && "Error: imblanced preprocessor conditionals."); + + // Next write out PPCond. + Offset PPCondOff = (Offset) Out.tell(); + + // Write out the size of PPCond so that clients can identifer empty tables. + Emit32(PPCond.size()); + + for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) { + Emit32(PPCond[i].first - TokenOff); + uint32_t x = PPCond[i].second; + assert(x != 0 && "PPCond entry not backpatched."); + // Emit zero for #endifs. This allows us to do checking when + // we read the PTH file back in. + Emit32(x == i ? 0 : x); + } + + return PTHEntry(TokenOff, PPCondOff); +} + +Offset PTHWriter::EmitCachedSpellings() { + // Write each cached strings to the PTH file. + Offset SpellingsOff = Out.tell(); + + for (std::vector<llvm::StringMapEntry<OffsetOpt>*>::iterator + I = StrEntries.begin(), E = StrEntries.end(); I!=E; ++I) + EmitBuf((*I)->getKeyData(), (*I)->getKeyLength()+1 /*nul included*/); + + return SpellingsOff; +} + +void PTHWriter::GeneratePTH(const std::string &MainFile) { + // Generate the prologue. + Out << "cfe-pth"; + Emit32(PTHManager::Version); + + // Leave 4 words for the prologue. + Offset PrologueOffset = Out.tell(); + for (unsigned i = 0; i < 4; ++i) + Emit32(0); + + // Write the name of the MainFile. + if (!MainFile.empty()) { + EmitString(MainFile); + } else { + // String with 0 bytes. + Emit16(0); + } + Emit8(0); + + // Iterate over all the files in SourceManager. Create a lexer + // for each file and cache the tokens. + SourceManager &SM = PP.getSourceManager(); + const LangOptions &LOpts = PP.getLangOptions(); + + for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(), + E = SM.fileinfo_end(); I != E; ++I) { + const SrcMgr::ContentCache &C = *I->second; + const FileEntry *FE = C.Entry; + + // FIXME: Handle files with non-absolute paths. + llvm::sys::Path P(FE->getName()); + if (!P.isAbsolute()) + continue; + + const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM); + if (!B) continue; + + FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer L(FID, FromFile, SM, LOpts); + PM.insert(FE, LexTokens(L)); + } + + // Write out the identifier table. + const std::pair<Offset,Offset> &IdTableOff = EmitIdentifierTable(); + + // Write out the cached strings table. + Offset SpellingOff = EmitCachedSpellings(); + + // Write out the file table. + Offset FileTableOff = EmitFileTable(); + + // Finally, write the prologue. + Out.seek(PrologueOffset); + Emit32(IdTableOff.first); + Emit32(IdTableOff.second); + Emit32(FileTableOff); + Emit32(SpellingOff); +} + +namespace { +/// StatListener - A simple "interpose" object used to monitor stat calls +/// invoked by FileManager while processing the original sources used +/// as input to PTH generation. StatListener populates the PTHWriter's +/// file map with stat information for directories as well as negative stats. +/// Stat information for files are populated elsewhere. +class StatListener : public StatSysCallCache { + PTHMap &PM; +public: + StatListener(PTHMap &pm) : PM(pm) {} + ~StatListener() {} + + int stat(const char *path, struct stat *buf) { + int result = StatSysCallCache::stat(path, buf); + + if (result != 0) // Failed 'stat'. + PM.insert(PTHEntryKeyVariant(path), PTHEntry()); + else if (S_ISDIR(buf->st_mode)) { + // Only cache directories with absolute paths. + if (!llvm::sys::Path(path).isAbsolute()) + return result; + + PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry()); + } + + return result; + } +}; +} // end anonymous namespace + + +void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { + // Get the name of the main file. + const SourceManager &SrcMgr = PP.getSourceManager(); + const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); + llvm::sys::Path MainFilePath(MainFile->getName()); + + MainFilePath.makeAbsolute(); + + // Create the PTHWriter. + PTHWriter PW(*OS, PP); + + // Install the 'stat' system call listener in the FileManager. + StatListener *StatCache = new StatListener(PW.getPM()); + PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true); + + // Lex through the entire file. This will populate SourceManager with + // all of the header information. + Token Tok; + PP.EnterMainSourceFile(); + do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); + + // Generate the PTH file. + PP.getFileManager().removeStatCache(StatCache); + PW.GeneratePTH(MainFilePath.str()); +} + +//===----------------------------------------------------------------------===// + +namespace { +class PTHIdKey { +public: + const IdentifierInfo* II; + uint32_t FileOffset; +}; + +class PTHIdentifierTableTrait { +public: + typedef PTHIdKey* key_type; + typedef key_type key_type_ref; + + typedef uint32_t data_type; + typedef data_type data_type_ref; + + static unsigned ComputeHash(PTHIdKey* key) { + return llvm::HashString(key->II->getName()); + } + + static std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) { + unsigned n = key->II->getLength() + 1; + ::Emit16(Out, n); + return std::make_pair(n, sizeof(uint32_t)); + } + + static void EmitKey(llvm::raw_ostream& Out, PTHIdKey* key, unsigned n) { + // Record the location of the key data. This is used when generating + // the mapping from persistent IDs to strings. + key->FileOffset = Out.tell(); + Out.write(key->II->getNameStart(), n); + } + + static void EmitData(llvm::raw_ostream& Out, PTHIdKey*, uint32_t pID, + unsigned) { + ::Emit32(Out, pID); + } +}; +} // end anonymous namespace + +/// EmitIdentifierTable - Emits two tables to the PTH file. The first is +/// a hashtable mapping from identifier strings to persistent IDs. The second +/// is a straight table mapping from persistent IDs to string data (the +/// keys of the first table). +/// +std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() { + // Build two maps: + // (1) an inverse map from persistent IDs -> (IdentifierInfo*,Offset) + // (2) a map from (IdentifierInfo*, Offset)* -> persistent IDs + + // Note that we use 'calloc', so all the bytes are 0. + PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey)); + + // Create the hashtable. + OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap; + + // Generate mapping from persistent IDs -> IdentifierInfo*. + for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) { + // Decrement by 1 because we are using a vector for the lookup and + // 0 is reserved for NULL. + assert(I->second > 0); + assert(I->second-1 < idcount); + unsigned idx = I->second-1; + + // Store the mapping from persistent ID to IdentifierInfo* + IIDMap[idx].II = I->first; + + // Store the reverse mapping in a hashtable. + IIOffMap.insert(&IIDMap[idx], I->second); + } + + // Write out the inverse map first. This causes the PCIDKey entries to + // record PTH file offsets for the string data. This is used to write + // the second table. + Offset StringTableOffset = IIOffMap.Emit(Out); + + // Now emit the table mapping from persistent IDs to PTH file offsets. + Offset IDOff = Out.tell(); + Emit32(idcount); // Emit the number of identifiers. + for (unsigned i = 0 ; i < idcount; ++i) + Emit32(IIDMap[i].FileOffset); + + // Finally, release the inverse map. + free(IIDMap); + + return std::make_pair(IDOff, StringTableOffset); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/CodeGenAction.cpp new file mode 100644 index 0000000..3416aa8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CodeGenAction.cpp @@ -0,0 +1,593 @@ +//===--- CodeGenAction.cpp - LLVM Code Generation Frontend Action ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CodeGenAction.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclGroup.h" +#include "clang/CodeGen/CodeGenOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/SchedulerRegistry.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/StandardPasses.h" +#include "llvm/Support/Timer.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegistry.h" +using namespace clang; +using namespace llvm; + +namespace { + enum BackendAction { + Backend_EmitAssembly, ///< Emit native assembly files + Backend_EmitBC, ///< Emit LLVM bitcode files + Backend_EmitLL, ///< Emit human-readable LLVM assembly + Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) + Backend_EmitMCNull, ///< Run CodeGen, but don't emit anything + Backend_EmitObj ///< Emit native object files + }; + + class BackendConsumer : public ASTConsumer { + Diagnostic &Diags; + BackendAction Action; + const CodeGenOptions &CodeGenOpts; + const LangOptions &LangOpts; + const TargetOptions &TargetOpts; + llvm::raw_ostream *AsmOutStream; + llvm::formatted_raw_ostream FormattedOutStream; + ASTContext *Context; + + Timer LLVMIRGeneration; + Timer CodeGenerationTime; + + llvm::OwningPtr<CodeGenerator> Gen; + + llvm::OwningPtr<llvm::Module> TheModule; + llvm::TargetData *TheTargetData; + + mutable FunctionPassManager *CodeGenPasses; + mutable PassManager *PerModulePasses; + mutable FunctionPassManager *PerFunctionPasses; + + FunctionPassManager *getCodeGenPasses() const; + PassManager *getPerModulePasses() const; + FunctionPassManager *getPerFunctionPasses() const; + + void CreatePasses(); + + /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. + /// + /// \return True on success. + bool AddEmitPasses(); + + void EmitAssembly(); + + public: + BackendConsumer(BackendAction action, Diagnostic &_Diags, + const LangOptions &langopts, const CodeGenOptions &compopts, + const TargetOptions &targetopts, bool TimePasses, + const std::string &infile, llvm::raw_ostream *OS, + LLVMContext &C) : + Diags(_Diags), + Action(action), + CodeGenOpts(compopts), + LangOpts(langopts), + TargetOpts(targetopts), + AsmOutStream(OS), + LLVMIRGeneration("LLVM IR Generation Time"), + CodeGenerationTime("Code Generation Time"), + Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), + TheTargetData(0), + CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) { + + if (AsmOutStream) + FormattedOutStream.setStream(*AsmOutStream, + formatted_raw_ostream::PRESERVE_STREAM); + + llvm::TimePassesIsEnabled = TimePasses; + } + + ~BackendConsumer() { + delete TheTargetData; + delete CodeGenPasses; + delete PerModulePasses; + delete PerFunctionPasses; + } + + llvm::Module *takeModule() { return TheModule.take(); } + + virtual void Initialize(ASTContext &Ctx) { + Context = &Ctx; + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.startTimer(); + + Gen->Initialize(Ctx); + + TheModule.reset(Gen->GetModule()); + TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription()); + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.stopTimer(); + } + + virtual void HandleTopLevelDecl(DeclGroupRef D) { + PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of declaration"); + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.startTimer(); + + Gen->HandleTopLevelDecl(D); + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.stopTimer(); + } + + virtual void HandleTranslationUnit(ASTContext &C) { + { + PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.startTimer(); + + Gen->HandleTranslationUnit(C); + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.stopTimer(); + } + + // EmitAssembly times and registers crash info itself. + EmitAssembly(); + + // Force a flush here in case we never get released. + if (AsmOutStream) + FormattedOutStream.flush(); + } + + virtual void HandleTagDeclDefinition(TagDecl *D) { + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of declaration"); + Gen->HandleTagDeclDefinition(D); + } + + virtual void CompleteTentativeDefinition(VarDecl *D) { + Gen->CompleteTentativeDefinition(D); + } + + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { + Gen->HandleVTable(RD, DefinitionRequired); + } + + static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, + unsigned LocCookie) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); + ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); + } + + void InlineAsmDiagHandler2(const llvm::SMDiagnostic &, + SourceLocation LocCookie); + }; +} + +FunctionPassManager *BackendConsumer::getCodeGenPasses() const { + if (!CodeGenPasses) { + CodeGenPasses = new FunctionPassManager(&*TheModule); + CodeGenPasses->add(new TargetData(*TheTargetData)); + } + + return CodeGenPasses; +} + +PassManager *BackendConsumer::getPerModulePasses() const { + if (!PerModulePasses) { + PerModulePasses = new PassManager(); + PerModulePasses->add(new TargetData(*TheTargetData)); + } + + return PerModulePasses; +} + +FunctionPassManager *BackendConsumer::getPerFunctionPasses() const { + if (!PerFunctionPasses) { + PerFunctionPasses = new FunctionPassManager(&*TheModule); + PerFunctionPasses->add(new TargetData(*TheTargetData)); + } + + return PerFunctionPasses; +} + +bool BackendConsumer::AddEmitPasses() { + if (Action == Backend_EmitNothing) + return true; + + if (Action == Backend_EmitBC) { + getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream)); + return true; + } + + if (Action == Backend_EmitLL) { + getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); + return true; + } + + bool Fast = CodeGenOpts.OptimizationLevel == 0; + + // Create the TargetMachine for generating code. + std::string Error; + std::string Triple = TheModule->getTargetTriple(); + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); + if (!TheTarget) { + Diags.Report(diag::err_fe_unable_to_create_target) << Error; + return false; + } + + // FIXME: Expose these capabilities via actual APIs!!!! Aside from just + // being gross, this is also totally broken if we ever care about + // concurrency. + llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; + if (CodeGenOpts.FloatABI == "soft") + llvm::FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + llvm::FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + llvm::FloatABIType = llvm::FloatABI::Default; + } + NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + llvm::UseSoftFloat = CodeGenOpts.SoftFloat; + UnwindTablesMandatory = CodeGenOpts.UnwindTables; + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections); + TargetMachine::setDataSections (CodeGenOpts.DataSections); + + // FIXME: Parse this earlier. + if (CodeGenOpts.RelocationModel == "static") { + TargetMachine::setRelocationModel(llvm::Reloc::Static); + } else if (CodeGenOpts.RelocationModel == "pic") { + TargetMachine::setRelocationModel(llvm::Reloc::PIC_); + } else { + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); + } + // FIXME: Parse this earlier. + if (CodeGenOpts.CodeModel == "small") { + TargetMachine::setCodeModel(llvm::CodeModel::Small); + } else if (CodeGenOpts.CodeModel == "kernel") { + TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + } else if (CodeGenOpts.CodeModel == "medium") { + TargetMachine::setCodeModel(llvm::CodeModel::Medium); + } else if (CodeGenOpts.CodeModel == "large") { + TargetMachine::setCodeModel(llvm::CodeModel::Large); + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + TargetMachine::setCodeModel(llvm::CodeModel::Default); + } + + std::vector<const char *> BackendArgs; + BackendArgs.push_back("clang"); // Fake program name. + if (!CodeGenOpts.DebugPass.empty()) { + BackendArgs.push_back("-debug-pass"); + BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); + } + if (!CodeGenOpts.LimitFloatPrecision.empty()) { + BackendArgs.push_back("-limit-float-precision"); + BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); + } + if (llvm::TimePassesIsEnabled) + BackendArgs.push_back("-time-passes"); + BackendArgs.push_back(0); + llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, + const_cast<char **>(&BackendArgs[0])); + + std::string FeaturesStr; + if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { + SubtargetFeatures Features; + Features.setCPU(TargetOpts.CPU); + for (std::vector<std::string>::const_iterator + it = TargetOpts.Features.begin(), + ie = TargetOpts.Features.end(); it != ie; ++it) + Features.AddFeature(*it); + FeaturesStr = Features.getString(); + } + TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); + + if (CodeGenOpts.RelaxAll) + TM->setMCRelaxAll(true); + + // Set register scheduler & allocation policy. + RegisterScheduler::setDefault(createDefaultScheduler); + RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : + createLinearScanRegisterAllocator); + + // Create the code generator passes. + FunctionPassManager *PM = getCodeGenPasses(); + CodeGenOpt::Level OptLevel = CodeGenOpt::Default; + + switch (CodeGenOpts.OptimizationLevel) { + default: break; + case 0: OptLevel = CodeGenOpt::None; break; + case 3: OptLevel = CodeGenOpt::Aggressive; break; + } + + // Normal mode, emit a .s or .o file by running the code generator. Note, + // this also adds codegenerator level optimization passes. + TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; + if (Action == Backend_EmitObj) + CGFT = TargetMachine::CGFT_ObjectFile; + else if (Action == Backend_EmitMCNull) + CGFT = TargetMachine::CGFT_Null; + else + assert(Action == Backend_EmitAssembly && "Invalid action!"); + if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel, + /*DisableVerify=*/!CodeGenOpts.VerifyModule)) { + Diags.Report(diag::err_fe_unable_to_interface_with_target); + return false; + } + + return true; +} + +void BackendConsumer::CreatePasses() { + unsigned OptLevel = CodeGenOpts.OptimizationLevel; + CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; + + // Handle disabling of LLVM optimization, where we want to preserve the + // internal module before any optimization. + if (CodeGenOpts.DisableLLVMOpts) { + OptLevel = 0; + Inlining = CodeGenOpts.NoInlining; + } + + // In -O0 if checking is disabled, we don't even have per-function passes. + if (CodeGenOpts.VerifyModule) + getPerFunctionPasses()->add(createVerifierPass()); + + // Assume that standard function passes aren't run for -O0. + if (OptLevel > 0) + llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel); + + llvm::Pass *InliningPass = 0; + switch (Inlining) { + case CodeGenOptions::NoInlining: break; + case CodeGenOptions::NormalInlining: { + // Set the inline threshold following llvm-gcc. + // + // FIXME: Derive these constants in a principled fashion. + unsigned Threshold = 225; + if (CodeGenOpts.OptimizeSize) + Threshold = 75; + else if (OptLevel > 2) + Threshold = 275; + InliningPass = createFunctionInliningPass(Threshold); + break; + } + case CodeGenOptions::OnlyAlwaysInlining: + InliningPass = createAlwaysInlinerPass(); // Respect always_inline + break; + } + + // For now we always create per module passes. + PassManager *PM = getPerModulePasses(); + llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize, + CodeGenOpts.UnitAtATime, + CodeGenOpts.UnrollLoops, + /*SimplifyLibCalls=*/!LangOpts.NoBuiltin, + /*HaveExceptions=*/true, + InliningPass); +} + +/// EmitAssembly - Handle interaction with LLVM backend to generate +/// actual machine code. +void BackendConsumer::EmitAssembly() { + // Silently ignore if we weren't initialized for some reason. + if (!TheModule || !TheTargetData) + return; + + TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); + + // Make sure IR generation is happy with the module. This is + // released by the module provider. + Module *M = Gen->ReleaseModule(); + if (!M) { + // The module has been released by IR gen on failures, do not + // double free. + TheModule.take(); + return; + } + + assert(TheModule.get() == M && + "Unexpected module change during IR generation"); + + CreatePasses(); + if (!AddEmitPasses()) + return; + + // Run passes. For now we do all passes at once, but eventually we + // would like to have the option of streaming code generation. + + if (PerFunctionPasses) { + PrettyStackTraceString CrashInfo("Per-function optimization"); + + PerFunctionPasses->doInitialization(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration()) + PerFunctionPasses->run(*I); + PerFunctionPasses->doFinalization(); + } + + if (PerModulePasses) { + PrettyStackTraceString CrashInfo("Per-module optimization passes"); + PerModulePasses->run(*M); + } + + if (CodeGenPasses) { + PrettyStackTraceString CrashInfo("Code generation"); + + // Install an inline asm handler so that diagnostics get printed through our + // diagnostics hooks. + LLVMContext &Ctx = TheModule->getContext(); + void *OldHandler = Ctx.getInlineAsmDiagnosticHandler(); + void *OldContext = Ctx.getInlineAsmDiagnosticContext(); + Ctx.setInlineAsmDiagnosticHandler((void*)(intptr_t)InlineAsmDiagHandler, + this); + + CodeGenPasses->doInitialization(); + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + if (!I->isDeclaration()) + CodeGenPasses->run(*I); + CodeGenPasses->doFinalization(); + + Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); + } +} + +/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr +/// buffer to be a valid FullSourceLoc. +static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, + SourceManager &CSM) { + // Get both the clang and llvm source managers. The location is relative to + // a memory buffer that the LLVM Source Manager is handling, we need to add + // a copy to the Clang source manager. + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + + // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr + // already owns its one and clang::SourceManager wants to own its one. + const MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + + // Create the copy and transfer ownership to clang::SourceManager. + llvm::MemoryBuffer *CBuf = + llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(), + LBuf->getBufferIdentifier()); + FileID FID = CSM.createFileIDForMemBuffer(CBuf); + + // Translate the offset into the file. + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + SourceLocation NewLoc = + CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset); + return FullSourceLoc(NewLoc, CSM); +} + + +/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an +/// error parsing inline asm. The SMDiagnostic indicates the error relative to +/// the temporary memory buffer that the inline asm parser has set up. +void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, + SourceLocation LocCookie) { + // There are a couple of different kinds of errors we could get here. First, + // we re-format the SMDiagnostic in terms of a clang diagnostic. + + // Strip "error: " off the start of the message string. + llvm::StringRef Message = D.getMessage(); + if (Message.startswith("error: ")) + Message = Message.substr(7); + + // There are two cases: the SMDiagnostic could have a inline asm source + // location or it might not. If it does, translate the location. + FullSourceLoc Loc; + if (D.getLoc() != SMLoc()) + Loc = ConvertBackendLocation(D, Context->getSourceManager()); + Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message); + + // This could be a problem with no clang-level source location information. + // In this case, LocCookie is invalid. If there is source level information, + // print an "generated from" note. + if (LocCookie.isValid()) + Diags.Report(FullSourceLoc(LocCookie, Context->getSourceManager()), + diag::note_fe_inline_asm_here); +} + +// + +CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} + +CodeGenAction::~CodeGenAction() {} + +void CodeGenAction::EndSourceFileAction() { + // If the consumer creation failed, do nothing. + if (!getCompilerInstance().hasASTConsumer()) + return; + + // Steal the module from the consumer. + BackendConsumer *Consumer = static_cast<BackendConsumer*>( + &getCompilerInstance().getASTConsumer()); + + TheModule.reset(Consumer->takeModule()); +} + +llvm::Module *CodeGenAction::takeModule() { + return TheModule.take(); +} + +ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + BackendAction BA = static_cast<BackendAction>(Act); + llvm::OwningPtr<llvm::raw_ostream> OS; + switch (BA) { + case Backend_EmitAssembly: + OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); + break; + case Backend_EmitLL: + OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); + break; + case Backend_EmitBC: + OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); + break; + case Backend_EmitNothing: + break; + case Backend_EmitMCNull: + case Backend_EmitObj: + OS.reset(CI.createDefaultOutputFile(true, InFile, "o")); + break; + } + if (BA != Backend_EmitNothing && !OS) + return 0; + + return new BackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(), + CI.getCodeGenOpts(), CI.getTargetOpts(), + CI.getFrontendOpts().ShowTimers, InFile, OS.take(), + CI.getLLVMContext()); +} + +EmitAssemblyAction::EmitAssemblyAction() + : CodeGenAction(Backend_EmitAssembly) {} + +EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {} + +EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {} + +EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {} + +EmitCodeGenOnlyAction::EmitCodeGenOnlyAction() : CodeGenAction(Backend_EmitMCNull) {} + +EmitObjAction::EmitObjAction() : CodeGenAction(Backend_EmitObj) {} diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp new file mode 100644 index 0000000..2b25168 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -0,0 +1,549 @@ +//===--- CompilerInstance.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Frontend/ChainedDiagnosticClient.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/Utils.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/Timer.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/System/Program.h" +using namespace clang; + +CompilerInstance::CompilerInstance() + : Invocation(new CompilerInvocation()) { +} + +CompilerInstance::~CompilerInstance() { +} + +void CompilerInstance::setLLVMContext(llvm::LLVMContext *Value) { + LLVMContext.reset(Value); +} + +void CompilerInstance::setInvocation(CompilerInvocation *Value) { + Invocation.reset(Value); +} + +void CompilerInstance::setDiagnostics(Diagnostic *Value) { + Diagnostics = Value; +} + +void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { + DiagClient.reset(Value); +} + +void CompilerInstance::setTarget(TargetInfo *Value) { + Target.reset(Value); +} + +void CompilerInstance::setFileManager(FileManager *Value) { + FileMgr.reset(Value); +} + +void CompilerInstance::setSourceManager(SourceManager *Value) { + SourceMgr.reset(Value); +} + +void CompilerInstance::setPreprocessor(Preprocessor *Value) { + PP.reset(Value); +} + +void CompilerInstance::setASTContext(ASTContext *Value) { + Context.reset(Value); +} + +void CompilerInstance::setASTConsumer(ASTConsumer *Value) { + Consumer.reset(Value); +} + +void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { + CompletionConsumer.reset(Value); +} + +// Diagnostics +namespace { + class BinaryDiagnosticSerializer : public DiagnosticClient { + llvm::raw_ostream &OS; + SourceManager *SourceMgr; + public: + explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS) + : OS(OS), SourceMgr(0) { } + + virtual void HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info); + }; +} + +void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + StoredDiagnostic(DiagLevel, Info).Serialize(OS); +} + +static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, + unsigned argc, char **argv, + Diagnostic &Diags) { + std::string ErrorInfo; + llvm::OwningPtr<llvm::raw_ostream> OS( + new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); + if (!ErrorInfo.empty()) { + Diags.Report(diag::err_fe_unable_to_open_logfile) + << DiagOpts.DumpBuildInformation << ErrorInfo; + return; + } + + (*OS) << "clang -cc1 command line arguments: "; + for (unsigned i = 0; i != argc; ++i) + (*OS) << argv[i] << ' '; + (*OS) << '\n'; + + // Chain in a diagnostic client which will log the diagnostics. + DiagnosticClient *Logger = + new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); + Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger)); +} + +void CompilerInstance::createDiagnostics(int Argc, char **Argv) { + Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv); + + if (Diagnostics) + DiagClient.reset(Diagnostics->getClient()); +} + +llvm::IntrusiveRefCntPtr<Diagnostic> +CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, + int Argc, char **Argv) { + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic()); + + // Create the diagnostic client for reporting errors or for + // implementing -verify. + llvm::OwningPtr<DiagnosticClient> DiagClient; + if (Opts.BinaryOutput) { + if (llvm::sys::Program::ChangeStderrToBinary()) { + // We weren't able to set standard error to binary, which is a + // bit of a problem. So, just create a text diagnostic printer + // to complain about this problem, and pretend that the user + // didn't try to use binary output. + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); + Diags->setClient(DiagClient.take()); + Diags->Report(diag::err_fe_stderr_binary); + return Diags; + } else { + DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs())); + } + } else { + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); + } + + // Chain in -verify checker, if requested. + if (Opts.VerifyDiagnostics) + DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); + + Diags->setClient(DiagClient.take()); + if (!Opts.DumpBuildInformation.empty()) + SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); + + // Configure our handling of diagnostics. + ProcessWarningOptions(*Diags, Opts); + + return Diags; +} + +// File Manager + +void CompilerInstance::createFileManager() { + FileMgr.reset(new FileManager()); +} + +// Source Manager + +void CompilerInstance::createSourceManager() { + SourceMgr.reset(new SourceManager(getDiagnostics())); +} + +// Preprocessor + +void CompilerInstance::createPreprocessor() { + PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), + getPreprocessorOpts(), getHeaderSearchOpts(), + getDependencyOutputOpts(), getTarget(), + getFrontendOpts(), getSourceManager(), + getFileManager())); +} + +Preprocessor * +CompilerInstance::createPreprocessor(Diagnostic &Diags, + const LangOptions &LangInfo, + const PreprocessorOptions &PPOpts, + const HeaderSearchOptions &HSOpts, + const DependencyOutputOptions &DepOpts, + const TargetInfo &Target, + const FrontendOptions &FEOpts, + SourceManager &SourceMgr, + FileManager &FileMgr) { + // Create a PTH manager if we are using some form of a token cache. + PTHManager *PTHMgr = 0; + if (!PPOpts.TokenCache.empty()) + PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); + + // Create the Preprocessor. + HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); + Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, + SourceMgr, *HeaderInfo, PTHMgr, + /*OwnsHeaderSearch=*/true); + + // Note that this is different then passing PTHMgr to Preprocessor's ctor. + // That argument is used as the IdentifierInfoLookup argument to + // IdentifierTable's ctor. + if (PTHMgr) { + PTHMgr->setPreprocessor(PP); + PP->setPTHManager(PTHMgr); + } + + if (PPOpts.DetailedRecord) + PP->createPreprocessingRecord(); + + InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); + + // Handle generating dependencies, if requested. + if (!DepOpts.OutputFile.empty()) + AttachDependencyFileGen(*PP, DepOpts); + + return PP; +} + +// ASTContext + +void CompilerInstance::createASTContext() { + Preprocessor &PP = getPreprocessor(); + Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), + getTarget(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), + /*FreeMemory=*/ !getFrontendOpts().DisableFree, + /*size_reserve=*/ 0)); +} + +// ExternalASTSource + +void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { + llvm::OwningPtr<ExternalASTSource> Source; + Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, + getPreprocessor(), getASTContext())); + getASTContext().setExternalSource(Source); +} + +ExternalASTSource * +CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, + const std::string &Sysroot, + Preprocessor &PP, + ASTContext &Context) { + llvm::OwningPtr<PCHReader> Reader; + Reader.reset(new PCHReader(PP, &Context, + Sysroot.empty() ? 0 : Sysroot.c_str())); + + switch (Reader->ReadPCH(Path)) { + case PCHReader::Success: + // Set the predefines buffer as suggested by the PCH reader. Typically, the + // predefines buffer will be empty. + PP.setPredefines(Reader->getSuggestedPredefines()); + return Reader.take(); + + case PCHReader::Failure: + // Unrecoverable failure: don't even try to process the input file. + break; + + case PCHReader::IgnorePCH: + // No suitable PCH file could be found. Return an error. + break; + } + + return 0; +} + +// Code Completion + +void CompilerInstance::createCodeCompletionConsumer() { + const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; + CompletionConsumer.reset( + createCodeCompletionConsumer(getPreprocessor(), + Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().DebugCodeCompletionPrinter, + getFrontendOpts().ShowMacrosInCodeCompletion, + getFrontendOpts().ShowCodePatternsInCodeCompletion, + llvm::outs())); + if (!CompletionConsumer) + return; + + if (CompletionConsumer->isOutputBinary() && + llvm::sys::Program::ChangeStdoutToBinary()) { + getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary); + CompletionConsumer.reset(); + } +} + +void CompilerInstance::createFrontendTimer() { + FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); +} + +CodeCompleteConsumer * +CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, + const std::string &Filename, + unsigned Line, + unsigned Column, + bool UseDebugPrinter, + bool ShowMacros, + bool ShowCodePatterns, + llvm::raw_ostream &OS) { + // Tell the source manager to chop off the given file at a specific + // line and column. + const FileEntry *Entry = PP.getFileManager().getFile(Filename); + if (!Entry) { + PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) + << Filename; + return 0; + } + + // Truncate the named file at the given line/column. + PP.SetCodeCompletionPoint(Entry, Line, Column); + + // Set up the creation routine for code-completion. + if (UseDebugPrinter) + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); + else + return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); +} + +// Output Files + +void CompilerInstance::addOutputFile(llvm::StringRef Path, + llvm::raw_ostream *OS) { + assert(OS && "Attempt to add empty stream to output list!"); + OutputFiles.push_back(std::make_pair(Path, OS)); +} + +void CompilerInstance::clearOutputFiles(bool EraseFiles) { + for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator + it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { + delete it->second; + if (EraseFiles && !it->first.empty()) + llvm::sys::Path(it->first).eraseFromDisk(); + } + OutputFiles.clear(); +} + +llvm::raw_fd_ostream * +CompilerInstance::createDefaultOutputFile(bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + return createOutputFile(getFrontendOpts().OutputFile, Binary, + InFile, Extension); +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension) { + std::string Error, OutputPathName; + llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, + InFile, Extension, + &OutputPathName); + if (!OS) { + getDiagnostics().Report(diag::err_fe_unable_to_open_output) + << OutputPath << Error; + return 0; + } + + // Add the output file -- but don't try to remove "-", since this means we are + // using stdin. + addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); + + return OS; +} + +llvm::raw_fd_ostream * +CompilerInstance::createOutputFile(llvm::StringRef OutputPath, + std::string &Error, + bool Binary, + llvm::StringRef InFile, + llvm::StringRef Extension, + std::string *ResultPathName) { + std::string OutFile; + if (!OutputPath.empty()) { + OutFile = OutputPath; + } else if (InFile == "-") { + OutFile = "-"; + } else if (!Extension.empty()) { + llvm::sys::Path Path(InFile); + Path.eraseSuffix(); + Path.appendSuffix(Extension); + OutFile = Path.str(); + } else { + OutFile = "-"; + } + + llvm::OwningPtr<llvm::raw_fd_ostream> OS( + new llvm::raw_fd_ostream(OutFile.c_str(), Error, + (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); + if (!Error.empty()) + return 0; + + if (ResultPathName) + *ResultPathName = OutFile; + + return OS.take(); +} + +// Initialization Utilities + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { + return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), + getSourceManager(), getFrontendOpts()); +} + +bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, + Diagnostic &Diags, + FileManager &FileMgr, + SourceManager &SourceMgr, + const FrontendOptions &Opts) { + // Figure out where to get and map in the main file. + if (InputFile != "-") { + const FileEntry *File = FileMgr.getFile(InputFile); + if (File) SourceMgr.createMainFileID(File, SourceLocation()); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading) << InputFile; + return false; + } + } else { + llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); + SourceMgr.createMainFileIDForMemBuffer(SB); + if (SourceMgr.getMainFileID().isInvalid()) { + Diags.Report(diag::err_fe_error_reading_stdin); + return false; + } + } + + return true; +} + +// High-Level Operations + +bool CompilerInstance::ExecuteAction(FrontendAction &Act) { + assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); + assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); + assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); + + // FIXME: Take this as an argument, once all the APIs we used have moved to + // taking it as an input instead of hard-coding llvm::errs. + llvm::raw_ostream &OS = llvm::errs(); + + // Create the target instance. + setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); + if (!hasTarget()) + return false; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + getTarget().setForcedLangOptions(getLangOpts()); + + // Validate/process some options. + if (getHeaderSearchOpts().Verbose) + OS << "clang -cc1 version " CLANG_VERSION_STRING + << " based upon " << PACKAGE_STRING + << " hosted on " << llvm::sys::getHostTriple() << "\n"; + + if (getFrontendOpts().ShowTimers) + createFrontendTimer(); + + if (getFrontendOpts().ShowStats) + llvm::EnableStatistics(); + + for (unsigned i = 0, e = getFrontendOpts().Inputs.size(); i != e; ++i) { + const std::string &InFile = getFrontendOpts().Inputs[i].second; + + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + bool IsAST = getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST; + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + createFileManager(); + + // Create the source manager. + createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + getSourceManager().clearIDTables(); + } + + // Create the preprocessor. + createPreprocessor(); + } + + if (Act.BeginSourceFile(*this, InFile, IsAST)) { + Act.Execute(); + Act.EndSourceFile(); + } + } + + if (getDiagnosticOpts().ShowCarets) { + unsigned NumWarnings = getDiagnostics().getNumWarnings(); + unsigned NumErrors = getDiagnostics().getNumErrors() - + getDiagnostics().getNumErrorsSuppressed(); + + if (NumWarnings) + OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); + if (NumWarnings && NumErrors) + OS << " and "; + if (NumErrors) + OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); + if (NumWarnings || NumErrors) + OS << " generated.\n"; + } + + if (getFrontendOpts().ShowStats) { + getFileManager().PrintStats(); + OS << "\n"; + } + + // Return the appropriate status when verifying diagnostics. + // + // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need + // this. + if (getDiagnosticOpts().VerifyDiagnostics) + return !static_cast<VerifyDiagnosticsClient&>( + getDiagnosticClient()).HadErrors(); + + return !getDiagnostics().getNumErrors(); +} + + diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp new file mode 100644 index 0000000..1d81e82 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -0,0 +1,1409 @@ +//===--- CompilerInvocation.cpp -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/OptTable.h" +#include "clang/Driver/Option.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/PCHReader.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +using namespace clang; + +static const char *getAnalysisName(Analyses Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis kind!"); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ + case NAME: return "-" CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisStoreName(AnalysisStores Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis store!"); +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis constraints!"); +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + case NAME##Model: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown analysis client!"); +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ + case PD_##NAME: return CMDFLAG; +#include "clang/Frontend/Analyses.def" + } +} + +//===----------------------------------------------------------------------===// +// Serialization (to args) +//===----------------------------------------------------------------------===// + +static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) + Res.push_back(getAnalysisName(Opts.AnalysisList[i])); + if (Opts.AnalysisStoreOpt != BasicStoreModel) { + Res.push_back("-analyzer-store"); + Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt)); + } + if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) { + Res.push_back("-analyzer-constraints"); + Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); + } + if (Opts.AnalysisDiagOpt != PD_HTML) { + Res.push_back("-analyzer-output"); + Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); + } + if (!Opts.AnalyzeSpecificFunction.empty()) { + Res.push_back("-analyze-function"); + Res.push_back(Opts.AnalyzeSpecificFunction); + } + if (Opts.AnalyzeAll) + Res.push_back("-analyzer-opt-analyze-headers"); + if (Opts.AnalyzerDisplayProgress) + Res.push_back("-analyzer-display-progress"); + if (Opts.AnalyzeNestedBlocks) + Res.push_back("-analyzer-opt-analyze-nested-blocks"); + if (Opts.EagerlyAssume) + Res.push_back("-analyzer-eagerly-assume"); + if (!Opts.PurgeDead) + Res.push_back("-analyzer-no-purge-dead"); + if (Opts.TrimGraph) + Res.push_back("-trim-egraph"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-graphviz"); + if (Opts.VisualizeEGDot) + Res.push_back("-analyzer-viz-egraph-ubigraph"); + if (Opts.EnableExperimentalChecks) + Res.push_back("-analyzer-experimental-checks"); + if (Opts.EnableExperimentalInternalChecks) + Res.push_back("-analyzer-experimental-internal-checks"); +} + +static void CodeGenOptsToArgs(const CodeGenOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.DebugInfo) + Res.push_back("-g"); + if (Opts.DisableLLVMOpts) + Res.push_back("-disable-llvm-optzns"); + if (Opts.DisableRedZone) + Res.push_back("-disable-red-zone"); + if (!Opts.DwarfDebugFlags.empty()) { + Res.push_back("-dwarf-debug-flags"); + Res.push_back(Opts.DwarfDebugFlags); + } + if (!Opts.MergeAllConstants) + Res.push_back("-fno-merge-all-constants"); + if (Opts.NoCommon) + Res.push_back("-fno-common"); + if (Opts.NoImplicitFloat) + Res.push_back("-no-implicit-float"); + if (Opts.OptimizeSize) { + assert(Opts.OptimizationLevel == 2 && "Invalid options!"); + Res.push_back("-Os"); + } else if (Opts.OptimizationLevel != 0) + Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); + if (!Opts.MainFileName.empty()) { + Res.push_back("-main-file-name"); + Res.push_back(Opts.MainFileName); + } + // SimplifyLibCalls is only derived. + // TimePasses is only derived. + // UnitAtATime is unused. + // UnrollLoops is only derived. + // Inlining is only derived. + + if (Opts.DataSections) + Res.push_back("-fdata-sections"); + if (Opts.FunctionSections) + Res.push_back("-ffunction-sections"); + if (Opts.AsmVerbose) + Res.push_back("-masm-verbose"); + if (!Opts.CodeModel.empty()) { + Res.push_back("-mcode-model"); + Res.push_back(Opts.CodeModel); + } + if (!Opts.CXAAtExit) + Res.push_back("-fno-use-cxa-atexit"); + if (Opts.CXXCtorDtorAliases) + Res.push_back("-mconstructor-aliases"); + if (!Opts.DebugPass.empty()) { + Res.push_back("-mdebug-pass"); + Res.push_back(Opts.DebugPass); + } + if (Opts.DisableFPElim) + Res.push_back("-mdisable-fp-elim"); + if (!Opts.FloatABI.empty()) { + Res.push_back("-mfloat-abi"); + Res.push_back(Opts.FloatABI); + } + if (!Opts.LimitFloatPrecision.empty()) { + Res.push_back("-mlimit-float-precision"); + Res.push_back(Opts.LimitFloatPrecision); + } + if (Opts.NoZeroInitializedInBSS) + Res.push_back("-mno-zero-initialized-bss"); + switch (Opts.getObjCDispatchMethod()) { + case CodeGenOptions::Legacy: + break; + case CodeGenOptions::Mixed: + Res.push_back("-fobjc-dispatch-method=mixed"); + break; + case CodeGenOptions::NonLegacy: + Res.push_back("-fobjc-dispatch-method=non-legacy"); + break; + } + if (Opts.RelaxAll) + Res.push_back("-mrelax-all"); + if (Opts.SoftFloat) + Res.push_back("-msoft-float"); + if (Opts.UnwindTables) + Res.push_back("-munwind-tables"); + if (Opts.RelocationModel != "pic") { + Res.push_back("-mrelocation-model"); + Res.push_back(Opts.RelocationModel); + } + if (!Opts.VerifyModule) + Res.push_back("-disable-llvm-verifier"); +} + +static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IncludeSystemHeaders) + Res.push_back("-sys-header-deps"); + if (Opts.UsePhonyTargets) + Res.push_back("-MP"); + if (!Opts.OutputFile.empty()) { + Res.push_back("-dependency-file"); + Res.push_back(Opts.OutputFile); + } + for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) { + Res.push_back("-MT"); + Res.push_back(Opts.Targets[i]); + } +} + +static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.IgnoreWarnings) + Res.push_back("-w"); + if (Opts.NoRewriteMacros) + Res.push_back("-Wno-rewrite-macros"); + if (Opts.Pedantic) + Res.push_back("-pedantic"); + if (Opts.PedanticErrors) + Res.push_back("-pedantic-errors"); + if (!Opts.ShowColumn) + Res.push_back("-fno-show-column"); + if (!Opts.ShowLocation) + Res.push_back("-fno-show-source-location"); + if (!Opts.ShowCarets) + Res.push_back("-fno-caret-diagnostics"); + if (!Opts.ShowFixits) + Res.push_back("-fno-diagnostics-fixit-info"); + if (Opts.ShowSourceRanges) + Res.push_back("-fdiagnostics-print-source-range-info"); + if (Opts.ShowColors) + Res.push_back("-fcolor-diagnostics"); + if (Opts.VerifyDiagnostics) + Res.push_back("-verify"); + if (Opts.BinaryOutput) + Res.push_back("-fdiagnostics-binary"); + if (Opts.ShowOptionNames) + Res.push_back("-fdiagnostics-show-option"); + if (Opts.ShowCategories == 1) + Res.push_back("-fdiagnostics-show-category=id"); + else if (Opts.ShowCategories == 2) + Res.push_back("-fdiagnostics-show-category=name"); + if (Opts.ErrorLimit) { + Res.push_back("-ferror-limit"); + Res.push_back(llvm::utostr(Opts.ErrorLimit)); + } + if (Opts.MacroBacktraceLimit + != DiagnosticOptions::DefaultMacroBacktraceLimit) { + Res.push_back("-fmacro-backtrace-limit"); + Res.push_back(llvm::utostr(Opts.MacroBacktraceLimit)); + } + if (Opts.TemplateBacktraceLimit + != DiagnosticOptions::DefaultTemplateBacktraceLimit) { + Res.push_back("-ftemplate-backtrace-limit"); + Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit)); + } + + if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { + Res.push_back("-ftabstop"); + Res.push_back(llvm::utostr(Opts.TabStop)); + } + if (Opts.MessageLength) { + Res.push_back("-fmessage-length"); + Res.push_back(llvm::utostr(Opts.MessageLength)); + } + if (!Opts.DumpBuildInformation.empty()) { + Res.push_back("-dump-build-information"); + Res.push_back(Opts.DumpBuildInformation); + } + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) + Res.push_back("-W" + Opts.Warnings[i]); +} + +static const char *getInputKindName(FrontendOptions::InputKind Kind) { + switch (Kind) { + case FrontendOptions::IK_None: break; + case FrontendOptions::IK_AST: return "ast"; + case FrontendOptions::IK_Asm: return "assembler-with-cpp"; + case FrontendOptions::IK_C: return "c"; + case FrontendOptions::IK_CXX: return "c++"; + case FrontendOptions::IK_ObjC: return "objective-c"; + case FrontendOptions::IK_ObjCXX: return "objective-c++"; + case FrontendOptions::IK_OpenCL: return "cl"; + case FrontendOptions::IK_PreprocessedC: return "cpp-output"; + case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output"; + case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output"; + case FrontendOptions::IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; + } + + llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static const char *getActionName(frontend::ActionKind Kind) { + switch (Kind) { + case frontend::PluginAction: + case frontend::InheritanceView: + llvm_unreachable("Invalid kind!"); + + case frontend::ASTDump: return "-ast-dump"; + case frontend::ASTPrint: return "-ast-print"; + case frontend::ASTPrintXML: return "-ast-print-xml"; + case frontend::ASTView: return "-ast-view"; + case frontend::BoostCon: return "-boostcon"; + case frontend::DumpRawTokens: return "-dump-raw-tokens"; + case frontend::DumpTokens: return "-dump-tokens"; + case frontend::EmitAssembly: return "-S"; + case frontend::EmitBC: return "-emit-llvm-bc"; + case frontend::EmitHTML: return "-emit-html"; + case frontend::EmitLLVM: return "-emit-llvm"; + case frontend::EmitLLVMOnly: return "-emit-llvm-only"; + case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; + case frontend::EmitObj: return "-emit-obj"; + case frontend::FixIt: return "-fixit"; + case frontend::GeneratePCH: return "-emit-pch"; + case frontend::GeneratePTH: return "-emit-pth"; + case frontend::InitOnly: return "-init-only"; + case frontend::ParseNoop: return "-parse-noop"; + case frontend::ParsePrintCallbacks: return "-parse-print-callbacks"; + case frontend::ParseSyntaxOnly: return "-fsyntax-only"; + case frontend::PrintDeclContext: return "-print-decl-contexts"; + case frontend::PrintPreprocessedInput: return "-E"; + case frontend::RewriteMacros: return "-rewrite-macros"; + case frontend::RewriteObjC: return "-rewrite-objc"; + case frontend::RewriteTest: return "-rewrite-test"; + case frontend::RunAnalysis: return "-analyze"; + case frontend::RunPreprocessorOnly: return "-Eonly"; + } + + llvm_unreachable("Unexpected language kind!"); + return 0; +} + +static void FrontendOptsToArgs(const FrontendOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.DebugCodeCompletionPrinter) + Res.push_back("-no-code-completion-debug-printer"); + if (Opts.DisableFree) + Res.push_back("-disable-free"); + if (Opts.RelocatablePCH) + Res.push_back("-relocatable-pch"); + if (Opts.ShowHelp) + Res.push_back("-help"); + if (Opts.ShowMacrosInCodeCompletion) + Res.push_back("-code-completion-macros"); + if (Opts.ShowCodePatternsInCodeCompletion) + Res.push_back("-code-completion-patterns"); + if (Opts.ShowStats) + Res.push_back("-print-stats"); + if (Opts.ShowTimers) + Res.push_back("-ftime-report"); + if (Opts.ShowVersion) + Res.push_back("-version"); + + bool NeedLang = false; + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) + if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) != + Opts.Inputs[i].first) + NeedLang = true; + if (NeedLang) { + Res.push_back("-x"); + Res.push_back(getInputKindName(Opts.Inputs[0].first)); + } + for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { + assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) && + "Unable to represent this input vector!"); + Res.push_back(Opts.Inputs[i].second); + } + + if (!Opts.OutputFile.empty()) { + Res.push_back("-o"); + Res.push_back(Opts.OutputFile); + } + if (!Opts.ViewClassInheritance.empty()) { + Res.push_back("-cxx-inheritance-view"); + Res.push_back(Opts.ViewClassInheritance); + } + if (!Opts.CodeCompletionAt.FileName.empty()) { + Res.push_back("-code-completion-at"); + Res.push_back(Opts.CodeCompletionAt.FileName + ":" + + llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + + llvm::utostr(Opts.CodeCompletionAt.Column)); + } + if (Opts.ProgramAction != frontend::InheritanceView && + Opts.ProgramAction != frontend::PluginAction) + Res.push_back(getActionName(Opts.ProgramAction)); + if (!Opts.ActionName.empty()) { + Res.push_back("-plugin"); + Res.push_back(Opts.ActionName); + } + for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) { + Res.push_back("-load"); + Res.push_back(Opts.Plugins[i]); + } + for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) { + Res.push_back("-ast-merge"); + Res.push_back(Opts.ASTMergeFiles[i]); + } + for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { + Res.push_back("-mllvm"); + Res.push_back(Opts.LLVMArgs[i]); + } +} + +static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, + std::vector<std::string> &Res) { + if (Opts.Sysroot != "/") { + Res.push_back("-isysroot"); + Res.push_back(Opts.Sysroot); + } + + /// User specified include entries. + for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; + if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) + llvm::report_fatal_error("Invalid option set!"); + if (E.IsUserSupplied) { + if (E.Group == frontend::After) { + Res.push_back("-idirafter"); + } else if (E.Group == frontend::Quoted) { + Res.push_back("-iquote"); + } else if (E.Group == frontend::System) { + Res.push_back("-isystem"); + } else { + assert(E.Group == frontend::Angled && "Invalid group!"); + Res.push_back(E.IsFramework ? "-F" : "-I"); + } + } else { + if (E.Group != frontend::Angled && E.Group != frontend::System) + llvm::report_fatal_error("Invalid option set!"); + Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : + "-iwithprefix"); + } + Res.push_back(E.Path); + } + + if (!Opts.EnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::report_fatal_error("Not yet implemented!"); + } + if (!Opts.CEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::report_fatal_error("Not yet implemented!"); + } + if (!Opts.ObjCEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::report_fatal_error("Not yet implemented!"); + } + if (!Opts.CXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::report_fatal_error("Not yet implemented!"); + } + if (!Opts.ObjCXXEnvIncPath.empty()) { + // FIXME: Provide an option for this, and move env detection to driver. + llvm::report_fatal_error("Not yet implemented!"); + } + if (!Opts.ResourceDir.empty()) { + Res.push_back("-resource-dir"); + Res.push_back(Opts.ResourceDir); + } + if (!Opts.UseStandardIncludes) + Res.push_back("-nostdinc"); + if (!Opts.UseStandardCXXIncludes) + Res.push_back("-nostdinc++"); + if (Opts.Verbose) + Res.push_back("-v"); +} + +static void LangOptsToArgs(const LangOptions &Opts, + std::vector<std::string> &Res) { + LangOptions DefaultLangOpts; + + // FIXME: Need to set -std to get all the implicit options. + + // FIXME: We want to only pass options relative to the defaults, which + // requires constructing a target. :( + // + // It would be better to push the all target specific choices into the driver, + // so that everything below that was more uniform. + + if (Opts.Trigraphs) + Res.push_back("-trigraphs"); + // Implicit based on the input kind: + // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL + // Implicit based on the input language standard: + // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode + if (Opts.DollarIdents) + Res.push_back("-fdollars-in-identifiers"); + if (Opts.GNUMode && !Opts.GNUKeywords) + Res.push_back("-fno-gnu-keywords"); + if (!Opts.GNUMode && Opts.GNUKeywords) + Res.push_back("-fgnu-keywords"); + if (Opts.Microsoft) + Res.push_back("-fms-extensions"); + if (Opts.ObjCNonFragileABI) + Res.push_back("-fobjc-nonfragile-abi"); + if (Opts.ObjCNonFragileABI2) + Res.push_back("-fobjc-nonfragile-abi2"); + // NoInline is implicit. + if (!Opts.CXXOperatorNames) + Res.push_back("-fno-operator-names"); + if (Opts.PascalStrings) + Res.push_back("-fpascal-strings"); + if (Opts.CatchUndefined) + Res.push_back("-fcatch-undefined-behavior"); + if (Opts.WritableStrings) + Res.push_back("-fwritable-strings"); + if (Opts.ConstStrings) + Res.push_back("-Wwrite-strings"); + if (!Opts.LaxVectorConversions) + Res.push_back("-fno-lax-vector-conversions"); + if (Opts.AltiVec) + Res.push_back("-faltivec"); + if (Opts.Exceptions) + Res.push_back("-fexceptions"); + if (Opts.SjLjExceptions) + Res.push_back("-fsjlj-exceptions"); + if (!Opts.RTTI) + Res.push_back("-fno-rtti"); + if (!Opts.NeXTRuntime) + Res.push_back("-fgnu-runtime"); + if (Opts.Freestanding) + Res.push_back("-ffreestanding"); + if (Opts.NoBuiltin) + Res.push_back("-fno-builtin"); + if (!Opts.AssumeSaneOperatorNew) + Res.push_back("-fno-assume-sane-operator-new"); + if (!Opts.ThreadsafeStatics) + Res.push_back("-fno-threadsafe-statics"); + if (Opts.POSIXThreads) + Res.push_back("-pthread"); + if (Opts.Blocks) + Res.push_back("-fblocks"); + if (Opts.EmitAllDecls) + Res.push_back("-femit-all-decls"); + if (Opts.MathErrno) + Res.push_back("-fmath-errno"); + if (Opts.OverflowChecking) + Res.push_back("-ftrapv"); + if (Opts.HeinousExtensions) + Res.push_back("-fheinous-gnu-extensions"); + // Optimize is implicit. + // OptimizeSize is implicit. + if (Opts.Static) + Res.push_back("-static-define"); + if (Opts.DumpRecordLayouts) + Res.push_back("-fdump-record-layouts"); + if (Opts.DumpVTableLayouts) + Res.push_back("-fdump-vtable-layouts"); + if (Opts.NoBitFieldTypeAlign) + Res.push_back("-fno-bitfield-type-alignment"); + if (Opts.SjLjExceptions) + Res.push_back("-fsjlj-exceptions"); + if (Opts.PICLevel) { + Res.push_back("-pic-level"); + Res.push_back(llvm::utostr(Opts.PICLevel)); + } + if (Opts.ObjCGCBitmapPrint) + Res.push_back("-print-ivar-layout"); + if (Opts.NoConstantCFStrings) + Res.push_back("-fno-constant-cfstrings"); + if (!Opts.AccessControl) + Res.push_back("-fno-access-control"); + if (!Opts.CharIsSigned) + Res.push_back("-fno-signed-char"); + if (Opts.ShortWChar) + Res.push_back("-fshort-wchar"); + if (!Opts.ElideConstructors) + Res.push_back("-fno-elide-constructors"); + if (Opts.getGCMode() != LangOptions::NonGC) { + if (Opts.getGCMode() == LangOptions::HybridGC) { + Res.push_back("-fobjc-gc"); + } else { + assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!"); + Res.push_back("-fobjc-gc-only"); + } + } + if (Opts.getVisibilityMode() != LangOptions::Default) { + Res.push_back("-fvisibility"); + if (Opts.getVisibilityMode() == LangOptions::Hidden) { + Res.push_back("hidden"); + } else { + assert(Opts.getVisibilityMode() == LangOptions::Protected && + "Invalid visibility!"); + Res.push_back("protected"); + } + } + if (Opts.getStackProtectorMode() != 0) { + Res.push_back("-stack-protector"); + Res.push_back(llvm::utostr(Opts.getStackProtectorMode())); + } + if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) { + Res.push_back("-ftemplate-depth"); + Res.push_back(llvm::utostr(Opts.InstantiationDepth)); + } + if (!Opts.ObjCConstantStringClass.empty()) { + Res.push_back("-fconstant-string-class"); + Res.push_back(Opts.ObjCConstantStringClass); + } +} + +static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, + std::vector<std::string> &Res) { + for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) + Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") + + Opts.Macros[i].first); + for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { + // FIXME: We need to avoid reincluding the implicit PCH and PTH includes. + Res.push_back("-include"); + Res.push_back(Opts.Includes[i]); + } + for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) { + Res.push_back("-imacros"); + Res.push_back(Opts.MacroIncludes[i]); + } + if (!Opts.UsePredefines) + Res.push_back("-undef"); + if (Opts.DetailedRecord) + Res.push_back("-detailed-preprocessing-record"); + if (!Opts.ImplicitPCHInclude.empty()) { + Res.push_back("-include-pch"); + Res.push_back(Opts.ImplicitPCHInclude); + } + if (!Opts.ImplicitPTHInclude.empty()) { + Res.push_back("-include-pth"); + Res.push_back(Opts.ImplicitPTHInclude); + } + if (!Opts.TokenCache.empty()) { + if (Opts.ImplicitPTHInclude.empty()) { + Res.push_back("-token-cache"); + Res.push_back(Opts.TokenCache); + } else + assert(Opts.ImplicitPTHInclude == Opts.TokenCache && + "Unsupported option combination!"); + } + for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { + Res.push_back("-remap-file"); + Res.push_back(Opts.RemappedFiles[i].first + ";" + + Opts.RemappedFiles[i].second); + } +} + +static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, + std::vector<std::string> &Res) { + if (!Opts.ShowCPP && !Opts.ShowMacros) + llvm::report_fatal_error("Invalid option combination!"); + + if (Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dD"); + else if (!Opts.ShowCPP && Opts.ShowMacros) + Res.push_back("-dM"); + + if (!Opts.ShowLineMarkers) + Res.push_back("-P"); + if (Opts.ShowComments) + Res.push_back("-C"); + if (Opts.ShowMacroComments) + Res.push_back("-CC"); +} + +static void TargetOptsToArgs(const TargetOptions &Opts, + std::vector<std::string> &Res) { + Res.push_back("-triple"); + Res.push_back(Opts.Triple); + if (!Opts.CPU.empty()) { + Res.push_back("-target-cpu"); + Res.push_back(Opts.CPU); + } + if (!Opts.ABI.empty()) { + Res.push_back("-target-abi"); + Res.push_back(Opts.ABI); + } + for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { + Res.push_back("-target-feature"); + Res.push_back(Opts.Features[i]); + } +} + +void CompilerInvocation::toArgs(std::vector<std::string> &Res) { + AnalyzerOptsToArgs(getAnalyzerOpts(), Res); + CodeGenOptsToArgs(getCodeGenOpts(), Res); + DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res); + DiagnosticOptsToArgs(getDiagnosticOpts(), Res); + FrontendOptsToArgs(getFrontendOpts(), Res); + HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res); + LangOptsToArgs(getLangOpts(), Res); + PreprocessorOptsToArgs(getPreprocessorOpts(), Res); + PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res); + TargetOptsToArgs(getTargetOpts(), Res); +} + +//===----------------------------------------------------------------------===// +// Deserialization (to args) +//===----------------------------------------------------------------------===// + +using namespace clang::driver; +using namespace clang::driver::cc1options; + +// + +static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + + Opts.AnalysisList.clear(); +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \ + if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME); +#include "clang/Frontend/Analyses.def" + + if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumStores); + // FIXME: Error handling. + if (Value == NumStores) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisStoreOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ + .Case(CMDFLAG, NAME##Model) +#include "clang/Frontend/Analyses.def" + .Default(NumConstraints); + // FIXME: Error handling. + if (Value == NumConstraints) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisConstraintsOpt = Value; + } + + if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { + llvm::StringRef Name = A->getValue(Args); + AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ + .Case(CMDFLAG, PD_##NAME) +#include "clang/Frontend/Analyses.def" + .Default(NUM_ANALYSIS_DIAG_CLIENTS); + // FIXME: Error handling. + if (Value == NUM_ANALYSIS_DIAG_CLIENTS) + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Name; + else + Opts.AnalysisDiagOpt = Value; + } + + Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); + Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); + Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); + Opts.AnalyzeNestedBlocks = + Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); + Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); + Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); + Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); + Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); + Opts.EnableExperimentalInternalChecks = + Args.hasArg(OPT_analyzer_experimental_internal_checks); + Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); + Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); + Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags); + Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); +} + +static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + // -Os implies -O2 + if (Args.hasArg(OPT_Os)) + Opts.OptimizationLevel = 2; + else { + Opts.OptimizationLevel = Args.getLastArgIntValue(OPT_O, 0, Diags); + if (Opts.OptimizationLevel > 3) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_O)->getAsString(Args) << Opts.OptimizationLevel; + Opts.OptimizationLevel = 3; + } + } + + // We must always run at least the always inlining pass. + Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining + : CodeGenOptions::OnlyAlwaysInlining; + + Opts.DebugInfo = Args.hasArg(OPT_g); + Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); + Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); + Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); + Opts.NoCommon = Args.hasArg(OPT_fno_common); + Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); + Opts.OptimizeSize = Args.hasArg(OPT_Os); + Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + + Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); + Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); + Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); + Opts.CodeModel = Args.getLastArgValue(OPT_mcode_model); + Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); + Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); + Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); + Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); + Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); + Opts.SoftFloat = Args.hasArg(OPT_msoft_float); + Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); + Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); + + Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); + Opts.DataSections = Args.hasArg(OPT_fdata_sections); + + Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); + Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + + if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { + llvm::StringRef Name = A->getValue(Args); + unsigned Method = llvm::StringSwitch<unsigned>(Name) + .Case("legacy", CodeGenOptions::Legacy) + .Case("non-legacy", CodeGenOptions::NonLegacy) + .Case("mixed", CodeGenOptions::Mixed) + .Default(~0U); + if (Method == ~0U) + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + else + Opts.ObjCDispatchMethod = Method; + } +} + +static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.OutputFile = Args.getLastArgValue(OPT_dependency_file); + Opts.Targets = Args.getAllArgValues(OPT_MT); + Opts.IncludeSystemHeaders = Args.hasArg(OPT_sys_header_deps); + Opts.UsePhonyTargets = Args.hasArg(OPT_MP); +} + +static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + Opts.IgnoreWarnings = Args.hasArg(OPT_w); + Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); + Opts.Pedantic = Args.hasArg(OPT_pedantic); + Opts.PedanticErrors = Args.hasArg(OPT_pedantic_errors); + Opts.ShowCarets = !Args.hasArg(OPT_fno_caret_diagnostics); + Opts.ShowColors = Args.hasArg(OPT_fcolor_diagnostics); + Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column); + Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); + Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); + Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); + + llvm::StringRef ShowCategory = + Args.getLastArgValue(OPT_fdiagnostics_show_category, "none"); + if (ShowCategory == "none") + Opts.ShowCategories = 0; + else if (ShowCategory == "id") + Opts.ShowCategories = 1; + else if (ShowCategory == "name") + Opts.ShowCategories = 2; + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fdiagnostics_show_category)->getAsString(Args) + << ShowCategory; + + Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); + Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); + Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); + Opts.MacroBacktraceLimit + = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, + DiagnosticOptions::DefaultMacroBacktraceLimit, Diags); + Opts.TemplateBacktraceLimit + = Args.getLastArgIntValue(OPT_ftemplate_backtrace_limit, + DiagnosticOptions::DefaultTemplateBacktraceLimit, + Diags); + Opts.TabStop = Args.getLastArgIntValue(OPT_ftabstop, + DiagnosticOptions::DefaultTabStop, Diags); + if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { + Diags.Report(diag::warn_ignoring_ftabstop_value) + << Opts.TabStop << DiagnosticOptions::DefaultTabStop; + Opts.TabStop = DiagnosticOptions::DefaultTabStop; + } + Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags); + Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information); + Opts.Warnings = Args.getAllArgValues(OPT_W); +} + +static FrontendOptions::InputKind +ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { + using namespace cc1options; + Opts.ProgramAction = frontend::ParseSyntaxOnly; + if (const Arg *A = Args.getLastArg(OPT_Action_Group)) { + switch (A->getOption().getID()) { + default: + assert(0 && "Invalid option in group!"); + case OPT_ast_dump: + Opts.ProgramAction = frontend::ASTDump; break; + case OPT_ast_print: + Opts.ProgramAction = frontend::ASTPrint; break; + case OPT_ast_print_xml: + Opts.ProgramAction = frontend::ASTPrintXML; break; + case OPT_ast_view: + Opts.ProgramAction = frontend::ASTView; break; + case OPT_boostcon: + Opts.ProgramAction = frontend::BoostCon; break; + case OPT_dump_raw_tokens: + Opts.ProgramAction = frontend::DumpRawTokens; break; + case OPT_dump_tokens: + Opts.ProgramAction = frontend::DumpTokens; break; + case OPT_S: + Opts.ProgramAction = frontend::EmitAssembly; break; + case OPT_emit_llvm_bc: + Opts.ProgramAction = frontend::EmitBC; break; + case OPT_emit_html: + Opts.ProgramAction = frontend::EmitHTML; break; + case OPT_emit_llvm: + Opts.ProgramAction = frontend::EmitLLVM; break; + case OPT_emit_llvm_only: + Opts.ProgramAction = frontend::EmitLLVMOnly; break; + case OPT_emit_codegen_only: + Opts.ProgramAction = frontend::EmitCodeGenOnly; break; + case OPT_emit_obj: + Opts.ProgramAction = frontend::EmitObj; break; + case OPT_fixit_EQ: + Opts.FixItSuffix = A->getValue(Args); + // fall-through! + case OPT_fixit: + Opts.ProgramAction = frontend::FixIt; break; + case OPT_emit_pch: + Opts.ProgramAction = frontend::GeneratePCH; break; + case OPT_emit_pth: + Opts.ProgramAction = frontend::GeneratePTH; break; + case OPT_init_only: + Opts.ProgramAction = frontend::InitOnly; break; + case OPT_parse_noop: + Opts.ProgramAction = frontend::ParseNoop; break; + case OPT_parse_print_callbacks: + Opts.ProgramAction = frontend::ParsePrintCallbacks; break; + case OPT_fsyntax_only: + Opts.ProgramAction = frontend::ParseSyntaxOnly; break; + case OPT_print_decl_contexts: + Opts.ProgramAction = frontend::PrintDeclContext; break; + case OPT_E: + Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_rewrite_macros: + Opts.ProgramAction = frontend::RewriteMacros; break; + case OPT_rewrite_objc: + Opts.ProgramAction = frontend::RewriteObjC; break; + case OPT_rewrite_test: + Opts.ProgramAction = frontend::RewriteTest; break; + case OPT_analyze: + Opts.ProgramAction = frontend::RunAnalysis; break; + case OPT_Eonly: + Opts.ProgramAction = frontend::RunPreprocessorOnly; break; + } + } + if (const Arg *A = Args.getLastArg(OPT_plugin)) { + Opts.ProgramAction = frontend::PluginAction; + Opts.ActionName = A->getValue(Args); + } + + if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { + Opts.CodeCompletionAt = + ParsedSourceLocation::FromString(A->getValue(Args)); + if (Opts.CodeCompletionAt.FileName.empty()) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + Opts.DebugCodeCompletionPrinter = + !Args.hasArg(OPT_no_code_completion_debug_printer); + Opts.DisableFree = Args.hasArg(OPT_disable_free); + + Opts.OutputFile = Args.getLastArgValue(OPT_o); + Opts.Plugins = Args.getAllArgValues(OPT_load); + Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); + Opts.ShowHelp = Args.hasArg(OPT_help); + Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); + Opts.ShowCodePatternsInCodeCompletion + = Args.hasArg(OPT_code_completion_patterns); + Opts.ShowStats = Args.hasArg(OPT_print_stats); + Opts.ShowTimers = Args.hasArg(OPT_ftime_report); + Opts.ShowVersion = Args.hasArg(OPT_version); + Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view); + Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); + Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); + + FrontendOptions::InputKind DashX = FrontendOptions::IK_None; + if (const Arg *A = Args.getLastArg(OPT_x)) { + DashX = llvm::StringSwitch<FrontendOptions::InputKind>(A->getValue(Args)) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c", FrontendOptions::IK_C) + .Case("cl", FrontendOptions::IK_OpenCL) + .Case("c++", FrontendOptions::IK_CXX) + .Case("objective-c", FrontendOptions::IK_ObjC) + .Case("objective-c++", FrontendOptions::IK_ObjCXX) + .Case("cpp-output", FrontendOptions::IK_PreprocessedC) + .Case("assembler-with-cpp", FrontendOptions::IK_Asm) + .Case("c++-cpp-output", FrontendOptions::IK_PreprocessedCXX) + .Case("objective-c-cpp-output", FrontendOptions::IK_PreprocessedObjC) + .Case("objective-c++-cpp-output", FrontendOptions::IK_PreprocessedObjCXX) + .Case("c-header", FrontendOptions::IK_C) + .Case("objective-c-header", FrontendOptions::IK_ObjC) + .Case("c++-header", FrontendOptions::IK_CXX) + .Case("objective-c++-header", FrontendOptions::IK_ObjCXX) + .Case("ast", FrontendOptions::IK_AST) + .Default(FrontendOptions::IK_None); + if (DashX == FrontendOptions::IK_None) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + // '-' is the default input if none is given. + std::vector<std::string> Inputs = Args.getAllArgValues(OPT_INPUT); + Opts.Inputs.clear(); + if (Inputs.empty()) + Inputs.push_back("-"); + for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { + FrontendOptions::InputKind IK = DashX; + if (IK == FrontendOptions::IK_None) { + IK = FrontendOptions::getInputKindForExtension( + llvm::StringRef(Inputs[i]).rsplit('.').second); + // FIXME: Remove this hack. + if (i == 0) + DashX = IK; + } + Opts.Inputs.push_back(std::make_pair(IK, Inputs[i])); + } + + return DashX; +} + +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { + llvm::sys::Path P = llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); + + if (!P.isEmpty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang/<version>/include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + } + + return P.str(); +} + +static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.Sysroot = Args.getLastArgValue(OPT_isysroot, "/"); + Opts.Verbose = Args.hasArg(OPT_v); + Opts.UseBuiltinIncludes = !Args.hasArg(OPT_nobuiltininc); + Opts.UseStandardIncludes = !Args.hasArg(OPT_nostdinc); + Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); + Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); + + // Add -I... and -F... options in order. + for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Angled, true, + /*IsFramework=*/ it->getOption().matches(OPT_F)); + + // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. + llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. + for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix, + OPT_iwithprefixbefore), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_iprefix)) + Prefix = it->getValue(Args); + else if (it->getOption().matches(OPT_iwithprefix)) + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::System, false, false); + else + Opts.AddPath(Prefix.str() + it->getValue(Args), + frontend::Angled, false, false); + } + + for (arg_iterator it = Args.filtered_begin(OPT_idirafter), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::After, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_iquote), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::Quoted, true, false); + for (arg_iterator it = Args.filtered_begin(OPT_isystem), + ie = Args.filtered_end(); it != ie; ++it) + Opts.AddPath(it->getValue(Args), frontend::System, true, false); + + // FIXME: Need options for the various environment variables! +} + +static void ParseLangArgs(LangOptions &Opts, ArgList &Args, + FrontendOptions::InputKind IK, + Diagnostic &Diags) { + // FIXME: Cleanup per-file based stuff. + + // Set some properties which depend soley on the input kind; it would be nice + // to move these to the language standard, and have the driver resolve the + // input kind + language standard. + if (IK == FrontendOptions::IK_Asm) { + Opts.AsmPreprocessor = 1; + } else if (IK == FrontendOptions::IK_ObjC || + IK == FrontendOptions::IK_ObjCXX || + IK == FrontendOptions::IK_PreprocessedObjC || + IK == FrontendOptions::IK_PreprocessedObjCXX) { + Opts.ObjC1 = Opts.ObjC2 = 1; + } + + LangStandard::Kind LangStd = LangStandard::lang_unspecified; + if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { + LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, LangStandard::lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(LangStandard::lang_unspecified); + if (LangStd == LangStandard::lang_unspecified) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << A->getValue(Args); + } + + if (LangStd == LangStandard::lang_unspecified) { + // Based on the base language, pick one. + switch (IK) { + case FrontendOptions::IK_None: + case FrontendOptions::IK_AST: + assert(0 && "Invalid input kind!"); + case FrontendOptions::IK_OpenCL: + LangStd = LangStandard::lang_opencl; + break; + case FrontendOptions::IK_Asm: + case FrontendOptions::IK_C: + case FrontendOptions::IK_PreprocessedC: + case FrontendOptions::IK_ObjC: + case FrontendOptions::IK_PreprocessedObjC: + LangStd = LangStandard::lang_gnu99; + break; + case FrontendOptions::IK_CXX: + case FrontendOptions::IK_PreprocessedCXX: + case FrontendOptions::IK_ObjCXX: + case FrontendOptions::IK_PreprocessedObjCXX: + LangStd = LangStandard::lang_gnucxx98; + break; + } + } + + const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); + Opts.BCPLComment = Std.hasBCPLComments(); + Opts.C99 = Std.isC99(); + Opts.CPlusPlus = Std.isCPlusPlus(); + Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.Digraphs = Std.hasDigraphs(); + Opts.GNUMode = Std.isGNUMode(); + Opts.GNUInline = !Std.isC99(); + Opts.HexFloats = Std.hasHexFloats(); + Opts.ImplicitInt = Std.hasImplicitInt(); + + // OpenCL has some additional defaults. + if (LangStd == LangStandard::lang_opencl) { + Opts.OpenCL = 1; + Opts.AltiVec = 1; + Opts.CXXOperatorNames = 1; + Opts.LaxVectorConversions = 1; + } + + // OpenCL and C++ both have bool, true, false keywords. + Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + + // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension + // keywords. This behavior is provided by GCC's poorly named '-fasm' flag, + // while a subset (the non-C++ GNU keywords) is provided by GCC's + // '-fgnu-keywords'. Clang conflates the two for simplicity under the single + // name, as it doesn't seem a useful distinction. + Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, + Opts.GNUMode); + + if (Opts.CPlusPlus) + Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); + + if (Args.hasArg(OPT_fobjc_gc_only)) + Opts.setGCMode(LangOptions::GCOnly); + else if (Args.hasArg(OPT_fobjc_gc)) + Opts.setGCMode(LangOptions::HybridGC); + + if (Args.hasArg(OPT_print_ivar_layout)) + Opts.ObjCGCBitmapPrint = 1; + if (Args.hasArg(OPT_fno_constant_cfstrings)) + Opts.NoConstantCFStrings = 1; + + if (Args.hasArg(OPT_faltivec)) + Opts.AltiVec = 1; + + if (Args.hasArg(OPT_pthread)) + Opts.POSIXThreads = 1; + + llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); + if (Vis == "default") + Opts.setVisibilityMode(LangOptions::Default); + else if (Vis == "hidden") + Opts.setVisibilityMode(LangOptions::Hidden); + else if (Vis == "protected") + Opts.setVisibilityMode(LangOptions::Protected); + else + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; + + Opts.OverflowChecking = Args.hasArg(OPT_ftrapv); + + // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs + // is specified, or -std is set to a conforming mode. + Opts.Trigraphs = !Opts.GNUMode; + if (Args.hasArg(OPT_trigraphs)) + Opts.Trigraphs = 1; + + Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers, + OPT_fno_dollars_in_identifiers, + !Opts.AsmPreprocessor); + Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); + Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); + Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings); + if (Args.hasArg(OPT_fno_lax_vector_conversions)) + Opts.LaxVectorConversions = 0; + if (Args.hasArg(OPT_fno_threadsafe_statics)) + Opts.ThreadsafeStatics = 0; + Opts.Exceptions = Args.hasArg(OPT_fexceptions); + Opts.RTTI = !Args.hasArg(OPT_fno_rtti); + Opts.Blocks = Args.hasArg(OPT_fblocks); + Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); + Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); + Opts.Freestanding = Args.hasArg(OPT_ffreestanding); + Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); + Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); + Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); + Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); + Opts.MathErrno = Args.hasArg(OPT_fmath_errno); + Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, + Diags); + Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); + Opts.ObjCConstantStringClass = + Args.getLastArgValue(OPT_fconstant_string_class); + Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi); + Opts.ObjCNonFragileABI2 = Args.hasArg(OPT_fobjc_nonfragile_abi2); + if (Opts.ObjCNonFragileABI2) + Opts.ObjCNonFragileABI = true; + Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); + Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); + Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); + Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); + Opts.Static = Args.hasArg(OPT_static_define); + Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); + Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); + Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align); + Opts.OptimizeSize = 0; + + // FIXME: Eliminate this dependency. + unsigned Opt = + Args.hasArg(OPT_Os) ? 2 : Args.getLastArgIntValue(OPT_O, 0, Diags); + Opts.Optimize = Opt != 0; + + // This is the __NO_INLINE__ define, which just depends on things like the + // optimization level and -fno-inline, not actually whether the backend has + // inlining enabled. + // + // FIXME: This is affected by other options (-fno-inline). + Opts.NoInline = !Opt; + + unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); + switch (SSP) { + default: + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP; + break; + case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break; + case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break; + case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break; + } +} + +static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, + Diagnostic &Diags) { + using namespace cc1options; + Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); + Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); + if (const Arg *A = Args.getLastArg(OPT_token_cache)) + Opts.TokenCache = A->getValue(Args); + else + Opts.TokenCache = Opts.ImplicitPTHInclude; + Opts.UsePredefines = !Args.hasArg(OPT_undef); + Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); + // Add macros from the command line. + for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), + ie = Args.filtered_end(); it != ie; ++it) { + if (it->getOption().matches(OPT_D)) + Opts.addMacroDef(it->getValue(Args)); + else + Opts.addMacroUndef(it->getValue(Args)); + } + + Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); + + // Add the ordered list of -includes. + for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch, + OPT_include_pth), + ie = Args.filtered_end(); it != ie; ++it) { + // PCH is handled specially, we need to extra the original include path. + if (it->getOption().matches(OPT_include_pch)) { + std::string OriginalFile = + PCHReader::getOriginalSourceFile(it->getValue(Args), Diags); + if (OriginalFile.empty()) + continue; + + Opts.Includes.push_back(OriginalFile); + } else + Opts.Includes.push_back(it->getValue(Args)); + } + + // Include 'altivec.h' if -faltivec option present + if (Args.hasArg(OPT_faltivec)) + Opts.Includes.push_back("altivec.h"); + + for (arg_iterator it = Args.filtered_begin(OPT_remap_file), + ie = Args.filtered_end(); it != ie; ++it) { + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(it->getValue(Args)).split(';'); + + if (Split.second.empty()) { + Diags.Report(diag::err_drv_invalid_remap_file) << it->getAsString(Args); + continue; + } + + Opts.addRemappedFile(Split.first, Split.second); + } +} + +static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, + ArgList &Args) { + using namespace cc1options; + Opts.ShowCPP = !Args.hasArg(OPT_dM); + Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); + Opts.ShowLineMarkers = !Args.hasArg(OPT_P); + Opts.ShowComments = Args.hasArg(OPT_C); + Opts.ShowMacroComments = Args.hasArg(OPT_CC); +} + +static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { + using namespace cc1options; + Opts.ABI = Args.getLastArgValue(OPT_target_abi); + Opts.CPU = Args.getLastArgValue(OPT_target_cpu); + Opts.Triple = Args.getLastArgValue(OPT_triple); + Opts.Features = Args.getAllArgValues(OPT_target_feature); + + // Use the host triple if unspecified. + if (Opts.Triple.empty()) + Opts.Triple = llvm::sys::getHostTriple(); +} + +// + +void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, + const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags) { + // Parse the arguments. + llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); + unsigned MissingArgIndex, MissingArgCount; + llvm::OwningPtr<InputArgList> Args( + Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Issue errors on unknown arguments. + for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + + ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); + ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags); + ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); + ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); + FrontendOptions::InputKind DashX = + ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); + ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); + if (DashX != FrontendOptions::IK_AST) + ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); + ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); + ParseTargetArgs(Res.getTargetOpts(), *Args); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp new file mode 100644 index 0000000..97a7f55 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp @@ -0,0 +1,189 @@ +//===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" + +namespace clang { + +//--------------------------------------------------------- +class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { + DocumentXML& Doc; + + void addSubNodes(FunctionDecl* FD) { + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { + Visit(FD->getParamDecl(i)); + Doc.toParent(); + } + } + + void addFunctionBody(FunctionDecl* FD) { + if (FD->isThisDeclarationADefinition()) { + Doc.addSubNode("Body"); + Doc.PrintStmt(FD->getBody()); + Doc.toParent(); + } + } + + void addSubNodes(RecordDecl* RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + Visit(*i); + Doc.toParent(); + } + } + + void addSubNodes(CXXRecordDecl* RD) { + addSubNodes(cast<RecordDecl>(RD)); + + if (RD->isDefinition()) { + // FIXME: This breaks XML generation + //Doc.addAttribute("num_bases", RD->getNumBases()); + + for (CXXRecordDecl::base_class_iterator + base = RD->bases_begin(), + bend = RD->bases_end(); + base != bend; + ++base) { + Doc.addSubNode("Base"); + Doc.addAttribute("id", base->getType()); + AccessSpecifier as = base->getAccessSpecifierAsWritten(); + const char* as_name = ""; + switch(as) { + case AS_none: as_name = ""; break; + case AS_public: as_name = "public"; break; + case AS_protected: as_name = "protected"; break; + case AS_private: as_name = "private"; break; + } + Doc.addAttributeOptional("access", as_name); + Doc.addAttribute("is_virtual", base->isVirtual()); + Doc.toParent(); + } + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + Visit(*i); + Doc.toParent(); + } + + } + + } + + void addSubNodes(EnumDecl* ED) { + for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(), + e = ED->enumerator_end(); i != e; ++i) { + Visit(*i); + Doc.toParent(); + } + } + + void addSubNodes(EnumConstantDecl* ECD) { + if (ECD->getInitExpr()) + Doc.PrintStmt(ECD->getInitExpr()); + } + + void addSubNodes(FieldDecl* FdD) { + if (FdD->isBitField()) + Doc.PrintStmt(FdD->getBitWidth()); + } + + void addSubNodes(VarDecl* V) { + if (V->getInit()) + Doc.PrintStmt(V->getInit()); + } + + void addSubNodes(ParmVarDecl* argDecl) { + if (argDecl->getDefaultArg()) + Doc.PrintStmt(argDecl->getDefaultArg()); + } + + void addSubNodes(NamespaceDecl* ns) { + + for (DeclContext::decl_iterator + d = ns->decls_begin(), + dend = ns->decls_end(); + d != dend; + ++d) { + Visit(*d); + Doc.toParent(); + } + } + + void addSpecialAttribute(const char* pName, EnumDecl* ED) { + const QualType& enumType = ED->getIntegerType(); + if (!enumType.isNull()) + Doc.addAttribute(pName, enumType); + } + + void addIdAttribute(LinkageSpecDecl* ED) { + Doc.addAttribute("id", ED); + } + + void addIdAttribute(NamedDecl* ND) { + Doc.addAttribute("id", ND); + } + +public: + DeclPrinter(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) \ + { \ + Doc.addSubNode(NAME); + +#define ID_ATTRIBUTE_XML addIdAttribute(T); +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); +#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation()); +#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T); + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#define SUB_NODE_XML( CLASS ) addSubNodes(T); +#define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T); +#define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T); + +#define SUB_NODE_FN_BODY_XML addFunctionBody(T); + +#include "clang/Frontend/DeclXML.def" +}; + + +//--------------------------------------------------------- +void DocumentXML::writeDeclToXML(Decl *D) { + DeclPrinter(*this).Visit(D); + toParent(); +} + +//--------------------------------------------------------- +} // NS clang + diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp new file mode 100644 index 0000000..14aee35 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp @@ -0,0 +1,174 @@ +//===--- DependencyFile.cpp - Generate dependency file --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code generates dependency files. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +using namespace clang; + +namespace { +class DependencyFileCallback : public PPCallbacks { + std::vector<std::string> Files; + llvm::StringSet<> FilesSet; + const Preprocessor *PP; + std::vector<std::string> Targets; + llvm::raw_ostream *OS; + bool IncludeSystemHeaders; + bool PhonyTarget; +private: + bool FileMatchesDepCriteria(const char *Filename, + SrcMgr::CharacteristicKind FileType); + void OutputDependencyFile(); + +public: + DependencyFileCallback(const Preprocessor *_PP, + llvm::raw_ostream *_OS, + const DependencyOutputOptions &Opts) + : PP(_PP), Targets(Opts.Targets), OS(_OS), + IncludeSystemHeaders(Opts.IncludeSystemHeaders), + PhonyTarget(Opts.UsePhonyTargets) {} + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType); + + virtual void EndOfMainFile() { + OutputDependencyFile(); + OS->flush(); + delete OS; + OS = 0; + } +}; +} + +void clang::AttachDependencyFileGen(Preprocessor &PP, + const DependencyOutputOptions &Opts) { + if (Opts.Targets.empty()) { + PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT); + return; + } + + std::string Err; + llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err)); + if (!Err.empty()) { + PP.getDiagnostics().Report(diag::err_fe_error_opening) + << Opts.OutputFile << Err; + return; + } + + PP.addPPCallbacks(new DependencyFileCallback(&PP, OS, Opts)); +} + +/// FileMatchesDepCriteria - Determine whether the given Filename should be +/// considered as a dependency. +bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename, + SrcMgr::CharacteristicKind FileType) { + if (strcmp("<built-in>", Filename) == 0) + return false; + + if (IncludeSystemHeaders) + return true; + + return FileType == SrcMgr::C_User; +} + +void DependencyFileCallback::FileChanged(SourceLocation Loc, + FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType) { + if (Reason != PPCallbacks::EnterFile) + return; + + // Dependency generation really does want to go all the way to the + // file entry for a source location to find out what is depended on. + // We do not want #line markers to affect dependency generation! + SourceManager &SM = PP->getSourceManager(); + + const FileEntry *FE = + SM.getFileEntryForID(SM.getFileID(SM.getInstantiationLoc(Loc))); + if (FE == 0) return; + + const char *Filename = FE->getName(); + if (!FileMatchesDepCriteria(Filename, FileType)) + return; + + // Remove leading "./" + if (Filename[0] == '.' && Filename[1] == '/') + Filename = &Filename[2]; + + if (FilesSet.insert(Filename)) + Files.push_back(Filename); +} + +void DependencyFileCallback::OutputDependencyFile() { + // Write out the dependency targets, trying to avoid overly long + // lines when possible. We try our best to emit exactly the same + // dependency file as GCC (4.2), assuming the included files are the + // same. + const unsigned MaxColumns = 75; + unsigned Columns = 0; + + for (std::vector<std::string>::iterator + I = Targets.begin(), E = Targets.end(); I != E; ++I) { + unsigned N = I->length(); + if (Columns == 0) { + Columns += N; + *OS << *I; + } else if (Columns + N + 2 > MaxColumns) { + Columns = N + 2; + *OS << " \\\n " << *I; + } else { + Columns += N + 1; + *OS << ' ' << *I; + } + } + + *OS << ':'; + Columns += 1; + + // Now add each dependency in the order it was seen, but avoiding + // duplicates. + for (std::vector<std::string>::iterator I = Files.begin(), + E = Files.end(); I != E; ++I) { + // Start a new line if this would exceed the column limit. Make + // sure to leave space for a trailing " \" in case we need to + // break the line on the next iteration. + unsigned N = I->length(); + if (Columns + (N + 1) + 2 > MaxColumns) { + *OS << " \\\n "; + Columns = 2; + } + *OS << ' ' << *I; + Columns += N + 1; + } + *OS << '\n'; + + // Create phony targets if requested. + if (PhonyTarget) { + // Skip the first entry, this is always the input file itself. + for (std::vector<std::string>::iterator I = Files.begin() + 1, + E = Files.end(); I != E; ++I) { + *OS << '\n'; + *OS << *I << ":\n"; + } + } +} + diff --git a/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp new file mode 100644 index 0000000..a50cc99 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/DiagChecker.cpp @@ -0,0 +1,301 @@ +//===--- DiagChecker.cpp - Diagnostic Checking Functions ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Process the input files and check that the diagnostic messages are expected. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Sema/ParseAST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +typedef TextDiagnosticBuffer::DiagList DiagList; +typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; + +static void EmitError(Preprocessor &PP, SourceLocation Pos, const char *String){ + unsigned ID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, String); + PP.Diag(Pos, ID); +} + + +// USING THE DIAGNOSTIC CHECKER: +// +// Indicating that a line expects an error or a warning is simple. Put a comment +// on the line that has the diagnostic, use "expected-{error,warning}" to tag +// if it's an expected error or warning, and place the expected text between {{ +// and }} markers. The full text doesn't have to be included, only enough to +// ensure that the correct diagnostic was emitted. +// +// Here's an example: +// +// int A = B; // expected-error {{use of undeclared identifier 'B'}} +// +// You can place as many diagnostics on one line as you wish. To make the code +// more readable, you can use slash-newline to separate out the diagnostics. +// +// The simple syntax above allows each specification to match exactly one error. +// You can use the extended syntax to customize this. The extended syntax is +// "expected-<type> <n> {{diag text}}", where <type> is one of "error", +// "warning" or "note", and <n> is a positive integer. This allows the +// diagnostic to appear as many times as specified. Example: +// +// void f(); // expected-note 2 {{previous declaration is here}} +// + +/// FindDiagnostics - Go through the comment and see if it indicates expected +/// diagnostics. If so, then put them in a diagnostic list. +/// +static void FindDiagnostics(const char *CommentStart, unsigned CommentLen, + DiagList &ExpectedDiags, + Preprocessor &PP, SourceLocation Pos, + const char *ExpectedStr) { + const char *CommentEnd = CommentStart+CommentLen; + unsigned ExpectedStrLen = strlen(ExpectedStr); + + // Find all expected-foo diagnostics in the string and add them to + // ExpectedDiags. + while (CommentStart != CommentEnd) { + CommentStart = std::find(CommentStart, CommentEnd, 'e'); + if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return; + + // If this isn't expected-foo, ignore it. + if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) { + ++CommentStart; + continue; + } + + CommentStart += ExpectedStrLen; + + // Skip whitespace. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // Default, if we find the '{' now, is 1 time. + int Times = 1; + int Temp = 0; + // In extended syntax, there could be a digit now. + while (CommentStart != CommentEnd && + CommentStart[0] >= '0' && CommentStart[0] <= '9') { + Temp *= 10; + Temp += CommentStart[0] - '0'; + ++CommentStart; + } + if (Temp > 0) + Times = Temp; + + // Skip whitespace again. + while (CommentStart != CommentEnd && + isspace(CommentStart[0])) + ++CommentStart; + + // We should have a {{ now. + if (CommentEnd-CommentStart < 2 || + CommentStart[0] != '{' || CommentStart[1] != '{') { + if (std::find(CommentStart, CommentEnd, '{') != CommentEnd) + EmitError(PP, Pos, "bogus characters before '{{' in expected string"); + else + EmitError(PP, Pos, "cannot find start ('{{') of expected string"); + return; + } + CommentStart += 2; + + // Find the }}. + const char *ExpectedEnd = CommentStart; + while (1) { + ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}'); + if (CommentEnd-ExpectedEnd < 2) { + EmitError(PP, Pos, "cannot find end ('}}') of expected string"); + return; + } + + if (ExpectedEnd[1] == '}') + break; + + ++ExpectedEnd; // Skip over singular }'s + } + + std::string Msg(CommentStart, ExpectedEnd); + std::string::size_type FindPos; + while ((FindPos = Msg.find("\\n")) != std::string::npos) + Msg.replace(FindPos, 2, "\n"); + // Add is possibly multiple times. + for (int i = 0; i < Times; ++i) + ExpectedDiags.push_back(std::make_pair(Pos, Msg)); + + CommentStart = ExpectedEnd; + } +} + +/// FindExpectedDiags - Lex the main source file to find all of the +// expected errors and warnings. +static void FindExpectedDiags(Preprocessor &PP, + DiagList &ExpectedErrors, + DiagList &ExpectedWarnings, + DiagList &ExpectedNotes) { + // Create a raw lexer to pull all the comments out of the main file. We don't + // want to look in #include'd headers for expected-error strings. + FileID FID = PP.getSourceManager().getMainFileID(); + + // Create a lexer to lex all the tokens of the main file in raw mode. + const llvm::MemoryBuffer *FromFile = PP.getSourceManager().getBuffer(FID); + Lexer RawLex(FID, FromFile, PP.getSourceManager(), PP.getLangOptions()); + + // Return comments as tokens, this is how we find expected diagnostics. + RawLex.SetCommentRetentionState(true); + + Token Tok; + Tok.setKind(tok::comment); + while (Tok.isNot(tok::eof)) { + RawLex.Lex(Tok); + if (!Tok.is(tok::comment)) continue; + + std::string Comment = PP.getSpelling(Tok); + if (Comment.empty()) continue; + + + // Find all expected errors. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, + Tok.getLocation(), "expected-error"); + + // Find all expected warnings. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, + Tok.getLocation(), "expected-warning"); + + // Find all expected notes. + FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, + Tok.getLocation(), "expected-note"); + }; +} + +/// PrintProblem - This takes a diagnostic map of the delta between expected and +/// seen diagnostics. If there's anything in it, then something unexpected +/// happened. Print the map out in a nice format and return "true". If the map +/// is empty and we're not going to print things, then return "false". +/// +static bool PrintProblem(SourceManager &SourceMgr, + const_diag_iterator diag_begin, + const_diag_iterator diag_end, + const char *Msg) { + if (diag_begin == diag_end) return false; + + llvm::errs() << Msg << "\n"; + for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) + llvm::errs() << " Line " << SourceMgr.getInstantiationLineNumber(I->first) + << " " << I->second << "\n"; + + return true; +} + +/// CompareDiagLists - Compare two diagnostic lists and return the difference +/// between them. +/// +static bool CompareDiagLists(SourceManager &SourceMgr, + const_diag_iterator d1_begin, + const_diag_iterator d1_end, + const_diag_iterator d2_begin, + const_diag_iterator d2_end, + const char *MsgLeftOnly, + const char *MsgRightOnly) { + DiagList LeftOnly; + DiagList Left(d1_begin, d1_end); + DiagList Right(d2_begin, d2_end); + + for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) { + unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first); + const std::string &Diag1 = I->second; + + DiagList::iterator II, IE; + for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { + unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); + if (LineNo1 != LineNo2) continue; + + const std::string &Diag2 = II->second; + if (Diag2.find(Diag1) != std::string::npos || + Diag1.find(Diag2) != std::string::npos) { + break; + } + } + if (II == IE) { + // Not found. + LeftOnly.push_back(*I); + } else { + // Found. The same cannot be found twice. + Right.erase(II); + } + } + // Now all that's left in Right are those that were not matched. + + return PrintProblem(SourceMgr, LeftOnly.begin(), LeftOnly.end(), MsgLeftOnly) + | PrintProblem(SourceMgr, Right.begin(), Right.end(), MsgRightOnly); +} + +/// CheckResults - This compares the expected results to those that +/// were actually reported. It emits any discrepencies. Return "true" if there +/// were problems. Return "false" otherwise. +/// +static bool CheckResults(Preprocessor &PP, + const DiagList &ExpectedErrors, + const DiagList &ExpectedWarnings, + const DiagList &ExpectedNotes) { + const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient(); + assert(DiagClient != 0 && + "DiagChecker requires a valid TextDiagnosticBuffer"); + const TextDiagnosticBuffer &Diags = + static_cast<const TextDiagnosticBuffer&>(*DiagClient); + SourceManager &SourceMgr = PP.getSourceManager(); + + // We want to capture the delta between what was expected and what was + // seen. + // + // Expected \ Seen - set expected but not seen + // Seen \ Expected - set seen but not expected + bool HadProblem = false; + + // See if there are error mismatches. + HadProblem |= CompareDiagLists(SourceMgr, + ExpectedErrors.begin(), ExpectedErrors.end(), + Diags.err_begin(), Diags.err_end(), + "Errors expected but not seen:", + "Errors seen but not expected:"); + + // See if there are warning mismatches. + HadProblem |= CompareDiagLists(SourceMgr, + ExpectedWarnings.begin(), + ExpectedWarnings.end(), + Diags.warn_begin(), Diags.warn_end(), + "Warnings expected but not seen:", + "Warnings seen but not expected:"); + + // See if there are note mismatches. + HadProblem |= CompareDiagLists(SourceMgr, + ExpectedNotes.begin(), + ExpectedNotes.end(), + Diags.note_begin(), Diags.note_end(), + "Notes expected but not seen:", + "Notes seen but not expected:"); + + return HadProblem; +} + + +/// CheckDiagnostics - Gather the expected diagnostics and check them. +bool clang::CheckDiagnostics(Preprocessor &PP) { + // Gather the set of expected diagnostics. + DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes; + FindExpectedDiags(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes); + + // Check that the expected diagnostics occurred. + return CheckResults(PP, ExpectedErrors, ExpectedWarnings, ExpectedNotes); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp new file mode 100644 index 0000000..894f230 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp @@ -0,0 +1,367 @@ +//===--- DocumentXML.cpp - XML document for ASTs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringExtras.h" + +namespace clang { + +//--------------------------------------------------------- +DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) : + Out(out), + Ctx(0), + HasCurrentNodeSubNodes(false) { + NodeStack.push(rootName); + Out << "<?xml version=\"1.0\"?>\n<" << rootName; +} + +//--------------------------------------------------------- +DocumentXML& DocumentXML::addSubNode(const std::string& name) { + if (!HasCurrentNodeSubNodes) + Out << ">\n"; + NodeStack.push(name); + HasCurrentNodeSubNodes = false; + Indent(); + Out << "<" << NodeStack.top(); + return *this; +} + +//--------------------------------------------------------- +void DocumentXML::Indent() { + for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i) + Out << ' '; +} + +//--------------------------------------------------------- +DocumentXML& DocumentXML::toParent() { + assert(NodeStack.size() > 1 && "too much backtracking"); + + if (HasCurrentNodeSubNodes) { + Indent(); + Out << "</" << NodeStack.top() << ">\n"; + } else + Out << "/>\n"; + NodeStack.pop(); + HasCurrentNodeSubNodes = true; + return *this; +} + +//--------------------------------------------------------- +namespace { + +enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST }; + +unsigned getNewId(tIdType idType) { + static unsigned int idCounts[ID_LAST] = { 0 }; + return ++idCounts[idType]; +} + +//--------------------------------------------------------- +inline std::string getPrefixedId(unsigned uId, tIdType idType) { + static const char idPrefix[ID_LAST] = { '_', 'f', 'l' }; + char buffer[20]; + char* BufPtr = llvm::utohex_buffer(uId, buffer + 20); + *--BufPtr = idPrefix[idType]; + return BufPtr; +} + +//--------------------------------------------------------- +template<class T, class V> +bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) { + typename T::iterator i = idMap.find(value); + bool toAdd = i == idMap.end(); + if (toAdd) + idMap.insert(typename T::value_type(value, getNewId(idType))); + return toAdd; +} + +} // anon NS + + +//--------------------------------------------------------- +std::string DocumentXML::escapeString(const char* pStr, + std::string::size_type len) { + std::string value; + value.reserve(len + 1); + char buffer[16]; + for (unsigned i = 0; i < len; ++i) { + switch (char C = pStr[i]) { + default: + if (isprint(C)) + value += C; + else { + sprintf(buffer, "\\%03o", C); + value += buffer; + } + break; + + case '\n': value += "\\n"; break; + case '\t': value += "\\t"; break; + case '\a': value += "\\a"; break; + case '\b': value += "\\b"; break; + case '\r': value += "\\r"; break; + + case '&': value += "&"; break; + case '<': value += "<"; break; + case '>': value += ">"; break; + case '"': value += """; break; + case '\'': value += "'"; break; + + } + } + return value; +} + +//--------------------------------------------------------- +void DocumentXML::finalize() { + assert(NodeStack.size() == 1 && "not completely backtracked"); + + addSubNode("ReferenceSection"); + addSubNode("Types"); + + for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); + i != e; ++i) { + if (i->first.hasLocalQualifiers()) { + writeTypeToXML(i->first); + addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); + toParent(); + } + } + + for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), + e = BasicTypes.end(); i != e; ++i) { + writeTypeToXML(i->first); + addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); + toParent(); + } + + + toParent().addSubNode("Contexts"); + + for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), + e = Contexts.end(); i != e; ++i) { + addSubNode(i->first->getDeclKindName()); + addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first)) + addAttribute("name", ND->getNameAsString()); + if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) + addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL)); + else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first)) + addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL)); + + if (const DeclContext* parent = i->first->getParent()) + addAttribute("context", parent); + toParent(); + } + + toParent().addSubNode("Files"); + + for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), + e = SourceFiles.end(); i != e; ++i) { + addSubNode("File"); + addAttribute("id", getPrefixedId(i->second, ID_FILE)); + addAttribute("name", escapeString(i->first.c_str(), i->first.size())); + toParent(); + } + + toParent().toParent(); + + // write the root closing node (which has always subnodes) + Out << "</" << NodeStack.top() << ">\n"; +} + +//--------------------------------------------------------- +void DocumentXML::addAttribute(const char* pAttributeName, + const QualType& pType) { + addTypeRecursively(pType); + addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL)); +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pAttributeName, + const Type* pType) { + addTypeRecursively(pType); + addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL)); +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pAttributeName, + const NestedNameSpecifier* pNNS) { + switch (pNNS->getKind()) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *ii = pNNS->getAsIdentifier(); + // FIXME how should we handle those ? + addPtrAttribute(pAttributeName, ii->getName().data()); + break; + } + case NestedNameSpecifier::Namespace: { + addPtrAttribute(pAttributeName, pNNS->getAsNamespace()); + break; + } + case NestedNameSpecifier::TypeSpec: { + addPtrAttribute(pAttributeName, pNNS->getAsType()); + break; + } + case NestedNameSpecifier::TypeSpecWithTemplate: { + addPtrAttribute(pAttributeName, pNNS->getAsType()); + break; + } + case NestedNameSpecifier::Global: { + addPtrAttribute(pAttributeName, "::"); + break; + } + } +} + +//--------------------------------------------------------- +void DocumentXML::addTypeRecursively(const QualType& pType) +{ + if (addToMap(Types, pType)) + { + addTypeRecursively(pType.getTypePtr()); + // beautifier: a non-qualified type shall be transparent + if (!pType.hasLocalQualifiers()) + { + Types[pType] = BasicTypes[pType.getTypePtr()]; + } + } +} + +//--------------------------------------------------------- +void DocumentXML::addTypeRecursively(const Type* pType) +{ + if (addToMap(BasicTypes, pType)) + { + addParentTypes(pType); +/* + // FIXME: doesn't work in the immediate streaming approach + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType)) + { + addSubNode("VariableArraySizeExpression"); + PrintStmt(VAT->getSizeExpr()); + toParent(); + } +*/ + } +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC) +{ + addContextsRecursively(DC); + addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL)); +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D) +{ + if (const DeclContext* DC = dyn_cast<DeclContext>(D)) + { + addContextsRecursively(DC); + addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL)); + } + else + { + addToMap(Decls, D); + addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL)); + } +} + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D) +{ + addPtrAttribute(pName, static_cast<const DeclContext*>(D)); +} + +//--------------------------------------------------------- +void DocumentXML::addContextsRecursively(const DeclContext *DC) +{ + if (DC != 0 && addToMap(Contexts, DC)) + { + addContextsRecursively(DC->getParent()); + } +} + +//--------------------------------------------------------- +void DocumentXML::addSourceFileAttribute(const std::string& fileName) +{ + addToMap(SourceFiles, fileName, ID_FILE); + addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE)); +} + + +//--------------------------------------------------------- +void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L) +{ + addToMap(Labels, L, ID_LABEL); + addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL)); +} + + +//--------------------------------------------------------- +PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc) +{ + SourceManager& SM = Ctx->getSourceManager(); + SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + PresumedLoc PLoc; + if (!SpellingLoc.isInvalid()) + { + PLoc = SM.getPresumedLoc(SpellingLoc); + addSourceFileAttribute(PLoc.getFilename()); + addAttribute("line", PLoc.getLine()); + addAttribute("col", PLoc.getColumn()); + } + // else there is no error in some cases (eg. CXXThisExpr) + return PLoc; +} + +//--------------------------------------------------------- +void DocumentXML::addLocationRange(const SourceRange& R) +{ + PresumedLoc PStartLoc = addLocation(R.getBegin()); + if (R.getBegin() != R.getEnd()) + { + SourceManager& SM = Ctx->getSourceManager(); + SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd()); + if (!SpellingLoc.isInvalid()) + { + PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc); + if (PStartLoc.isInvalid() || + strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) { + addToMap(SourceFiles, PLoc.getFilename(), ID_FILE); + addAttribute("endfile", PLoc.getFilename()); + addAttribute("endline", PLoc.getLine()); + addAttribute("endcol", PLoc.getColumn()); + } else if (PLoc.getLine() != PStartLoc.getLine()) { + addAttribute("endline", PLoc.getLine()); + addAttribute("endcol", PLoc.getColumn()); + } else { + addAttribute("endcol", PLoc.getColumn()); + } + } + } +} + +//--------------------------------------------------------- +void DocumentXML::PrintDecl(Decl *D) +{ + writeDeclToXML(D); +} + +//--------------------------------------------------------- +} // NS clang + diff --git a/contrib/llvm/tools/clang/lib/Frontend/FixItRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/FixItRewriter.cpp new file mode 100644 index 0000000..7c9a566 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/FixItRewriter.cpp @@ -0,0 +1,167 @@ +//===--- FixItRewriter.cpp - Fix-It Rewriter Diagnostic Client --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a diagnostic client adaptor that performs rewrites as +// suggested by code modification hints attached to diagnostics. It +// then forwards any diagnostics to the adapted diagnostic client. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FixItRewriter.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include <cstdio> + +using namespace clang; + +FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts, + FixItPathRewriter *PathRewriter) + : Diags(Diags), + Rewrite(SourceMgr, LangOpts), + PathRewriter(PathRewriter), + NumFailures(0) { + Client = Diags.getClient(); + Diags.setClient(this); +} + +FixItRewriter::~FixItRewriter() { + Diags.setClient(Client); +} + +bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) { + const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); + if (!RewriteBuf) return true; + RewriteBuf->write(OS); + OS.flush(); + return false; +} + +bool FixItRewriter::WriteFixedFiles() { + if (NumFailures > 0) { + Diag(FullSourceLoc(), diag::warn_fixit_no_changes); + return true; + } + + for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { + const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); + std::string Filename = Entry->getName(); + if (PathRewriter) + Filename = PathRewriter->RewriteFilename(Filename); + std::string Err; + llvm::raw_fd_ostream OS(Filename.c_str(), Err, + llvm::raw_fd_ostream::F_Binary); + if (!Err.empty()) { + Diags.Report(clang::diag::err_fe_unable_to_open_output) + << Filename << Err; + continue; + } + RewriteBuffer &RewriteBuf = I->second; + RewriteBuf.write(OS); + OS.flush(); + } + + return false; +} + +bool FixItRewriter::IncludeInDiagnosticCounts() const { + return Client ? Client->IncludeInDiagnosticCounts() : true; +} + +void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + Client->HandleDiagnostic(DiagLevel, Info); + + // Skip over any diagnostics that are ignored or notes. + if (DiagLevel <= Diagnostic::Note) + return; + + // Make sure that we can perform all of the modifications we + // in this diagnostic. + bool CanRewrite = Info.getNumFixItHints() > 0; + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); + Idx < Last; ++Idx) { + const FixItHint &Hint = Info.getFixItHint(Idx); + if (Hint.RemoveRange.isValid() && + Rewrite.getRangeSize(Hint.RemoveRange) == -1) { + CanRewrite = false; + break; + } + + if (Hint.InsertionLoc.isValid() && + !Rewrite.isRewritable(Hint.InsertionLoc)) { + CanRewrite = false; + break; + } + } + + if (!CanRewrite) { + if (Info.getNumFixItHints() > 0) + Diag(Info.getLocation(), diag::note_fixit_in_macro); + + // If this was an error, refuse to perform any rewriting. + if (DiagLevel == Diagnostic::Error || DiagLevel == Diagnostic::Fatal) { + if (++NumFailures == 1) + Diag(Info.getLocation(), diag::note_fixit_unfixed_error); + } + return; + } + + bool Failed = false; + for (unsigned Idx = 0, Last = Info.getNumFixItHints(); + Idx < Last; ++Idx) { + const FixItHint &Hint = Info.getFixItHint(Idx); + if (!Hint.RemoveRange.isValid()) { + // We're adding code. + if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert)) + Failed = true; + continue; + } + + if (Hint.CodeToInsert.empty()) { + // We're removing code. + if (Rewrite.RemoveText(Hint.RemoveRange.getBegin(), + Rewrite.getRangeSize(Hint.RemoveRange))) + Failed = true; + continue; + } + + // We're replacing code. + if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(), + Rewrite.getRangeSize(Hint.RemoveRange), + Hint.CodeToInsert)) + Failed = true; + } + + if (Failed) { + ++NumFailures; + Diag(Info.getLocation(), diag::note_fixit_failed); + return; + } + + Diag(Info.getLocation(), diag::note_fixit_applied); +} + +/// \brief Emit a diagnostic via the adapted diagnostic client. +void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) { + // When producing this diagnostic, we temporarily bypass ourselves, + // clear out any current diagnostic, and let the downstream client + // format the diagnostic. + Diags.setClient(Client); + Diags.Clear(); + Diags.Report(Loc, DiagID); + Diags.setClient(this); +} + +FixItPathRewriter::~FixItPathRewriter() {} diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp new file mode 100644 index 0000000..87fc122 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -0,0 +1,231 @@ +//===--- FrontendAction.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendAction.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Sema/ParseAST.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +FrontendAction::FrontendAction() : Instance(0) {} + +FrontendAction::~FrontendAction() {} + +void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) { + CurrentFile = Value; + CurrentASTUnit.reset(AST); +} + +bool FrontendAction::BeginSourceFile(CompilerInstance &CI, + llvm::StringRef Filename, + bool IsAST) { + assert(!Instance && "Already processing a source file!"); + assert(!Filename.empty() && "Unexpected empty filename!"); + setCurrentFile(Filename); + setCompilerInstance(&CI); + + // AST files follow a very different path, since they share objects via the + // AST unit. + if (IsAST) { + assert(!usesPreprocessorOnly() && + "Attempt to pass AST file to preprocessor only action!"); + assert(hasASTSupport() && "This action does not have AST support!"); + + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics()); + std::string Error; + ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, Diags); + if (!AST) + goto failure; + + setCurrentFile(Filename, AST); + + // Set the shared objects, these are reset when we finish processing the + // file, otherwise the CompilerInstance will happily destroy them. + CI.setFileManager(&AST->getFileManager()); + CI.setSourceManager(&AST->getSourceManager()); + CI.setPreprocessor(&AST->getPreprocessor()); + CI.setASTContext(&AST->getASTContext()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST consumer. + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + return true; + } + + // Inform the diagnostic client we are processing a source file. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), + &CI.getPreprocessor()); + + // Initialize the action. + if (!BeginSourceFileAction(CI, Filename)) + goto failure; + + /// Create the AST context and consumer unless this is a preprocessor only + /// action. + if (!usesPreprocessorOnly()) { + CI.createASTContext(); + CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + if (!CI.hasASTConsumer()) + goto failure; + + /// Use PCH? + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + assert(hasPCHSupport() && "This action does not have PCH support!"); + CI.createPCHExternalASTSource( + CI.getPreprocessorOpts().ImplicitPCHInclude); + if (!CI.getASTContext().getExternalSource()) + goto failure; + } + } + + // Initialize builtin info as long as we aren't using an external AST + // source. + if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { + Preprocessor &PP = CI.getPreprocessor(); + PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), + PP.getLangOptions().NoBuiltin); + } + + return true; + + // If we failed, reset state since the client will not end up calling the + // matching EndSourceFile(). + failure: + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + CI.getDiagnosticClient().EndSourceFile(); + setCurrentFile(""); + setCompilerInstance(0); + return false; +} + +void FrontendAction::Execute() { + CompilerInstance &CI = getCompilerInstance(); + + // Initialize the main file entry. This needs to be delayed until after PCH + // has loaded. + if (isCurrentFileAST()) { + // Set the main file ID to an empty file. + // + // FIXME: We probably shouldn't need this, but for now this is the + // simplest way to reuse the logic in ParseAST. + const char *EmptyStr = ""; + llvm::MemoryBuffer *SB = + llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>"); + CI.getSourceManager().createMainFileIDForMemBuffer(SB); + } else { + if (!CI.InitializeSourceManager(getCurrentFile())) + return; + } + + if (CI.hasFrontendTimer()) { + llvm::TimeRegion Timer(CI.getFrontendTimer()); + ExecuteAction(); + } + else ExecuteAction(); +} + +void FrontendAction::EndSourceFile() { + CompilerInstance &CI = getCompilerInstance(); + + // Finalize the action. + EndSourceFileAction(); + + // Release the consumer and the AST, in that order since the consumer may + // perform actions in its destructor which require the context. + // + // FIXME: There is more per-file stuff we could just drop here? + if (CI.getFrontendOpts().DisableFree) { + CI.takeASTConsumer(); + if (!isCurrentFileAST()) + CI.takeASTContext(); + } else { + CI.setASTConsumer(0); + if (!isCurrentFileAST()) + CI.setASTContext(0); + } + + // Inform the preprocessor we are done. + if (CI.hasPreprocessor()) + CI.getPreprocessor().EndSourceFile(); + + if (CI.getFrontendOpts().ShowStats) { + llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; + CI.getPreprocessor().PrintStats(); + CI.getPreprocessor().getIdentifierTable().PrintStats(); + CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); + CI.getSourceManager().PrintStats(); + llvm::errs() << "\n"; + } + + // Cleanup the output streams, and erase the output files if we encountered + // an error. + CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); + + // Inform the diagnostic client we are done with this source file. + CI.getDiagnosticClient().EndSourceFile(); + + if (isCurrentFileAST()) { + CI.takeASTContext(); + CI.takePreprocessor(); + CI.takeSourceManager(); + CI.takeFileManager(); + } + + setCompilerInstance(0); + setCurrentFile(""); +} + +//===----------------------------------------------------------------------===// +// Utility Actions +//===----------------------------------------------------------------------===// + +void ASTFrontendAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + + // FIXME: Move the truncation aspect of this into Sema, we delayed this till + // here so the source manager would be initialized. + if (hasCodeCompletionSupport() && + !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) + CI.createCodeCompletionConsumer(); + + // Use a code completion consumer? + CodeCompleteConsumer *CompletionConsumer = 0; + if (CI.hasCodeCompletionConsumer()) + CompletionConsumer = &CI.getCodeCompletionConsumer(); + + ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), + CI.getFrontendOpts().ShowStats, + usesCompleteTranslationUnit(), CompletionConsumer); +} + +ASTConsumer * +PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp new file mode 100644 index 0000000..6cd960b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -0,0 +1,272 @@ +//===--- FrontendActions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendActions.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Parser.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/AnalysisConsumer.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FixItRewriter.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Custom Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +void InitOnlyAction::ExecuteAction() { +} + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateAnalysisConsumer(CI.getPreprocessor(), + CI.getFrontendOpts().OutputFile, + CI.getAnalyzerOpts()); +} + +ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateASTPrinter(OS); + return 0; +} + +ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) + return CreateASTPrinterXML(OS); + return 0; +} + +ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTDumper(); +} + +ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateASTViewer(); +} + +ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateDeclContextPrinter(); +} + +ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; + if (CI.getFrontendOpts().RelocatablePCH && + Sysroot.empty()) { + CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + return 0; + } + + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + if (!OS) + return 0; + + if (CI.getFrontendOpts().RelocatablePCH) + return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); + + return CreatePCHGenerator(CI.getPreprocessor(), OS); +} + +ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) + return CreateHTMLPrinter(OS, CI.getPreprocessor()); + return 0; +} + +ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); +} + +FixItAction::FixItAction() {} +FixItAction::~FixItAction() {} + +ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +class FixItActionSuffixInserter : public FixItPathRewriter { + std::string NewSuffix; + +public: + explicit FixItActionSuffixInserter(std::string NewSuffix) + : NewSuffix(NewSuffix) {} + + std::string RewriteFilename(const std::string &Filename) { + llvm::sys::Path Path(Filename); + std::string Suffix = Path.getSuffix(); + Path.eraseSuffix(); + Path.appendSuffix(NewSuffix + "." + Suffix); + return Path.c_str(); + } +}; + +bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, + llvm::StringRef Filename) { + const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); + if (!FEOpts.FixItSuffix.empty()) { + PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix)); + } else { + PathRewriter.reset(); + } + Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), + CI.getLangOpts(), PathRewriter.get())); + return true; +} + +void FixItAction::EndSourceFileAction() { + // Otherwise rewrite all files. + Rewriter->WriteFixedFiles(); +} + +ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) + return CreateObjCRewriter(InFile, OS, + CI.getDiagnostics(), CI.getLangOpts(), + CI.getDiagnosticOpts().NoRewriteMacros); + return 0; +} + +ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +void DumpRawTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + + // Start lexing the specified input file. + const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); + RawLex.SetKeepWhitespaceMode(true); + + Token RawTok; + RawLex.LexFromRawLexer(RawTok); + while (RawTok.isNot(tok::eof)) { + PP.DumpToken(RawTok, true); + llvm::errs() << "\n"; + RawLex.LexFromRawLexer(RawTok); + } +} + +void DumpTokensAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + // Start preprocessing the specified input file. + Token Tok; + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + PP.DumpToken(Tok, true); + llvm::errs() << "\n"; + } while (Tok.isNot(tok::eof)); +} + +void GeneratePTHAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + if (CI.getFrontendOpts().OutputFile.empty() || + CI.getFrontendOpts().OutputFile == "-") { + // FIXME: Don't fail this way. + // FIXME: Verify that we can actually seek in the given file. + llvm::report_fatal_error("PTH requires a seekable file for output!"); + } + llvm::raw_fd_ostream *OS = + CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + + CacheTokens(CI.getPreprocessor(), OS); +} + +void ParseOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::OwningPtr<Action> PA(new MinimalAction(PP)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PreprocessOnlyAction::ExecuteAction() { + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + + Token Tok; + // Start parsing the specified input file. + PP.EnterMainSourceFile(); + do { + PP.Lex(Tok); + } while (Tok.isNot(tok::eof)); +} + +void PrintParseAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + Preprocessor &PP = getCompilerInstance().getPreprocessor(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + + llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); + + Parser P(PP, *PA); + PP.EnterMainSourceFile(); + P.ParseTranslationUnit(); +} + +void PrintPreprocessedAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + // Output file needs to be set to 'Binary', to avoid converting Unix style + // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + + DoPrintPreprocessedInput(CI.getPreprocessor(), OS, + CI.getPreprocessorOutputOpts()); +} + +void RewriteMacrosAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); + if (!OS) return; + + RewriteMacrosInInput(CI.getPreprocessor(), OS); +} + +void RewriteTestAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); + if (!OS) return; + + DoRewriteTest(CI.getPreprocessor(), OS); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp new file mode 100644 index 0000000..bd91638 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendOptions.cpp @@ -0,0 +1,31 @@ +//===--- FrontendOptions.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendOptions.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +FrontendOptions::InputKind +FrontendOptions::getInputKindForExtension(llvm::StringRef Extension) { + return llvm::StringSwitch<InputKind>(Extension) + .Case("ast", IK_AST) + .Case("c", IK_C) + .Cases("S", "s", IK_Asm) + .Case("i", IK_PreprocessedC) + .Case("ii", IK_PreprocessedCXX) + .Case("m", IK_ObjC) + .Case("mi", IK_PreprocessedObjC) + .Cases("mm", "M", IK_ObjCXX) + .Case("mii", IK_PreprocessedObjCXX) + .Case("C", IK_CXX) + .Cases("C", "cc", "cp", IK_CXX) + .Cases("cpp", "CPP", "c++", "cxx", "hpp", IK_CXX) + .Case("cl", IK_OpenCL) + .Default(IK_C); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp new file mode 100644 index 0000000..6251bac --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/GeneratePCH.cpp @@ -0,0 +1,80 @@ +//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CreatePCHGenerate function, which creates an +// ASTConsume that generates a PCH file. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/PCHWriter.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +using namespace clang; + +namespace { + class PCHGenerator : public SemaConsumer { + const Preprocessor &PP; + const char *isysroot; + llvm::raw_ostream *Out; + Sema *SemaPtr; + MemorizeStatCalls *StatCalls; // owned by the FileManager + + public: + explicit PCHGenerator(const Preprocessor &PP, + const char *isysroot, + llvm::raw_ostream *Out); + virtual void InitializeSema(Sema &S) { SemaPtr = &S; } + virtual void HandleTranslationUnit(ASTContext &Ctx); + }; +} + +PCHGenerator::PCHGenerator(const Preprocessor &PP, + const char *isysroot, + llvm::raw_ostream *OS) + : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0) { + + // Install a stat() listener to keep track of all of the stat() + // calls. + StatCalls = new MemorizeStatCalls; + PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true); +} + +void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { + if (PP.getDiagnostics().hasErrorOccurred()) + return; + + // Write the PCH contents into a buffer + std::vector<unsigned char> Buffer; + llvm::BitstreamWriter Stream(Buffer); + PCHWriter Writer(Stream); + + // Emit the PCH file + assert(SemaPtr && "No Sema?"); + Writer.WritePCH(*SemaPtr, StatCalls, isysroot); + + // Write the generated bitstream to "Out". + Out->write((char *)&Buffer.front(), Buffer.size()); + + // Make sure it hits disk now. + Out->flush(); +} + +ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP, + llvm::raw_ostream *OS, + const char *isysroot) { + return new PCHGenerator(PP, isysroot, OS); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/HTMLDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Frontend/HTMLDiagnostics.cpp new file mode 100644 index 0000000..022a34d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/HTMLDiagnostics.cpp @@ -0,0 +1,577 @@ +//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HTMLDiagnostics object. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PathDiagnosticClients.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/HTMLRewrite.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Boilerplate. +//===----------------------------------------------------------------------===// + +namespace { + +class HTMLDiagnostics : public PathDiagnosticClient { + llvm::sys::Path Directory, FilePrefix; + bool createdDir, noDir; + const Preprocessor &PP; + std::vector<const PathDiagnostic*> BatchedDiags; +public: + HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp); + + virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); } + + virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); + + virtual void HandlePathDiagnostic(const PathDiagnostic* D); + + virtual llvm::StringRef getName() const { + return "HTMLDiagnostics"; + } + + unsigned ProcessMacroPiece(llvm::raw_ostream& os, + const PathDiagnosticMacroPiece& P, + unsigned num); + + void HandlePiece(Rewriter& R, FileID BugFileID, + const PathDiagnosticPiece& P, unsigned num, unsigned max); + + void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, + const char *HighlightStart = "<span class=\"mrange\">", + const char *HighlightEnd = "</span>"); + + void ReportDiag(const PathDiagnostic& D, + llvm::SmallVectorImpl<std::string> *FilesMade); +}; + +} // end anonymous namespace + +HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, + const Preprocessor &pp) + : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false), + PP(pp) { + // All html files begin with "report" + FilePrefix.appendComponent("report"); +} + +PathDiagnosticClient* +clang::CreateHTMLDiagnosticClient(const std::string& prefix, + const Preprocessor &PP) { + return new HTMLDiagnostics(prefix, PP); +} + +//===----------------------------------------------------------------------===// +// Report processing. +//===----------------------------------------------------------------------===// + +void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { + if (!D) + return; + + if (D->empty()) { + delete D; + return; + } + + const_cast<PathDiagnostic*>(D)->flattenLocations(); + BatchedDiags.push_back(D); +} + +void +HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade) +{ + while (!BatchedDiags.empty()) { + const PathDiagnostic* D = BatchedDiags.back(); + BatchedDiags.pop_back(); + ReportDiag(*D, FilesMade); + delete D; + } + + BatchedDiags.clear(); +} + +void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, + llvm::SmallVectorImpl<std::string> *FilesMade){ + // Create the HTML directory if it is missing. + if (!createdDir) { + createdDir = true; + std::string ErrorMsg; + Directory.createDirectoryOnDisk(true, &ErrorMsg); + + if (!Directory.isDirectory()) { + llvm::errs() << "warning: could not create directory '" + << Directory.str() << "'\n" + << "reason: " << ErrorMsg << '\n'; + + noDir = true; + + return; + } + } + + if (noDir) + return; + + const SourceManager &SMgr = D.begin()->getLocation().getManager(); + FileID FID; + + // Verify that the entire path is from the same FileID. + for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) { + FullSourceLoc L = I->getLocation().asLocation().getInstantiationLoc(); + + if (FID.isInvalid()) { + FID = SMgr.getFileID(L); + } else if (SMgr.getFileID(L) != FID) + return; // FIXME: Emit a warning? + + // Check the source ranges. + for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(), + RE=I->ranges_end(); RI!=RE; ++RI) { + + SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin()); + + if (!L.isFileID() || SMgr.getFileID(L) != FID) + return; // FIXME: Emit a warning? + + L = SMgr.getInstantiationLoc(RI->getEnd()); + + if (!L.isFileID() || SMgr.getFileID(L) != FID) + return; // FIXME: Emit a warning? + } + } + + if (FID.isInvalid()) + return; // FIXME: Emit a warning? + + // Create a new rewriter to generate HTML. + Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOptions()); + + // Process the path. + unsigned n = D.size(); + unsigned max = n; + + for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend(); + I!=E; ++I, --n) + HandlePiece(R, FID, *I, n, max); + + // Add line numbers, header, footer, etc. + + // unsigned FID = R.getSourceMgr().getMainFileID(); + html::EscapeText(R, FID); + html::AddLineNumbers(R, FID); + + // If we have a preprocessor, relex the file and syntax highlight. + // We might not have a preprocessor if we come from a deserialized AST file, + // for example. + + html::SyntaxHighlight(R, FID, PP); + html::HighlightMacros(R, FID, PP); + + // Get the full directory name of the analyzed file. + + const FileEntry* Entry = SMgr.getFileEntryForID(FID); + + // This is a cludge; basically we want to append either the full + // working directory if we have no directory information. This is + // a work in progress. + + std::string DirName = ""; + + if (!llvm::sys::Path(Entry->getName()).isAbsolute()) { + llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory(); + DirName = P.str() + "/"; + } + + // Add the name of the file as an <h1> tag. + + { + std::string s; + llvm::raw_string_ostream os(s); + + os << "<!-- REPORTHEADER -->\n" + << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n" + "<tr><td class=\"rowname\">File:</td><td>" + << html::EscapeText(DirName) + << html::EscapeText(Entry->getName()) + << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" + "<a href=\"#EndPath\">line " + << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber() + << ", column " + << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber() + << "</a></td></tr>\n" + "<tr><td class=\"rowname\">Description:</td><td>" + << D.getDescription() << "</td></tr>\n"; + + // Output any other meta data. + + for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end(); + I!=E; ++I) { + os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n"; + } + + os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n" + "<h3>Annotated Source Code</h3>\n"; + + R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); + } + + // Embed meta-data tags. + { + std::string s; + llvm::raw_string_ostream os(s); + + const std::string& BugDesc = D.getDescription(); + if (!BugDesc.empty()) + os << "\n<!-- BUGDESC " << BugDesc << " -->\n"; + + const std::string& BugType = D.getBugType(); + if (!BugType.empty()) + os << "\n<!-- BUGTYPE " << BugType << " -->\n"; + + const std::string& BugCategory = D.getCategory(); + if (!BugCategory.empty()) + os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n"; + + os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; + + os << "\n<!-- BUGLINE " + << D.back()->getLocation().asLocation().getInstantiationLineNumber() + << " -->\n"; + + os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n"; + + // Mark the end of the tags. + os << "\n<!-- BUGMETAEND -->\n"; + + // Insert the text. + R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); + } + + // Add CSS, header, and footer. + + html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName()); + + // Get the rewrite buffer. + const RewriteBuffer *Buf = R.getRewriteBufferFor(FID); + + if (!Buf) { + llvm::errs() << "warning: no diagnostics generated for main file.\n"; + return; + } + + // Create a path for the target HTML file. + llvm::sys::Path F(FilePrefix); + F.makeUnique(false, NULL); + + // Rename the file with an HTML extension. + llvm::sys::Path H(F); + H.appendSuffix("html"); + F.renamePathOnDisk(H, NULL); + + std::string ErrorMsg; + llvm::raw_fd_ostream os(H.c_str(), ErrorMsg); + + if (!ErrorMsg.empty()) { + (llvm::errs() << "warning: could not create file '" << F.str() + << "'\n").flush(); + return; + } + + if (FilesMade) + FilesMade->push_back(H.getLast()); + + // Emit the HTML to disk. + for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) + os << *I; +} + +void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, + const PathDiagnosticPiece& P, + unsigned num, unsigned max) { + + // For now, just draw a box above the line in question, and emit the + // warning. + FullSourceLoc Pos = P.getLocation().asLocation(); + + if (!Pos.isValid()) + return; + + SourceManager &SM = R.getSourceMgr(); + assert(&Pos.getManager() == &SM && "SourceManagers are different!"); + std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos); + + if (LPosInfo.first != BugFileID) + return; + + const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first); + const char* FileStart = Buf->getBufferStart(); + + // Compute the column number. Rewind from the current position to the start + // of the line. + unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second); + const char *TokInstantiationPtr =Pos.getInstantiationLoc().getCharacterData(); + const char *LineStart = TokInstantiationPtr-ColNo; + + // Compute LineEnd. + const char *LineEnd = TokInstantiationPtr; + const char* FileEnd = Buf->getBufferEnd(); + while (*LineEnd != '\n' && LineEnd != FileEnd) + ++LineEnd; + + // Compute the margin offset by counting tabs and non-tabs. + unsigned PosNo = 0; + for (const char* c = LineStart; c != TokInstantiationPtr; ++c) + PosNo += *c == '\t' ? 8 : 1; + + // Create the html for the message. + + const char *Kind = 0; + switch (P.getKind()) { + case PathDiagnosticPiece::Event: Kind = "Event"; break; + case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; + // Setting Kind to "Control" is intentional. + case PathDiagnosticPiece::Macro: Kind = "Control"; break; + } + + std::string sbuf; + llvm::raw_string_ostream os(sbuf); + + os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\""; + + if (num == max) + os << "EndPath"; + else + os << "Path" << num; + + os << "\" class=\"msg"; + if (Kind) + os << " msg" << Kind; + os << "\" style=\"margin-left:" << PosNo << "ex"; + + // Output a maximum size. + if (!isa<PathDiagnosticMacroPiece>(P)) { + // Get the string and determining its maximum substring. + const std::string& Msg = P.getString(); + unsigned max_token = 0; + unsigned cnt = 0; + unsigned len = Msg.size(); + + for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) + switch (*I) { + default: + ++cnt; + continue; + case ' ': + case '\t': + case '\n': + if (cnt > max_token) max_token = cnt; + cnt = 0; + } + + if (cnt > max_token) + max_token = cnt; + + // Determine the approximate size of the message bubble in em. + unsigned em; + const unsigned max_line = 120; + + if (max_token >= max_line) + em = max_token / 2; + else { + unsigned characters = max_line; + unsigned lines = len / max_line; + + if (lines > 0) { + for (; characters > max_token; --characters) + if (len / characters > lines) { + ++characters; + break; + } + } + + em = characters / 2; + } + + if (em < max_line/2) + os << "; max-width:" << em << "em"; + } + else + os << "; max-width:100em"; + + os << "\">"; + + if (max > 1) { + os << "<table class=\"msgT\"><tr><td valign=\"top\">"; + os << "<div class=\"PathIndex"; + if (Kind) os << " PathIndex" << Kind; + os << "\">" << num << "</div>"; + os << "</td><td>"; + } + + if (const PathDiagnosticMacroPiece *MP = + dyn_cast<PathDiagnosticMacroPiece>(&P)) { + + os << "Within the expansion of the macro '"; + + // Get the name of the macro by relexing it. + { + FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc(); + assert(L.isFileID()); + llvm::StringRef BufferInfo = L.getBufferData(); + const char* MacroName = L.getDecomposedLoc().second + BufferInfo.data(); + Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.begin(), + MacroName, BufferInfo.end()); + + Token TheTok; + rawLexer.LexFromRawLexer(TheTok); + for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i) + os << MacroName[i]; + } + + os << "':\n"; + + if (max > 1) + os << "</td></tr></table>"; + + // Within a macro piece. Write out each event. + ProcessMacroPiece(os, *MP, 0); + } + else { + os << html::EscapeText(P.getString()); + + if (max > 1) + os << "</td></tr></table>"; + } + + os << "</div></td></tr>"; + + // Insert the new html. + unsigned DisplayPos = LineEnd - FileStart; + SourceLocation Loc = + SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos); + + R.InsertTextBefore(Loc, os.str()); + + // Now highlight the ranges. + for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end(); + I != E; ++I) + HighlightRange(R, LPosInfo.first, *I); + +#if 0 + // If there is a code insertion hint, insert that code. + // FIXME: This code is disabled because it seems to mangle the HTML + // output. I'm leaving it here because it's generally the right idea, + // but needs some help from someone more familiar with the rewriter. + for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end(); + Hint != HintEnd; ++Hint) { + if (Hint->RemoveRange.isValid()) { + HighlightRange(R, LPosInfo.first, Hint->RemoveRange, + "<span class=\"CodeRemovalHint\">", "</span>"); + } + if (Hint->InsertionLoc.isValid()) { + std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true); + EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode + + "</span>"; + R.InsertTextBefore(Hint->InsertionLoc, EscapedCode); + } + } +#endif +} + +static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) { + unsigned x = n % ('z' - 'a'); + n /= 'z' - 'a'; + + if (n > 0) + EmitAlphaCounter(os, n); + + os << char('a' + x); +} + +unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os, + const PathDiagnosticMacroPiece& P, + unsigned num) { + + for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end(); + I!=E; ++I) { + + if (const PathDiagnosticMacroPiece *MP = + dyn_cast<PathDiagnosticMacroPiece>(*I)) { + num = ProcessMacroPiece(os, *MP, num); + continue; + } + + if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) { + os << "<div class=\"msg msgEvent\" style=\"width:94%; " + "margin-left:5px\">" + "<table class=\"msgT\"><tr>" + "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">"; + EmitAlphaCounter(os, num++); + os << "</div></td><td valign=\"top\">" + << html::EscapeText(EP->getString()) + << "</td></tr></table></div>\n"; + } + } + + return num; +} + +void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, + SourceRange Range, + const char *HighlightStart, + const char *HighlightEnd) { + SourceManager &SM = R.getSourceMgr(); + const LangOptions &LangOpts = R.getLangOpts(); + + SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin()); + unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart); + + SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd()); + unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd); + + if (EndLineNo < StartLineNo) + return; + + if (SM.getFileID(InstantiationStart) != BugFileID || + SM.getFileID(InstantiationEnd) != BugFileID) + return; + + // Compute the column number of the end. + unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd); + unsigned OldEndColNo = EndColNo; + + if (EndColNo) { + // Add in the length of the token, so that we cover multi-char tokens. + EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1; + } + + // Highlight the range. Make the span tag the outermost tag for the + // selected range. + + SourceLocation E = + InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo); + + html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/HTMLPrint.cpp b/contrib/llvm/tools/clang/lib/Frontend/HTMLPrint.cpp new file mode 100644 index 0000000..9ea8cb3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/HTMLPrint.cpp @@ -0,0 +1,94 @@ +//===--- HTMLPrint.cpp - Source code -> HTML pretty-printing --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Pretty-printing of source code to HTML. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTConsumers.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/HTMLRewrite.h" +#include "clang/Rewrite/Rewriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Functional HTML pretty-printing. +//===----------------------------------------------------------------------===// + +namespace { + class HTMLPrinter : public ASTConsumer { + Rewriter R; + llvm::raw_ostream *Out; + Preprocessor &PP; + bool SyntaxHighlight, HighlightMacros; + + public: + HTMLPrinter(llvm::raw_ostream *OS, Preprocessor &pp, + bool _SyntaxHighlight, bool _HighlightMacros) + : Out(OS), PP(pp), SyntaxHighlight(_SyntaxHighlight), + HighlightMacros(_HighlightMacros) {} + + void Initialize(ASTContext &context); + void HandleTranslationUnit(ASTContext &Ctx); + }; +} + +ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS, + Preprocessor &PP, + bool SyntaxHighlight, + bool HighlightMacros) { + return new HTMLPrinter(OS, PP, SyntaxHighlight, HighlightMacros); +} + +void HTMLPrinter::Initialize(ASTContext &context) { + R.setSourceMgr(context.getSourceManager(), context.getLangOptions()); +} + +void HTMLPrinter::HandleTranslationUnit(ASTContext &Ctx) { + if (PP.getDiagnostics().hasErrorOccurred()) + return; + + // Format the file. + FileID FID = R.getSourceMgr().getMainFileID(); + const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID); + const char* Name; + // In some cases, in particular the case where the input is from stdin, + // there is no entry. Fall back to the memory buffer for a name in those + // cases. + if (Entry) + Name = Entry->getName(); + else + Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier(); + + html::AddLineNumbers(R, FID); + html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name); + + // If we have a preprocessor, relex the file and syntax highlight. + // We might not have a preprocessor if we come from a deserialized AST file, + // for example. + + if (SyntaxHighlight) html::SyntaxHighlight(R, FID, PP); + if (HighlightMacros) html::HighlightMacros(R, FID, PP); + html::EscapeText(R, FID, false, true); + + // Emit the HTML. + const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID); + char *Buffer = (char*)malloc(RewriteBuf.size()); + std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer); + Out->write(Buffer, RewriteBuf.size()); + free(Buffer); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp new file mode 100644 index 0000000..e0391c2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -0,0 +1,873 @@ +//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the InitHeaderSearch class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Lex/HeaderSearch.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/Config/config.h" +#ifdef _MSC_VER + #define WIN32_LEAN_AND_MEAN 1 + #include <windows.h> +#endif +using namespace clang; +using namespace clang::frontend; + +namespace { + +/// InitHeaderSearch - This class makes it easier to set the search paths of +/// a HeaderSearch object. InitHeaderSearch stores several search path lists +/// internally, which can be sent to a HeaderSearch object in one swoop. +class InitHeaderSearch { + std::vector<DirectoryLookup> IncludeGroup[4]; + HeaderSearch& Headers; + bool Verbose; + std::string isysroot; + +public: + + InitHeaderSearch(HeaderSearch &HS, + bool verbose = false, const std::string &iSysroot = "") + : Headers(HS), Verbose(verbose), isysroot(iSysroot) {} + + /// AddPath - Add the specified path to the specified group list. + void AddPath(const llvm::Twine &Path, IncludeDirGroup Group, + bool isCXXAware, bool isUserSupplied, + bool isFramework, bool IgnoreSysRoot = false); + + /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu + /// libstdc++. + void AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, + const llvm::Triple &triple); + + /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to suport a MinGW + /// libstdc++. + void AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version); + + /// AddDelimitedPaths - Add a list of paths delimited by the system PATH + /// separator. The processing follows that of the CPATH variable for gcc. + void AddDelimitedPaths(llvm::StringRef String); + + // AddDefaultCIncludePaths - Add paths that should always be searched. + void AddDefaultCIncludePaths(const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts); + + // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when + // compiling c++. + void AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple); + + /// AddDefaultSystemIncludePaths - Adds the default system include paths so + /// that e.g. stdio.h is found. + void AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts); + + /// Realize - Merges all search path lists into one list and send it to + /// HeaderSearch. + void Realize(); +}; + +} + +void InitHeaderSearch::AddPath(const llvm::Twine &Path, + IncludeDirGroup Group, bool isCXXAware, + bool isUserSupplied, bool isFramework, + bool IgnoreSysRoot) { + assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); + FileManager &FM = Headers.getFileMgr(); + + // Compute the actual path, taking into consideration -isysroot. + llvm::SmallString<256> MappedPathStr; + llvm::raw_svector_ostream MappedPath(MappedPathStr); + + // Handle isysroot. + if (Group == System && !IgnoreSysRoot) { + // FIXME: Portability. This should be a sys::Path interface, this doesn't + // handle things like C:\ right, nor win32 \\network\device\blah. + if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present. + MappedPath << isysroot; + } + + Path.print(MappedPath); + + // Compute the DirectoryLookup type. + SrcMgr::CharacteristicKind Type; + if (Group == Quoted || Group == Angled) + Type = SrcMgr::C_User; + else if (isCXXAware) + Type = SrcMgr::C_System; + else + Type = SrcMgr::C_ExternCSystem; + + + // If the directory exists, add it. + if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) { + IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied, + isFramework)); + return; + } + + // Check to see if this is an apple-style headermap (which are not allowed to + // be frameworks). + if (!isFramework) { + if (const FileEntry *FE = FM.getFile(MappedPath.str())) { + if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) { + // It is a headermap, add it to the search path. + IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied)); + return; + } + } + } + + if (Verbose) + llvm::errs() << "ignoring nonexistent directory \"" + << MappedPath.str() << "\"\n"; +} + + +void InitHeaderSearch::AddDelimitedPaths(llvm::StringRef at) { + if (at.empty()) // Empty string should not add '.' path. + return; + + llvm::StringRef::size_type delim; + while ((delim = at.find(llvm::sys::PathSeparator)) != llvm::StringRef::npos) { + if (delim == 0) + AddPath(".", Angled, false, true, false); + else + AddPath(at.substr(0, delim), Angled, false, true, false); + at = at.substr(delim + 1); + } + + if (at.empty()) + AddPath(".", Angled, false, true, false); + else + AddPath(at, Angled, false, true, false); +} + +void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef ArchDir, + llvm::StringRef Dir32, + llvm::StringRef Dir64, + const llvm::Triple &triple) { + // Add the base dir + AddPath(Base, System, true, false, false); + + // Add the multilib dirs + llvm::Triple::ArchType arch = triple.getArch(); + bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64; + if (is64bit) + AddPath(Base + "/" + ArchDir + "/" + Dir64, System, true, false, false); + else + AddPath(Base + "/" + ArchDir + "/" + Dir32, System, true, false, false); + + // Add the backward dir + AddPath(Base + "/backward", System, true, false, false); +} + +void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, + llvm::StringRef Arch, + llvm::StringRef Version) { + AddPath(Base + "/" + Arch + "/" + Version + "/include", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", + System, true, false, false); +} + + // FIXME: This probably should goto to some platform utils place. +#ifdef _MSC_VER + + // Read registry string. + // This also supports a means to look for high-versioned keys by use + // of a $VERSION placeholder in the key path. + // $VERSION in the key path is a placeholder for the version number, + // causing the highest value path to be searched for and used. + // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". + // There can be additional characters in the component. Only the numberic + // characters are compared. +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + char *value, size_t maxLength) { + HKEY hRootKey = NULL; + HKEY hKey = NULL; + const char* subKey = NULL; + DWORD valueType; + DWORD valueSize = maxLength - 1; + long lResult; + bool returnValue = false; + if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { + hRootKey = HKEY_CLASSES_ROOT; + subKey = keyPath + 18; + } + else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { + hRootKey = HKEY_USERS; + subKey = keyPath + 11; + } + else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { + hRootKey = HKEY_LOCAL_MACHINE; + subKey = keyPath + 19; + } + else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { + hRootKey = HKEY_CURRENT_USER; + subKey = keyPath + 18; + } + else + return(false); + const char *placeHolder = strstr(subKey, "$VERSION"); + char bestName[256]; + bestName[0] = '\0'; + // If we have a $VERSION placeholder, do the highest-version search. + if (placeHolder) { + const char *keyEnd = placeHolder - 1; + const char *nextKey = placeHolder; + // Find end of previous key. + while ((keyEnd > subKey) && (*keyEnd != '\\')) + keyEnd--; + // Find end of key containing $VERSION. + while (*nextKey && (*nextKey != '\\')) + nextKey++; + size_t partialKeyLength = keyEnd - subKey; + char partialKey[256]; + if (partialKeyLength > sizeof(partialKey)) + partialKeyLength = sizeof(partialKey); + strncpy(partialKey, subKey, partialKeyLength); + partialKey[partialKeyLength] = '\0'; + HKEY hTopKey = NULL; + lResult = RegOpenKeyEx(hRootKey, partialKey, 0, KEY_READ, &hTopKey); + if (lResult == ERROR_SUCCESS) { + char keyName[256]; + int bestIndex = -1; + double bestValue = 0.0; + DWORD index, size = sizeof(keyName) - 1; + for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL, + NULL, NULL, NULL) == ERROR_SUCCESS; index++) { + const char *sp = keyName; + while (*sp && !isdigit(*sp)) + sp++; + if (!*sp) + continue; + const char *ep = sp + 1; + while (*ep && (isdigit(*ep) || (*ep == '.'))) + ep++; + char numBuf[32]; + strncpy(numBuf, sp, sizeof(numBuf) - 1); + numBuf[sizeof(numBuf) - 1] = '\0'; + double value = strtod(numBuf, NULL); + if (value > bestValue) { + bestIndex = (int)index; + bestValue = value; + strcpy(bestName, keyName); + } + size = sizeof(keyName) - 1; + } + // If we found the highest versioned key, open the key and get the value. + if (bestIndex != -1) { + // Append rest of key. + strncat(bestName, nextKey, sizeof(bestName) - 1); + bestName[sizeof(bestName) - 1] = '\0'; + // Open the chosen key path remainder. + lResult = RegOpenKeyEx(hTopKey, bestName, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } + } + RegCloseKey(hTopKey); + } + } + else { + lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey); + if (lResult == ERROR_SUCCESS) { + lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType, + (LPBYTE)value, &valueSize); + if (lResult == ERROR_SUCCESS) + returnValue = true; + RegCloseKey(hKey); + } + } + return(returnValue); +} +#else // _MSC_VER + // Read registry string. +static bool getSystemRegistryString(const char*, const char*, char*, size_t) { + return(false); +} +#endif // _MSC_VER + + // Get Visual Studio installation directory. +static bool getVisualStudioDir(std::string &path) { + char vsIDEInstallDir[256]; + char vsExpressIDEInstallDir[256]; + // Try the Windows registry first. + bool hasVCDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", + "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); + bool hasVCExpressDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\$VERSION", + "InstallDir", vsExpressIDEInstallDir, sizeof(vsExpressIDEInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasVCDir && vsIDEInstallDir[0]) { + char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsIDEInstallDir; + return(true); + } + else if (hasVCExpressDir && vsExpressIDEInstallDir[0]) { + char *p = (char*)strstr(vsExpressIDEInstallDir, "\\Common7\\IDE"); + if (p) + *p = '\0'; + path = vsExpressIDEInstallDir; + return(true); + } + else { + // Try the environment. + const char* vs100comntools = getenv("VS100COMNTOOLS"); + const char* vs90comntools = getenv("VS90COMNTOOLS"); + const char* vs80comntools = getenv("VS80COMNTOOLS"); + const char* vscomntools = NULL; + + // Try to find the version that we were compiled with + if(false) {} + #if (_MSC_VER >= 1600) // VC100 + else if(vs100comntools) { + vscomntools = vs100comntools; + } + #elif (_MSC_VER == 1500) // VC80 + else if(vs90comntools) { + vscomntools = vs90comntools; + } + #elif (_MSC_VER == 1400) // VC80 + else if(vs80comntools) { + vscomntools = vs80comntools; + } + #endif + // Otherwise find any version we can + else if (vs100comntools) + vscomntools = vs100comntools; + else if (vs90comntools) + vscomntools = vs90comntools; + else if (vs80comntools) + vscomntools = vs80comntools; + + if (vscomntools && *vscomntools) { + char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools")); + if (p) + *p = '\0'; + path = vscomntools; + return(true); + } + else + return(false); + } + return(false); +} + + // Get Windows SDK installation directory. +static bool getWindowsSDKDir(std::string &path) { + char windowsSDKInstallDir[256]; + // Try the Windows registry. + bool hasSDKDir = getSystemRegistryString( + "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\$VERSION", + "InstallationFolder", windowsSDKInstallDir, sizeof(windowsSDKInstallDir) - 1); + // If we have both vc80 and vc90, pick version we were compiled with. + if (hasSDKDir && windowsSDKInstallDir[0]) { + path = windowsSDKInstallDir; + return(true); + } + return(false); +} + +void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts) { + // FIXME: temporary hack: hard-coded paths. + AddPath("/usr/local/include", System, true, false, false); + + // Builtin includes use #include_next directives and should be positioned + // just prior C include dirs. + if (HSOpts.UseBuiltinIncludes) { + // Ignore the sys root, we *always* look for clang headers relative to + // supplied path. + llvm::sys::Path P(HSOpts.ResourceDir); + P.appendComponent("include"); + AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true); + } + + // Add dirs specified via 'configure --with-c-include-dirs'. + llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + llvm::SmallVector<llvm::StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (llvm::SmallVectorImpl<llvm::StringRef>::iterator i = dirs.begin(); + i != dirs.end(); + ++i) + AddPath(*i, System, false, false, false); + return; + } + llvm::Triple::OSType os = triple.getOS(); + switch (os) { + case llvm::Triple::Win32: + { + std::string VSDir; + std::string WindowsSDKDir; + if (getVisualStudioDir(VSDir)) { + AddPath(VSDir + "\\VC\\include", System, false, false, false); + if (getWindowsSDKDir(WindowsSDKDir)) + AddPath(WindowsSDKDir, System, false, false, false); + else + AddPath(VSDir + "\\VC\\PlatformSDK\\Include", + System, false, false, false); + } + else { + // Default install paths. + AddPath("C:/Program Files/Microsoft Visual Studio 10.0/VC/include", + System, false, false, false); + AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include", + System, false, false, false); + AddPath( + "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", + System, false, false, false); + AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include", + System, false, false, false); + AddPath( + "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include", + System, false, false, false); + // For some clang developers. + AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include", + System, false, false, false); + AddPath( + "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include", + System, false, false, false); + } + } + break; + case llvm::Triple::Haiku: + AddPath("/boot/common/include", System, true, false, false); + AddPath("/boot/develop/headers/os", System, true, false, false); + AddPath("/boot/develop/headers/os/app", System, true, false, false); + AddPath("/boot/develop/headers/os/arch", System, true, false, false); + AddPath("/boot/develop/headers/os/device", System, true, false, false); + AddPath("/boot/develop/headers/os/drivers", System, true, false, false); + AddPath("/boot/develop/headers/os/game", System, true, false, false); + AddPath("/boot/develop/headers/os/interface", System, true, false, false); + AddPath("/boot/develop/headers/os/kernel", System, true, false, false); + AddPath("/boot/develop/headers/os/locale", System, true, false, false); + AddPath("/boot/develop/headers/os/mail", System, true, false, false); + AddPath("/boot/develop/headers/os/media", System, true, false, false); + AddPath("/boot/develop/headers/os/midi", System, true, false, false); + AddPath("/boot/develop/headers/os/midi2", System, true, false, false); + AddPath("/boot/develop/headers/os/net", System, true, false, false); + AddPath("/boot/develop/headers/os/storage", System, true, false, false); + AddPath("/boot/develop/headers/os/support", System, true, false, false); + AddPath("/boot/develop/headers/os/translation", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/graphics", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/input_server", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/screen_saver", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/tracker", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/Deskbar", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/NetPositive", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/Tracker", + System, true, false, false); + AddPath("/boot/develop/headers/cpp", System, true, false, false); + AddPath("/boot/develop/headers/cpp/i586-pc-haiku", + System, true, false, false); + AddPath("/boot/develop/headers/3rdparty", System, true, false, false); + AddPath("/boot/develop/headers/bsd", System, true, false, false); + AddPath("/boot/develop/headers/glibc", System, true, false, false); + AddPath("/boot/develop/headers/posix", System, true, false, false); + AddPath("/boot/develop/headers", System, true, false, false); + break; + case llvm::Triple::MinGW64: + case llvm::Triple::MinGW32: + AddPath("c:/mingw/include", System, true, false, false); + break; + default: + break; + } + + AddPath("/usr/include", System, false, false, false); +} + +void InitHeaderSearch:: +AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { + llvm::Triple::OSType os = triple.getOS(); + llvm::StringRef CxxIncludeRoot(CXX_INCLUDE_ROOT); + if (CxxIncludeRoot != "") { + llvm::StringRef CxxIncludeArch(CXX_INCLUDE_ARCH); + if (CxxIncludeArch == "") + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, triple.str().c_str(), + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, + triple); + else + AddGnuCPlusPlusIncludePaths(CxxIncludeRoot, CXX_INCLUDE_ARCH, + CXX_INCLUDE_32BIT_DIR, CXX_INCLUDE_64BIT_DIR, + triple); + return; + } + // FIXME: temporary hack: hard-coded paths. + switch (os) { + case llvm::Triple::Cygwin: + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include", + System, true, false, false); + AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++", + System, true, false, false); + break; + case llvm::Triple::MinGW64: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); + // Fall through. + case llvm::Triple::MinGW32: + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); + break; + case llvm::Triple::Darwin: + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1", + "i686-apple-darwin10", "", "x86_64", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0", + "i686-apple-darwin8", "", "", triple); + break; + case llvm::Triple::DragonFly: + AddPath("/usr/include/c++/4.1", System, true, false, false); + break; + case llvm::Triple::Linux: + //===------------------------------------------------------------------===// + // Debian based distros. + // Note: these distros symlink /usr/include/c++/X.Y.Z -> X.Y + //===------------------------------------------------------------------===// + // Ubuntu 10.04 LTS "Lucid Lynx" -- gcc-4.4.3 + // Ubuntu 9.10 "Karmic Koala" -- gcc-4.4.1 + // Debian 6.0 "squeeze" -- gcc-4.4.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 9.04 "Jaunty Jackalope" -- gcc-4.3.3 + // Ubuntu 8.10 "Intrepid Ibex" -- gcc-4.3.2 + // Debian 5.0 "lenny" -- gcc-4.3.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 8.04.4 LTS "Hardy Heron" -- gcc-4.2.4 + // Ubuntu 8.04.[0-3] LTS "Hardy Heron" -- gcc-4.2.3 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", + "i486-linux-gnu", "", "64", triple); + // Ubuntu 7.10 "Gutsy Gibbon" -- gcc-4.1.3 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", + "x86_64-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1", + "i486-linux-gnu", "", "64", triple); + + //===------------------------------------------------------------------===// + // Redhat based distros. + //===------------------------------------------------------------------===// + // Fedora 13 + // Fedora 12 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "i686-redhat-linux","", "", triple); + // Fedora 12 (pre-FEB-2010) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "i686-redhat-linux","", "", triple); + // Fedora 11 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "i586-redhat-linux","", "", triple); + // Fedora 10 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "i386-redhat-linux","", "", triple); + // Fedora 9 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0", + "i386-redhat-linux", "", "", triple); + // Fedora 8 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "x86_64-redhat-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2", + "i386-redhat-linux", "", "", triple); + + //===------------------------------------------------------------------===// + + // Exherbo (2010-01-25) + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "x86_64-pc-linux-gnu", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "i686-pc-linux-gnu", "", "", triple); + + // openSUSE 11.1 32 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "i586-suse-linux", "", "", triple); + // openSUSE 11.1 64 bit + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", + "x86_64-suse-linux", "32", "", triple); + // openSUSE 11.2 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "i586-suse-linux", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4", + "x86_64-suse-linux", "", "", triple); + // Arch Linux 2008-06-24 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "i686-pc-linux-gnu", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", + "x86_64-unknown-linux-gnu", "", "", triple); + // Gentoo x86 2009.1 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 2009.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 2008.0 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo amd64 stable + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + + // Gentoo amd64 gcc 4.3.2 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.3.2/include/g++-v4", + "x86_64-pc-linux-gnu", "", "", triple); + + // Gentoo amd64 gcc 4.4.3 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4", + "x86_64-pc-linux-gnu", "32", "", triple); + + break; + case llvm::Triple::FreeBSD: + // FreeBSD 8.0 + // FreeBSD 7.3 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); + break; + case llvm::Triple::Solaris: + // Solaris - Fall though.. + case llvm::Triple::AuroraUX: + // AuroraUX + AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4", + "i386-pc-solaris2.11", "", "", triple); + break; + default: + break; + } +} + +void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, + const llvm::Triple &triple, + const HeaderSearchOptions &HSOpts) { + if (Lang.CPlusPlus && HSOpts.UseStandardCXXIncludes) + AddDefaultCPlusPlusIncludePaths(triple); + + AddDefaultCIncludePaths(triple, HSOpts); + + // Add the default framework include paths on Darwin. + if (triple.getOS() == llvm::Triple::Darwin) { + AddPath("/System/Library/Frameworks", System, true, false, true); + AddPath("/Library/Frameworks", System, true, false, true); + } +} + +/// RemoveDuplicates - If there are duplicate directory entries in the specified +/// search list, remove the later (dead) ones. +static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList, + bool Verbose) { + llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs; + llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs; + llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps; + for (unsigned i = 0; i != SearchList.size(); ++i) { + unsigned DirToRemove = i; + + const DirectoryLookup &CurEntry = SearchList[i]; + + if (CurEntry.isNormalDir()) { + // If this isn't the first time we've seen this dir, remove it. + if (SeenDirs.insert(CurEntry.getDir())) + continue; + } else if (CurEntry.isFramework()) { + // If this isn't the first time we've seen this framework dir, remove it. + if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir())) + continue; + } else { + assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); + // If this isn't the first time we've seen this headermap, remove it. + if (SeenHeaderMaps.insert(CurEntry.getHeaderMap())) + continue; + } + + // If we have a normal #include dir/framework/headermap that is shadowed + // later in the chain by a system include location, we actually want to + // ignore the user's request and drop the user dir... keeping the system + // dir. This is weird, but required to emulate GCC's search path correctly. + // + // Since dupes of system dirs are rare, just rescan to find the original + // that we're nuking instead of using a DenseMap. + if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) { + // Find the dir that this is the same of. + unsigned FirstDir; + for (FirstDir = 0; ; ++FirstDir) { + assert(FirstDir != i && "Didn't find dupe?"); + + const DirectoryLookup &SearchEntry = SearchList[FirstDir]; + + // If these are different lookup types, then they can't be the dupe. + if (SearchEntry.getLookupType() != CurEntry.getLookupType()) + continue; + + bool isSame; + if (CurEntry.isNormalDir()) + isSame = SearchEntry.getDir() == CurEntry.getDir(); + else if (CurEntry.isFramework()) + isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir(); + else { + assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); + isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap(); + } + + if (isSame) + break; + } + + // If the first dir in the search path is a non-system dir, zap it + // instead of the system one. + if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User) + DirToRemove = FirstDir; + } + + if (Verbose) { + llvm::errs() << "ignoring duplicate directory \"" + << CurEntry.getName() << "\"\n"; + if (DirToRemove != i) + llvm::errs() << " as it is a non-system directory that duplicates " + << "a system directory\n"; + } + + // This is reached if the current entry is a duplicate. Remove the + // DirToRemove (usually the current dir). + SearchList.erase(SearchList.begin()+DirToRemove); + --i; + } +} + + +void InitHeaderSearch::Realize() { + // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList. + std::vector<DirectoryLookup> SearchList; + SearchList = IncludeGroup[Angled]; + SearchList.insert(SearchList.end(), IncludeGroup[System].begin(), + IncludeGroup[System].end()); + SearchList.insert(SearchList.end(), IncludeGroup[After].begin(), + IncludeGroup[After].end()); + RemoveDuplicates(SearchList, Verbose); + RemoveDuplicates(IncludeGroup[Quoted], Verbose); + + // Prepend QUOTED list on the search list. + SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(), + IncludeGroup[Quoted].end()); + + + bool DontSearchCurDir = false; // TODO: set to true if -I- is set? + Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(), + DontSearchCurDir); + + // If verbose, print the list of directories that will be searched. + if (Verbose) { + llvm::errs() << "#include \"...\" search starts here:\n"; + unsigned QuotedIdx = IncludeGroup[Quoted].size(); + for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { + if (i == QuotedIdx) + llvm::errs() << "#include <...> search starts here:\n"; + const char *Name = SearchList[i].getName(); + const char *Suffix; + if (SearchList[i].isNormalDir()) + Suffix = ""; + else if (SearchList[i].isFramework()) + Suffix = " (framework directory)"; + else { + assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); + Suffix = " (headermap)"; + } + llvm::errs() << " " << Name << Suffix << "\n"; + } + llvm::errs() << "End of search list.\n"; + } +} + +void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &Triple) { + InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); + + // Add the user defined entries. + for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { + const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; + Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework, + false); + } + + // Add entries from CPATH and friends. + Init.AddDelimitedPaths(HSOpts.EnvIncPath); + if (Lang.CPlusPlus && Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCXXEnvIncPath); + else if (Lang.CPlusPlus) + Init.AddDelimitedPaths(HSOpts.CXXEnvIncPath); + else if (Lang.ObjC1) + Init.AddDelimitedPaths(HSOpts.ObjCEnvIncPath); + else + Init.AddDelimitedPaths(HSOpts.CEnvIncPath); + + if (HSOpts.UseStandardIncludes) + Init.AddDefaultSystemIncludePaths(Lang, Triple, HSOpts); + + Init.Realize(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp new file mode 100644 index 0000000..2b35c8e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -0,0 +1,573 @@ +//===--- InitPreprocessor.cpp - PP initialization code. ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the clang::InitializePreprocessor function. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "clang/Frontend/Utils.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/PreprocessorOptions.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +using namespace clang; + +// Append a #define line to Buf for Macro. Macro should be of the form XXX, +// in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit +// "#define XXX Y z W". To get a #define with no value, use "XXX=". +static void DefineBuiltinMacro(MacroBuilder &Builder, llvm::StringRef Macro, + Diagnostic &Diags) { + std::pair<llvm::StringRef, llvm::StringRef> MacroPair = Macro.split('='); + llvm::StringRef MacroName = MacroPair.first; + llvm::StringRef MacroBody = MacroPair.second; + if (MacroName.size() != Macro.size()) { + // Per GCC -D semantics, the macro ends at \n if it exists. + llvm::StringRef::size_type End = MacroBody.find_first_of("\n\r"); + if (End != llvm::StringRef::npos) + Diags.Report(diag::warn_fe_macro_contains_embedded_newline) + << MacroName; + Builder.defineMacro(MacroName, MacroBody.substr(0, End)); + } else { + // Push "macroname 1". + Builder.defineMacro(Macro); + } +} + +std::string clang::NormalizeDashIncludePath(llvm::StringRef File) { + // Implicit include paths should be resolved relative to the current + // working directory first, and then use the regular header search + // mechanism. The proper way to handle this is to have the + // predefines buffer located at the current working directory, but + // it has not file entry. For now, workaround this by using an + // absolute path if we find the file here, and otherwise letting + // header search handle it. + llvm::sys::Path Path(File); + Path.makeAbsolute(); + if (!Path.exists()) + Path = File; + + return Lexer::Stringify(Path.str()); +} + +/// AddImplicitInclude - Add an implicit #include of the specified file to the +/// predefines buffer. +static void AddImplicitInclude(MacroBuilder &Builder, llvm::StringRef File) { + Builder.append("#include \"" + + llvm::Twine(NormalizeDashIncludePath(File)) + "\""); +} + +static void AddImplicitIncludeMacros(MacroBuilder &Builder, + llvm::StringRef File) { + Builder.append("#__include_macros \"" + + llvm::Twine(NormalizeDashIncludePath(File)) + "\""); + // Marker token to stop the __include_macros fetch loop. + Builder.append("##"); // ##? +} + +/// AddImplicitIncludePTH - Add an implicit #include using the original file +/// used to generate a PTH cache. +static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, + llvm::StringRef ImplicitIncludePTH) { + PTHManager *P = PP.getPTHManager(); + assert(P && "No PTHManager."); + const char *OriginalFile = P->getOriginalSourceFile(); + + if (!OriginalFile) { + PP.getDiagnostics().Report(diag::err_fe_pth_file_has_no_source_header) + << ImplicitIncludePTH; + return; + } + + AddImplicitInclude(Builder, OriginalFile); +} + +/// PickFP - This is used to pick a value based on the FP semantics of the +/// specified FP model. +template <typename T> +static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, + T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal, + T IEEEQuadVal) { + if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle) + return IEEESingleVal; + if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEdouble) + return IEEEDoubleVal; + if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::x87DoubleExtended) + return X87DoubleExtendedVal; + if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::PPCDoubleDouble) + return PPCDoubleDoubleVal; + assert(Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEquad); + return IEEEQuadVal; +} + +static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, + const llvm::fltSemantics *Sem) { + const char *DenormMin, *Epsilon, *Max, *Min; + DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", + "3.64519953188247460253e-4951L", + "4.94065645841246544176568792868221e-324L", + "6.47517511943802511092443895822764655e-4966L"); + int Digits = PickFP(Sem, 6, 15, 18, 31, 33); + Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16", + "1.08420217248550443401e-19L", + "4.94065645841246544176568792868221e-324L", + "1.92592994438723585305597794258492732e-34L"); + int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113); + int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931); + int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932); + int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381); + int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384); + Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308", + "3.36210314311209350626e-4932L", + "2.00416836000897277799610805135016e-292L", + "3.36210314311209350626267781732175260e-4932L"); + Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308", + "1.18973149535723176502e+4932L", + "1.79769313486231580793728971405301e+308L", + "1.18973149535723176508575932662800702e+4932L"); + + llvm::SmallString<32> DefPrefix; + DefPrefix = "__"; + DefPrefix += Prefix; + DefPrefix += "_"; + + Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); + Builder.defineMacro(DefPrefix + "HAS_DENORM__"); + Builder.defineMacro(DefPrefix + "DIG__", llvm::Twine(Digits)); + Builder.defineMacro(DefPrefix + "EPSILON__", llvm::Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); + Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); + Builder.defineMacro(DefPrefix + "MANT_DIG__", llvm::Twine(MantissaDigits)); + + Builder.defineMacro(DefPrefix + "MAX_10_EXP__", llvm::Twine(Max10Exp)); + Builder.defineMacro(DefPrefix + "MAX_EXP__", llvm::Twine(MaxExp)); + Builder.defineMacro(DefPrefix + "MAX__", llvm::Twine(Max)); + + Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+llvm::Twine(Min10Exp)+")"); + Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+llvm::Twine(MinExp)+")"); + Builder.defineMacro(DefPrefix + "MIN__", llvm::Twine(Min)); +} + + +/// DefineTypeSize - Emit a macro to the predefines buffer that declares a macro +/// named MacroName with the max value for a type with width 'TypeWidth' a +/// signedness of 'isSigned' and with a value suffix of 'ValSuffix' (e.g. LL). +static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, + llvm::StringRef ValSuffix, bool isSigned, + MacroBuilder& Builder) { + long long MaxVal; + if (isSigned) + MaxVal = (1LL << (TypeWidth - 1)) - 1; + else + MaxVal = ~0LL >> (64-TypeWidth); + + Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix); +} + +/// DefineTypeSize - An overloaded helper that uses TargetInfo to determine +/// the width, suffix, and signedness of the given type +static void DefineTypeSize(llvm::StringRef MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, MacroBuilder &Builder) { + DefineTypeSize(MacroName, TI.getTypeWidth(Ty), TI.getTypeConstantSuffix(Ty), + TI.isTypeSigned(Ty), Builder); +} + +static void DefineType(const llvm::Twine &MacroName, TargetInfo::IntType Ty, + MacroBuilder &Builder) { + Builder.defineMacro(MacroName, TargetInfo::getTypeName(Ty)); +} + +static void DefineTypeWidth(llvm::StringRef MacroName, TargetInfo::IntType Ty, + const TargetInfo &TI, MacroBuilder &Builder) { + Builder.defineMacro(MacroName, llvm::Twine(TI.getTypeWidth(Ty))); +} + +static void DefineExactWidthIntType(TargetInfo::IntType Ty, + const TargetInfo &TI, MacroBuilder &Builder) { + int TypeWidth = TI.getTypeWidth(Ty); + DefineType("__INT" + llvm::Twine(TypeWidth) + "_TYPE__", Ty, Builder); + + llvm::StringRef ConstSuffix(TargetInfo::getTypeConstantSuffix(Ty)); + if (!ConstSuffix.empty()) + Builder.defineMacro("__INT" + llvm::Twine(TypeWidth) + "_C_SUFFIX__", + ConstSuffix); +} + +static void InitializePredefinedMacros(const TargetInfo &TI, + const LangOptions &LangOpts, + const FrontendOptions &FEOpts, + MacroBuilder &Builder) { + // Compiler version introspection macros. + Builder.defineMacro("__llvm__"); // LLVM Backend + Builder.defineMacro("__clang__"); // Clang Frontend +#define TOSTR2(X) #X +#define TOSTR(X) TOSTR2(X) + Builder.defineMacro("__clang_major__", TOSTR(CLANG_VERSION_MAJOR)); + Builder.defineMacro("__clang_minor__", TOSTR(CLANG_VERSION_MINOR)); +#ifdef CLANG_VERSION_PATCHLEVEL + Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL)); +#else + Builder.defineMacro("__clang_patchlevel__", "0"); +#endif + Builder.defineMacro("__clang_version__", + "\"" CLANG_VERSION_STRING " (" + + getClangFullRepositoryVersion() + ")\""); +#undef TOSTR +#undef TOSTR2 + // Currently claim to be compatible with GCC 4.2.1-5621. + Builder.defineMacro("__GNUC_MINOR__", "2"); + Builder.defineMacro("__GNUC_PATCHLEVEL__", "1"); + Builder.defineMacro("__GNUC__", "4"); + Builder.defineMacro("__GXX_ABI_VERSION", "1002"); + Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\""); + + // Initialize language-specific preprocessor defines. + + // These should all be defined in the preprocessor according to the + // current language configuration. + if (!LangOpts.Microsoft) + Builder.defineMacro("__STDC__"); + if (LangOpts.AsmPreprocessor) + Builder.defineMacro("__ASSEMBLER__"); + + if (!LangOpts.CPlusPlus) { + if (LangOpts.C99) + Builder.defineMacro("__STDC_VERSION__", "199901L"); + else if (!LangOpts.GNUMode && LangOpts.Digraphs) + Builder.defineMacro("__STDC_VERSION__", "199409L"); + } + + // Standard conforming mode? + if (!LangOpts.GNUMode) + Builder.defineMacro("__STRICT_ANSI__"); + + if (LangOpts.CPlusPlus0x) + Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__"); + + if (LangOpts.Freestanding) + Builder.defineMacro("__STDC_HOSTED__", "0"); + else + Builder.defineMacro("__STDC_HOSTED__"); + + if (LangOpts.ObjC1) { + Builder.defineMacro("__OBJC__"); + if (LangOpts.ObjCNonFragileABI) { + Builder.defineMacro("__OBJC2__"); + Builder.defineMacro("OBJC_ZEROCOST_EXCEPTIONS"); + } + + if (LangOpts.getGCMode() != LangOptions::NonGC) + Builder.defineMacro("__OBJC_GC__"); + + if (LangOpts.NeXTRuntime) + Builder.defineMacro("__NEXT_RUNTIME__"); + } + + // darwin_constant_cfstrings controls this. This is also dependent + // on other things like the runtime I believe. This is set even for C code. + Builder.defineMacro("__CONSTANT_CFSTRINGS__"); + + if (LangOpts.ObjC2) + Builder.defineMacro("OBJC_NEW_PROPERTIES"); + + if (LangOpts.PascalStrings) + Builder.defineMacro("__PASCAL_STRINGS__"); + + if (LangOpts.Blocks) { + Builder.defineMacro("__block", "__attribute__((__blocks__(byref)))"); + Builder.defineMacro("__BLOCKS__"); + } + + if (LangOpts.Exceptions) + Builder.defineMacro("__EXCEPTIONS"); + if (LangOpts.SjLjExceptions) + Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); + + if (LangOpts.CPlusPlus) { + Builder.defineMacro("__DEPRECATED"); + Builder.defineMacro("__GNUG__", "4"); + Builder.defineMacro("__GXX_WEAK__"); + if (LangOpts.GNUMode) + Builder.defineMacro("__cplusplus"); + else + // C++ [cpp.predefined]p1: + // The name_ _cplusplusis defined to the value199711Lwhen compiling a + // C++ translation unit. + Builder.defineMacro("__cplusplus", "199711L"); + Builder.defineMacro("__private_extern__", "extern"); + } + + if (LangOpts.Microsoft) { + // Filter out some microsoft extensions when trying to parse in ms-compat + // mode. + Builder.defineMacro("__int8", "__INT8_TYPE__"); + Builder.defineMacro("__int16", "__INT16_TYPE__"); + Builder.defineMacro("__int32", "__INT32_TYPE__"); + Builder.defineMacro("__int64", "__INT64_TYPE__"); + // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however + // VC++ appears to only like __FUNCTION__. + Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); + // Work around some issues with Visual C++ headerws. + if (LangOpts.CPlusPlus) { + // Since we define wchar_t in C++ mode. + Builder.defineMacro("_WCHAR_T_DEFINED"); + Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); + // FIXME: This should be temporary until we have a __pragma + // solution, to avoid some errors flagged in VC++ headers. + Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0"); + } + } + + if (LangOpts.Optimize) + Builder.defineMacro("__OPTIMIZE__"); + if (LangOpts.OptimizeSize) + Builder.defineMacro("__OPTIMIZE_SIZE__"); + + // Initialize target-specific preprocessor defines. + + // Define type sizing macros based on the target properties. + assert(TI.getCharWidth() == 8 && "Only support 8-bit char so far"); + Builder.defineMacro("__CHAR_BIT__", "8"); + + DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Builder); + DefineTypeSize("__SHRT_MAX__", TargetInfo::SignedShort, TI, Builder); + DefineTypeSize("__INT_MAX__", TargetInfo::SignedInt, TI, Builder); + DefineTypeSize("__LONG_MAX__", TargetInfo::SignedLong, TI, Builder); + DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder); + DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder); + DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder); + + DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder); + DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder); + DefineTypeWidth("__INTMAX_WIDTH__", TI.getIntMaxType(), TI, Builder); + DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder); + DefineTypeWidth("__PTRDIFF_WIDTH__", TI.getPtrDiffType(0), TI, Builder); + DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder); + DefineTypeWidth("__INTPTR_WIDTH__", TI.getIntPtrType(), TI, Builder); + DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder); + DefineTypeWidth("__SIZE_WIDTH__", TI.getSizeType(), TI, Builder); + DefineType("__WCHAR_TYPE__", TI.getWCharType(), Builder); + DefineTypeWidth("__WCHAR_WIDTH__", TI.getWCharType(), TI, Builder); + DefineType("__WINT_TYPE__", TI.getWIntType(), Builder); + DefineTypeWidth("__WINT_WIDTH__", TI.getWIntType(), TI, Builder); + DefineTypeWidth("__SIG_ATOMIC_WIDTH__", TI.getSigAtomicType(), TI, Builder); + + DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat()); + DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat()); + DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat()); + + // Define a __POINTER_WIDTH__ macro for stdint.h. + Builder.defineMacro("__POINTER_WIDTH__", + llvm::Twine((int)TI.getPointerWidth(0))); + + if (!LangOpts.CharIsSigned) + Builder.defineMacro("__CHAR_UNSIGNED__"); + + // Define exact-width integer types for stdint.h + Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__", + "char"); + + if (TI.getShortWidth() > TI.getCharWidth()) + DefineExactWidthIntType(TargetInfo::SignedShort, TI, Builder); + + if (TI.getIntWidth() > TI.getShortWidth()) + DefineExactWidthIntType(TargetInfo::SignedInt, TI, Builder); + + if (TI.getLongWidth() > TI.getIntWidth()) + DefineExactWidthIntType(TargetInfo::SignedLong, TI, Builder); + + if (TI.getLongLongWidth() > TI.getLongWidth()) + DefineExactWidthIntType(TargetInfo::SignedLongLong, TI, Builder); + + // Add __builtin_va_list typedef. + Builder.append(TI.getVAListDeclaration()); + + if (const char *Prefix = TI.getUserLabelPrefix()) + Builder.defineMacro("__USER_LABEL_PREFIX__", Prefix); + + // Build configuration options. FIXME: these should be controlled by + // command line options or something. + Builder.defineMacro("__FINITE_MATH_ONLY__", "0"); + + if (LangOpts.GNUInline) + Builder.defineMacro("__GNUC_GNU_INLINE__"); + else + Builder.defineMacro("__GNUC_STDC_INLINE__"); + + if (LangOpts.NoInline) + Builder.defineMacro("__NO_INLINE__"); + + if (unsigned PICLevel = LangOpts.PICLevel) { + Builder.defineMacro("__PIC__", llvm::Twine(PICLevel)); + Builder.defineMacro("__pic__", llvm::Twine(PICLevel)); + } + + // Macros to control C99 numerics and <float.h> + Builder.defineMacro("__FLT_EVAL_METHOD__", "0"); + Builder.defineMacro("__FLT_RADIX__", "2"); + int Dig = PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36); + Builder.defineMacro("__DECIMAL_DIG__", llvm::Twine(Dig)); + + if (LangOpts.getStackProtectorMode() == LangOptions::SSPOn) + Builder.defineMacro("__SSP__"); + else if (LangOpts.getStackProtectorMode() == LangOptions::SSPReq) + Builder.defineMacro("__SSP_ALL__", "2"); + + if (FEOpts.ProgramAction == frontend::RewriteObjC) + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + + // Define a macro that exists only when using the static analyzer. + if (FEOpts.ProgramAction == frontend::RunAnalysis) + Builder.defineMacro("__clang_analyzer__"); + + // Get other target #defines. + TI.getTargetDefines(LangOpts, Builder); +} + +// Initialize the remapping of files to alternative contents, e.g., +// those specified through other files. +static void InitializeFileRemapping(Diagnostic &Diags, + SourceManager &SourceMgr, + FileManager &FileMgr, + const PreprocessorOptions &InitOpts) { + // Remap files in the source manager (with buffers). + for (PreprocessorOptions::remapped_file_buffer_iterator + Remap = InitOpts.remapped_file_buffer_begin(), + RemapEnd = InitOpts.remapped_file_buffer_end(); + Remap != RemapEnd; + ++Remap) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + Remap->second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + delete Remap->second; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Remap->second); + } + + // Remap files in the source manager (with other files). + for (PreprocessorOptions::remapped_file_iterator + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); + Remap != RemapEnd; + ++Remap) { + // Find the file that we're mapping to. + const FileEntry *ToFile = FileMgr.getFile(Remap->second); + if (!ToFile) { + Diags.Report(diag::err_fe_remap_missing_to_file) + << Remap->first << Remap->second; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + ToFile->getSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Load the contents of the file we're mapping to. + std::string ErrorStr; + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + if (!Buffer) { + Diags.Report(diag::err_fe_error_opening) + << Remap->second << ErrorStr; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Buffer); + } +} + +/// InitializePreprocessor - Initialize the preprocessor getting it and the +/// environment ready to process a single file. This returns true on error. +/// +void clang::InitializePreprocessor(Preprocessor &PP, + const PreprocessorOptions &InitOpts, + const HeaderSearchOptions &HSOpts, + const FrontendOptions &FEOpts) { + std::string PredefineBuffer; + PredefineBuffer.reserve(4080); + llvm::raw_string_ostream Predefines(PredefineBuffer); + MacroBuilder Builder(Predefines); + + InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), + PP.getFileManager(), InitOpts); + + // Emit line markers for various builtin sections of the file. We don't do + // this in asm preprocessor mode, because "# 4" is not a line marker directive + // in this mode. + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<built-in>\" 3"); + + // Install things like __POWERPC__, __GNUC__, etc into the macro table. + if (InitOpts.UsePredefines) + InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), + FEOpts, Builder); + + // Add on the predefines from the driver. Wrap in a #line directive to report + // that they come from the command line. + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<command line>\" 1"); + + // Process #define's and #undef's in the order they are given. + for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { + if (InitOpts.Macros[i].second) // isUndef + Builder.undefineMacro(InitOpts.Macros[i].first); + else + DefineBuiltinMacro(Builder, InitOpts.Macros[i].first, + PP.getDiagnostics()); + } + + // If -imacros are specified, include them now. These are processed before + // any -include directives. + for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) + AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i]); + + // Process -include directives. + for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { + const std::string &Path = InitOpts.Includes[i]; + if (Path == InitOpts.ImplicitPTHInclude) + AddImplicitIncludePTH(Builder, PP, Path); + else + AddImplicitInclude(Builder, Path); + } + + // Exit the command line and go back to <built-in> (2 is LC_LEAVE). + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<built-in>\" 2"); + + // Copy PredefinedBuffer into the Preprocessor. + PP.setPredefines(Predefines.str()); + + // Initialize the header search object. + ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, + PP.getLangOptions(), + PP.getTargetInfo().getTriple()); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp new file mode 100644 index 0000000..af1721d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp @@ -0,0 +1,44 @@ +//===--- LangStandards.cpp - Language Standard Definitions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/LangStandard.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; +using namespace clang::frontend; + +#define LANGSTANDARD(id, name, desc, features) \ + static const LangStandard Lang_##id = { name, desc, features }; +#include "clang/Frontend/LangStandards.def" + +const LangStandard &LangStandard::getLangStandardForKind(Kind K) { + switch (K) { + default: + llvm_unreachable("Invalid language kind!"); + case lang_unspecified: + llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); +#define LANGSTANDARD(id, name, desc, features) \ + case lang_##id: return Lang_##id; +#include "clang/Frontend/LangStandards.def" + } +} + +const LangStandard *LangStandard::getLangStandardForName(llvm::StringRef Name) { + Kind K = llvm::StringSwitch<Kind>(Name) +#define LANGSTANDARD(id, name, desc, features) \ + .Case(name, lang_##id) +#include "clang/Frontend/LangStandards.def" + .Default(lang_unspecified); + if (K == lang_unspecified) + return 0; + + return &getLangStandardForKind(K); +} + + diff --git a/contrib/llvm/tools/clang/lib/Frontend/Makefile b/contrib/llvm/tools/clang/lib/Frontend/Makefile new file mode 100644 index 0000000..9e1a864 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/Makefile @@ -0,0 +1,17 @@ +##===- clang/lib/Frontend/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangFrontend +BUILD_ARCHIVE = 1 + +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp new file mode 100644 index 0000000..88e9b9d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReader.cpp @@ -0,0 +1,3096 @@ +//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PCHReader class, which reads a precompiled header. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHReader.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/Utils.h" +#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Path.h" +#include <algorithm> +#include <iterator> +#include <cstdio> +#include <sys/stat.h> +using namespace clang; + +//===----------------------------------------------------------------------===// +// PCH reader validator implementation +//===----------------------------------------------------------------------===// + +PCHReaderListener::~PCHReaderListener() {} + +bool +PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { + const LangOptions &PPLangOpts = PP.getLangOptions(); +#define PARSE_LANGOPT_BENIGN(Option) +#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ + if (PPLangOpts.Option != LangOpts.Option) { \ + Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \ + return true; \ + } + + PARSE_LANGOPT_BENIGN(Trigraphs); + PARSE_LANGOPT_BENIGN(BCPLComment); + PARSE_LANGOPT_BENIGN(DollarIdents); + PARSE_LANGOPT_BENIGN(AsmPreprocessor); + PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); + PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords); + PARSE_LANGOPT_BENIGN(ImplicitInt); + PARSE_LANGOPT_BENIGN(Digraphs); + PARSE_LANGOPT_BENIGN(HexFloats); + PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); + PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); + PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); + PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); + PARSE_LANGOPT_BENIGN(CXXOperatorName); + PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); + PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); + PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); + PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2); + PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings, + diag::warn_pch_no_constant_cfstrings); + PARSE_LANGOPT_BENIGN(PascalStrings); + PARSE_LANGOPT_BENIGN(WritableStrings); + PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, + diag::warn_pch_lax_vector_conversions); + PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec); + PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); + PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions); + PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); + PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); + PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); + PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, + diag::warn_pch_thread_safe_statics); + PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads); + PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); + PARSE_LANGOPT_BENIGN(EmitAllDecls); + PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); + PARSE_LANGOPT_IMPORTANT(OverflowChecking, diag::warn_pch_overflow_checking); + PARSE_LANGOPT_IMPORTANT(HeinousExtensions, + diag::warn_pch_heinous_extensions); + // FIXME: Most of the options below are benign if the macro wasn't + // used. Unfortunately, this means that a PCH compiled without + // optimization can't be used with optimization turned on, even + // though the only thing that changes is whether __OPTIMIZE__ was + // defined... but if __OPTIMIZE__ never showed up in the header, it + // doesn't matter. We could consider making this some special kind + // of check. + PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); + PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); + PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); + PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); + PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); + PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); + PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); + PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); + PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); + if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { + Reader.Diag(diag::warn_pch_gc_mode) + << LangOpts.getGCMode() << PPLangOpts.getGCMode(); + return true; + } + PARSE_LANGOPT_BENIGN(getVisibilityMode()); + PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(), + diag::warn_pch_stack_protector); + PARSE_LANGOPT_BENIGN(InstantiationDepth); + PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); + PARSE_LANGOPT_BENIGN(CatchUndefined); + PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); +#undef PARSE_LANGOPT_IMPORTANT +#undef PARSE_LANGOPT_BENIGN + + return false; +} + +bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { + if (Triple == PP.getTargetInfo().getTriple().str()) + return false; + + Reader.Diag(diag::warn_pch_target_triple) + << Triple << PP.getTargetInfo().getTriple().str(); + return true; +} + +bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, + FileID PCHBufferID, + llvm::StringRef OriginalFileName, + std::string &SuggestedPredefines) { + // We are in the context of an implicit include, so the predefines buffer will + // have a #include entry for the PCH file itself (as normalized by the + // preprocessor initialization). Find it and skip over it in the checking + // below. + llvm::SmallString<256> PCHInclude; + PCHInclude += "#include \""; + PCHInclude += NormalizeDashIncludePath(OriginalFileName); + PCHInclude += "\"\n"; + std::pair<llvm::StringRef,llvm::StringRef> Split = + llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); + llvm::StringRef Left = Split.first, Right = Split.second; + if (Left == PP.getPredefines()) { + Error("Missing PCH include entry!"); + return true; + } + + // If the predefines is equal to the joined left and right halves, we're done! + if (Left.size() + Right.size() == PCHPredef.size() && + PCHPredef.startswith(Left) && PCHPredef.endswith(Right)) + return false; + + SourceManager &SourceMgr = PP.getSourceManager(); + + // The predefines buffers are different. Determine what the differences are, + // and whether they require us to reject the PCH file. + llvm::SmallVector<llvm::StringRef, 8> PCHLines; + PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + + llvm::SmallVector<llvm::StringRef, 8> CmdLineLines; + Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + + // Sort both sets of predefined buffer lines, since we allow some extra + // definitions and they may appear at any point in the output. + std::sort(CmdLineLines.begin(), CmdLineLines.end()); + std::sort(PCHLines.begin(), PCHLines.end()); + + // Determine which predefines that were used to build the PCH file are missing + // from the command line. + std::vector<llvm::StringRef> MissingPredefines; + std::set_difference(PCHLines.begin(), PCHLines.end(), + CmdLineLines.begin(), CmdLineLines.end(), + std::back_inserter(MissingPredefines)); + + bool MissingDefines = false; + bool ConflictingDefines = false; + for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { + llvm::StringRef Missing = MissingPredefines[I]; + if (!Missing.startswith("#define ")) { + Reader.Diag(diag::warn_pch_compiler_options_mismatch); + return true; + } + + // This is a macro definition. Determine the name of the macro we're + // defining. + std::string::size_type StartOfMacroName = strlen("#define "); + std::string::size_type EndOfMacroName + = Missing.find_first_of("( \n\r", StartOfMacroName); + assert(EndOfMacroName != std::string::npos && + "Couldn't find the end of the macro name"); + llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); + + // Determine whether this macro was given a different definition on the + // command line. + std::string MacroDefStart = "#define " + MacroName.str(); + std::string::size_type MacroDefLen = MacroDefStart.size(); + llvm::SmallVector<llvm::StringRef, 8>::iterator ConflictPos + = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), + MacroDefStart); + for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { + if (!ConflictPos->startswith(MacroDefStart)) { + // Different macro; we're done. + ConflictPos = CmdLineLines.end(); + break; + } + + assert(ConflictPos->size() > MacroDefLen && + "Invalid #define in predefines buffer?"); + if ((*ConflictPos)[MacroDefLen] != ' ' && + (*ConflictPos)[MacroDefLen] != '(') + continue; // Longer macro name; keep trying. + + // We found a conflicting macro definition. + break; + } + + if (ConflictPos != CmdLineLines.end()) { + Reader.Diag(diag::warn_cmdline_conflicting_macro_def) + << MacroName; + + // Show the definition of this macro within the PCH file. + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; + + ConflictingDefines = true; + continue; + } + + // If the macro doesn't conflict, then we'll just pick up the macro + // definition from the PCH file. Warn the user that they made a mistake. + if (ConflictingDefines) + continue; // Don't complain if there are already conflicting defs + + if (!MissingDefines) { + Reader.Diag(diag::warn_cmdline_missing_macro_defs); + MissingDefines = true; + } + + // Show the definition of this macro within the PCH file. + llvm::StringRef::size_type Offset = PCHPredef.find(Missing); + assert(Offset != llvm::StringRef::npos && "Unable to find macro!"); + SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID) + .getFileLocWithOffset(Offset); + Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); + } + + if (ConflictingDefines) + return true; + + // Determine what predefines were introduced based on command-line + // parameters that were not present when building the PCH + // file. Extra #defines are okay, so long as the identifiers being + // defined were not used within the precompiled header. + std::vector<llvm::StringRef> ExtraPredefines; + std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), + PCHLines.begin(), PCHLines.end(), + std::back_inserter(ExtraPredefines)); + for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { + llvm::StringRef &Extra = ExtraPredefines[I]; + if (!Extra.startswith("#define ")) { + Reader.Diag(diag::warn_pch_compiler_options_mismatch); + return true; + } + + // This is an extra macro definition. Determine the name of the + // macro we're defining. + std::string::size_type StartOfMacroName = strlen("#define "); + std::string::size_type EndOfMacroName + = Extra.find_first_of("( \n\r", StartOfMacroName); + assert(EndOfMacroName != std::string::npos && + "Couldn't find the end of the macro name"); + llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); + + // Check whether this name was used somewhere in the PCH file. If + // so, defining it as a macro could change behavior, so we reject + // the PCH file. + if (IdentifierInfo *II = Reader.get(MacroName)) { + Reader.Diag(diag::warn_macro_name_used_in_pch) << II; + return true; + } + + // Add this definition to the suggested predefines buffer. + SuggestedPredefines += Extra; + SuggestedPredefines += '\n'; + } + + // If we get here, it's because the predefines buffer had compatible + // contents. Accept the PCH file. + return false; +} + +void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, + unsigned ID) { + PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); + ++NumHeaderInfos; +} + +void PCHValidator::ReadCounter(unsigned Value) { + PP.setCounterValue(Value); +} + +//===----------------------------------------------------------------------===// +// PCH reader implementation +//===----------------------------------------------------------------------===// + +PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, + const char *isysroot) + : Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()), + FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), + SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0), + IdentifierTableData(0), IdentifierLookupTable(0), + IdentifierOffsets(0), + MethodPoolLookupTable(0), MethodPoolLookupTableData(0), + TotalSelectorsInMethodPool(0), SelectorOffsets(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), + NumSLocEntriesRead(0), NumStatementsRead(0), + NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), + NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), + CurrentlyLoadingTypeOrDecl(0) { + RelocatablePCH = false; +} + +PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags, const char *isysroot) + : SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), + SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), + IdentifierTableData(0), IdentifierLookupTable(0), + IdentifierOffsets(0), + MethodPoolLookupTable(0), MethodPoolLookupTableData(0), + TotalSelectorsInMethodPool(0), SelectorOffsets(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), + NumSLocEntriesRead(0), NumStatementsRead(0), + NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), + NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), + CurrentlyLoadingTypeOrDecl(0) { + RelocatablePCH = false; +} + +PCHReader::~PCHReader() {} + +Expr *PCHReader::ReadDeclExpr() { + return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor)); +} + +Expr *PCHReader::ReadTypeExpr() { + return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor)); +} + + +namespace { +class PCHMethodPoolLookupTrait { + PCHReader &Reader; + +public: + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + + typedef Selector external_key_type; + typedef external_key_type internal_key_type; + + explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return a == b; + } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = llvm::HashString(II->getName(), R); + return R; + } + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned KeyLen = ReadUnalignedLE16(d); + unsigned DataLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); + } + + internal_key_type ReadKey(const unsigned char* d, unsigned) { + using namespace clang::io; + SelectorTable &SelTable = Reader.getContext()->Selectors; + unsigned N = ReadUnalignedLE16(d); + IdentifierInfo *FirstII + = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); + if (N == 0) + return SelTable.getNullarySelector(FirstII); + else if (N == 1) + return SelTable.getUnarySelector(FirstII); + + llvm::SmallVector<IdentifierInfo *, 16> Args; + Args.push_back(FirstII); + for (unsigned I = 1; I != N; ++I) + Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d))); + + return SelTable.getSelector(N, Args.data()); + } + + data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { + using namespace clang::io; + unsigned NumInstanceMethods = ReadUnalignedLE16(d); + unsigned NumFactoryMethods = ReadUnalignedLE16(d); + + data_type Result; + + // Load instance methods + ObjCMethodList *Prev = 0; + for (unsigned I = 0; I != NumInstanceMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.first.Method) { + // This is the first method, which is the easy case. + Result.first.Method = Method; + Prev = &Result.first; + continue; + } + + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); + Prev->Next = new (Mem) ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + // Load factory methods + Prev = 0; + for (unsigned I = 0; I != NumFactoryMethods; ++I) { + ObjCMethodDecl *Method + = cast<ObjCMethodDecl>(Reader.GetDecl(ReadUnalignedLE32(d))); + if (!Result.second.Method) { + // This is the first method, which is the easy case. + Result.second.Method = Method; + Prev = &Result.second; + continue; + } + + ObjCMethodList *Mem = + Reader.getSema()->BumpAlloc.Allocate<ObjCMethodList>(); + Prev->Next = new (Mem) ObjCMethodList(Method, 0); + Prev = Prev->Next; + } + + return Result; + } +}; + +} // end anonymous namespace + +/// \brief The on-disk hash table used for the global method pool. +typedef OnDiskChainedHashTable<PCHMethodPoolLookupTrait> + PCHMethodPoolLookupTable; + +namespace { +class PCHIdentifierLookupTrait { + PCHReader &Reader; + + // If we know the IdentifierInfo in advance, it is here and we will + // not build a new one. Used when deserializing information about an + // identifier that was constructed before the PCH file was read. + IdentifierInfo *KnownII; + +public: + typedef IdentifierInfo * data_type; + + typedef const std::pair<const char*, unsigned> external_key_type; + + typedef external_key_type internal_key_type; + + explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0) + : Reader(Reader), KnownII(II) { } + + static bool EqualKey(const internal_key_type& a, + const internal_key_type& b) { + return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 + : false; + } + + static unsigned ComputeHash(const internal_key_type& a) { + return llvm::HashString(llvm::StringRef(a.first, a.second)); + } + + // This hopefully will just get inlined and removed by the optimizer. + static const internal_key_type& + GetInternalKey(const external_key_type& x) { return x; } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + using namespace clang::io; + unsigned DataLen = ReadUnalignedLE16(d); + unsigned KeyLen = ReadUnalignedLE16(d); + return std::make_pair(KeyLen, DataLen); + } + + static std::pair<const char*, unsigned> + ReadKey(const unsigned char* d, unsigned n) { + assert(n >= 2 && d[n-1] == '\0'); + return std::make_pair((const char*) d, n-1); + } + + IdentifierInfo *ReadData(const internal_key_type& k, + const unsigned char* d, + unsigned DataLen) { + using namespace clang::io; + pch::IdentID ID = ReadUnalignedLE32(d); + bool IsInteresting = ID & 0x01; + + // Wipe out the "is interesting" bit. + ID = ID >> 1; + + if (!IsInteresting) { + // For unintersting identifiers, just build the IdentifierInfo + // and associate it with the persistent ID. + IdentifierInfo *II = KnownII; + if (!II) + II = &Reader.getIdentifierTable().CreateIdentifierInfo( + k.first, k.first + k.second); + Reader.SetIdentifierInfo(ID, II); + return II; + } + + unsigned Bits = ReadUnalignedLE16(d); + bool CPlusPlusOperatorKeyword = Bits & 0x01; + Bits >>= 1; + bool Poisoned = Bits & 0x01; + Bits >>= 1; + bool ExtensionToken = Bits & 0x01; + Bits >>= 1; + bool hasMacroDefinition = Bits & 0x01; + Bits >>= 1; + unsigned ObjCOrBuiltinID = Bits & 0x3FF; + Bits >>= 10; + + assert(Bits == 0 && "Extra bits in the identifier?"); + DataLen -= 6; + + // Build the IdentifierInfo itself and link the identifier ID with + // the new IdentifierInfo. + IdentifierInfo *II = KnownII; + if (!II) + II = &Reader.getIdentifierTable().CreateIdentifierInfo( + k.first, k.first + k.second); + Reader.SetIdentifierInfo(ID, II); + + // Set or check the various bits in the IdentifierInfo structure. + // FIXME: Load token IDs lazily, too? + II->setObjCOrBuiltinID(ObjCOrBuiltinID); + assert(II->isExtensionToken() == ExtensionToken && + "Incorrect extension token flag"); + (void)ExtensionToken; + II->setIsPoisoned(Poisoned); + assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && + "Incorrect C++ operator keyword flag"); + (void)CPlusPlusOperatorKeyword; + + // If this identifier is a macro, deserialize the macro + // definition. + if (hasMacroDefinition) { + uint32_t Offset = ReadUnalignedLE32(d); + Reader.ReadMacroRecord(Offset); + DataLen -= 4; + } + + // Read all of the declarations visible at global scope with this + // name. + if (Reader.getContext() == 0) return II; + if (DataLen > 0) { + llvm::SmallVector<uint32_t, 4> DeclIDs; + for (; DataLen > 0; DataLen -= 4) + DeclIDs.push_back(ReadUnalignedLE32(d)); + Reader.SetGloballyVisibleDecls(II, DeclIDs); + } + + return II; + } +}; + +} // end anonymous namespace + +/// \brief The on-disk hash table used to contain information about +/// all of the identifiers in the program. +typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait> + PCHIdentifierLookupTable; + +void PCHReader::Error(const char *Msg) { + Diag(diag::err_fe_pch_malformed) << Msg; +} + +/// \brief Check the contents of the predefines buffer against the +/// contents of the predefines buffer used to build the PCH file. +/// +/// The contents of the two predefines buffers should be the same. If +/// not, then some command-line option changed the preprocessor state +/// and we must reject the PCH file. +/// +/// \param PCHPredef The start of the predefines buffer in the PCH +/// file. +/// +/// \param PCHPredefLen The length of the predefines buffer in the PCH +/// file. +/// +/// \param PCHBufferID The FileID for the PCH predefines buffer. +/// +/// \returns true if there was a mismatch (in which case the PCH file +/// should be ignored), or false otherwise. +bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef, + FileID PCHBufferID) { + if (Listener) + return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID, + ActualOriginalFileName, + SuggestedPredefines); + return false; +} + +//===----------------------------------------------------------------------===// +// Source Manager Deserialization +//===----------------------------------------------------------------------===// + +/// \brief Read the line table in the source manager block. +/// \returns true if ther was an error. +bool PCHReader::ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record) { + unsigned Idx = 0; + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + // Parse the file names + std::map<int, int> FileIDs; + for (int I = 0, N = Record[Idx++]; I != N; ++I) { + // Extract the file name + unsigned FilenameLen = Record[Idx++]; + std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); + Idx += FilenameLen; + MaybeAddSystemRootToFilename(Filename); + FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(), + Filename.size()); + } + + // Parse the line entries + std::vector<LineEntry> Entries; + while (Idx < Record.size()) { + int FID = FileIDs[Record[Idx++]]; + + // Extract the line entries + unsigned NumEntries = Record[Idx++]; + Entries.clear(); + Entries.reserve(NumEntries); + for (unsigned I = 0; I != NumEntries; ++I) { + unsigned FileOffset = Record[Idx++]; + unsigned LineNo = Record[Idx++]; + int FilenameID = Record[Idx++]; + SrcMgr::CharacteristicKind FileKind + = (SrcMgr::CharacteristicKind)Record[Idx++]; + unsigned IncludeOffset = Record[Idx++]; + Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, + FileKind, IncludeOffset)); + } + LineTable.AddEntry(FID, Entries); + } + + return false; +} + +namespace { + +class PCHStatData { +public: + const bool hasStat; + const ino_t ino; + const dev_t dev; + const mode_t mode; + const time_t mtime; + const off_t size; + + PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s) + : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {} + + PCHStatData() + : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {} +}; + +class PCHStatLookupTrait { + public: + typedef const char *external_key_type; + typedef const char *internal_key_type; + + typedef PCHStatData data_type; + + static unsigned ComputeHash(const char *path) { + return llvm::HashString(path); + } + + static internal_key_type GetInternalKey(const char *path) { return path; } + + static bool EqualKey(internal_key_type a, internal_key_type b) { + return strcmp(a, b) == 0; + } + + static std::pair<unsigned, unsigned> + ReadKeyDataLength(const unsigned char*& d) { + unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); + unsigned DataLen = (unsigned) *d++; + return std::make_pair(KeyLen + 1, DataLen); + } + + static internal_key_type ReadKey(const unsigned char *d, unsigned) { + return (const char *)d; + } + + static data_type ReadData(const internal_key_type, const unsigned char *d, + unsigned /*DataLen*/) { + using namespace clang::io; + + if (*d++ == 1) + return data_type(); + + ino_t ino = (ino_t) ReadUnalignedLE32(d); + dev_t dev = (dev_t) ReadUnalignedLE32(d); + mode_t mode = (mode_t) ReadUnalignedLE16(d); + time_t mtime = (time_t) ReadUnalignedLE64(d); + off_t size = (off_t) ReadUnalignedLE64(d); + return data_type(ino, dev, mode, mtime, size); + } +}; + +/// \brief stat() cache for precompiled headers. +/// +/// This cache is very similar to the stat cache used by pretokenized +/// headers. +class PCHStatCache : public StatSysCallCache { + typedef OnDiskChainedHashTable<PCHStatLookupTrait> CacheTy; + CacheTy *Cache; + + unsigned &NumStatHits, &NumStatMisses; +public: + PCHStatCache(const unsigned char *Buckets, + const unsigned char *Base, + unsigned &NumStatHits, + unsigned &NumStatMisses) + : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) { + Cache = CacheTy::Create(Buckets, Base); + } + + ~PCHStatCache() { delete Cache; } + + int stat(const char *path, struct stat *buf) { + // Do the lookup for the file's data in the PCH file. + CacheTy::iterator I = Cache->find(path); + + // If we don't get a hit in the PCH file just forward to 'stat'. + if (I == Cache->end()) { + ++NumStatMisses; + return StatSysCallCache::stat(path, buf); + } + + ++NumStatHits; + PCHStatData Data = *I; + + if (!Data.hasStat) + return 1; + + buf->st_ino = Data.ino; + buf->st_dev = Data.dev; + buf->st_mtime = Data.mtime; + buf->st_mode = Data.mode; + buf->st_size = Data.size; + return 0; + } +}; +} // end anonymous namespace + + +/// \brief Read the source manager block +PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { + using namespace SrcMgr; + + // Set the source-location entry cursor to the current position in + // the stream. This cursor will be used to read the contents of the + // source manager block initially, and then lazily read + // source-location entries as needed. + SLocEntryCursor = Stream; + + // The stream itself is going to skip over the source manager block. + if (Stream.SkipBlock()) { + Error("malformed block record in PCH file"); + return Failure; + } + + // Enter the source manager block. + if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) { + Error("malformed source manager block record in PCH file"); + return Failure; + } + + RecordData Record; + while (true) { + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (SLocEntryCursor.ReadBlockEnd()) { + Error("error at end of Source Manager block in PCH file"); + return Failure; + } + return Success; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + SLocEntryCursor.ReadSubBlockID(); + if (SLocEntryCursor.SkipBlock()) { + Error("malformed block record in PCH file"); + return Failure; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + SLocEntryCursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case pch::SM_LINE_TABLE: + if (ParseLineTable(Record)) + return Failure; + break; + + case pch::SM_SLOC_FILE_ENTRY: + case pch::SM_SLOC_BUFFER_ENTRY: + case pch::SM_SLOC_INSTANTIATION_ENTRY: + // Once we hit one of the source location entries, we're done. + return Success; + } + } +} + +/// \brief Read in the source location entry with the given ID. +PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { + if (ID == 0) + return Success; + + if (ID > TotalNumSLocEntries) { + Error("source location entry ID out-of-range for PCH file"); + return Failure; + } + + ++NumSLocEntriesRead; + SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]); + unsigned Code = SLocEntryCursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK || + Code == llvm::bitc::ENTER_SUBBLOCK || + Code == llvm::bitc::DEFINE_ABBREV) { + Error("incorrectly-formatted source location entry in PCH file"); + return Failure; + } + + RecordData Record; + const char *BlobStart; + unsigned BlobLen; + switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: + Error("incorrectly-formatted source location entry in PCH file"); + return Failure; + + case pch::SM_SLOC_FILE_ENTRY: { + std::string Filename(BlobStart, BlobStart + BlobLen); + MaybeAddSystemRootToFilename(Filename); + const FileEntry *File = FileMgr.getFile(Filename); + if (File == 0) { + std::string ErrorStr = "could not find file '"; + ErrorStr += Filename; + ErrorStr += "' referenced by PCH file"; + Error(ErrorStr.c_str()); + return Failure; + } + + if (Record.size() < 10) { + Error("source location entry is incorrect"); + return Failure; + } + + if ((off_t)Record[4] != File->getSize() +#if !defined(LLVM_ON_WIN32) + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || (time_t)Record[5] != File->getModificationTime() +#endif + ) { + Diag(diag::err_fe_pch_file_modified) + << Filename; + return Failure; + } + + FileID FID = SourceMgr.createFileID(File, + SourceLocation::getFromRawEncoding(Record[1]), + (SrcMgr::CharacteristicKind)Record[2], + ID, Record[0]); + if (Record[3]) + const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()) + .setHasLineDirectives(); + + // Reconstruct header-search information for this file. + HeaderFileInfo HFI; + HFI.isImport = Record[6]; + HFI.DirInfo = Record[7]; + HFI.NumIncludes = Record[8]; + HFI.ControllingMacroID = Record[9]; + if (Listener) + Listener->ReadHeaderFileInfo(HFI, File->getUID()); + break; + } + + case pch::SM_SLOC_BUFFER_ENTRY: { + const char *Name = BlobStart; + unsigned Offset = Record[0]; + unsigned Code = SLocEntryCursor.ReadCode(); + Record.clear(); + unsigned RecCode + = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); + + if (RecCode != pch::SM_SLOC_BUFFER_BLOB) { + Error("PCH record has invalid code"); + return Failure; + } + + llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(BlobStart, BlobLen - 1), + Name); + FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset); + + if (strcmp(Name, "<built-in>") == 0) { + PCHPredefinesBufferID = BufferID; + PCHPredefines = BlobStart; + PCHPredefinesLen = BlobLen - 1; + } + + break; + } + + case pch::SM_SLOC_INSTANTIATION_ENTRY: { + SourceLocation SpellingLoc + = SourceLocation::getFromRawEncoding(Record[1]); + SourceMgr.createInstantiationLoc(SpellingLoc, + SourceLocation::getFromRawEncoding(Record[2]), + SourceLocation::getFromRawEncoding(Record[3]), + Record[4], + ID, + Record[0]); + break; + } + } + + return Success; +} + +/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the +/// specified cursor. Read the abbreviations that are at the top of the block +/// and then leave the cursor pointing into the block. +bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, + unsigned BlockID) { + if (Cursor.EnterSubBlock(BlockID)) { + Error("malformed block record in PCH file"); + return Failure; + } + + while (true) { + unsigned Code = Cursor.ReadCode(); + + // We expect all abbrevs to be at the start of the block. + if (Code != llvm::bitc::DEFINE_ABBREV) + return false; + Cursor.ReadAbbrevRecord(); + } +} + +void PCHReader::ReadMacroRecord(uint64_t Offset) { + assert(PP && "Forgot to set Preprocessor ?"); + + // Keep track of where we are in the stream, then jump back there + // after reading this macro. + SavedStreamPosition SavedPosition(Stream); + + Stream.JumpToBit(Offset); + RecordData Record; + llvm::SmallVector<IdentifierInfo*, 16> MacroArgs; + MacroInfo *Macro = 0; + + while (true) { + unsigned Code = Stream.ReadCode(); + switch (Code) { + case llvm::bitc::END_BLOCK: + return; + + case llvm::bitc::ENTER_SUBBLOCK: + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) { + Error("malformed block record in PCH file"); + return; + } + continue; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + default: break; + } + + // Read a record. + Record.clear(); + pch::PreprocessorRecordTypes RecType = + (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record); + switch (RecType) { + case pch::PP_MACRO_OBJECT_LIKE: + case pch::PP_MACRO_FUNCTION_LIKE: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + IdentifierInfo *II = DecodeIdentifierInfo(Record[0]); + if (II == 0) { + Error("macro must have a name in PCH file"); + return; + } + SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]); + bool isUsed = Record[2]; + + MacroInfo *MI = PP->AllocateMacroInfo(Loc); + MI->setIsUsed(isUsed); + + unsigned NextIndex = 3; + if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { + // Decode function-like macro info. + bool isC99VarArgs = Record[3]; + bool isGNUVarArgs = Record[4]; + MacroArgs.clear(); + unsigned NumArgs = Record[5]; + NextIndex = 6 + NumArgs; + for (unsigned i = 0; i != NumArgs; ++i) + MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i])); + + // Install function-like macro info. + MI->setIsFunctionLike(); + if (isC99VarArgs) MI->setIsC99Varargs(); + if (isGNUVarArgs) MI->setIsGNUVarargs(); + MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), + PP->getPreprocessorAllocator()); + } + + // Finally, install the macro. + PP->setMacroInfo(II, MI); + + // Remember that we saw this macro last so that we add the tokens that + // form its body to it. + Macro = MI; + + if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) { + // We have a macro definition. Load it now. + PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro, + getMacroDefinition(Record[NextIndex])); + } + + ++NumMacrosRead; + break; + } + + case pch::PP_TOKEN: { + // If we see a TOKEN before a PP_MACRO_*, then the file is + // erroneous, just pretend we didn't see this. + if (Macro == 0) break; + + Token Tok; + Tok.startToken(); + Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0])); + Tok.setLength(Record[1]); + if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2])) + Tok.setIdentifierInfo(II); + Tok.setKind((tok::TokenKind)Record[3]); + Tok.setFlag((Token::TokenFlags)Record[4]); + Macro->AddTokenToBody(Tok); + break; + } + + case pch::PP_MACRO_INSTANTIATION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + MacroInstantiation *MI + = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[1]), + SourceLocation::getFromRawEncoding(Record[2])), + getMacroDefinition(Record[4])); + PPRec.SetPreallocatedEntity(Record[0], MI); + return; + } + + case pch::PP_MACRO_DEFINITION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + if (Record[1] >= MacroDefinitionsLoaded.size()) { + Error("out-of-bounds macro definition record"); + return; + } + + MacroDefinition *MD + = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]), + SourceLocation::getFromRawEncoding(Record[5]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[2]), + SourceLocation::getFromRawEncoding(Record[3]))); + PPRec.SetPreallocatedEntity(Record[0], MD); + MacroDefinitionsLoaded[Record[1]] = MD; + return; + } + } + } +} + +void PCHReader::ReadDefinedMacros() { + // If there was no preprocessor block, do nothing. + if (!MacroCursor.getBitStreamReader()) + return; + + llvm::BitstreamCursor Cursor = MacroCursor; + if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) { + Error("malformed preprocessor block record in PCH file"); + return; + } + + RecordData Record; + while (true) { + unsigned Code = Cursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Cursor.ReadBlockEnd()) + Error("error at end of preprocessor block in PCH file"); + return; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Cursor.ReadSubBlockID(); + if (Cursor.SkipBlock()) { + Error("malformed block record in PCH file"); + return; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Cursor.ReadAbbrevRecord(); + continue; + } + + // Read a record. + const char *BlobStart; + unsigned BlobLen; + Record.clear(); + switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case pch::PP_MACRO_OBJECT_LIKE: + case pch::PP_MACRO_FUNCTION_LIKE: + DecodeIdentifierInfo(Record[0]); + break; + + case pch::PP_TOKEN: + // Ignore tokens. + break; + + case pch::PP_MACRO_INSTANTIATION: + case pch::PP_MACRO_DEFINITION: + // Read the macro record. + ReadMacroRecord(Cursor.GetCurrentBitNo()); + break; + } + } +} + +MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) { + if (ID == 0 || ID >= MacroDefinitionsLoaded.size()) + return 0; + + if (!MacroDefinitionsLoaded[ID]) + ReadMacroRecord(MacroDefinitionOffsets[ID]); + + return MacroDefinitionsLoaded[ID]; +} + +/// \brief If we are loading a relocatable PCH file, and the filename is +/// not an absolute path, add the system root to the beginning of the file +/// name. +void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) { + // If this is not a relocatable PCH file, there's nothing to do. + if (!RelocatablePCH) + return; + + if (Filename.empty() || llvm::sys::Path(Filename).isAbsolute()) + return; + + if (isysroot == 0) { + // If no system root was given, default to '/' + Filename.insert(Filename.begin(), '/'); + return; + } + + unsigned Length = strlen(isysroot); + if (isysroot[Length - 1] != '/') + Filename.insert(Filename.begin(), '/'); + + Filename.insert(Filename.begin(), isysroot, isysroot + Length); +} + +PCHReader::PCHReadResult +PCHReader::ReadPCHBlock() { + if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { + Error("malformed block record in PCH file"); + return Failure; + } + + // Read all of the records and blocks for the PCH file. + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Error("error at end of module block in PCH file"); + return Failure; + } + + return Success; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + case pch::DECLTYPES_BLOCK_ID: + // We lazily load the decls block, but we want to set up the + // DeclsCursor cursor to point into it. Clone our current bitcode + // cursor to it, enter the block and read the abbrevs in that block. + // With the main cursor, we just skip over it. + DeclsCursor = Stream; + if (Stream.SkipBlock() || // Skip with the main cursor. + // Read the abbrevs. + ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { + Error("malformed block record in PCH file"); + return Failure; + } + break; + + case pch::PREPROCESSOR_BLOCK_ID: + MacroCursor = Stream; + if (PP) + PP->setExternalSource(this); + + if (Stream.SkipBlock()) { + Error("malformed block record in PCH file"); + return Failure; + } + break; + + case pch::SOURCE_MANAGER_BLOCK_ID: + switch (ReadSourceManagerBlock()) { + case Success: + break; + + case Failure: + Error("malformed source manager block in PCH file"); + return Failure; + + case IgnorePCH: + return IgnorePCH; + } + break; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read and process a record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + default: // Default behavior: ignore. + break; + + case pch::TYPE_OFFSET: + if (!TypesLoaded.empty()) { + Error("duplicate TYPE_OFFSET record in PCH file"); + return Failure; + } + TypeOffsets = (const uint32_t *)BlobStart; + TypesLoaded.resize(Record[0]); + break; + + case pch::DECL_OFFSET: + if (!DeclsLoaded.empty()) { + Error("duplicate DECL_OFFSET record in PCH file"); + return Failure; + } + DeclOffsets = (const uint32_t *)BlobStart; + DeclsLoaded.resize(Record[0]); + break; + + case pch::LANGUAGE_OPTIONS: + if (ParseLanguageOptions(Record)) + return IgnorePCH; + break; + + case pch::METADATA: { + if (Record[0] != pch::VERSION_MAJOR) { + Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old + : diag::warn_pch_version_too_new); + return IgnorePCH; + } + + RelocatablePCH = Record[4]; + if (Listener) { + std::string TargetTriple(BlobStart, BlobLen); + if (Listener->ReadTargetTriple(TargetTriple)) + return IgnorePCH; + } + break; + } + + case pch::IDENTIFIER_TABLE: + IdentifierTableData = BlobStart; + if (Record[0]) { + IdentifierLookupTable + = PCHIdentifierLookupTable::Create( + (const unsigned char *)IdentifierTableData + Record[0], + (const unsigned char *)IdentifierTableData, + PCHIdentifierLookupTrait(*this)); + if (PP) + PP->getIdentifierTable().setExternalIdentifierLookup(this); + } + break; + + case pch::IDENTIFIER_OFFSET: + if (!IdentifiersLoaded.empty()) { + Error("duplicate IDENTIFIER_OFFSET record in PCH file"); + return Failure; + } + IdentifierOffsets = (const uint32_t *)BlobStart; + IdentifiersLoaded.resize(Record[0]); + if (PP) + PP->getHeaderSearchInfo().SetExternalLookup(this); + break; + + case pch::EXTERNAL_DEFINITIONS: + if (!ExternalDefinitions.empty()) { + Error("duplicate EXTERNAL_DEFINITIONS record in PCH file"); + return Failure; + } + ExternalDefinitions.swap(Record); + break; + + case pch::SPECIAL_TYPES: + SpecialTypes.swap(Record); + break; + + case pch::STATISTICS: + TotalNumStatements = Record[0]; + TotalNumMacros = Record[1]; + TotalLexicalDeclContexts = Record[2]; + TotalVisibleDeclContexts = Record[3]; + break; + + case pch::TENTATIVE_DEFINITIONS: + if (!TentativeDefinitions.empty()) { + Error("duplicate TENTATIVE_DEFINITIONS record in PCH file"); + return Failure; + } + TentativeDefinitions.swap(Record); + break; + + case pch::UNUSED_STATIC_FUNCS: + if (!UnusedStaticFuncs.empty()) { + Error("duplicate UNUSED_STATIC_FUNCS record in PCH file"); + return Failure; + } + UnusedStaticFuncs.swap(Record); + break; + + case pch::LOCALLY_SCOPED_EXTERNAL_DECLS: + if (!LocallyScopedExternalDecls.empty()) { + Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file"); + return Failure; + } + LocallyScopedExternalDecls.swap(Record); + break; + + case pch::SELECTOR_OFFSETS: + SelectorOffsets = (const uint32_t *)BlobStart; + TotalNumSelectors = Record[0]; + SelectorsLoaded.resize(TotalNumSelectors); + break; + + case pch::METHOD_POOL: + MethodPoolLookupTableData = (const unsigned char *)BlobStart; + if (Record[0]) + MethodPoolLookupTable + = PCHMethodPoolLookupTable::Create( + MethodPoolLookupTableData + Record[0], + MethodPoolLookupTableData, + PCHMethodPoolLookupTrait(*this)); + TotalSelectorsInMethodPool = Record[1]; + break; + + case pch::PP_COUNTER_VALUE: + if (!Record.empty() && Listener) + Listener->ReadCounter(Record[0]); + break; + + case pch::SOURCE_LOCATION_OFFSETS: + SLocOffsets = (const uint32_t *)BlobStart; + TotalNumSLocEntries = Record[0]; + SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]); + break; + + case pch::SOURCE_LOCATION_PRELOADS: + for (unsigned I = 0, N = Record.size(); I != N; ++I) { + PCHReadResult Result = ReadSLocEntryRecord(Record[I]); + if (Result != Success) + return Result; + } + break; + + case pch::STAT_CACHE: { + PCHStatCache *MyStatCache = + new PCHStatCache((const unsigned char *)BlobStart + Record[0], + (const unsigned char *)BlobStart, + NumStatHits, NumStatMisses); + FileMgr.addStatCache(MyStatCache); + StatCache = MyStatCache; + break; + } + + case pch::EXT_VECTOR_DECLS: + if (!ExtVectorDecls.empty()) { + Error("duplicate EXT_VECTOR_DECLS record in PCH file"); + return Failure; + } + ExtVectorDecls.swap(Record); + break; + + case pch::ORIGINAL_FILE_NAME: + ActualOriginalFileName.assign(BlobStart, BlobLen); + OriginalFileName = ActualOriginalFileName; + MaybeAddSystemRootToFilename(OriginalFileName); + break; + + case pch::VERSION_CONTROL_BRANCH_REVISION: { + const std::string &CurBranch = getClangFullRepositoryVersion(); + llvm::StringRef PCHBranch(BlobStart, BlobLen); + if (llvm::StringRef(CurBranch) != PCHBranch) { + Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; + return IgnorePCH; + } + break; + } + + case pch::MACRO_DEFINITION_OFFSETS: + MacroDefinitionOffsets = (const uint32_t *)BlobStart; + if (PP) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]); + } else { + NumPreallocatedPreprocessingEntities = Record[0]; + } + + MacroDefinitionsLoaded.resize(Record[1]); + break; + } + } + Error("premature end of bitstream in PCH file"); + return Failure; +} + +PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { + // Set the PCH file name. + this->FileName = FileName; + + // Open the PCH file. + // + // FIXME: This shouldn't be here, we should just take a raw_ostream. + std::string ErrStr; + Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); + if (!Buffer) { + Error(ErrStr.c_str()); + return IgnorePCH; + } + + // Initialize the stream + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + Diag(diag::err_not_a_pch_file) << FileName; + return Failure; + } + + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code != llvm::bitc::ENTER_SUBBLOCK) { + Error("invalid record at top-level of PCH file"); + return Failure; + } + + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the PCH subblock ID. + switch (BlockID) { + case llvm::bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) { + Error("malformed BlockInfoBlock in PCH file"); + return Failure; + } + break; + case pch::PCH_BLOCK_ID: + switch (ReadPCHBlock()) { + case Success: + break; + + case Failure: + return Failure; + + case IgnorePCH: + // FIXME: We could consider reading through to the end of this + // PCH block, skipping subblocks, to see if there are other + // PCH blocks elsewhere. + + // Clear out any preallocated source location entries, so that + // the source manager does not try to resolve them later. + SourceMgr.ClearPreallocatedSLocEntries(); + + // Remove the stat cache. + if (StatCache) + FileMgr.removeStatCache((PCHStatCache*)StatCache); + + return IgnorePCH; + } + break; + default: + if (Stream.SkipBlock()) { + Error("malformed block record in PCH file"); + return Failure; + } + break; + } + } + + // Check the predefines buffer. + if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen), + PCHPredefinesBufferID)) + return IgnorePCH; + + if (PP) { + // Initialization of keywords and pragmas occurs before the + // PCH file is read, so there may be some identifiers that were + // loaded into the IdentifierTable before we intercepted the + // creation of identifiers. Iterate through the list of known + // identifiers and determine whether we have to establish + // preprocessor definitions or top-level identifier declaration + // chains for those identifiers. + // + // We copy the IdentifierInfo pointers to a small vector first, + // since de-serializing declarations or macro definitions can add + // new entries into the identifier table, invalidating the + // iterators. + llvm::SmallVector<IdentifierInfo *, 128> Identifiers; + for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(), + IdEnd = PP->getIdentifierTable().end(); + Id != IdEnd; ++Id) + Identifiers.push_back(Id->second); + PCHIdentifierLookupTable *IdTable + = (PCHIdentifierLookupTable *)IdentifierLookupTable; + for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { + IdentifierInfo *II = Identifiers[I]; + // Look in the on-disk hash table for an entry for + PCHIdentifierLookupTrait Info(*this, II); + std::pair<const char*, unsigned> Key(II->getNameStart(), II->getLength()); + PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); + if (Pos == IdTable->end()) + continue; + + // Dereferencing the iterator has the effect of populating the + // IdentifierInfo node with the various declarations it needs. + (void)*Pos; + } + } + + if (Context) + InitializeContext(*Context); + + return Success; +} + +void PCHReader::setPreprocessor(Preprocessor &pp) { + PP = &pp; + + if (NumPreallocatedPreprocessingEntities) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, + NumPreallocatedPreprocessingEntities); + NumPreallocatedPreprocessingEntities = 0; + } +} + +void PCHReader::InitializeContext(ASTContext &Ctx) { + Context = &Ctx; + assert(Context && "Passed null context!"); + + assert(PP && "Forgot to set Preprocessor ?"); + PP->getIdentifierTable().setExternalIdentifierLookup(this); + PP->getHeaderSearchInfo().SetExternalLookup(this); + PP->setExternalSource(this); + + // Load the translation unit declaration + ReadDeclRecord(DeclOffsets[0], 0); + + // Load the special types. + Context->setBuiltinVaListType( + GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST])); + if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID]) + Context->setObjCIdType(GetType(Id)); + if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR]) + Context->setObjCSelType(GetType(Sel)); + if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL]) + Context->setObjCProtoType(GetType(Proto)); + if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) + Context->setObjCClassType(GetType(Class)); + + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) + Context->setCFConstantStringType(GetType(String)); + if (unsigned FastEnum + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) + Context->setObjCFastEnumerationStateType(GetType(FastEnum)); + if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) { + QualType FileType = GetType(File); + if (FileType.isNull()) { + Error("FILE type is NULL"); + return; + } + if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) + Context->setFILEDecl(Typedef->getDecl()); + else { + const TagType *Tag = FileType->getAs<TagType>(); + if (!Tag) { + Error("Invalid FILE type in PCH file"); + return; + } + Context->setFILEDecl(Tag->getDecl()); + } + } + if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) { + QualType Jmp_bufType = GetType(Jmp_buf); + if (Jmp_bufType.isNull()) { + Error("jmp_bug type is NULL"); + return; + } + if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) + Context->setjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Jmp_bufType->getAs<TagType>(); + if (!Tag) { + Error("Invalid jmp_bug type in PCH file"); + return; + } + Context->setjmp_bufDecl(Tag->getDecl()); + } + } + if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) { + QualType Sigjmp_bufType = GetType(Sigjmp_buf); + if (Sigjmp_bufType.isNull()) { + Error("sigjmp_buf type is NULL"); + return; + } + if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) + Context->setsigjmp_bufDecl(Typedef->getDecl()); + else { + const TagType *Tag = Sigjmp_bufType->getAs<TagType>(); + assert(Tag && "Invalid sigjmp_buf type in PCH file"); + Context->setsigjmp_bufDecl(Tag->getDecl()); + } + } + if (unsigned ObjCIdRedef + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID_REDEFINITION]) + Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef); + if (unsigned ObjCClassRedef + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) + Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) + Context->setBlockDescriptorType(GetType(String)); + if (unsigned String + = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) + Context->setBlockDescriptorExtendedType(GetType(String)); + if (unsigned ObjCSelRedef + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) + Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING]) + Context->setNSConstantStringType(GetType(String)); +} + +/// \brief Retrieve the name of the original source file name +/// directly from the PCH file, without actually loading the PCH +/// file. +std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName, + Diagnostic &Diags) { + // Open the PCH file. + std::string ErrStr; + llvm::OwningPtr<llvm::MemoryBuffer> Buffer; + Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr)); + if (!Buffer) { + Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; + return std::string(); + } + + // Initialize the stream + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName; + return std::string(); + } + + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the PCH subblock ID. + switch (BlockID) { + case pch::PCH_BLOCK_ID: + if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; + return std::string(); + } + break; + + default: + if (Stream.SkipBlock()) { + Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; + return std::string(); + } + break; + } + continue; + } + + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName; + return std::string(); + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) + == pch::ORIGINAL_FILE_NAME) + return std::string(BlobStart, BlobLen); + } + + return std::string(); +} + +/// \brief Parse the record that corresponds to a LangOptions data +/// structure. +/// +/// This routine compares the language options used to generate the +/// PCH file against the language options set for the current +/// compilation. For each option, we classify differences between the +/// two compiler states as either "benign" or "important". Benign +/// differences don't matter, and we accept them without complaint +/// (and without modifying the language options). Differences between +/// the states for important options cause the PCH file to be +/// unusable, so we emit a warning and return true to indicate that +/// there was an error. +/// +/// \returns true if the PCH file is unacceptable, false otherwise. +bool PCHReader::ParseLanguageOptions( + const llvm::SmallVectorImpl<uint64_t> &Record) { + if (Listener) { + LangOptions LangOpts; + + #define PARSE_LANGOPT(Option) \ + LangOpts.Option = Record[Idx]; \ + ++Idx + + unsigned Idx = 0; + PARSE_LANGOPT(Trigraphs); + PARSE_LANGOPT(BCPLComment); + PARSE_LANGOPT(DollarIdents); + PARSE_LANGOPT(AsmPreprocessor); + PARSE_LANGOPT(GNUMode); + PARSE_LANGOPT(GNUKeywords); + PARSE_LANGOPT(ImplicitInt); + PARSE_LANGOPT(Digraphs); + PARSE_LANGOPT(HexFloats); + PARSE_LANGOPT(C99); + PARSE_LANGOPT(Microsoft); + PARSE_LANGOPT(CPlusPlus); + PARSE_LANGOPT(CPlusPlus0x); + PARSE_LANGOPT(CXXOperatorNames); + PARSE_LANGOPT(ObjC1); + PARSE_LANGOPT(ObjC2); + PARSE_LANGOPT(ObjCNonFragileABI); + PARSE_LANGOPT(ObjCNonFragileABI2); + PARSE_LANGOPT(NoConstantCFStrings); + PARSE_LANGOPT(PascalStrings); + PARSE_LANGOPT(WritableStrings); + PARSE_LANGOPT(LaxVectorConversions); + PARSE_LANGOPT(AltiVec); + PARSE_LANGOPT(Exceptions); + PARSE_LANGOPT(SjLjExceptions); + PARSE_LANGOPT(NeXTRuntime); + PARSE_LANGOPT(Freestanding); + PARSE_LANGOPT(NoBuiltin); + PARSE_LANGOPT(ThreadsafeStatics); + PARSE_LANGOPT(POSIXThreads); + PARSE_LANGOPT(Blocks); + PARSE_LANGOPT(EmitAllDecls); + PARSE_LANGOPT(MathErrno); + PARSE_LANGOPT(OverflowChecking); + PARSE_LANGOPT(HeinousExtensions); + PARSE_LANGOPT(Optimize); + PARSE_LANGOPT(OptimizeSize); + PARSE_LANGOPT(Static); + PARSE_LANGOPT(PICLevel); + PARSE_LANGOPT(GNUInline); + PARSE_LANGOPT(NoInline); + PARSE_LANGOPT(AccessControl); + PARSE_LANGOPT(CharIsSigned); + PARSE_LANGOPT(ShortWChar); + LangOpts.setGCMode((LangOptions::GCMode)Record[Idx]); + ++Idx; + LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx]); + ++Idx; + LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode) + Record[Idx]); + ++Idx; + PARSE_LANGOPT(InstantiationDepth); + PARSE_LANGOPT(OpenCL); + PARSE_LANGOPT(CatchUndefined); + // FIXME: Missing ElideConstructors?! + #undef PARSE_LANGOPT + + return Listener->ReadLanguageOptions(LangOpts); + } + + return false; +} + +void PCHReader::ReadPreprocessedEntities() { + ReadDefinedMacros(); +} + +/// \brief Read and return the type at the given offset. +/// +/// This routine actually reads the record corresponding to the type +/// at the given offset in the bitstream. It is a helper routine for +/// GetType, which deals with reading type IDs. +QualType PCHReader::ReadTypeRecord(uint64_t Offset) { + // Keep track of where we are in the stream, then jump back there + // after reading this type. + SavedStreamPosition SavedPosition(DeclsCursor); + + // Note that we are loading a type record. + LoadingTypeOrDecl Loading(*this); + + DeclsCursor.JumpToBit(Offset); + RecordData Record; + unsigned Code = DeclsCursor.ReadCode(); + switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { + case pch::TYPE_EXT_QUAL: { + if (Record.size() != 2) { + Error("Incorrect encoding of extended qualifier type"); + return QualType(); + } + QualType Base = GetType(Record[0]); + Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); + return Context->getQualifiedType(Base, Quals); + } + + case pch::TYPE_COMPLEX: { + if (Record.size() != 1) { + Error("Incorrect encoding of complex type"); + return QualType(); + } + QualType ElemType = GetType(Record[0]); + return Context->getComplexType(ElemType); + } + + case pch::TYPE_POINTER: { + if (Record.size() != 1) { + Error("Incorrect encoding of pointer type"); + return QualType(); + } + QualType PointeeType = GetType(Record[0]); + return Context->getPointerType(PointeeType); + } + + case pch::TYPE_BLOCK_POINTER: { + if (Record.size() != 1) { + Error("Incorrect encoding of block pointer type"); + return QualType(); + } + QualType PointeeType = GetType(Record[0]); + return Context->getBlockPointerType(PointeeType); + } + + case pch::TYPE_LVALUE_REFERENCE: { + if (Record.size() != 1) { + Error("Incorrect encoding of lvalue reference type"); + return QualType(); + } + QualType PointeeType = GetType(Record[0]); + return Context->getLValueReferenceType(PointeeType); + } + + case pch::TYPE_RVALUE_REFERENCE: { + if (Record.size() != 1) { + Error("Incorrect encoding of rvalue reference type"); + return QualType(); + } + QualType PointeeType = GetType(Record[0]); + return Context->getRValueReferenceType(PointeeType); + } + + case pch::TYPE_MEMBER_POINTER: { + if (Record.size() != 1) { + Error("Incorrect encoding of member pointer type"); + return QualType(); + } + QualType PointeeType = GetType(Record[0]); + QualType ClassType = GetType(Record[1]); + return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr()); + } + + case pch::TYPE_CONSTANT_ARRAY: { + QualType ElementType = GetType(Record[0]); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + unsigned Idx = 3; + llvm::APInt Size = ReadAPInt(Record, Idx); + return Context->getConstantArrayType(ElementType, Size, + ASM, IndexTypeQuals); + } + + case pch::TYPE_INCOMPLETE_ARRAY: { + QualType ElementType = GetType(Record[0]); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); + } + + case pch::TYPE_VARIABLE_ARRAY: { + QualType ElementType = GetType(Record[0]); + ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; + unsigned IndexTypeQuals = Record[2]; + SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]); + SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]); + return Context->getVariableArrayType(ElementType, ReadTypeExpr(), + ASM, IndexTypeQuals, + SourceRange(LBLoc, RBLoc)); + } + + case pch::TYPE_VECTOR: { + if (Record.size() != 4) { + Error("incorrect encoding of vector type in PCH file"); + return QualType(); + } + + QualType ElementType = GetType(Record[0]); + unsigned NumElements = Record[1]; + bool AltiVec = Record[2]; + bool Pixel = Record[3]; + return Context->getVectorType(ElementType, NumElements, AltiVec, Pixel); + } + + case pch::TYPE_EXT_VECTOR: { + if (Record.size() != 4) { + Error("incorrect encoding of extended vector type in PCH file"); + return QualType(); + } + + QualType ElementType = GetType(Record[0]); + unsigned NumElements = Record[1]; + return Context->getExtVectorType(ElementType, NumElements); + } + + case pch::TYPE_FUNCTION_NO_PROTO: { + if (Record.size() != 4) { + Error("incorrect encoding of no-proto function type"); + return QualType(); + } + QualType ResultType = GetType(Record[0]); + FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]); + return Context->getFunctionNoProtoType(ResultType, Info); + } + + case pch::TYPE_FUNCTION_PROTO: { + QualType ResultType = GetType(Record[0]); + bool NoReturn = Record[1]; + unsigned RegParm = Record[2]; + CallingConv CallConv = (CallingConv)Record[3]; + unsigned Idx = 4; + unsigned NumParams = Record[Idx++]; + llvm::SmallVector<QualType, 16> ParamTypes; + for (unsigned I = 0; I != NumParams; ++I) + ParamTypes.push_back(GetType(Record[Idx++])); + bool isVariadic = Record[Idx++]; + unsigned Quals = Record[Idx++]; + bool hasExceptionSpec = Record[Idx++]; + bool hasAnyExceptionSpec = Record[Idx++]; + unsigned NumExceptions = Record[Idx++]; + llvm::SmallVector<QualType, 2> Exceptions; + for (unsigned I = 0; I != NumExceptions; ++I) + Exceptions.push_back(GetType(Record[Idx++])); + return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, + isVariadic, Quals, hasExceptionSpec, + hasAnyExceptionSpec, NumExceptions, + Exceptions.data(), + FunctionType::ExtInfo(NoReturn, RegParm, + CallConv)); + } + + case pch::TYPE_UNRESOLVED_USING: + return Context->getTypeDeclType( + cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0]))); + + case pch::TYPE_TYPEDEF: + if (Record.size() != 1) { + Error("incorrect encoding of typedef type"); + return QualType(); + } + return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0]))); + + case pch::TYPE_TYPEOF_EXPR: + return Context->getTypeOfExprType(ReadTypeExpr()); + + case pch::TYPE_TYPEOF: { + if (Record.size() != 1) { + Error("incorrect encoding of typeof(type) in PCH file"); + return QualType(); + } + QualType UnderlyingType = GetType(Record[0]); + return Context->getTypeOfType(UnderlyingType); + } + + case pch::TYPE_DECLTYPE: + return Context->getDecltypeType(ReadTypeExpr()); + + case pch::TYPE_RECORD: + if (Record.size() != 1) { + Error("incorrect encoding of record type"); + return QualType(); + } + return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0]))); + + case pch::TYPE_ENUM: + if (Record.size() != 1) { + Error("incorrect encoding of enum type"); + return QualType(); + } + return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0]))); + + case pch::TYPE_ELABORATED: { + if (Record.size() != 2) { + Error("incorrect encoding of elaborated type"); + return QualType(); + } + unsigned Tag = Record[1]; + // FIXME: Deserialize the qualifier (C++ only) + return Context->getElaboratedType((ElaboratedTypeKeyword) Tag, + /* NNS */ 0, + GetType(Record[0])); + } + + case pch::TYPE_OBJC_INTERFACE: { + unsigned Idx = 0; + ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + return Context->getObjCInterfaceType(ItfD); + } + + case pch::TYPE_OBJC_OBJECT: { + unsigned Idx = 0; + QualType Base = GetType(Record[Idx++]); + unsigned NumProtos = Record[Idx++]; + llvm::SmallVector<ObjCProtocolDecl*, 4> Protos; + for (unsigned I = 0; I != NumProtos; ++I) + Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); + return Context->getObjCObjectType(Base, Protos.data(), NumProtos); + } + + case pch::TYPE_OBJC_OBJECT_POINTER: { + unsigned Idx = 0; + QualType Pointee = GetType(Record[Idx++]); + return Context->getObjCObjectPointerType(Pointee); + } + + case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { + unsigned Idx = 0; + QualType Parm = GetType(Record[Idx++]); + QualType Replacement = GetType(Record[Idx++]); + return + Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + Replacement); + } + + case pch::TYPE_INJECTED_CLASS_NAME: { + CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0])); + QualType TST = GetType(Record[1]); // probably derivable + return Context->getInjectedClassNameType(D, TST); + } + } + // Suppress a GCC warning + return QualType(); +} + +namespace { + +class TypeLocReader : public TypeLocVisitor<TypeLocReader> { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + +public: + TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx) + : Reader(Reader), Record(Record), Idx(Idx) { } + + // We want compile-time assurance that we've enumerated all of + // these, so unfortunately we have to declare them first, then + // define them out-of-line. +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitFunctionTypeLoc(FunctionTypeLoc); + void VisitArrayTypeLoc(ArrayTypeLoc); +}; + +} + +void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (TL.needsExtraLocalData()) { + TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); + TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); + TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); + TL.setModeAttr(Record[Idx++]); + } +} +void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { + TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (Record[Idx++]) + TL.setSizeExpr(Reader.ReadDeclExpr()); + else + TL.setSizeExpr(0); +} +void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { + TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + } +} +void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx)); +} +void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, + Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(), + Record, Idx)); +} +void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); +} +void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + TL.setHasBaseTypeAsWritten(Record[Idx++]); + TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); +} +void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, + unsigned &Idx) { + QualType InfoTy = GetType(Record[Idx++]); + if (InfoTy.isNull()) + return 0; + + TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); + TypeLocReader TLR(*this, Record, Idx); + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLR.Visit(TL); + return TInfo; +} + +QualType PCHReader::GetType(pch::TypeID ID) { + unsigned FastQuals = ID & Qualifiers::FastMask; + unsigned Index = ID >> Qualifiers::FastWidth; + + if (Index < pch::NUM_PREDEF_TYPE_IDS) { + QualType T; + switch ((pch::PredefinedTypeIDs)Index) { + case pch::PREDEF_TYPE_NULL_ID: return QualType(); + case pch::PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break; + case pch::PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break; + + case pch::PREDEF_TYPE_CHAR_U_ID: + case pch::PREDEF_TYPE_CHAR_S_ID: + // FIXME: Check that the signedness of CharTy is correct! + T = Context->CharTy; + break; + + case pch::PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break; + case pch::PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break; + case pch::PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break; + case pch::PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break; + case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break; + case pch::PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break; + case pch::PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break; + case pch::PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break; + case pch::PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break; + case pch::PREDEF_TYPE_INT_ID: T = Context->IntTy; break; + case pch::PREDEF_TYPE_LONG_ID: T = Context->LongTy; break; + case pch::PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break; + case pch::PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break; + case pch::PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break; + case pch::PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break; + case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break; + case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break; + case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break; + case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break; + case pch::PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break; + case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break; + case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break; + case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break; + case pch::PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break; + } + + assert(!T.isNull() && "Unknown predefined type"); + return T.withFastQualifiers(FastQuals); + } + + Index -= pch::NUM_PREDEF_TYPE_IDS; + //assert(Index < TypesLoaded.size() && "Type index out-of-range"); + if (TypesLoaded[Index].isNull()) + TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]); + + return TypesLoaded[Index].withFastQualifiers(FastQuals); +} + +TemplateArgumentLocInfo +PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const RecordData &Record, + unsigned &Index) { + switch (Kind) { + case TemplateArgument::Expression: + return ReadDeclExpr(); + case TemplateArgument::Type: + return GetTypeSourceInfo(Record, Index); + case TemplateArgument::Template: { + SourceLocation + QualStart = SourceLocation::getFromRawEncoding(Record[Index++]), + QualEnd = SourceLocation::getFromRawEncoding(Record[Index++]), + TemplateNameLoc = SourceLocation::getFromRawEncoding(Record[Index++]); + return TemplateArgumentLocInfo(SourceRange(QualStart, QualEnd), + TemplateNameLoc); + } + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + return TemplateArgumentLocInfo(); + } + llvm_unreachable("unexpected template argument loc"); + return TemplateArgumentLocInfo(); +} + +Decl *PCHReader::GetDecl(pch::DeclID ID) { + if (ID == 0) + return 0; + + if (ID > DeclsLoaded.size()) { + Error("declaration ID out-of-range for PCH file"); + return 0; + } + + unsigned Index = ID - 1; + if (!DeclsLoaded[Index]) + ReadDeclRecord(DeclOffsets[Index], Index); + + return DeclsLoaded[Index]; +} + +/// \brief Resolve the offset of a statement into a statement. +/// +/// This operation will read a new statement from the external +/// source each time it is called, and is meant to be used via a +/// LazyOffsetPtr (which is used by Decls for the body of functions, etc). +Stmt *PCHReader::GetDeclStmt(uint64_t Offset) { + // Since we know tha this statement is part of a decl, make sure to use the + // decl cursor to read it. + DeclsCursor.JumpToBit(Offset); + return ReadStmt(DeclsCursor); +} + +bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, + llvm::SmallVectorImpl<pch::DeclID> &Decls) { + assert(DC->hasExternalLexicalStorage() && + "DeclContext has no lexical decls in storage"); + + uint64_t Offset = DeclContextOffsets[DC].first; + if (Offset == 0) { + Error("DeclContext has no lexical decls in storage"); + return true; + } + + // Keep track of where we are in the stream, then jump back there + // after reading this context. + SavedStreamPosition SavedPosition(DeclsCursor); + + // Load the record containing all of the declarations lexically in + // this context. + DeclsCursor.JumpToBit(Offset); + RecordData Record; + unsigned Code = DeclsCursor.ReadCode(); + unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); + if (RecCode != pch::DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; + } + + // Load all of the declaration IDs + Decls.clear(); + Decls.insert(Decls.end(), Record.begin(), Record.end()); + ++NumLexicalDeclContextsRead; + return false; +} + +bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, + llvm::SmallVectorImpl<VisibleDeclaration> &Decls) { + assert(DC->hasExternalVisibleStorage() && + "DeclContext has no visible decls in storage"); + uint64_t Offset = DeclContextOffsets[DC].second; + if (Offset == 0) { + Error("DeclContext has no visible decls in storage"); + return true; + } + + // Keep track of where we are in the stream, then jump back there + // after reading this context. + SavedStreamPosition SavedPosition(DeclsCursor); + + // Load the record containing all of the declarations visible in + // this context. + DeclsCursor.JumpToBit(Offset); + RecordData Record; + unsigned Code = DeclsCursor.ReadCode(); + unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); + if (RecCode != pch::DECL_CONTEXT_VISIBLE) { + Error("Expected visible block"); + return true; + } + + if (Record.size() == 0) + return false; + + Decls.clear(); + + unsigned Idx = 0; + while (Idx < Record.size()) { + Decls.push_back(VisibleDeclaration()); + Decls.back().Name = ReadDeclarationName(Record, Idx); + + unsigned Size = Record[Idx++]; + llvm::SmallVector<unsigned, 4> &LoadedDecls = Decls.back().Declarations; + LoadedDecls.reserve(Size); + for (unsigned I = 0; I < Size; ++I) + LoadedDecls.push_back(Record[Idx++]); + } + + ++NumVisibleDeclContextsRead; + return false; +} + +void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) { + this->Consumer = Consumer; + + if (!Consumer) + return; + + for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) { + // Force deserialization of this decl, which will cause it to be passed to + // the consumer (or queued). + GetDecl(ExternalDefinitions[I]); + } + + for (unsigned I = 0, N = InterestingDecls.size(); I != N; ++I) { + DeclGroupRef DG(InterestingDecls[I]); + Consumer->HandleTopLevelDecl(DG); + } +} + +void PCHReader::PrintStats() { + std::fprintf(stderr, "*** PCH Statistics:\n"); + + unsigned NumTypesLoaded + = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), + QualType()); + unsigned NumDeclsLoaded + = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), + (Decl *)0); + unsigned NumIdentifiersLoaded + = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), + IdentifiersLoaded.end(), + (IdentifierInfo *)0); + unsigned NumSelectorsLoaded + = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), + SelectorsLoaded.end(), + Selector()); + + std::fprintf(stderr, " %u stat cache hits\n", NumStatHits); + std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses); + if (TotalNumSLocEntries) + std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", + NumSLocEntriesRead, TotalNumSLocEntries, + ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); + if (!TypesLoaded.empty()) + std::fprintf(stderr, " %u/%u types read (%f%%)\n", + NumTypesLoaded, (unsigned)TypesLoaded.size(), + ((float)NumTypesLoaded/TypesLoaded.size() * 100)); + if (!DeclsLoaded.empty()) + std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", + NumDeclsLoaded, (unsigned)DeclsLoaded.size(), + ((float)NumDeclsLoaded/DeclsLoaded.size() * 100)); + if (!IdentifiersLoaded.empty()) + std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", + NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), + ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); + if (TotalNumSelectors) + std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", + NumSelectorsLoaded, TotalNumSelectors, + ((float)NumSelectorsLoaded/TotalNumSelectors * 100)); + if (TotalNumStatements) + std::fprintf(stderr, " %u/%u statements read (%f%%)\n", + NumStatementsRead, TotalNumStatements, + ((float)NumStatementsRead/TotalNumStatements * 100)); + if (TotalNumMacros) + std::fprintf(stderr, " %u/%u macros read (%f%%)\n", + NumMacrosRead, TotalNumMacros, + ((float)NumMacrosRead/TotalNumMacros * 100)); + if (TotalLexicalDeclContexts) + std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", + NumLexicalDeclContextsRead, TotalLexicalDeclContexts, + ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts + * 100)); + if (TotalVisibleDeclContexts) + std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", + NumVisibleDeclContextsRead, TotalVisibleDeclContexts, + ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts + * 100)); + if (TotalSelectorsInMethodPool) { + std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", + NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool, + ((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool + * 100)); + std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); + } + std::fprintf(stderr, "\n"); +} + +void PCHReader::InitializeSema(Sema &S) { + SemaObj = &S; + S.ExternalSource = this; + + // Makes sure any declarations that were deserialized "too early" + // still get added to the identifier's declaration chains. + for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { + SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I])); + SemaObj->IdResolver.AddDecl(PreloadedDecls[I]); + } + PreloadedDecls.clear(); + + // If there were any tentative definitions, deserialize them and add + // them to Sema's list of tentative definitions. + for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { + VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I])); + SemaObj->TentativeDefinitions.push_back(Var); + } + + // If there were any unused static functions, deserialize them and add to + // Sema's list of unused static functions. + for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) { + FunctionDecl *FD = cast<FunctionDecl>(GetDecl(UnusedStaticFuncs[I])); + SemaObj->UnusedStaticFuncs.push_back(FD); + } + + // If there were any locally-scoped external declarations, + // deserialize them and add them to Sema's table of locally-scoped + // external declarations. + for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { + NamedDecl *D = cast<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I])); + SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D; + } + + // If there were any ext_vector type declarations, deserialize them + // and add them to Sema's vector of such declarations. + for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) + SemaObj->ExtVectorDecls.push_back( + cast<TypedefDecl>(GetDecl(ExtVectorDecls[I]))); +} + +IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) { + // Try to find this name within our on-disk hash table + PCHIdentifierLookupTable *IdTable + = (PCHIdentifierLookupTable *)IdentifierLookupTable; + std::pair<const char*, unsigned> Key(NameStart, NameEnd - NameStart); + PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key); + if (Pos == IdTable->end()) + return 0; + + // Dereferencing the iterator has the effect of building the + // IdentifierInfo node and populating it with the various + // declarations it needs. + return *Pos; +} + +std::pair<ObjCMethodList, ObjCMethodList> +PCHReader::ReadMethodPool(Selector Sel) { + if (!MethodPoolLookupTable) + return std::pair<ObjCMethodList, ObjCMethodList>(); + + // Try to find this selector within our on-disk hash table. + PCHMethodPoolLookupTable *PoolTable + = (PCHMethodPoolLookupTable*)MethodPoolLookupTable; + PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel); + if (Pos == PoolTable->end()) { + ++NumMethodPoolMisses; + return std::pair<ObjCMethodList, ObjCMethodList>();; + } + + ++NumMethodPoolSelectorsRead; + return *Pos; +} + +void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) { + assert(ID && "Non-zero identifier ID required"); + assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); + IdentifiersLoaded[ID - 1] = II; +} + +/// \brief Set the globally-visible declarations associated with the given +/// identifier. +/// +/// If the PCH reader is currently in a state where the given declaration IDs +/// cannot safely be resolved, they are queued until it is safe to resolve +/// them. +/// +/// \param II an IdentifierInfo that refers to one or more globally-visible +/// declarations. +/// +/// \param DeclIDs the set of declaration IDs with the name @p II that are +/// visible at global scope. +/// +/// \param Nonrecursive should be true to indicate that the caller knows that +/// this call is non-recursive, and therefore the globally-visible declarations +/// will not be placed onto the pending queue. +void +PCHReader::SetGloballyVisibleDecls(IdentifierInfo *II, + const llvm::SmallVectorImpl<uint32_t> &DeclIDs, + bool Nonrecursive) { + if (CurrentlyLoadingTypeOrDecl && !Nonrecursive) { + PendingIdentifierInfos.push_back(PendingIdentifierInfo()); + PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); + PII.II = II; + for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) + PII.DeclIDs.push_back(DeclIDs[I]); + return; + } + + for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { + NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I])); + if (SemaObj) { + // Introduce this declaration into the translation-unit scope + // and add it to the declaration chain for this identifier, so + // that (unqualified) name lookup will find it. + SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D)); + SemaObj->IdResolver.AddDeclToIdentifierChain(II, D); + } else { + // Queue this declaration so that it will be added to the + // translation unit scope and identifier's declaration chain + // once a Sema object is known. + PreloadedDecls.push_back(D); + } + } +} + +IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { + if (ID == 0) + return 0; + + if (!IdentifierTableData || IdentifiersLoaded.empty()) { + Error("no identifier table in PCH file"); + return 0; + } + + assert(PP && "Forgot to set Preprocessor ?"); + if (!IdentifiersLoaded[ID - 1]) { + uint32_t Offset = IdentifierOffsets[ID - 1]; + const char *Str = IdentifierTableData + Offset; + + // All of the strings in the PCH file are preceded by a 16-bit + // length. Extract that 16-bit length to avoid having to execute + // strlen(). + // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as + // unsigned integers. This is important to avoid integer overflow when + // we cast them to 'unsigned'. + const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; + unsigned StrLen = (((unsigned) StrLenPtr[0]) + | (((unsigned) StrLenPtr[1]) << 8)) - 1; + IdentifiersLoaded[ID - 1] + = &PP->getIdentifierTable().get(Str, StrLen); + } + + return IdentifiersLoaded[ID - 1]; +} + +void PCHReader::ReadSLocEntry(unsigned ID) { + ReadSLocEntryRecord(ID); +} + +Selector PCHReader::DecodeSelector(unsigned ID) { + if (ID == 0) + return Selector(); + + if (!MethodPoolLookupTableData) + return Selector(); + + if (ID > TotalNumSelectors) { + Error("selector ID out of range in PCH file"); + return Selector(); + } + + unsigned Index = ID - 1; + if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) { + // Load this selector from the selector table. + // FIXME: endianness portability issues with SelectorOffsets table + PCHMethodPoolLookupTrait Trait(*this); + SelectorsLoaded[Index] + = Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0); + } + + return SelectorsLoaded[Index]; +} + +Selector PCHReader::GetSelector(uint32_t ID) { + return DecodeSelector(ID); +} + +uint32_t PCHReader::GetNumKnownSelectors() { + return TotalNumSelectors + 1; +} + +DeclarationName +PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { + DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; + switch (Kind) { + case DeclarationName::Identifier: + return DeclarationName(GetIdentifierInfo(Record, Idx)); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return DeclarationName(GetSelector(Record, Idx)); + + case DeclarationName::CXXConstructorName: + return Context->DeclarationNames.getCXXConstructorName( + Context->getCanonicalType(GetType(Record[Idx++]))); + + case DeclarationName::CXXDestructorName: + return Context->DeclarationNames.getCXXDestructorName( + Context->getCanonicalType(GetType(Record[Idx++]))); + + case DeclarationName::CXXConversionFunctionName: + return Context->DeclarationNames.getCXXConversionFunctionName( + Context->getCanonicalType(GetType(Record[Idx++]))); + + case DeclarationName::CXXOperatorName: + return Context->DeclarationNames.getCXXOperatorName( + (OverloadedOperatorKind)Record[Idx++]); + + case DeclarationName::CXXLiteralOperatorName: + return Context->DeclarationNames.getCXXLiteralOperatorName( + GetIdentifierInfo(Record, Idx)); + + case DeclarationName::CXXUsingDirective: + return DeclarationName::getUsingDirectiveName(); + } + + // Required to silence GCC warning + return DeclarationName(); +} + +NestedNameSpecifier * +PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { + unsigned N = Record[Idx++]; + NestedNameSpecifier *NNS = 0, *Prev = 0; + for (unsigned I = 0; I != N; ++I) { + NestedNameSpecifier::SpecifierKind Kind + = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; + switch (Kind) { + case NestedNameSpecifier::Identifier: { + IdentifierInfo *II = GetIdentifierInfo(Record, Idx); + NNS = NestedNameSpecifier::Create(*Context, Prev, II); + break; + } + + case NestedNameSpecifier::Namespace: { + NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++])); + NNS = NestedNameSpecifier::Create(*Context, Prev, NS); + break; + } + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + Type *T = GetType(Record[Idx++]).getTypePtr(); + bool Template = Record[Idx++]; + NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T); + break; + } + + case NestedNameSpecifier::Global: { + NNS = NestedNameSpecifier::GlobalSpecifier(*Context); + // No associated value, and there can't be a prefix. + break; + } + Prev = NNS; + } + } + return NNS; +} + +SourceRange +PCHReader::ReadSourceRange(const RecordData &Record, unsigned &Idx) { + return SourceRange(SourceLocation::getFromRawEncoding(Record[Idx++]), + SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +/// \brief Read an integral value +llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { + unsigned BitWidth = Record[Idx++]; + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); + Idx += NumWords; + return Result; +} + +/// \brief Read a signed integral value +llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { + bool isUnsigned = Record[Idx++]; + return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); +} + +/// \brief Read a floating-point value +llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { + return llvm::APFloat(ReadAPInt(Record, Idx)); +} + +// \brief Read a string +std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) { + unsigned Len = Record[Idx++]; + std::string Result(Record.data() + Idx, Record.data() + Idx + Len); + Idx += Len; + return Result; +} + +CXXTemporary *PCHReader::ReadCXXTemporary(const RecordData &Record, + unsigned &Idx) { + CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++])); + return CXXTemporary::Create(*Context, Decl); +} + +DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { + return Diag(SourceLocation(), DiagID); +} + +DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) { + return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); +} + +/// \brief Retrieve the identifier table associated with the +/// preprocessor. +IdentifierTable &PCHReader::getIdentifierTable() { + assert(PP && "Forgot to set Preprocessor ?"); + return PP->getIdentifierTable(); +} + +/// \brief Record that the given ID maps to the given switch-case +/// statement. +void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { + assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID"); + SwitchCaseStmts[ID] = SC; +} + +/// \brief Retrieve the switch-case statement with the given ID. +SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) { + assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID"); + return SwitchCaseStmts[ID]; +} + +/// \brief Record that the given label statement has been +/// deserialized and has the given ID. +void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) { + assert(LabelStmts.find(ID) == LabelStmts.end() && + "Deserialized label twice"); + LabelStmts[ID] = S; + + // If we've already seen any goto statements that point to this + // label, resolve them now. + typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter; + std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID); + for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto) + Goto->second->setLabel(S); + UnresolvedGotoStmts.erase(Gotos.first, Gotos.second); + + // If we've already seen any address-label statements that point to + // this label, resolve them now. + typedef std::multimap<unsigned, AddrLabelExpr *>::iterator AddrLabelIter; + std::pair<AddrLabelIter, AddrLabelIter> AddrLabels + = UnresolvedAddrLabelExprs.equal_range(ID); + for (AddrLabelIter AddrLabel = AddrLabels.first; + AddrLabel != AddrLabels.second; ++AddrLabel) + AddrLabel->second->setLabel(S); + UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second); +} + +/// \brief Set the label of the given statement to the label +/// identified by ID. +/// +/// Depending on the order in which the label and other statements +/// referencing that label occur, this operation may complete +/// immediately (updating the statement) or it may queue the +/// statement to be back-patched later. +void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) { + std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID); + if (Label != LabelStmts.end()) { + // We've already seen this label, so set the label of the goto and + // we're done. + S->setLabel(Label->second); + } else { + // We haven't seen this label yet, so add this goto to the set of + // unresolved goto statements. + UnresolvedGotoStmts.insert(std::make_pair(ID, S)); + } +} + +/// \brief Set the label of the given expression to the label +/// identified by ID. +/// +/// Depending on the order in which the label and other statements +/// referencing that label occur, this operation may complete +/// immediately (updating the statement) or it may queue the +/// statement to be back-patched later. +void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) { + std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID); + if (Label != LabelStmts.end()) { + // We've already seen this label, so set the label of the + // label-address expression and we're done. + S->setLabel(Label->second); + } else { + // We haven't seen this label yet, so add this label-address + // expression to the set of unresolved label-address expressions. + UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S)); + } +} + + +PCHReader::LoadingTypeOrDecl::LoadingTypeOrDecl(PCHReader &Reader) + : Reader(Reader), Parent(Reader.CurrentlyLoadingTypeOrDecl) { + Reader.CurrentlyLoadingTypeOrDecl = this; +} + +PCHReader::LoadingTypeOrDecl::~LoadingTypeOrDecl() { + if (!Parent) { + // If any identifiers with corresponding top-level declarations have + // been loaded, load those declarations now. + while (!Reader.PendingIdentifierInfos.empty()) { + Reader.SetGloballyVisibleDecls(Reader.PendingIdentifierInfos.front().II, + Reader.PendingIdentifierInfos.front().DeclIDs, + true); + Reader.PendingIdentifierInfos.pop_front(); + } + } + + Reader.CurrentlyLoadingTypeOrDecl = Parent; +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp new file mode 100644 index 0000000..1ef0441 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderDecl.cpp @@ -0,0 +1,1077 @@ +//===--- PCHReaderDecl.cpp - Decl Deserialization ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PCHReader::ReadDeclRecord method, which is the +// entrypoint for loading a decl. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHReader.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +using namespace clang; + + +//===----------------------------------------------------------------------===// +// Declaration deserialization +//===----------------------------------------------------------------------===// + +namespace { + class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + + public: + PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx) + : Reader(Reader), Record(Record), Idx(Idx) { } + + void VisitDecl(Decl *D); + void VisitTranslationUnitDecl(TranslationUnitDecl *TU); + void VisitNamedDecl(NamedDecl *ND); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitTypeDecl(TypeDecl *TD); + void VisitTypedefDecl(TypedefDecl *TD); + void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D); + void VisitTagDecl(TagDecl *TD); + void VisitEnumDecl(EnumDecl *ED); + void VisitRecordDecl(RecordDecl *RD); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); + void VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + void VisitValueDecl(ValueDecl *VD); + void VisitEnumConstantDecl(EnumConstantDecl *ECD); + void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D); + void VisitDeclaratorDecl(DeclaratorDecl *DD); + void VisitFunctionDecl(FunctionDecl *FD); + void VisitCXXMethodDecl(CXXMethodDecl *D); + void VisitCXXConstructorDecl(CXXConstructorDecl *D); + void VisitCXXDestructorDecl(CXXDestructorDecl *D); + void VisitCXXConversionDecl(CXXConversionDecl *D); + void VisitFieldDecl(FieldDecl *FD); + void VisitVarDecl(VarDecl *VD); + void VisitImplicitParamDecl(ImplicitParamDecl *PD); + void VisitParmVarDecl(ParmVarDecl *PD); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateDecl(TemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void visitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitUsing(UsingDecl *D); + void VisitUsingShadow(UsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); + void VisitFriendTemplateDecl(FriendTemplateDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); + void VisitBlockDecl(BlockDecl *BD); + + std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); + + // FIXME: Reorder according to DeclNodes.def? + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCContainerDecl(ObjCContainerDecl *D); + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + void VisitObjCIvarDecl(ObjCIvarDecl *D); + void VisitObjCProtocolDecl(ObjCProtocolDecl *D); + void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); + void VisitObjCClassDecl(ObjCClassDecl *D); + void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + void VisitObjCCategoryDecl(ObjCCategoryDecl *D); + void VisitObjCImplDecl(ObjCImplDecl *D); + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + void VisitObjCImplementationDecl(ObjCImplementationDecl *D); + void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + }; +} + +void PCHDeclReader::VisitDecl(Decl *D) { + D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setLexicalDeclContext( + cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + D->setInvalidDecl(Record[Idx++]); + if (Record[Idx++]) + D->addAttr(Reader.ReadAttributes()); + D->setImplicit(Record[Idx++]); + D->setUsed(Record[Idx++]); + D->setAccess((AccessSpecifier)Record[Idx++]); + D->setPCHLevel(Record[Idx++] + 1); +} + +void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { + VisitDecl(TU); + TU->setAnonymousNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { + VisitDecl(ND); + ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); +} + +void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) { + VisitNamedDecl(TD); + TD->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); +} + +void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { + // Note that we cannot use VisitTypeDecl here, because we need to + // set the underlying type of the typedef *before* we try to read + // the type associated with the TypedefDecl. + VisitNamedDecl(TD); + uint64_t TypeData = Record[Idx++]; + TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + TD->setTypeForDecl(Reader.GetType(TypeData).getTypePtr()); +} + +void PCHDeclReader::VisitTagDecl(TagDecl *TD) { + VisitTypeDecl(TD); + TD->setPreviousDeclaration( + cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++]))); + TD->setTagKind((TagDecl::TagKind)Record[Idx++]); + TD->setDefinition(Record[Idx++]); + TD->setEmbeddedInDeclarator(Record[Idx++]); + TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: maybe read optional qualifier and its range. + TD->setTypedefForAnonDecl( + cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { + VisitTagDecl(ED); + ED->setIntegerType(Reader.GetType(Record[Idx++])); + ED->setPromotionType(Reader.GetType(Record[Idx++])); + ED->setNumPositiveBits(Record[Idx++]); + ED->setNumNegativeBits(Record[Idx++]); + // FIXME: C++ InstantiatedFrom +} + +void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) { + VisitTagDecl(RD); + RD->setHasFlexibleArrayMember(Record[Idx++]); + RD->setAnonymousStructOrUnion(Record[Idx++]); + RD->setHasObjectMember(Record[Idx++]); +} + +void PCHDeclReader::VisitValueDecl(ValueDecl *VD) { + VisitNamedDecl(VD); + VD->setType(Reader.GetType(Record[Idx++])); +} + +void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { + VisitValueDecl(ECD); + if (Record[Idx++]) + ECD->setInitExpr(Reader.ReadDeclExpr()); + ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); +} + +void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { + VisitValueDecl(DD); + TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); + if (TInfo) + DD->setTypeSourceInfo(TInfo); + // FIXME: read optional qualifier and its range. +} + +void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { + VisitDeclaratorDecl(FD); + if (Record[Idx++]) + FD->setLazyBody(Reader.getDeclsCursor().GetCurrentBitNo()); + FD->setPreviousDeclaration( + cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); + FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); + FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]); + FD->setInlineSpecified(Record[Idx++]); + FD->setVirtualAsWritten(Record[Idx++]); + FD->setPure(Record[Idx++]); + FD->setHasInheritedPrototype(Record[Idx++]); + FD->setHasWrittenPrototype(Record[Idx++]); + FD->setDeleted(Record[Idx++]); + FD->setTrivial(Record[Idx++]); + FD->setCopyAssignment(Record[Idx++]); + FD->setHasImplicitReturnZero(Record[Idx++]); + FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: C++ TemplateOrInstantiation + + // Read in the parameters. + unsigned NumParams = Record[Idx++]; + llvm::SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + FD->setParams(Params.data(), NumParams); + + // FIXME: order this properly w.r.t. friendness + // FIXME: this same thing needs to happen for function templates + if (FD->isOverloadedOperator() && !FD->getDeclContext()->isRecord()) + FD->setNonMemberOperator(); +} + +void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { + VisitNamedDecl(MD); + if (Record[Idx++]) { + // In practice, this won't be executed (since method definitions + // don't occur in header files). + MD->setBody(Reader.ReadDeclStmt()); + MD->setSelfDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++]))); + MD->setCmdDecl(cast<ImplicitParamDecl>(Reader.GetDecl(Record[Idx++]))); + } + MD->setInstanceMethod(Record[Idx++]); + MD->setVariadic(Record[Idx++]); + MD->setSynthesized(Record[Idx++]); + MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); + MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); + MD->setNumSelectorArgs(unsigned(Record[Idx++])); + MD->setResultType(Reader.GetType(Record[Idx++])); + MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + unsigned NumParams = Record[Idx++]; + llvm::SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams, + NumParams); +} + +void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { + VisitNamedDecl(CD); + SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]); + CD->setAtEndRange(SourceRange(A, B)); +} + +void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { + VisitObjCContainerDecl(ID); + ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); + ID->setSuperClass(cast_or_null<ObjCInterfaceDecl> + (Reader.GetDecl(Record[Idx++]))); + unsigned NumProtocols = Record[Idx++]; + llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols; + Protocols.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(), + *Reader.getContext()); + unsigned NumIvars = Record[Idx++]; + llvm::SmallVector<ObjCIvarDecl *, 16> IVars; + IVars.reserve(NumIvars); + for (unsigned I = 0; I != NumIvars; ++I) + IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + ID->setCategoryList( + cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); + ID->setForwardDecl(Record[Idx++]); + ID->setImplicitInterfaceDecl(Record[Idx++]); + ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + ID->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) { + VisitFieldDecl(IVD); + IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]); +} + +void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { + VisitObjCContainerDecl(PD); + PD->setForwardDecl(Record[Idx++]); + PD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); + unsigned NumProtoRefs = Record[Idx++]; + llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + ProtoRefs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); +} + +void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { + VisitFieldDecl(FD); +} + +void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { + VisitDecl(CD); + unsigned NumClassRefs = Record[Idx++]; + llvm::SmallVector<ObjCInterfaceDecl *, 16> ClassRefs; + ClassRefs.reserve(NumClassRefs); + for (unsigned I = 0; I != NumClassRefs; ++I) + ClassRefs.push_back(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + llvm::SmallVector<SourceLocation, 16> SLocs; + SLocs.reserve(NumClassRefs); + for (unsigned I = 0; I != NumClassRefs; ++I) + SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(), + NumClassRefs); +} + +void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { + VisitDecl(FPD); + unsigned NumProtoRefs = Record[Idx++]; + llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + ProtoRefs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); +} + +void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { + VisitObjCContainerDecl(CD); + CD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + unsigned NumProtoRefs = Record[Idx++]; + llvm::SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; + ProtoRefs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); + CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); + CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} + +void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { + VisitNamedDecl(CAD); + CAD->setClassInterface(cast<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + VisitNamedDecl(D); + D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + D->setType(Reader.GetType(Record[Idx++])); + // FIXME: stable encoding + D->setPropertyAttributes( + (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); + // FIXME: stable encoding + D->setPropertyImplementation( + (ObjCPropertyDecl::PropertyControl)Record[Idx++]); + D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); + D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); + D->setGetterMethodDecl( + cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + D->setSetterMethodDecl( + cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + D->setPropertyIvarDecl( + cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { + VisitObjCContainerDecl(D); + D->setClassInterface( + cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitObjCImplDecl(D); + D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx)); +} + +void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitObjCImplDecl(D); + D->setSuperClass( + cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + // FIXME. Add reading of IvarInitializers and NumIvarInitializers. +} + + +void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + VisitDecl(D); + D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + D->setPropertyDecl( + cast_or_null<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++]))); + D->setPropertyIvarDecl( + cast_or_null<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + // FIXME. read GetterCXXConstructor and SetterCXXAssignment +} + +void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { + VisitDeclaratorDecl(FD); + FD->setMutable(Record[Idx++]); + if (Record[Idx++]) + FD->setBitWidth(Reader.ReadDeclExpr()); +} + +void PCHDeclReader::VisitVarDecl(VarDecl *VD) { + VisitDeclaratorDecl(VD); + VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]); + VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]); + VD->setThreadSpecified(Record[Idx++]); + VD->setCXXDirectInitializer(Record[Idx++]); + VD->setDeclaredInCondition(Record[Idx++]); + VD->setExceptionVariable(Record[Idx++]); + VD->setNRVOVariable(Record[Idx++]); + VD->setPreviousDeclaration( + cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + if (Record[Idx++]) + VD->setInit(Reader.ReadDeclExpr()); +} + +void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { + VisitVarDecl(PD); +} + +void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { + VisitVarDecl(PD); + PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); + PD->setHasInheritedDefaultArg(Record[Idx++]); +} + +void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { + VisitDecl(AD); + AD->setAsmString(cast<StringLiteral>(Reader.ReadDeclExpr())); +} + +void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { + VisitDecl(BD); + BD->setBody(cast_or_null<CompoundStmt>(Reader.ReadDeclStmt())); + unsigned NumParams = Record[Idx++]; + llvm::SmallVector<ParmVarDecl *, 16> Params; + Params.reserve(NumParams); + for (unsigned I = 0; I != NumParams; ++I) + Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + BD->setParams(Params.data(), NumParams); +} + +void PCHDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); + D->setHasBraces(Record[Idx++]); +} + +void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { + VisitNamedDecl(D); + D->setLBracLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setRBracLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setNextNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + + // Only read one reference--the original or anonymous namespace. + bool IsOriginal = Record[Idx++]; + if (IsOriginal) + D->setAnonymousNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); + else + D->setOriginalNamespace( + cast_or_null<NamespaceDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitNamedDecl(D); + + D->setAliasLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); + D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); + D->setTargetNameLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setAliasedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUsing(UsingDecl *D) { + VisitNamedDecl(D); + D->setUsingLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx)); + + // FIXME: It would probably be more efficient to read these into a vector + // and then re-cosntruct the shadow decl set over that vector since it + // would avoid existence checks. + unsigned NumShadows = Record[Idx++]; + for(unsigned I = 0; I != NumShadows; ++I) { + D->addShadowDecl(cast<UsingShadowDecl>(Reader.GetDecl(Record[Idx++]))); + } + D->setTypeName(Record[Idx++]); +} + +void PCHDeclReader::VisitUsingShadow(UsingShadowDecl *D) { + VisitNamedDecl(D); + D->setTargetDecl(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + D->setUsingDecl(cast<UsingDecl>(Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); + D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); + D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx)); + D->setNominatedNamespace(cast<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + D->setCommonAncestor(cast_or_null<DeclContext>( + Reader.GetDecl(Record[Idx++]))); +} + +void PCHDeclReader::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); +} + +void PCHDeclReader::VisitUnresolvedUsingTypename( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); + D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTypenameLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); +} + +void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { + // assert(false && "cannot read CXXRecordDecl"); + VisitRecordDecl(D); +} + +void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { + // assert(false && "cannot read CXXMethodDecl"); + VisitFunctionDecl(D); +} + +void PCHDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + // assert(false && "cannot read CXXConstructorDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + // assert(false && "cannot read CXXDestructorDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { + // assert(false && "cannot read CXXConversionDecl"); + VisitCXXMethodDecl(D); +} + +void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { + assert(false && "cannot read FriendTemplateDecl"); +} + +void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) { + assert(false && "cannot read TemplateDecl"); +} + +void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { + assert(false && "cannot read ClassTemplateDecl"); +} + +void PCHDeclReader::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + assert(false && "cannot read ClassTemplateSpecializationDecl"); +} + +void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); +} + +void PCHDeclReader::visitFunctionTemplateDecl(FunctionTemplateDecl *D) { + assert(false && "cannot read FunctionTemplateDecl"); +} + +void PCHDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + assert(false && "cannot read TemplateTypeParmDecl"); +} + +void PCHDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + assert(false && "cannot read NonTypeTemplateParmDecl"); +} + +void PCHDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + assert(false && "cannot read TemplateTemplateParmDecl"); +} + +void PCHDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { + assert(false && "cannot read StaticAssertDecl"); +} + +std::pair<uint64_t, uint64_t> +PCHDeclReader::VisitDeclContext(DeclContext *DC) { + uint64_t LexicalOffset = Record[Idx++]; + uint64_t VisibleOffset = Record[Idx++]; + return std::make_pair(LexicalOffset, VisibleOffset); +} + +//===----------------------------------------------------------------------===// +// Attribute Reading +//===----------------------------------------------------------------------===// + +/// \brief Reads attributes from the current stream position. +Attr *PCHReader::ReadAttributes() { + unsigned Code = DeclsCursor.ReadCode(); + assert(Code == llvm::bitc::UNABBREV_RECORD && + "Expected unabbreviated record"); (void)Code; + + RecordData Record; + unsigned Idx = 0; + unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); + assert(RecCode == pch::DECL_ATTR && "Expected attribute record"); + (void)RecCode; + +#define SIMPLE_ATTR(Name) \ + case Attr::Name: \ + New = ::new (*Context) Name##Attr(); \ + break + +#define STRING_ATTR(Name) \ + case Attr::Name: \ + New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \ + break + +#define UNSIGNED_ATTR(Name) \ + case Attr::Name: \ + New = ::new (*Context) Name##Attr(Record[Idx++]); \ + break + + Attr *Attrs = 0; + while (Idx < Record.size()) { + Attr *New = 0; + Attr::Kind Kind = (Attr::Kind)Record[Idx++]; + bool IsInherited = Record[Idx++]; + + switch (Kind) { + default: + assert(0 && "Unknown attribute!"); + break; + STRING_ATTR(Alias); + SIMPLE_ATTR(AlignMac68k); + UNSIGNED_ATTR(Aligned); + SIMPLE_ATTR(AlwaysInline); + SIMPLE_ATTR(AnalyzerNoReturn); + STRING_ATTR(Annotate); + STRING_ATTR(AsmLabel); + SIMPLE_ATTR(BaseCheck); + + case Attr::Blocks: + New = ::new (*Context) BlocksAttr( + (BlocksAttr::BlocksAttrTypes)Record[Idx++]); + break; + + SIMPLE_ATTR(CDecl); + + case Attr::Cleanup: + New = ::new (*Context) CleanupAttr( + cast<FunctionDecl>(GetDecl(Record[Idx++]))); + break; + + SIMPLE_ATTR(Const); + UNSIGNED_ATTR(Constructor); + SIMPLE_ATTR(DLLExport); + SIMPLE_ATTR(DLLImport); + SIMPLE_ATTR(Deprecated); + UNSIGNED_ATTR(Destructor); + SIMPLE_ATTR(FastCall); + SIMPLE_ATTR(Final); + + case Attr::Format: { + std::string Type = ReadString(Record, Idx); + unsigned FormatIdx = Record[Idx++]; + unsigned FirstArg = Record[Idx++]; + New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg); + break; + } + + case Attr::FormatArg: { + unsigned FormatIdx = Record[Idx++]; + New = ::new (*Context) FormatArgAttr(FormatIdx); + break; + } + + case Attr::Sentinel: { + int sentinel = Record[Idx++]; + int nullPos = Record[Idx++]; + New = ::new (*Context) SentinelAttr(sentinel, nullPos); + break; + } + + SIMPLE_ATTR(GNUInline); + SIMPLE_ATTR(Hiding); + + case Attr::IBActionKind: + New = ::new (*Context) IBActionAttr(); + break; + + case Attr::IBOutletKind: + New = ::new (*Context) IBOutletAttr(); + break; + + case Attr::IBOutletCollectionKind: { + ObjCInterfaceDecl *D = + cast_or_null<ObjCInterfaceDecl>(GetDecl(Record[Idx++])); + New = ::new (*Context) IBOutletCollectionAttr(D); + break; + } + + SIMPLE_ATTR(Malloc); + SIMPLE_ATTR(NoDebug); + SIMPLE_ATTR(NoInline); + SIMPLE_ATTR(NoReturn); + SIMPLE_ATTR(NoThrow); + + case Attr::NonNull: { + unsigned Size = Record[Idx++]; + llvm::SmallVector<unsigned, 16> ArgNums; + ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size); + Idx += Size; + New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size); + break; + } + + case Attr::ReqdWorkGroupSize: { + unsigned X = Record[Idx++]; + unsigned Y = Record[Idx++]; + unsigned Z = Record[Idx++]; + New = ::new (*Context) ReqdWorkGroupSizeAttr(X, Y, Z); + break; + } + + SIMPLE_ATTR(ObjCException); + SIMPLE_ATTR(ObjCNSObject); + SIMPLE_ATTR(CFReturnsNotRetained); + SIMPLE_ATTR(CFReturnsRetained); + SIMPLE_ATTR(NSReturnsNotRetained); + SIMPLE_ATTR(NSReturnsRetained); + SIMPLE_ATTR(Overloadable); + SIMPLE_ATTR(Override); + SIMPLE_ATTR(Packed); + UNSIGNED_ATTR(MaxFieldAlignment); + SIMPLE_ATTR(Pure); + UNSIGNED_ATTR(Regparm); + STRING_ATTR(Section); + SIMPLE_ATTR(StdCall); + SIMPLE_ATTR(ThisCall); + SIMPLE_ATTR(TransparentUnion); + SIMPLE_ATTR(Unavailable); + SIMPLE_ATTR(Unused); + SIMPLE_ATTR(Used); + + case Attr::Visibility: + New = ::new (*Context) VisibilityAttr( + (VisibilityAttr::VisibilityTypes)Record[Idx++]); + break; + + SIMPLE_ATTR(WarnUnusedResult); + SIMPLE_ATTR(Weak); + SIMPLE_ATTR(WeakRef); + SIMPLE_ATTR(WeakImport); + } + + assert(New && "Unable to decode attribute?"); + New->setInherited(IsInherited); + New->setNext(Attrs); + Attrs = New; + } +#undef UNSIGNED_ATTR +#undef STRING_ATTR +#undef SIMPLE_ATTR + + // The list of attributes was built backwards. Reverse the list + // before returning it. + Attr *PrevAttr = 0, *NextAttr = 0; + while (Attrs) { + NextAttr = Attrs->getNext(); + Attrs->setNext(PrevAttr); + PrevAttr = Attrs; + Attrs = NextAttr; + } + + return PrevAttr; +} + +//===----------------------------------------------------------------------===// +// PCHReader Implementation +//===----------------------------------------------------------------------===// + +/// \brief Note that we have loaded the declaration with the given +/// Index. +/// +/// This routine notes that this declaration has already been loaded, +/// so that future GetDecl calls will return this declaration rather +/// than trying to load a new declaration. +inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) { + assert(!DeclsLoaded[Index] && "Decl loaded twice?"); + DeclsLoaded[Index] = D; +} + + +/// \brief Determine whether the consumer will be interested in seeing +/// this declaration (via HandleTopLevelDecl). +/// +/// This routine should return true for anything that might affect +/// code generation, e.g., inline function definitions, Objective-C +/// declarations with metadata, etc. +static bool isConsumerInterestedIn(Decl *D) { + if (isa<FileScopeAsmDecl>(D)) + return true; + if (VarDecl *Var = dyn_cast<VarDecl>(D)) + return Var->isFileVarDecl() && Var->getInit(); + if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) + return Func->isThisDeclarationADefinition(); + return isa<ObjCProtocolDecl>(D); +} + +/// \brief Read the declaration at the given offset from the PCH file. +Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { + // Keep track of where we are in the stream, then jump back there + // after reading this declaration. + SavedStreamPosition SavedPosition(DeclsCursor); + + // Note that we are loading a declaration record. + LoadingTypeOrDecl Loading(*this); + + DeclsCursor.JumpToBit(Offset); + RecordData Record; + unsigned Code = DeclsCursor.ReadCode(); + unsigned Idx = 0; + PCHDeclReader Reader(*this, Record, Idx); + + Decl *D = 0; + switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) { + case pch::DECL_ATTR: + case pch::DECL_CONTEXT_LEXICAL: + case pch::DECL_CONTEXT_VISIBLE: + assert(false && "Record cannot be de-serialized with ReadDeclRecord"); + break; + case pch::DECL_TRANSLATION_UNIT: + assert(Index == 0 && "Translation unit must be at index 0"); + D = Context->getTranslationUnitDecl(); + break; + case pch::DECL_TYPEDEF: + D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_ENUM: + D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), 0); + break; + case pch::DECL_RECORD: + D = RecordDecl::Create(*Context, TTK_Struct, 0, SourceLocation(), + 0, SourceLocation(), 0); + break; + case pch::DECL_ENUM_CONSTANT: + D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), + 0, llvm::APSInt()); + break; + case pch::DECL_FUNCTION: + D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), + QualType(), 0); + break; + case pch::DECL_LINKAGE_SPEC: + D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), + (LinkageSpecDecl::LanguageIDs)0, + false); + break; + case pch::DECL_NAMESPACE: + D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0); + break; + case pch::DECL_NAMESPACE_ALIAS: + D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, SourceRange(), 0, + SourceLocation(), 0); + break; + case pch::DECL_USING: + D = UsingDecl::Create(*Context, 0, SourceLocation(), SourceRange(), + SourceLocation(), 0, DeclarationName(), false); + break; + case pch::DECL_USING_SHADOW: + D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_USING_DIRECTIVE: + D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceRange(), 0, + SourceLocation(), 0, 0); + break; + case pch::DECL_UNRESOLVED_USING_VALUE: + D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(), + SourceRange(), 0, SourceLocation(), + DeclarationName()); + break; + case pch::DECL_UNRESOLVED_USING_TYPENAME: + D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceRange(), + 0, SourceLocation(), + DeclarationName()); + break; + case pch::DECL_CXX_RECORD: + D = CXXRecordDecl::Create(*Context, TTK_Struct, 0, + SourceLocation(), 0, SourceLocation(), 0); + break; + case pch::DECL_CXX_METHOD: + D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), + QualType(), 0); + break; + case pch::DECL_CXX_CONSTRUCTOR: + D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_CXX_DESTRUCTOR: + D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_CXX_CONVERSION: + D = CXXConversionDecl::Create(*Context, Decl::EmptyShell()); + break; + case pch::DECL_FRIEND: + assert(false && "cannot read FriendDecl"); + break; + case pch::DECL_FRIEND_TEMPLATE: + assert(false && "cannot read FriendTemplateDecl"); + break; + case pch::DECL_TEMPLATE: + // FIXME: Should TemplateDecl be ABSTRACT_DECL??? + assert(false && "TemplateDecl should be abstract!"); + break; + case pch::DECL_CLASS_TEMPLATE: + assert(false && "cannot read ClassTemplateDecl"); + break; + case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION: + assert(false && "cannot read ClasstemplateSpecializationDecl"); + break; + case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: + assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); + break; + case pch::DECL_FUNCTION_TEMPLATE: + assert(false && "cannot read FunctionTemplateDecl"); + break; + case pch::DECL_TEMPLATE_TYPE_PARM: + assert(false && "cannot read TemplateTypeParmDecl"); + break; + case pch::DECL_NON_TYPE_TEMPLATE_PARM: + assert(false && "cannot read NonTypeTemplateParmDecl"); + break; + case pch::DECL_TEMPLATE_TEMPLATE_PARM: + assert(false && "cannot read TemplateTemplateParmDecl"); + break; + case pch::DECL_STATIC_ASSERT: + assert(false && "cannot read StaticAssertDecl"); + break; + + case pch::DECL_OBJC_METHOD: + D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(), + Selector(), QualType(), 0, 0); + break; + case pch::DECL_OBJC_INTERFACE: + D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0); + break; + case pch::DECL_OBJC_IVAR: + D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, + ObjCIvarDecl::None); + break; + case pch::DECL_OBJC_PROTOCOL: + D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0); + break; + case pch::DECL_OBJC_AT_DEFS_FIELD: + D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0, + QualType(), 0); + break; + case pch::DECL_OBJC_CLASS: + D = ObjCClassDecl::Create(*Context, 0, SourceLocation()); + break; + case pch::DECL_OBJC_FORWARD_PROTOCOL: + D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation()); + break; + case pch::DECL_OBJC_CATEGORY: + D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceLocation(), 0); + break; + case pch::DECL_OBJC_CATEGORY_IMPL: + D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_OBJC_IMPLEMENTATION: + D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_OBJC_COMPATIBLE_ALIAS: + D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0); + break; + case pch::DECL_OBJC_PROPERTY: + D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), + QualType()); + break; + case pch::DECL_OBJC_PROPERTY_IMPL: + D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, + ObjCPropertyImplDecl::Dynamic, 0); + break; + case pch::DECL_FIELD: + D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0, + false); + break; + case pch::DECL_VAR: + D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, + VarDecl::None, VarDecl::None); + break; + + case pch::DECL_IMPLICIT_PARAM: + D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + break; + + case pch::DECL_PARM_VAR: + D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, + VarDecl::None, VarDecl::None, 0); + break; + case pch::DECL_FILE_SCOPE_ASM: + D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); + break; + case pch::DECL_BLOCK: + D = BlockDecl::Create(*Context, 0, SourceLocation()); + break; + } + + assert(D && "Unknown declaration reading PCH file"); + LoadedDecl(Index, D); + Reader.Visit(D); + + // If this declaration is also a declaration context, get the + // offsets for its tables of lexical and visible declarations. + if (DeclContext *DC = dyn_cast<DeclContext>(D)) { + std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC); + if (Offsets.first || Offsets.second) { + DC->setHasExternalLexicalStorage(Offsets.first != 0); + DC->setHasExternalVisibleStorage(Offsets.second != 0); + DeclContextOffsets[DC] = Offsets; + } + } + assert(Idx == Record.size()); + + // If we have deserialized a declaration that has a definition the + // AST consumer might need to know about, notify the consumer + // about that definition now or queue it for later. + if (isConsumerInterestedIn(D)) { + if (Consumer) { + DeclGroupRef DG(D); + Consumer->HandleTopLevelDecl(DG); + } else { + InterestingDecls.push_back(D); + } + } + + return D; +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp new file mode 100644 index 0000000..3931adb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHReaderStmt.cpp @@ -0,0 +1,1499 @@ +//===--- PCHReaderStmt.cpp - Stmt/Expr Deserialization ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Statement/expression deserialization. This implements the +// PCHReader::ReadStmt method. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHReader.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/StmtVisitor.h" +using namespace clang; + +namespace { + class PCHStmtReader : public StmtVisitor<PCHStmtReader, unsigned> { + PCHReader &Reader; + const PCHReader::RecordData &Record; + unsigned &Idx; + llvm::SmallVectorImpl<Stmt *> &StmtStack; + + public: + PCHStmtReader(PCHReader &Reader, const PCHReader::RecordData &Record, + unsigned &Idx, llvm::SmallVectorImpl<Stmt *> &StmtStack) + : Reader(Reader), Record(Record), Idx(Idx), StmtStack(StmtStack) { } + + /// \brief The number of record fields required for the Stmt class + /// itself. + static const unsigned NumStmtFields = 0; + + /// \brief The number of record fields required for the Expr class + /// itself. + static const unsigned NumExprFields = NumStmtFields + 3; + + // Each of the Visit* functions reads in part of the expression + // from the given record and the current expression stack, then + // return the total number of operands that it read from the + // expression stack. + + unsigned VisitStmt(Stmt *S); + unsigned VisitNullStmt(NullStmt *S); + unsigned VisitCompoundStmt(CompoundStmt *S); + unsigned VisitSwitchCase(SwitchCase *S); + unsigned VisitCaseStmt(CaseStmt *S); + unsigned VisitDefaultStmt(DefaultStmt *S); + unsigned VisitLabelStmt(LabelStmt *S); + unsigned VisitIfStmt(IfStmt *S); + unsigned VisitSwitchStmt(SwitchStmt *S); + unsigned VisitWhileStmt(WhileStmt *S); + unsigned VisitDoStmt(DoStmt *S); + unsigned VisitForStmt(ForStmt *S); + unsigned VisitGotoStmt(GotoStmt *S); + unsigned VisitIndirectGotoStmt(IndirectGotoStmt *S); + unsigned VisitContinueStmt(ContinueStmt *S); + unsigned VisitBreakStmt(BreakStmt *S); + unsigned VisitReturnStmt(ReturnStmt *S); + unsigned VisitDeclStmt(DeclStmt *S); + unsigned VisitAsmStmt(AsmStmt *S); + unsigned VisitExpr(Expr *E); + unsigned VisitPredefinedExpr(PredefinedExpr *E); + unsigned VisitDeclRefExpr(DeclRefExpr *E); + unsigned VisitIntegerLiteral(IntegerLiteral *E); + unsigned VisitFloatingLiteral(FloatingLiteral *E); + unsigned VisitImaginaryLiteral(ImaginaryLiteral *E); + unsigned VisitStringLiteral(StringLiteral *E); + unsigned VisitCharacterLiteral(CharacterLiteral *E); + unsigned VisitParenExpr(ParenExpr *E); + unsigned VisitUnaryOperator(UnaryOperator *E); + unsigned VisitOffsetOfExpr(OffsetOfExpr *E); + unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E); + unsigned VisitCallExpr(CallExpr *E); + unsigned VisitMemberExpr(MemberExpr *E); + unsigned VisitCastExpr(CastExpr *E); + unsigned VisitBinaryOperator(BinaryOperator *E); + unsigned VisitCompoundAssignOperator(CompoundAssignOperator *E); + unsigned VisitConditionalOperator(ConditionalOperator *E); + unsigned VisitImplicitCastExpr(ImplicitCastExpr *E); + unsigned VisitExplicitCastExpr(ExplicitCastExpr *E); + unsigned VisitCStyleCastExpr(CStyleCastExpr *E); + unsigned VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + unsigned VisitExtVectorElementExpr(ExtVectorElementExpr *E); + unsigned VisitInitListExpr(InitListExpr *E); + unsigned VisitDesignatedInitExpr(DesignatedInitExpr *E); + unsigned VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); + unsigned VisitVAArgExpr(VAArgExpr *E); + unsigned VisitAddrLabelExpr(AddrLabelExpr *E); + unsigned VisitStmtExpr(StmtExpr *E); + unsigned VisitTypesCompatibleExpr(TypesCompatibleExpr *E); + unsigned VisitChooseExpr(ChooseExpr *E); + unsigned VisitGNUNullExpr(GNUNullExpr *E); + unsigned VisitShuffleVectorExpr(ShuffleVectorExpr *E); + unsigned VisitBlockExpr(BlockExpr *E); + unsigned VisitBlockDeclRefExpr(BlockDeclRefExpr *E); + unsigned VisitObjCStringLiteral(ObjCStringLiteral *E); + unsigned VisitObjCEncodeExpr(ObjCEncodeExpr *E); + unsigned VisitObjCSelectorExpr(ObjCSelectorExpr *E); + unsigned VisitObjCProtocolExpr(ObjCProtocolExpr *E); + unsigned VisitObjCIvarRefExpr(ObjCIvarRefExpr *E); + unsigned VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); + unsigned VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E); + unsigned VisitObjCMessageExpr(ObjCMessageExpr *E); + unsigned VisitObjCSuperExpr(ObjCSuperExpr *E); + unsigned VisitObjCIsaExpr(ObjCIsaExpr *E); + + unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *); + unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *); + unsigned VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *); + unsigned VisitObjCAtTryStmt(ObjCAtTryStmt *); + unsigned VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *); + unsigned VisitObjCAtThrowStmt(ObjCAtThrowStmt *); + + unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); + unsigned VisitCXXConstructExpr(CXXConstructExpr *E); + unsigned VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + unsigned VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + unsigned VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E); + unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); + unsigned VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); + unsigned VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); + unsigned VisitCXXTypeidExpr(CXXTypeidExpr *E); + unsigned VisitCXXThisExpr(CXXThisExpr *E); + unsigned VisitCXXThrowExpr(CXXThrowExpr *E); + unsigned VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); + unsigned VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); + + unsigned VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + unsigned VisitCXXNewExpr(CXXNewExpr *E); + + unsigned VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); + }; +} + +unsigned PCHStmtReader::VisitStmt(Stmt *S) { + assert(Idx == NumStmtFields && "Incorrect statement field count"); + return 0; +} + +unsigned PCHStmtReader::VisitNullStmt(NullStmt *S) { + VisitStmt(S); + S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); + unsigned NumStmts = Record[Idx++]; + S->setStmts(*Reader.getContext(), + StmtStack.data() + StmtStack.size() - NumStmts, NumStmts); + S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return NumStmts; +} + +unsigned PCHStmtReader::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); + Reader.RecordSwitchCaseID(S, Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitCaseStmt(CaseStmt *S) { + VisitSwitchCase(S); + S->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 3])); + S->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + S->setSubStmt(StmtStack.back()); + S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setEllipsisLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 3; +} + +unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) { + VisitSwitchCase(S); + S->setSubStmt(StmtStack.back()); + S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + S->setID(Reader.GetIdentifierInfo(Record, Idx)); + S->setSubStmt(StmtStack.back()); + S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + Reader.RecordLabelStmt(S, Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) { + VisitStmt(S); + S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3])); + S->setThen(StmtStack[StmtStack.size() - 2]); + S->setElse(StmtStack[StmtStack.size() - 1]); + S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setElseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 3; +} + +unsigned PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); + S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 2])); + S->setBody(StmtStack.back()); + S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + SwitchCase *PrevSC = 0; + for (unsigned N = Record.size(); Idx != N; ++Idx) { + SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]); + if (PrevSC) + PrevSC->setNextSwitchCase(SC); + else + S->setSwitchCaseList(SC); + + // Retain this SwitchCase, since SwitchStmt::addSwitchCase() would + // normally retain it (but we aren't calling addSwitchCase). + SC->Retain(); + PrevSC = SC; + } + return 2; +} + +unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); + S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + S->setBody(StmtStack.back()); + S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitDoStmt(DoStmt *S) { + VisitStmt(S); + S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + S->setBody(StmtStack.back()); + S->setDoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitForStmt(ForStmt *S) { + VisitStmt(S); + S->setInit(StmtStack[StmtStack.size() - 4]); + S->setCond(cast_or_null<Expr>(StmtStack[StmtStack.size() - 3])); + S->setConditionVariable(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setInc(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + S->setBody(StmtStack.back()); + S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 4; +} + +unsigned PCHStmtReader::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + Reader.SetLabelOf(S, Record[Idx++]); + S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setTarget(cast_or_null<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); + S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); + S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); + S->setRetValue(cast_or_null<Expr>(StmtStack.back())); + S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setNRVOCandidate(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + return 1; +} + +unsigned PCHStmtReader::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + S->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + + if (Idx + 1 == Record.size()) { + // Single declaration + S->setDeclGroup(DeclGroupRef(Reader.GetDecl(Record[Idx++]))); + } else { + llvm::SmallVector<Decl *, 16> Decls; + Decls.reserve(Record.size() - Idx); + for (unsigned N = Record.size(); Idx != N; ++Idx) + Decls.push_back(Reader.GetDecl(Record[Idx])); + S->setDeclGroup(DeclGroupRef(DeclGroup::Create(*Reader.getContext(), + Decls.data(), + Decls.size()))); + } + return 0; +} + +unsigned PCHStmtReader::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + unsigned NumOutputs = Record[Idx++]; + unsigned NumInputs = Record[Idx++]; + unsigned NumClobbers = Record[Idx++]; + S->setAsmLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setVolatile(Record[Idx++]); + S->setSimple(Record[Idx++]); + S->setMSAsm(Record[Idx++]); + + unsigned StackIdx + = StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1); + S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); + + // Outputs and inputs + llvm::SmallVector<IdentifierInfo *, 16> Names; + llvm::SmallVector<StringLiteral*, 16> Constraints; + llvm::SmallVector<Stmt*, 16> Exprs; + for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) { + Names.push_back(Reader.GetIdentifierInfo(Record, Idx)); + Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); + Exprs.push_back(StmtStack[StackIdx++]); + } + + // Constraints + llvm::SmallVector<StringLiteral*, 16> Clobbers; + for (unsigned I = 0; I != NumClobbers; ++I) + Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++])); + + S->setOutputsAndInputsAndClobbers(*Reader.getContext(), + Names.data(), Constraints.data(), + Exprs.data(), NumOutputs, NumInputs, + Clobbers.data(), NumClobbers); + + assert(StackIdx == StmtStack.size() && "Error deserializing AsmStmt"); + return NumOutputs*2 + NumInputs*2 + NumClobbers + 1; +} + +unsigned PCHStmtReader::VisitExpr(Expr *E) { + VisitStmt(E); + E->setType(Reader.GetType(Record[Idx++])); + E->setTypeDependent(Record[Idx++]); + E->setValueDependent(Record[Idx++]); + assert(Idx == NumExprFields && "Incorrect expression field count"); + return 0; +} + +unsigned PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { + VisitExpr(E); + E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + // FIXME: read qualifier + // FIXME: read explicit template arguments + return 0; +} + +unsigned PCHStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setValue(Reader.ReadAPInt(Record, Idx)); + return 0; +} + +unsigned PCHStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { + VisitExpr(E); + E->setValue(Reader.ReadAPFloat(Record, Idx)); + E->setExact(Record[Idx++]); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) { + VisitExpr(E); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitStringLiteral(StringLiteral *E) { + VisitExpr(E); + unsigned Len = Record[Idx++]; + assert(Record[Idx] == E->getNumConcatenated() && + "Wrong number of concatenated tokens!"); + ++Idx; + E->setWide(Record[Idx++]); + + // Read string data + llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len); + E->setString(*Reader.getContext(), Str.str()); + Idx += Len; + + // Read source locations + for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I) + E->setStrTokenLoc(I, SourceLocation::getFromRawEncoding(Record[Idx++])); + + return 0; +} + +unsigned PCHStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { + VisitExpr(E); + E->setValue(Record[Idx++]); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setWide(Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitParenExpr(ParenExpr *E) { + VisitExpr(E); + E->setLParen(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParen(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) { + VisitExpr(E); + E->setSubExpr(cast<Expr>(StmtStack.back())); + E->setOpcode((UnaryOperator::Opcode)Record[Idx++]); + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { + typedef OffsetOfExpr::OffsetOfNode Node; + VisitExpr(E); + assert(E->getNumComponents() == Record[Idx]); + ++Idx; + assert(E->getNumExpressions() == Record[Idx]); + ++Idx; + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]); + SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]); + switch (Kind) { + case Node::Array: + E->setComponent(I, Node(Start, Record[Idx++], End)); + break; + + case Node::Field: + E->setComponent(I, + Node(Start, + dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])), + End)); + break; + + case Node::Identifier: + E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End)); + break; + + case Node::Base: + // FIXME: Implement this! + llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); + break; + } + } + + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + E->setIndexExpr(I, cast_or_null<Expr>(StmtStack[StmtStack.size() - N + I])); + + return E->getNumExpressions(); +} + +unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + VisitExpr(E); + E->setSizeof(Record[Idx++]); + if (Record[Idx] == 0) { + E->setArgument(cast<Expr>(StmtStack.back())); + ++Idx; + } else { + E->setArgument(Reader.GetTypeSourceInfo(Record, Idx)); + } + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return E->isArgumentType()? 0 : 1; +} + +unsigned PCHStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + VisitExpr(E); + E->setLHS(cast<Expr>(StmtStack[StmtStack.size() - 2])); + E->setRHS(cast<Expr>(StmtStack[StmtStack.size() - 1])); + E->setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitCallExpr(CallExpr *E) { + VisitExpr(E); + E->setNumArgs(*Reader.getContext(), Record[Idx++]); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setCallee(cast<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1])); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); + return E->getNumArgs() + 1; +} + +unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) { + VisitExpr(E); + E->setBase(cast<Expr>(StmtStack.back())); + E->setMemberDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); + E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setArrow(Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) { + VisitExpr(E); + E->setBase(cast<Expr>(StmtStack.back())); + E->setIsaMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setArrow(Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) { + VisitExpr(E); + E->setSubExpr(cast<Expr>(StmtStack.back())); + E->setCastKind((CastExpr::CastKind)Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitBinaryOperator(BinaryOperator *E) { + VisitExpr(E); + E->setLHS(cast<Expr>(StmtStack.end()[-2])); + E->setRHS(cast<Expr>(StmtStack.end()[-1])); + E->setOpcode((BinaryOperator::Opcode)Record[Idx++]); + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { + VisitBinaryOperator(E); + E->setComputationLHSType(Reader.GetType(Record[Idx++])); + E->setComputationResultType(Reader.GetType(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitConditionalOperator(ConditionalOperator *E) { + VisitExpr(E); + E->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3])); + E->setLHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + E->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 1])); + E->setQuestionLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 3; +} + +unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { + VisitCastExpr(E); + E->setLvalueCast(Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { + VisitCastExpr(E); + E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); + return 1; +} + +unsigned PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { + VisitExplicitCastExpr(E); + E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + VisitExpr(E); + E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + E->setInitializer(cast<Expr>(StmtStack.back())); + E->setFileScope(Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { + VisitExpr(E); + E->setBase(cast<Expr>(StmtStack.back())); + E->setAccessor(Reader.GetIdentifierInfo(Record, Idx)); + E->setAccessorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) { + VisitExpr(E); + unsigned NumInits = Record[Idx++]; + E->reserveInits(*Reader.getContext(), NumInits); + for (unsigned I = 0; I != NumInits; ++I) + E->updateInit(*Reader.getContext(), I, + cast<Expr>(StmtStack[StmtStack.size() - NumInits - 1 + I])); + E->setSyntacticForm(cast_or_null<InitListExpr>(StmtStack.back())); + E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setInitializedFieldInUnion( + cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]))); + E->sawArrayRangeDesignator(Record[Idx++]); + return NumInits + 1; +} + +unsigned PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + typedef DesignatedInitExpr::Designator Designator; + + VisitExpr(E); + unsigned NumSubExprs = Record[Idx++]; + assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs"); + for (unsigned I = 0; I != NumSubExprs; ++I) + E->setSubExpr(I, cast<Expr>(StmtStack[StmtStack.size() - NumSubExprs + I])); + E->setEqualOrColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setGNUSyntax(Record[Idx++]); + + llvm::SmallVector<Designator, 4> Designators; + while (Idx < Record.size()) { + switch ((pch::DesignatorTypes)Record[Idx++]) { + case pch::DESIG_FIELD_DECL: { + FieldDecl *Field = cast<FieldDecl>(Reader.GetDecl(Record[Idx++])); + SourceLocation DotLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation FieldLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + Designators.push_back(Designator(Field->getIdentifier(), DotLoc, + FieldLoc)); + Designators.back().setField(Field); + break; + } + + case pch::DESIG_FIELD_NAME: { + const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx); + SourceLocation DotLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation FieldLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + Designators.push_back(Designator(Name, DotLoc, FieldLoc)); + break; + } + + case pch::DESIG_ARRAY: { + unsigned Index = Record[Idx++]; + SourceLocation LBracketLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation RBracketLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc)); + break; + } + + case pch::DESIG_ARRAY_RANGE: { + unsigned Index = Record[Idx++]; + SourceLocation LBracketLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation EllipsisLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation RBracketLoc + = SourceLocation::getFromRawEncoding(Record[Idx++]); + Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc, + RBracketLoc)); + break; + } + } + } + E->setDesignators(*Reader.getContext(), + Designators.data(), Designators.size()); + + return NumSubExprs; +} + +unsigned PCHStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { + VisitExpr(E); + return 0; +} + +unsigned PCHStmtReader::VisitVAArgExpr(VAArgExpr *E) { + VisitExpr(E); + E->setSubExpr(cast<Expr>(StmtStack.back())); + E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + Reader.SetLabelOf(E, Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitStmtExpr(StmtExpr *E) { + VisitExpr(E); + E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setSubStmt(cast_or_null<CompoundStmt>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { + VisitExpr(E); + E->setArgType1(Reader.GetType(Record[Idx++])); + E->setArgType2(Reader.GetType(Record[Idx++])); + E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitChooseExpr(ChooseExpr *E) { + VisitExpr(E); + E->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3])); + E->setLHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + E->setRHS(cast_or_null<Expr>(StmtStack[StmtStack.size() - 1])); + E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 3; +} + +unsigned PCHStmtReader::VisitGNUNullExpr(GNUNullExpr *E) { + VisitExpr(E); + E->setTokenLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + VisitExpr(E); + unsigned NumExprs = Record[Idx++]; + E->setExprs(*Reader.getContext(), + (Expr **)&StmtStack[StmtStack.size() - NumExprs], NumExprs); + E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return NumExprs; +} + +unsigned PCHStmtReader::VisitBlockExpr(BlockExpr *E) { + VisitExpr(E); + E->setBlockDecl(cast_or_null<BlockDecl>(Reader.GetDecl(Record[Idx++]))); + E->setHasBlockDeclRefExprs(Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + VisitExpr(E); + E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setByRef(Record[Idx++]); + E->setConstQualAdded(Record[Idx++]); + return 0; +} + +//===----------------------------------------------------------------------===// +// Objective-C Expressions and Statements + +unsigned PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) { + VisitExpr(E); + E->setString(cast<StringLiteral>(StmtStack.back())); + E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + VisitExpr(E); + E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + VisitExpr(E); + E->setSelector(Reader.GetSelector(Record, Idx)); + E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + VisitExpr(E); + E->setProtocol(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); + E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + VisitExpr(E); + E->setDecl(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setBase(cast<Expr>(StmtStack.back())); + E->setIsArrow(Record[Idx++]); + E->setIsFreeIvar(Record[Idx++]); + return 1; +} + +unsigned PCHStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + VisitExpr(E); + E->setProperty(cast<ObjCPropertyDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setBase(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { + VisitExpr(E); + E->setGetterMethod( + cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + E->setSetterMethod( + cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + E->setInterfaceDecl( + cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + E->setBase(cast_or_null<Expr>(StmtStack.back())); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { + VisitExpr(E); + assert(Record[Idx] == E->getNumArgs()); + ++Idx; + ObjCMessageExpr::ReceiverKind Kind + = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]); + switch (Kind) { + case ObjCMessageExpr::Instance: + E->setInstanceReceiver( + cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1])); + break; + + case ObjCMessageExpr::Class: + E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx)); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: { + QualType T = Reader.GetType(Record[Idx++]); + SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]); + E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); + break; + } + } + + assert(Kind == E->getReceiverKind()); + + if (Record[Idx++]) + E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + else + E->setSelector(Reader.GetSelector(Record, Idx)); + + E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); + return E->getNumArgs() + (Kind == ObjCMessageExpr::Instance); +} + +unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) { + VisitExpr(E); + E->setLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); + S->setElement(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3])); + S->setCollection(cast_or_null<Expr>(StmtStack[StmtStack.size() - 2])); + S->setBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); + S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 3; +} + +unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + VisitStmt(S); + S->setCatchBody(cast_or_null<Stmt>(StmtStack.back())); + S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + VisitStmt(S); + S->setFinallyBody(StmtStack.back()); + S->setAtFinallyLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + VisitStmt(S); + assert(Record[Idx] == S->getNumCatchStmts()); + ++Idx; + bool HasFinally = Record[Idx++]; + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + unsigned Offset = StmtStack.size() - N - HasFinally + I; + S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(StmtStack[Offset])); + } + + unsigned TryOffset + = StmtStack.size() - S->getNumCatchStmts() - HasFinally - 1; + S->setTryBody(cast_or_null<Stmt>(StmtStack[TryOffset])); + if (HasFinally) + S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); + S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1 + S->getNumCatchStmts() + HasFinally; +} + +unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + VisitStmt(S); + S->setSynchExpr(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2])); + S->setSynchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); + S->setAtSynchronizedLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 2; +} + +unsigned PCHStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + VisitStmt(S); + S->setThrowExpr(StmtStack.back()); + S->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 1; +} + +//===----------------------------------------------------------------------===// +// C++ Expressions and Statements + +unsigned PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + unsigned num = VisitCallExpr(E); + E->setOperator((OverloadedOperatorKind)Record[Idx++]); + return num; +} + +unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { + VisitExpr(E); + E->setConstructor(cast<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setElidable(Record[Idx++]); + E->setRequiresZeroInitialization(Record[Idx++]); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); + E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); + return E->getNumArgs(); +} + +unsigned PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + +unsigned PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + +unsigned PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + E->setValue(Record[Idx++]); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + E->setSourceRange(Reader.ReadSourceRange(Record, Idx)); + if (E->isTypeOperand()) { // typeid(int) + E->setTypeOperandSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + return 0; + } + + // typeid(42+2) + E->setExprOperand(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setImplicit(Record[Idx++]); + return 0; +} + +unsigned PCHStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + E->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + E->setUsedLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); + bool HasStoredExpr = Record[Idx++]; + if (!HasStoredExpr) return 0; + E->setExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + E->setTemporary(Reader.ReadCXXTemporary(Record, Idx)); + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + +unsigned PCHStmtReader::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + VisitExpr(E); + E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return 0; +} + +unsigned PCHStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + E->setGlobalNew(Record[Idx++]); + E->setParenTypeId(Record[Idx++]); + E->setHasInitializer(Record[Idx++]); + bool isArray = Record[Idx++]; + unsigned NumPlacementArgs = Record[Idx++]; + unsigned NumCtorArgs = Record[Idx++]; + E->setOperatorNew(cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); + E->setOperatorDelete( + cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); + E->setConstructor( + cast_or_null<CXXConstructorDecl>(Reader.GetDecl(Record[Idx++]))); + E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + + E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs, + NumCtorArgs); + + // Install all the subexpressions. + unsigned TotalSubExprs = E->raw_arg_end()-E->raw_arg_begin(); + unsigned SSIdx = StmtStack.size()-TotalSubExprs; + for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end(); + I != e; ++I) + *I = StmtStack[SSIdx++]; + + return TotalSubExprs; +} + + +unsigned PCHStmtReader::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { + VisitExpr(E); + unsigned NumTemps = Record[Idx++]; + if (NumTemps) { + E->setNumTemporaries(*Reader.getContext(), NumTemps); + for (unsigned i = 0; i != NumTemps; ++i) + E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx)); + } + E->setSubExpr(cast<Expr>(StmtStack.back())); + return 1; +} + + +// Within the bitstream, expressions are stored in Reverse Polish +// Notation, with each of the subexpressions preceding the +// expression they are stored in. To evaluate expressions, we +// continue reading expressions and placing them on the stack, with +// expressions having operands removing those operands from the +// stack. Evaluation terminates when we see a STMT_STOP record, and +// the single remaining expression on the stack is our result. +Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { + RecordData Record; + unsigned Idx; + llvm::SmallVector<Stmt *, 16> StmtStack; + PCHStmtReader Reader(*this, Record, Idx, StmtStack); + Stmt::EmptyShell Empty; + + while (true) { + unsigned Code = Cursor.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Cursor.ReadBlockEnd()) { + Error("error at end of block in PCH file"); + return 0; + } + break; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Cursor.ReadSubBlockID(); + if (Cursor.SkipBlock()) { + Error("malformed block record in PCH file"); + return 0; + } + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Cursor.ReadAbbrevRecord(); + continue; + } + + Stmt *S = 0; + Idx = 0; + Record.clear(); + bool Finished = false; + switch ((pch::StmtCode)Cursor.ReadRecord(Code, Record)) { + case pch::STMT_STOP: + Finished = true; + break; + + case pch::STMT_NULL_PTR: + S = 0; + break; + + case pch::STMT_NULL: + S = new (Context) NullStmt(Empty); + break; + + case pch::STMT_COMPOUND: + S = new (Context) CompoundStmt(Empty); + break; + + case pch::STMT_CASE: + S = new (Context) CaseStmt(Empty); + break; + + case pch::STMT_DEFAULT: + S = new (Context) DefaultStmt(Empty); + break; + + case pch::STMT_LABEL: + S = new (Context) LabelStmt(Empty); + break; + + case pch::STMT_IF: + S = new (Context) IfStmt(Empty); + break; + + case pch::STMT_SWITCH: + S = new (Context) SwitchStmt(Empty); + break; + + case pch::STMT_WHILE: + S = new (Context) WhileStmt(Empty); + break; + + case pch::STMT_DO: + S = new (Context) DoStmt(Empty); + break; + + case pch::STMT_FOR: + S = new (Context) ForStmt(Empty); + break; + + case pch::STMT_GOTO: + S = new (Context) GotoStmt(Empty); + break; + + case pch::STMT_INDIRECT_GOTO: + S = new (Context) IndirectGotoStmt(Empty); + break; + + case pch::STMT_CONTINUE: + S = new (Context) ContinueStmt(Empty); + break; + + case pch::STMT_BREAK: + S = new (Context) BreakStmt(Empty); + break; + + case pch::STMT_RETURN: + S = new (Context) ReturnStmt(Empty); + break; + + case pch::STMT_DECL: + S = new (Context) DeclStmt(Empty); + break; + + case pch::STMT_ASM: + S = new (Context) AsmStmt(Empty); + break; + + case pch::EXPR_PREDEFINED: + S = new (Context) PredefinedExpr(Empty); + break; + + case pch::EXPR_DECL_REF: + S = new (Context) DeclRefExpr(Empty); + break; + + case pch::EXPR_INTEGER_LITERAL: + S = new (Context) IntegerLiteral(Empty); + break; + + case pch::EXPR_FLOATING_LITERAL: + S = new (Context) FloatingLiteral(Empty); + break; + + case pch::EXPR_IMAGINARY_LITERAL: + S = new (Context) ImaginaryLiteral(Empty); + break; + + case pch::EXPR_STRING_LITERAL: + S = StringLiteral::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields + 1]); + break; + + case pch::EXPR_CHARACTER_LITERAL: + S = new (Context) CharacterLiteral(Empty); + break; + + case pch::EXPR_PAREN: + S = new (Context) ParenExpr(Empty); + break; + + case pch::EXPR_UNARY_OPERATOR: + S = new (Context) UnaryOperator(Empty); + break; + + case pch::EXPR_OFFSETOF: + S = OffsetOfExpr::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields], + Record[PCHStmtReader::NumExprFields + 1]); + break; + + case pch::EXPR_SIZEOF_ALIGN_OF: + S = new (Context) SizeOfAlignOfExpr(Empty); + break; + + case pch::EXPR_ARRAY_SUBSCRIPT: + S = new (Context) ArraySubscriptExpr(Empty); + break; + + case pch::EXPR_CALL: + S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty); + break; + + case pch::EXPR_MEMBER: + S = new (Context) MemberExpr(Empty); + break; + + case pch::EXPR_BINARY_OPERATOR: + S = new (Context) BinaryOperator(Empty); + break; + + case pch::EXPR_COMPOUND_ASSIGN_OPERATOR: + S = new (Context) CompoundAssignOperator(Empty); + break; + + case pch::EXPR_CONDITIONAL_OPERATOR: + S = new (Context) ConditionalOperator(Empty); + break; + + case pch::EXPR_IMPLICIT_CAST: + S = new (Context) ImplicitCastExpr(Empty); + break; + + case pch::EXPR_CSTYLE_CAST: + S = new (Context) CStyleCastExpr(Empty); + break; + + case pch::EXPR_COMPOUND_LITERAL: + S = new (Context) CompoundLiteralExpr(Empty); + break; + + case pch::EXPR_EXT_VECTOR_ELEMENT: + S = new (Context) ExtVectorElementExpr(Empty); + break; + + case pch::EXPR_INIT_LIST: + S = new (Context) InitListExpr(*getContext(), Empty); + break; + + case pch::EXPR_DESIGNATED_INIT: + S = DesignatedInitExpr::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields] - 1); + + break; + + case pch::EXPR_IMPLICIT_VALUE_INIT: + S = new (Context) ImplicitValueInitExpr(Empty); + break; + + case pch::EXPR_VA_ARG: + S = new (Context) VAArgExpr(Empty); + break; + + case pch::EXPR_ADDR_LABEL: + S = new (Context) AddrLabelExpr(Empty); + break; + + case pch::EXPR_STMT: + S = new (Context) StmtExpr(Empty); + break; + + case pch::EXPR_TYPES_COMPATIBLE: + S = new (Context) TypesCompatibleExpr(Empty); + break; + + case pch::EXPR_CHOOSE: + S = new (Context) ChooseExpr(Empty); + break; + + case pch::EXPR_GNU_NULL: + S = new (Context) GNUNullExpr(Empty); + break; + + case pch::EXPR_SHUFFLE_VECTOR: + S = new (Context) ShuffleVectorExpr(Empty); + break; + + case pch::EXPR_BLOCK: + S = new (Context) BlockExpr(Empty); + break; + + case pch::EXPR_BLOCK_DECL_REF: + S = new (Context) BlockDeclRefExpr(Empty); + break; + + case pch::EXPR_OBJC_STRING_LITERAL: + S = new (Context) ObjCStringLiteral(Empty); + break; + case pch::EXPR_OBJC_ENCODE: + S = new (Context) ObjCEncodeExpr(Empty); + break; + case pch::EXPR_OBJC_SELECTOR_EXPR: + S = new (Context) ObjCSelectorExpr(Empty); + break; + case pch::EXPR_OBJC_PROTOCOL_EXPR: + S = new (Context) ObjCProtocolExpr(Empty); + break; + case pch::EXPR_OBJC_IVAR_REF_EXPR: + S = new (Context) ObjCIvarRefExpr(Empty); + break; + case pch::EXPR_OBJC_PROPERTY_REF_EXPR: + S = new (Context) ObjCPropertyRefExpr(Empty); + break; + case pch::EXPR_OBJC_KVC_REF_EXPR: + S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty); + break; + case pch::EXPR_OBJC_MESSAGE_EXPR: + S = ObjCMessageExpr::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields]); + break; + case pch::EXPR_OBJC_SUPER_EXPR: + S = new (Context) ObjCSuperExpr(Empty); + break; + case pch::EXPR_OBJC_ISA: + S = new (Context) ObjCIsaExpr(Empty); + break; + case pch::STMT_OBJC_FOR_COLLECTION: + S = new (Context) ObjCForCollectionStmt(Empty); + break; + case pch::STMT_OBJC_CATCH: + S = new (Context) ObjCAtCatchStmt(Empty); + break; + case pch::STMT_OBJC_FINALLY: + S = new (Context) ObjCAtFinallyStmt(Empty); + break; + case pch::STMT_OBJC_AT_TRY: + S = ObjCAtTryStmt::CreateEmpty(*Context, + Record[PCHStmtReader::NumStmtFields], + Record[PCHStmtReader::NumStmtFields + 1]); + break; + case pch::STMT_OBJC_AT_SYNCHRONIZED: + S = new (Context) ObjCAtSynchronizedStmt(Empty); + break; + case pch::STMT_OBJC_AT_THROW: + S = new (Context) ObjCAtThrowStmt(Empty); + break; + + case pch::EXPR_CXX_OPERATOR_CALL: + S = new (Context) CXXOperatorCallExpr(*Context, Empty); + break; + + case pch::EXPR_CXX_MEMBER_CALL: + S = new (Context) CXXMemberCallExpr(*Context, Empty); + break; + + case pch::EXPR_CXX_CONSTRUCT: + S = new (Context) CXXConstructExpr(Empty, *Context, + Record[PCHStmtReader::NumExprFields + 2]); + break; + + case pch::EXPR_CXX_STATIC_CAST: + S = new (Context) CXXStaticCastExpr(Empty); + break; + + case pch::EXPR_CXX_DYNAMIC_CAST: + S = new (Context) CXXDynamicCastExpr(Empty); + break; + + case pch::EXPR_CXX_REINTERPRET_CAST: + S = new (Context) CXXReinterpretCastExpr(Empty); + break; + + case pch::EXPR_CXX_CONST_CAST: + S = new (Context) CXXConstCastExpr(Empty); + break; + + case pch::EXPR_CXX_FUNCTIONAL_CAST: + S = new (Context) CXXFunctionalCastExpr(Empty); + break; + + case pch::EXPR_CXX_BOOL_LITERAL: + S = new (Context) CXXBoolLiteralExpr(Empty); + break; + + case pch::EXPR_CXX_NULL_PTR_LITERAL: + S = new (Context) CXXNullPtrLiteralExpr(Empty); + break; + case pch::EXPR_CXX_TYPEID_EXPR: + S = new (Context) CXXTypeidExpr(Empty, true); + break; + case pch::EXPR_CXX_TYPEID_TYPE: + S = new (Context) CXXTypeidExpr(Empty, false); + break; + case pch::EXPR_CXX_THIS: + S = new (Context) CXXThisExpr(Empty); + break; + case pch::EXPR_CXX_THROW: + S = new (Context) CXXThrowExpr(Empty); + break; + case pch::EXPR_CXX_DEFAULT_ARG: + S = new (Context) CXXDefaultArgExpr(Empty); + break; + case pch::EXPR_CXX_BIND_TEMPORARY: + S = new (Context) CXXBindTemporaryExpr(Empty); + break; + + case pch::EXPR_CXX_ZERO_INIT_VALUE: + S = new (Context) CXXZeroInitValueExpr(Empty); + break; + case pch::EXPR_CXX_NEW: + S = new (Context) CXXNewExpr(Empty); + break; + + + case pch::EXPR_CXX_EXPR_WITH_TEMPORARIES: + S = new (Context) CXXExprWithTemporaries(Empty); + break; + } + + // We hit a STMT_STOP, so we're done with this expression. + if (Finished) + break; + + ++NumStatementsRead; + + if (S) { + unsigned NumSubStmts = Reader.Visit(S); + while (NumSubStmts > 0) { + StmtStack.pop_back(); + --NumSubStmts; + } + } + + assert(Idx == Record.size() && "Invalid deserialization of statement"); + StmtStack.push_back(S); + } + assert(StmtStack.size() == 1 && "Extra expressions on stack!"); + return StmtStack.back(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp new file mode 100644 index 0000000..3d5b7d8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriter.cpp @@ -0,0 +1,2461 @@ +//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PCHWriter class, which writes a precompiled header. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHWriter.h" +#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema +#include "../Sema/IdentifierResolver.h" // FIXME: move header +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/OnDiskHashTable.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include <cstdio> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Type serialization +//===----------------------------------------------------------------------===// + +namespace { + class PCHTypeWriter { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + + public: + /// \brief Type code that corresponds to the record generated. + pch::TypeCode Code; + + PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { } + + void VisitArrayType(const ArrayType *T); + void VisitFunctionType(const FunctionType *T); + void VisitTagType(const TagType *T); + +#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + void VisitInjectedClassNameType(const InjectedClassNameType *T); + }; +} + +void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { + assert(false && "Built-in types are never serialized"); +} + +void PCHTypeWriter::VisitComplexType(const ComplexType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Code = pch::TYPE_COMPLEX; +} + +void PCHTypeWriter::VisitPointerType(const PointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_POINTER; +} + +void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_BLOCK_POINTER; +} + +void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_LVALUE_REFERENCE; +} + +void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_RVALUE_REFERENCE; +} + +void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Writer.AddTypeRef(QualType(T->getClass(), 0), Record); + Code = pch::TYPE_MEMBER_POINTER; +} + +void PCHTypeWriter::VisitArrayType(const ArrayType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Record.push_back(T->getSizeModifier()); // FIXME: stable values + Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values +} + +void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { + VisitArrayType(T); + Writer.AddAPInt(T->getSize(), Record); + Code = pch::TYPE_CONSTANT_ARRAY; +} + +void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + VisitArrayType(T); + Code = pch::TYPE_INCOMPLETE_ARRAY; +} + +void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { + VisitArrayType(T); + Writer.AddSourceLocation(T->getLBracketLoc(), Record); + Writer.AddSourceLocation(T->getRBracketLoc(), Record); + Writer.AddStmt(T->getSizeExpr()); + Code = pch::TYPE_VARIABLE_ARRAY; +} + +void PCHTypeWriter::VisitVectorType(const VectorType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Record.push_back(T->getNumElements()); + Record.push_back(T->isAltiVec()); + Record.push_back(T->isPixel()); + Code = pch::TYPE_VECTOR; +} + +void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { + VisitVectorType(T); + Code = pch::TYPE_EXT_VECTOR; +} + +void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { + Writer.AddTypeRef(T->getResultType(), Record); + FunctionType::ExtInfo C = T->getExtInfo(); + Record.push_back(C.getNoReturn()); + Record.push_back(C.getRegParm()); + // FIXME: need to stabilize encoding of calling convention... + Record.push_back(C.getCC()); +} + +void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + VisitFunctionType(T); + Code = pch::TYPE_FUNCTION_NO_PROTO; +} + +void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { + VisitFunctionType(T); + Record.push_back(T->getNumArgs()); + for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) + Writer.AddTypeRef(T->getArgType(I), Record); + Record.push_back(T->isVariadic()); + Record.push_back(T->getTypeQuals()); + Record.push_back(T->hasExceptionSpec()); + Record.push_back(T->hasAnyExceptionSpec()); + Record.push_back(T->getNumExceptions()); + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) + Writer.AddTypeRef(T->getExceptionType(I), Record); + Code = pch::TYPE_FUNCTION_PROTO; +} + +#if 0 +// For when we want it.... +void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_UNRESOLVED_USING; +} +#endif + +void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_TYPEDEF; +} + +void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { + Writer.AddStmt(T->getUnderlyingExpr()); + Code = pch::TYPE_TYPEOF_EXPR; +} + +void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) { + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Code = pch::TYPE_TYPEOF; +} + +void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) { + Writer.AddStmt(T->getUnderlyingExpr()); + Code = pch::TYPE_DECLTYPE; +} + +void PCHTypeWriter::VisitTagType(const TagType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + assert(!T->isBeingDefined() && + "Cannot serialize in the middle of a type definition"); +} + +void PCHTypeWriter::VisitRecordType(const RecordType *T) { + VisitTagType(T); + Code = pch::TYPE_RECORD; +} + +void PCHTypeWriter::VisitEnumType(const EnumType *T) { + VisitTagType(T); + Code = pch::TYPE_ENUM; +} + +void +PCHTypeWriter::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTypeRef(T->getReplacementType(), Record); + Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void +PCHTypeWriter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + // FIXME: Serialize this type (C++ only) + assert(false && "Cannot serialize template specialization types"); +} + +void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { + Writer.AddTypeRef(T->getNamedType(), Record); + Record.push_back(T->getKeyword()); + // FIXME: Serialize the qualifier (C++ only) + assert(T->getQualifier() == 0 && "Cannot serialize qualified name types"); + Code = pch::TYPE_ELABORATED; +} + +void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Writer.AddTypeRef(T->getInjectedSpecializationType(), Record); + Code = pch::TYPE_INJECTED_CLASS_NAME; +} + +void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Code = pch::TYPE_OBJC_INTERFACE; +} + +void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { + Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getNumProtocols()); + for (ObjCObjectType::qual_iterator I = T->qual_begin(), + E = T->qual_end(); I != E; ++I) + Writer.AddDeclRef(*I, Record); + Code = pch::TYPE_OBJC_OBJECT; +} + +void +PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + Writer.AddTypeRef(T->getPointeeType(), Record); + Code = pch::TYPE_OBJC_OBJECT_POINTER; +} + +namespace { + +class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + +public: + TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); + void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); +}; + +} + +void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + // nothing to do +} +void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); + if (TL.needsExtraLocalData()) { + Record.push_back(TL.getWrittenTypeSpec()); + Record.push_back(TL.getWrittenSignSpec()); + Record.push_back(TL.getWrittenWidthSpec()); + Record.push_back(TL.hasModeAttr()); + } +} +void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getCaretLoc(), Record); +} +void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpLoc(), Record); +} +void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); +} +void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} +void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { + Writer.AddSourceLocation(TL.getLBracketLoc(), Record); + Writer.AddSourceLocation(TL.getRBracketLoc(), Record); + Record.push_back(TL.getSizeExpr() ? 1 : 0); + if (TL.getSizeExpr()) + Writer.AddStmt(TL.getSizeExpr()); +} +void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedArrayTypeLoc( + DependentSizedArrayTypeLoc TL) { + VisitArrayTypeLoc(TL); +} +void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( + DependentSizedExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddDeclRef(TL.getArg(i), Record); +} +void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { + VisitFunctionTypeLoc(TL); +} +void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); +} +void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + Writer.AddSourceLocation(TL.getTypeofLoc(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); +} +void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + Writer.AddTemplateArgumentLoc(TL.getArgLoc(i), Record); +} +void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); +} +void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getKeywordLoc(), Record); + Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} +void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + Record.push_back(TL.hasBaseTypeAsWritten()); + Writer.AddSourceLocation(TL.getLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) + Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); +} +void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + Writer.AddSourceLocation(TL.getStarLoc(), Record); +} + +//===----------------------------------------------------------------------===// +// PCHWriter Implementation +//===----------------------------------------------------------------------===// + +static void EmitBlockID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { + Record.clear(); + Record.push_back(ID); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); + + // Emit the block name if present. + if (Name == 0 || Name[0] == 0) return; + Record.clear(); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); +} + +static void EmitRecordID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { + Record.clear(); + Record.push_back(ID); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); +} + +static void AddStmtsExprs(llvm::BitstreamWriter &Stream, + PCHWriter::RecordData &Record) { +#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) + RECORD(STMT_STOP); + RECORD(STMT_NULL_PTR); + RECORD(STMT_NULL); + RECORD(STMT_COMPOUND); + RECORD(STMT_CASE); + RECORD(STMT_DEFAULT); + RECORD(STMT_LABEL); + RECORD(STMT_IF); + RECORD(STMT_SWITCH); + RECORD(STMT_WHILE); + RECORD(STMT_DO); + RECORD(STMT_FOR); + RECORD(STMT_GOTO); + RECORD(STMT_INDIRECT_GOTO); + RECORD(STMT_CONTINUE); + RECORD(STMT_BREAK); + RECORD(STMT_RETURN); + RECORD(STMT_DECL); + RECORD(STMT_ASM); + RECORD(EXPR_PREDEFINED); + RECORD(EXPR_DECL_REF); + RECORD(EXPR_INTEGER_LITERAL); + RECORD(EXPR_FLOATING_LITERAL); + RECORD(EXPR_IMAGINARY_LITERAL); + RECORD(EXPR_STRING_LITERAL); + RECORD(EXPR_CHARACTER_LITERAL); + RECORD(EXPR_PAREN); + RECORD(EXPR_UNARY_OPERATOR); + RECORD(EXPR_SIZEOF_ALIGN_OF); + RECORD(EXPR_ARRAY_SUBSCRIPT); + RECORD(EXPR_CALL); + RECORD(EXPR_MEMBER); + RECORD(EXPR_BINARY_OPERATOR); + RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR); + RECORD(EXPR_CONDITIONAL_OPERATOR); + RECORD(EXPR_IMPLICIT_CAST); + RECORD(EXPR_CSTYLE_CAST); + RECORD(EXPR_COMPOUND_LITERAL); + RECORD(EXPR_EXT_VECTOR_ELEMENT); + RECORD(EXPR_INIT_LIST); + RECORD(EXPR_DESIGNATED_INIT); + RECORD(EXPR_IMPLICIT_VALUE_INIT); + RECORD(EXPR_VA_ARG); + RECORD(EXPR_ADDR_LABEL); + RECORD(EXPR_STMT); + RECORD(EXPR_TYPES_COMPATIBLE); + RECORD(EXPR_CHOOSE); + RECORD(EXPR_GNU_NULL); + RECORD(EXPR_SHUFFLE_VECTOR); + RECORD(EXPR_BLOCK); + RECORD(EXPR_BLOCK_DECL_REF); + RECORD(EXPR_OBJC_STRING_LITERAL); + RECORD(EXPR_OBJC_ENCODE); + RECORD(EXPR_OBJC_SELECTOR_EXPR); + RECORD(EXPR_OBJC_PROTOCOL_EXPR); + RECORD(EXPR_OBJC_IVAR_REF_EXPR); + RECORD(EXPR_OBJC_PROPERTY_REF_EXPR); + RECORD(EXPR_OBJC_KVC_REF_EXPR); + RECORD(EXPR_OBJC_MESSAGE_EXPR); + RECORD(EXPR_OBJC_SUPER_EXPR); + RECORD(STMT_OBJC_FOR_COLLECTION); + RECORD(STMT_OBJC_CATCH); + RECORD(STMT_OBJC_FINALLY); + RECORD(STMT_OBJC_AT_TRY); + RECORD(STMT_OBJC_AT_SYNCHRONIZED); + RECORD(STMT_OBJC_AT_THROW); + RECORD(EXPR_CXX_OPERATOR_CALL); + RECORD(EXPR_CXX_CONSTRUCT); + RECORD(EXPR_CXX_STATIC_CAST); + RECORD(EXPR_CXX_DYNAMIC_CAST); + RECORD(EXPR_CXX_REINTERPRET_CAST); + RECORD(EXPR_CXX_CONST_CAST); + RECORD(EXPR_CXX_FUNCTIONAL_CAST); + RECORD(EXPR_CXX_BOOL_LITERAL); + RECORD(EXPR_CXX_NULL_PTR_LITERAL); +#undef RECORD +} + +void PCHWriter::WriteBlockInfoBlock() { + RecordData Record; + Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3); + +#define BLOCK(X) EmitBlockID(pch::X ## _ID, #X, Stream, Record) +#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) + + // PCH Top-Level Block. + BLOCK(PCH_BLOCK); + RECORD(ORIGINAL_FILE_NAME); + RECORD(TYPE_OFFSET); + RECORD(DECL_OFFSET); + RECORD(LANGUAGE_OPTIONS); + RECORD(METADATA); + RECORD(IDENTIFIER_OFFSET); + RECORD(IDENTIFIER_TABLE); + RECORD(EXTERNAL_DEFINITIONS); + RECORD(SPECIAL_TYPES); + RECORD(STATISTICS); + RECORD(TENTATIVE_DEFINITIONS); + RECORD(UNUSED_STATIC_FUNCS); + RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); + RECORD(SELECTOR_OFFSETS); + RECORD(METHOD_POOL); + RECORD(PP_COUNTER_VALUE); + RECORD(SOURCE_LOCATION_OFFSETS); + RECORD(SOURCE_LOCATION_PRELOADS); + RECORD(STAT_CACHE); + RECORD(EXT_VECTOR_DECLS); + RECORD(VERSION_CONTROL_BRANCH_REVISION); + RECORD(UNUSED_STATIC_FUNCS); + RECORD(MACRO_DEFINITION_OFFSETS); + + // SourceManager Block. + BLOCK(SOURCE_MANAGER_BLOCK); + RECORD(SM_SLOC_FILE_ENTRY); + RECORD(SM_SLOC_BUFFER_ENTRY); + RECORD(SM_SLOC_BUFFER_BLOB); + RECORD(SM_SLOC_INSTANTIATION_ENTRY); + RECORD(SM_LINE_TABLE); + + // Preprocessor Block. + BLOCK(PREPROCESSOR_BLOCK); + RECORD(PP_MACRO_OBJECT_LIKE); + RECORD(PP_MACRO_FUNCTION_LIKE); + RECORD(PP_TOKEN); + RECORD(PP_MACRO_INSTANTIATION); + RECORD(PP_MACRO_DEFINITION); + + // Decls and Types block. + BLOCK(DECLTYPES_BLOCK); + RECORD(TYPE_EXT_QUAL); + RECORD(TYPE_COMPLEX); + RECORD(TYPE_POINTER); + RECORD(TYPE_BLOCK_POINTER); + RECORD(TYPE_LVALUE_REFERENCE); + RECORD(TYPE_RVALUE_REFERENCE); + RECORD(TYPE_MEMBER_POINTER); + RECORD(TYPE_CONSTANT_ARRAY); + RECORD(TYPE_INCOMPLETE_ARRAY); + RECORD(TYPE_VARIABLE_ARRAY); + RECORD(TYPE_VECTOR); + RECORD(TYPE_EXT_VECTOR); + RECORD(TYPE_FUNCTION_PROTO); + RECORD(TYPE_FUNCTION_NO_PROTO); + RECORD(TYPE_TYPEDEF); + RECORD(TYPE_TYPEOF_EXPR); + RECORD(TYPE_TYPEOF); + RECORD(TYPE_RECORD); + RECORD(TYPE_ENUM); + RECORD(TYPE_OBJC_INTERFACE); + RECORD(TYPE_OBJC_OBJECT); + RECORD(TYPE_OBJC_OBJECT_POINTER); + RECORD(DECL_ATTR); + RECORD(DECL_TRANSLATION_UNIT); + RECORD(DECL_TYPEDEF); + RECORD(DECL_ENUM); + RECORD(DECL_RECORD); + RECORD(DECL_ENUM_CONSTANT); + RECORD(DECL_FUNCTION); + RECORD(DECL_OBJC_METHOD); + RECORD(DECL_OBJC_INTERFACE); + RECORD(DECL_OBJC_PROTOCOL); + RECORD(DECL_OBJC_IVAR); + RECORD(DECL_OBJC_AT_DEFS_FIELD); + RECORD(DECL_OBJC_CLASS); + RECORD(DECL_OBJC_FORWARD_PROTOCOL); + RECORD(DECL_OBJC_CATEGORY); + RECORD(DECL_OBJC_CATEGORY_IMPL); + RECORD(DECL_OBJC_IMPLEMENTATION); + RECORD(DECL_OBJC_COMPATIBLE_ALIAS); + RECORD(DECL_OBJC_PROPERTY); + RECORD(DECL_OBJC_PROPERTY_IMPL); + RECORD(DECL_FIELD); + RECORD(DECL_VAR); + RECORD(DECL_IMPLICIT_PARAM); + RECORD(DECL_PARM_VAR); + RECORD(DECL_FILE_SCOPE_ASM); + RECORD(DECL_BLOCK); + RECORD(DECL_CONTEXT_LEXICAL); + RECORD(DECL_CONTEXT_VISIBLE); + // Statements and Exprs can occur in the Decls and Types block. + AddStmtsExprs(Stream, Record); +#undef RECORD +#undef BLOCK + Stream.ExitBlock(); +} + +/// \brief Adjusts the given filename to only write out the portion of the +/// filename that is not part of the system root directory. +/// +/// \param Filename the file name to adjust. +/// +/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and +/// the returned filename will be adjusted by this system root. +/// +/// \returns either the original filename (if it needs no adjustment) or the +/// adjusted filename (which points into the @p Filename parameter). +static const char * +adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) { + assert(Filename && "No file name to adjust?"); + + if (!isysroot) + return Filename; + + // Verify that the filename and the system root have the same prefix. + unsigned Pos = 0; + for (; Filename[Pos] && isysroot[Pos]; ++Pos) + if (Filename[Pos] != isysroot[Pos]) + return Filename; // Prefixes don't match. + + // We hit the end of the filename before we hit the end of the system root. + if (!Filename[Pos]) + return Filename; + + // If the file name has a '/' at the current position, skip over the '/'. + // We distinguish sysroot-based includes from absolute includes by the + // absence of '/' at the beginning of sysroot-based includes. + if (Filename[Pos] == '/') + ++Pos; + + return Filename + Pos; +} + +/// \brief Write the PCH metadata (e.g., i686-apple-darwin9). +void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { + using namespace llvm; + + // Metadata + const TargetInfo &Target = Context.Target; + BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); + MetaAbbrev->Add(BitCodeAbbrevOp(pch::METADATA)); + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable + MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple + unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); + + RecordData Record; + Record.push_back(pch::METADATA); + Record.push_back(pch::VERSION_MAJOR); + Record.push_back(pch::VERSION_MINOR); + Record.push_back(CLANG_VERSION_MAJOR); + Record.push_back(CLANG_VERSION_MINOR); + Record.push_back(isysroot != 0); + const std::string &TripleStr = Target.getTriple().getTriple(); + Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, TripleStr); + + // Original file name + SourceManager &SM = Context.getSourceManager(); + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { + BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); + FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME)); + FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); + + llvm::sys::Path MainFilePath(MainFile->getName()); + + MainFilePath.makeAbsolute(); + + const char *MainFileNameStr = MainFilePath.c_str(); + MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, + isysroot); + RecordData Record; + Record.push_back(pch::ORIGINAL_FILE_NAME); + Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); + } + + // Repository branch/version information. + BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); + RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); + RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); + Record.clear(); + Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION); + Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, + getClangFullRepositoryVersion()); +} + +/// \brief Write the LangOptions structure. +void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { + RecordData Record; + Record.push_back(LangOpts.Trigraphs); + Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments. + Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. + Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. + Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) + Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords + Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. + Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ + Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. + Record.push_back(LangOpts.C99); // C99 Support + Record.push_back(LangOpts.Microsoft); // Microsoft extensions. + Record.push_back(LangOpts.CPlusPlus); // C++ Support + Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support + Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords. + + Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. + Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. + Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C + // modern abi enabled. + Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced + // modern abi enabled. + Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. + + Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings + Record.push_back(LangOpts.WritableStrings); // Allow writable strings + Record.push_back(LangOpts.LaxVectorConversions); + Record.push_back(LangOpts.AltiVec); + Record.push_back(LangOpts.Exceptions); // Support exception handling. + Record.push_back(LangOpts.SjLjExceptions); + + Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. + Record.push_back(LangOpts.Freestanding); // Freestanding implementation + Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin) + + // Whether static initializers are protected by locks. + Record.push_back(LangOpts.ThreadsafeStatics); + Record.push_back(LangOpts.POSIXThreads); + Record.push_back(LangOpts.Blocks); // block extension to C + Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if + // they are unused. + Record.push_back(LangOpts.MathErrno); // Math functions must respect errno + // (modulo the platform support). + + Record.push_back(LangOpts.OverflowChecking); // Extension to call a handler function when + // signed integer arithmetic overflows. + + Record.push_back(LangOpts.HeinousExtensions); // Extensions that we really don't like and + // may be ripped out at any time. + + Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. + Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be + // defined. + Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as + // opposed to __DYNAMIC__). + Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero. + + Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be + // used (instead of C99 semantics). + Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. + Record.push_back(LangOpts.AccessControl); // Whether C++ access control should + // be enabled. + Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or + // unsigned type + Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short + Record.push_back(LangOpts.getGCMode()); + Record.push_back(LangOpts.getVisibilityMode()); + Record.push_back(LangOpts.getStackProtectorMode()); + Record.push_back(LangOpts.InstantiationDepth); + Record.push_back(LangOpts.OpenCL); + Record.push_back(LangOpts.CatchUndefined); + Record.push_back(LangOpts.ElideConstructors); + Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); +} + +//===----------------------------------------------------------------------===// +// stat cache Serialization +//===----------------------------------------------------------------------===// + +namespace { +// Trait used for the on-disk hash table of stat cache results. +class PCHStatCacheTrait { +public: + typedef const char * key_type; + typedef key_type key_type_ref; + + typedef std::pair<int, struct stat> data_type; + typedef const data_type& data_type_ref; + + static unsigned ComputeHash(const char *path) { + return llvm::HashString(path); + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, const char *path, + data_type_ref Data) { + unsigned StrLen = strlen(path); + clang::io::Emit16(Out, StrLen); + unsigned DataLen = 1; // result value + if (Data.first == 0) + DataLen += 4 + 4 + 2 + 8 + 8; + clang::io::Emit8(Out, DataLen); + return std::make_pair(StrLen + 1, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) { + Out.write(path, KeyLen); + } + + void EmitData(llvm::raw_ostream& Out, key_type_ref, + data_type_ref Data, unsigned DataLen) { + using namespace clang::io; + uint64_t Start = Out.tell(); (void)Start; + + // Result of stat() + Emit8(Out, Data.first? 1 : 0); + + if (Data.first == 0) { + Emit32(Out, (uint32_t) Data.second.st_ino); + Emit32(Out, (uint32_t) Data.second.st_dev); + Emit16(Out, (uint16_t) Data.second.st_mode); + Emit64(Out, (uint64_t) Data.second.st_mtime); + Emit64(Out, (uint64_t) Data.second.st_size); + } + + assert(Out.tell() - Start == DataLen && "Wrong data length"); + } +}; +} // end anonymous namespace + +/// \brief Write the stat() system call cache to the PCH file. +void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls, + const char *isysroot) { + // Build the on-disk hash table containing information about every + // stat() call. + OnDiskChainedHashTableGenerator<PCHStatCacheTrait> Generator; + unsigned NumStatEntries = 0; + for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), + StatEnd = StatCalls.end(); + Stat != StatEnd; ++Stat, ++NumStatEntries) { + const char *Filename = Stat->first(); + Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); + Generator.insert(Filename, Stat->second); + } + + // Create the on-disk hash table in a buffer. + llvm::SmallString<4096> StatCacheData; + uint32_t BucketOffset; + { + llvm::raw_svector_ostream Out(StatCacheData); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out); + } + + // Create a blob abbreviation + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::STAT_CACHE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the stat cache + RecordData Record; + Record.push_back(pch::STAT_CACHE); + Record.push_back(BucketOffset); + Record.push_back(NumStatEntries); + Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str()); +} + +//===----------------------------------------------------------------------===// +// Source Manager Serialization +//===----------------------------------------------------------------------===// + +/// \brief Create an abbreviation for the SLocEntry that refers to a +/// file. +static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_FILE_ENTRY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives + // FileEntry fields. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time + // HeaderFileInfo fields. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + return Stream.EmitAbbrev(Abbrev); +} + +/// \brief Create an abbreviation for the SLocEntry that refers to a +/// buffer. +static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_ENTRY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob + return Stream.EmitAbbrev(Abbrev); +} + +/// \brief Create an abbreviation for the SLocEntry that refers to a +/// buffer's blob. +static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_BLOB)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob + return Stream.EmitAbbrev(Abbrev); +} + +/// \brief Create an abbreviation for the SLocEntry that refers to an +/// buffer. +static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) { + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_INSTANTIATION_ENTRY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length + return Stream.EmitAbbrev(Abbrev); +} + +/// \brief Writes the block containing the serialized form of the +/// source manager. +/// +/// TODO: We should probably use an on-disk hash table (stored in a +/// blob), indexed based on the file name, so that we only create +/// entries for files that we actually need. In the common case (no +/// errors), we probably won't have to create file entries for any of +/// the files in the AST. +void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, + const Preprocessor &PP, + const char *isysroot) { + RecordData Record; + + // Enter the source manager block. + Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3); + + // Abbreviations for the various kinds of source-location entries. + unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); + unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); + unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream); + unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream); + + // Write the line table. + if (SourceMgr.hasLineTable()) { + LineTableInfo &LineTable = SourceMgr.getLineTable(); + + // Emit the file names + Record.push_back(LineTable.getNumFilenames()); + for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { + // Emit the file name + const char *Filename = LineTable.getFilename(I); + Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); + unsigned FilenameLen = Filename? strlen(Filename) : 0; + Record.push_back(FilenameLen); + if (FilenameLen) + Record.insert(Record.end(), Filename, Filename + FilenameLen); + } + + // Emit the line entries + for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); + L != LEnd; ++L) { + // Emit the file ID + Record.push_back(L->first); + + // Emit the line entries + Record.push_back(L->second.size()); + for (std::vector<LineEntry>::iterator LE = L->second.begin(), + LEEnd = L->second.end(); + LE != LEEnd; ++LE) { + Record.push_back(LE->FileOffset); + Record.push_back(LE->LineNo); + Record.push_back(LE->FilenameID); + Record.push_back((unsigned)LE->FileKind); + Record.push_back(LE->IncludeOffset); + } + } + Stream.EmitRecord(pch::SM_LINE_TABLE, Record); + } + + // Write out the source location entry table. We skip the first + // entry, which is always the same dummy entry. + std::vector<uint32_t> SLocEntryOffsets; + RecordData PreloadSLocs; + SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1); + for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) { + // Get this source location entry. + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); + + // Record the offset of this source-location entry. + SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); + + // Figure out which record code to use. + unsigned Code; + if (SLoc->isFile()) { + if (SLoc->getFile().getContentCache()->Entry) + Code = pch::SM_SLOC_FILE_ENTRY; + else + Code = pch::SM_SLOC_BUFFER_ENTRY; + } else + Code = pch::SM_SLOC_INSTANTIATION_ENTRY; + Record.clear(); + Record.push_back(Code); + + Record.push_back(SLoc->getOffset()); + if (SLoc->isFile()) { + const SrcMgr::FileInfo &File = SLoc->getFile(); + Record.push_back(File.getIncludeLoc().getRawEncoding()); + Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding + Record.push_back(File.hasLineDirectives()); + + const SrcMgr::ContentCache *Content = File.getContentCache(); + if (Content->Entry) { + // The source location entry is a file. The blob associated + // with this entry is the file name. + + // Emit size/modification time for this file. + Record.push_back(Content->Entry->getSize()); + Record.push_back(Content->Entry->getModificationTime()); + + // Emit header-search information associated with this file. + HeaderFileInfo HFI; + HeaderSearch &HS = PP.getHeaderSearchInfo(); + if (Content->Entry->getUID() < HS.header_file_size()) + HFI = HS.header_file_begin()[Content->Entry->getUID()]; + Record.push_back(HFI.isImport); + Record.push_back(HFI.DirInfo); + Record.push_back(HFI.NumIncludes); + AddIdentifierRef(HFI.ControllingMacro, Record); + + // Turn the file name into an absolute path, if it isn't already. + const char *Filename = Content->Entry->getName(); + llvm::sys::Path FilePath(Filename, strlen(Filename)); + FilePath.makeAbsolute(); + Filename = FilePath.c_str(); + + Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); + Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename); + + // FIXME: For now, preload all file source locations, so that + // we get the appropriate File entries in the reader. This is + // a temporary measure. + PreloadSLocs.push_back(SLocEntryOffsets.size()); + } else { + // The source location entry is a buffer. The blob associated + // with this entry contains the contents of the buffer. + + // We add one to the size so that we capture the trailing NULL + // that is required by llvm::MemoryBuffer::getMemBuffer (on + // the reader side). + const llvm::MemoryBuffer *Buffer + = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); + const char *Name = Buffer->getBufferIdentifier(); + Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, + llvm::StringRef(Name, strlen(Name) + 1)); + Record.clear(); + Record.push_back(pch::SM_SLOC_BUFFER_BLOB); + Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, + llvm::StringRef(Buffer->getBufferStart(), + Buffer->getBufferSize() + 1)); + + if (strcmp(Name, "<built-in>") == 0) + PreloadSLocs.push_back(SLocEntryOffsets.size()); + } + } else { + // The source location entry is an instantiation. + const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation(); + Record.push_back(Inst.getSpellingLoc().getRawEncoding()); + Record.push_back(Inst.getInstantiationLocStart().getRawEncoding()); + Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding()); + + // Compute the token length for this macro expansion. + unsigned NextOffset = SourceMgr.getNextOffset(); + if (I + 1 != N) + NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset(); + Record.push_back(NextOffset - SLoc->getOffset() - 1); + Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record); + } + } + + Stream.ExitBlock(); + + if (SLocEntryOffsets.empty()) + return; + + // Write the source-location offsets table into the PCH block. This + // table is used for lazily loading source-location information. + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SOURCE_LOCATION_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets + unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(pch::SOURCE_LOCATION_OFFSETS); + Record.push_back(SLocEntryOffsets.size()); + Record.push_back(SourceMgr.getNextOffset()); + Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, + (const char *)&SLocEntryOffsets.front(), + SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0])); + + // Write the source location entry preloads array, telling the PCH + // reader which source locations entries it should load eagerly. + Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs); +} + +//===----------------------------------------------------------------------===// +// Preprocessor Serialization +//===----------------------------------------------------------------------===// + +/// \brief Writes the block containing the serialized form of the +/// preprocessor. +/// +void PCHWriter::WritePreprocessor(const Preprocessor &PP) { + RecordData Record; + + // If the preprocessor __COUNTER__ value has been bumped, remember it. + if (PP.getCounterValue() != 0) { + Record.push_back(PP.getCounterValue()); + Stream.EmitRecord(pch::PP_COUNTER_VALUE, Record); + Record.clear(); + } + + // Enter the preprocessor block. + Stream.EnterSubblock(pch::PREPROCESSOR_BLOCK_ID, 2); + + // If the PCH file contains __DATE__ or __TIME__ emit a warning about this. + // FIXME: use diagnostics subsystem for localization etc. + if (PP.SawDateOrTime()) + fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); + + // Loop over all the macro definitions that are live at the end of the file, + // emitting each to the PP section. + PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); + for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); + I != E; ++I) { + // FIXME: This emits macros in hash table order, we should do it in a stable + // order so that output is reproducible. + MacroInfo *MI = I->second; + + // Don't emit builtin macros like __LINE__ to the PCH file unless they have + // been redefined by the header (in which case they are not isBuiltinMacro). + if (MI->isBuiltinMacro()) + continue; + + AddIdentifierRef(I->first, Record); + MacroOffsets[I->first] = Stream.GetCurrentBitNo(); + Record.push_back(MI->getDefinitionLoc().getRawEncoding()); + Record.push_back(MI->isUsed()); + + unsigned Code; + if (MI->isObjectLike()) { + Code = pch::PP_MACRO_OBJECT_LIKE; + } else { + Code = pch::PP_MACRO_FUNCTION_LIKE; + + Record.push_back(MI->isC99Varargs()); + Record.push_back(MI->isGNUVarargs()); + Record.push_back(MI->getNumArgs()); + for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); + I != E; ++I) + AddIdentifierRef(*I, Record); + } + + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI))); + + Stream.EmitRecord(Code, Record); + Record.clear(); + + // Emit the tokens array. + for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { + // Note that we know that the preprocessor does not have any annotation + // tokens in it because they are created by the parser, and thus can't be + // in a macro definition. + const Token &Tok = MI->getReplacementToken(TokNo); + + Record.push_back(Tok.getLocation().getRawEncoding()); + Record.push_back(Tok.getLength()); + + // FIXME: When reading literal tokens, reconstruct the literal pointer if + // it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + + // FIXME: Should translate token kind to a stable encoding. + Record.push_back(Tok.getKind()); + // FIXME: Should translate token flags to a stable encoding. + Record.push_back(Tok.getFlags()); + + Stream.EmitRecord(pch::PP_TOKEN, Record); + Record.clear(); + } + ++NumMacros; + } + + // If the preprocessor has a preprocessing record, emit it. + unsigned NumPreprocessingRecords = 0; + if (PPRec) { + for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end(); + E != EEnd; ++E) { + Record.clear(); + + if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { + Record.push_back(NumPreprocessingRecords++); + AddSourceLocation(MI->getSourceRange().getBegin(), Record); + AddSourceLocation(MI->getSourceRange().getEnd(), Record); + AddIdentifierRef(MI->getName(), Record); + Record.push_back(getMacroDefinitionID(MI->getDefinition())); + Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record); + continue; + } + + if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) { + // Record this macro definition's location. + pch::IdentID ID = getMacroDefinitionID(MD); + if (ID != MacroDefinitionOffsets.size()) { + if (ID > MacroDefinitionOffsets.size()) + MacroDefinitionOffsets.resize(ID + 1); + + MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo(); + } else + MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); + + Record.push_back(NumPreprocessingRecords++); + Record.push_back(ID); + AddSourceLocation(MD->getSourceRange().getBegin(), Record); + AddSourceLocation(MD->getSourceRange().getEnd(), Record); + AddIdentifierRef(MD->getName(), Record); + AddSourceLocation(MD->getLocation(), Record); + Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record); + continue; + } + } + } + + Stream.ExitBlock(); + + // Write the offsets table for the preprocessing record. + if (NumPreprocessingRecords > 0) { + // Write the offsets table for identifier IDs. + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(pch::MACRO_DEFINITION_OFFSETS); + Record.push_back(NumPreprocessingRecords); + Record.push_back(MacroDefinitionOffsets.size()); + Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, + (const char *)&MacroDefinitionOffsets.front(), + MacroDefinitionOffsets.size() * sizeof(uint32_t)); + } +} + +//===----------------------------------------------------------------------===// +// Type Serialization +//===----------------------------------------------------------------------===// + +/// \brief Write the representation of a type to the PCH stream. +void PCHWriter::WriteType(QualType T) { + pch::TypeID &ID = TypeIDs[T]; + if (ID == 0) // we haven't seen this type before. + ID = NextTypeID++; + + // Record the offset for this type. + if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS) + TypeOffsets.push_back(Stream.GetCurrentBitNo()); + else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) { + TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS); + TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = Stream.GetCurrentBitNo(); + } + + RecordData Record; + + // Emit the type's representation. + PCHTypeWriter W(*this, Record); + + if (T.hasLocalNonFastQualifiers()) { + Qualifiers Qs = T.getLocalQualifiers(); + AddTypeRef(T.getLocalUnqualifiedType(), Record); + Record.push_back(Qs.getAsOpaqueValue()); + W.Code = pch::TYPE_EXT_QUAL; + } else { + switch (T->getTypeClass()) { + // For all of the concrete, non-dependent types, call the + // appropriate visitor function. +#define TYPE(Class, Base) \ + case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + + // For all of the dependent type nodes (which only occur in C++ + // templates), produce an error. +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Cannot serialize dependent type nodes"); + break; + } + } + + // Emit the serialized record. + Stream.EmitRecord(W.Code, Record); + + // Flush any expressions that were written as part of this type. + FlushStmts(); +} + +//===----------------------------------------------------------------------===// +// Declaration Serialization +//===----------------------------------------------------------------------===// + +/// \brief Write the block containing all of the declaration IDs +/// lexically declared within the given DeclContext. +/// +/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the +/// bistream, or 0 if no block was written. +uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context, + DeclContext *DC) { + if (DC->decls_empty()) + return 0; + + uint64_t Offset = Stream.GetCurrentBitNo(); + RecordData Record; + for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); + D != DEnd; ++D) + AddDeclRef(*D, Record); + + ++NumLexicalDeclContexts; + Stream.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record); + return Offset; +} + +/// \brief Write the block containing all of the declaration IDs +/// visible from the given DeclContext. +/// +/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the +/// bistream, or 0 if no block was written. +uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context, + DeclContext *DC) { + if (DC->getPrimaryContext() != DC) + return 0; + + // Since there is no name lookup into functions or methods, and we + // perform name lookup for the translation unit via the + // IdentifierInfo chains, don't bother to build a + // visible-declarations table for these entities. + if (DC->isFunctionOrMethod() || DC->isTranslationUnit()) + return 0; + + // Force the DeclContext to build a its name-lookup table. + DC->lookup(DeclarationName()); + + // Serialize the contents of the mapping used for lookup. Note that, + // although we have two very different code paths, the serialized + // representation is the same for both cases: a declaration name, + // followed by a size, followed by references to the visible + // declarations that have that name. + uint64_t Offset = Stream.GetCurrentBitNo(); + RecordData Record; + StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(DC->getLookupPtr()); + if (!Map) + return 0; + + for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); + D != DEnd; ++D) { + AddDeclarationName(D->first, Record); + DeclContext::lookup_result Result = D->second.getLookupResult(Context); + Record.push_back(Result.second - Result.first); + for (; Result.first != Result.second; ++Result.first) + AddDeclRef(*Result.first, Record); + } + + if (Record.size() == 0) + return 0; + + Stream.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record); + ++NumVisibleDeclContexts; + return Offset; +} + +//===----------------------------------------------------------------------===// +// Global Method Pool and Selector Serialization +//===----------------------------------------------------------------------===// + +namespace { +// Trait used for the on-disk hash table used in the method pool. +class PCHMethodPoolTrait { + PCHWriter &Writer; + +public: + typedef Selector key_type; + typedef key_type key_type_ref; + + typedef std::pair<ObjCMethodList, ObjCMethodList> data_type; + typedef const data_type& data_type_ref; + + explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { } + + static unsigned ComputeHash(Selector Sel) { + unsigned N = Sel.getNumArgs(); + if (N == 0) + ++N; + unsigned R = 5381; + for (unsigned I = 0; I != N; ++I) + if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) + R = llvm::HashString(II->getName(), R); + return R; + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel, + data_type_ref Methods) { + unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); + clang::io::Emit16(Out, KeyLen); + unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + DataLen += 4; + clang::io::Emit16(Out, DataLen); + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) { + uint64_t Start = Out.tell(); + assert((Start >> 32) == 0 && "Selector key offset too large"); + Writer.SetSelectorOffset(Sel, Start); + unsigned N = Sel.getNumArgs(); + clang::io::Emit16(Out, N); + if (N == 0) + N = 1; + for (unsigned I = 0; I != N; ++I) + clang::io::Emit32(Out, + Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); + } + + void EmitData(llvm::raw_ostream& Out, key_type_ref, + data_type_ref Methods, unsigned DataLen) { + uint64_t Start = Out.tell(); (void)Start; + unsigned NumInstanceMethods = 0; + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + ++NumInstanceMethods; + + unsigned NumFactoryMethods = 0; + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + ++NumFactoryMethods; + + clang::io::Emit16(Out, NumInstanceMethods); + clang::io::Emit16(Out, NumFactoryMethods); + for (const ObjCMethodList *Method = &Methods.first; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + for (const ObjCMethodList *Method = &Methods.second; Method; + Method = Method->Next) + if (Method->Method) + clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); + + assert(Out.tell() - Start == DataLen && "Data length is wrong"); + } +}; +} // end anonymous namespace + +/// \brief Write the method pool into the PCH file. +/// +/// The method pool contains both instance and factory methods, stored +/// in an on-disk hash table indexed by the selector. +void PCHWriter::WriteMethodPool(Sema &SemaRef) { + using namespace llvm; + + // Create and write out the blob that contains the instance and + // factor method pools. + bool Empty = true; + { + OnDiskChainedHashTableGenerator<PCHMethodPoolTrait> Generator; + + // Create the on-disk hash table representation. Start by + // iterating through the instance method pool. + PCHMethodPoolTrait::key_type Key; + unsigned NumSelectorsInMethodPool = 0; + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Instance = SemaRef.InstanceMethodPool.begin(), + InstanceEnd = SemaRef.InstanceMethodPool.end(); + Instance != InstanceEnd; ++Instance) { + // Check whether there is a factory method with the same + // selector. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Factory + = SemaRef.FactoryMethodPool.find(Instance->first); + + if (Factory == SemaRef.FactoryMethodPool.end()) + Generator.insert(Instance->first, + std::make_pair(Instance->second, + ObjCMethodList())); + else + Generator.insert(Instance->first, + std::make_pair(Instance->second, Factory->second)); + + ++NumSelectorsInMethodPool; + Empty = false; + } + + // Now iterate through the factory method pool, to pick up any + // selectors that weren't already in the instance method pool. + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + Factory = SemaRef.FactoryMethodPool.begin(), + FactoryEnd = SemaRef.FactoryMethodPool.end(); + Factory != FactoryEnd; ++Factory) { + // Check whether there is an instance method with the same + // selector. If so, there is no work to do here. + llvm::DenseMap<Selector, ObjCMethodList>::iterator Instance + = SemaRef.InstanceMethodPool.find(Factory->first); + + if (Instance == SemaRef.InstanceMethodPool.end()) { + Generator.insert(Factory->first, + std::make_pair(ObjCMethodList(), Factory->second)); + ++NumSelectorsInMethodPool; + } + + Empty = false; + } + + if (Empty && SelectorOffsets.empty()) + return; + + // Create the on-disk hash table in a buffer. + llvm::SmallString<4096> MethodPool; + uint32_t BucketOffset; + SelectorOffsets.resize(SelVector.size()); + { + PCHMethodPoolTrait Trait(*this); + llvm::raw_svector_ostream Out(MethodPool); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out, Trait); + + // For every selector that we have seen but which was not + // written into the hash table, write the selector itself and + // record it's offset. + for (unsigned I = 0, N = SelVector.size(); I != N; ++I) + if (SelectorOffsets[I] == 0) + Trait.EmitKey(Out, SelVector[I], 0); + } + + // Create a blob abbreviation + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the method pool + RecordData Record; + Record.push_back(pch::METHOD_POOL); + Record.push_back(BucketOffset); + Record.push_back(NumSelectorsInMethodPool); + Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str()); + + // Create a blob abbreviation for the selector table offsets. + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the selector offsets table. + Record.clear(); + Record.push_back(pch::SELECTOR_OFFSETS); + Record.push_back(SelectorOffsets.size()); + Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, + (const char *)&SelectorOffsets.front(), + SelectorOffsets.size() * 4); + } +} + +//===----------------------------------------------------------------------===// +// Identifier Table Serialization +//===----------------------------------------------------------------------===// + +namespace { +class PCHIdentifierTableTrait { + PCHWriter &Writer; + Preprocessor &PP; + + /// \brief Determines whether this is an "interesting" identifier + /// that needs a full IdentifierInfo structure written into the hash + /// table. + static bool isInterestingIdentifier(const IdentifierInfo *II) { + return II->isPoisoned() || + II->isExtensionToken() || + II->hasMacroDefinition() || + II->getObjCOrBuiltinID() || + II->getFETokenInfo<void>(); + } + +public: + typedef const IdentifierInfo* key_type; + typedef key_type key_type_ref; + + typedef pch::IdentID data_type; + typedef data_type data_type_ref; + + PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP) + : Writer(Writer), PP(PP) { } + + static unsigned ComputeHash(const IdentifierInfo* II) { + return llvm::HashString(II->getName()); + } + + std::pair<unsigned,unsigned> + EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, + pch::IdentID ID) { + unsigned KeyLen = II->getLength() + 1; + unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 + if (isInterestingIdentifier(II)) { + DataLen += 2; // 2 bytes for builtin ID, flags + if (II->hasMacroDefinition() && + !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro()) + DataLen += 4; + for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), + DEnd = IdentifierResolver::end(); + D != DEnd; ++D) + DataLen += sizeof(pch::DeclID); + } + clang::io::Emit16(Out, DataLen); + // We emit the key length after the data length so that every + // string is preceded by a 16-bit length. This matches the PTH + // format for storing identifiers. + clang::io::Emit16(Out, KeyLen); + return std::make_pair(KeyLen, DataLen); + } + + void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II, + unsigned KeyLen) { + // Record the location of the key data. This is used when generating + // the mapping from persistent IDs to strings. + Writer.SetIdentifierOffset(II, Out.tell()); + Out.write(II->getNameStart(), KeyLen); + } + + void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, + pch::IdentID ID, unsigned) { + if (!isInterestingIdentifier(II)) { + clang::io::Emit32(Out, ID << 1); + return; + } + + clang::io::Emit32(Out, (ID << 1) | 0x01); + uint32_t Bits = 0; + bool hasMacroDefinition = + II->hasMacroDefinition() && + !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro(); + Bits = (uint32_t)II->getObjCOrBuiltinID(); + Bits = (Bits << 1) | unsigned(hasMacroDefinition); + Bits = (Bits << 1) | unsigned(II->isExtensionToken()); + Bits = (Bits << 1) | unsigned(II->isPoisoned()); + Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); + clang::io::Emit16(Out, Bits); + + if (hasMacroDefinition) + clang::io::Emit32(Out, Writer.getMacroOffset(II)); + + // Emit the declaration IDs in reverse order, because the + // IdentifierResolver provides the declarations as they would be + // visible (e.g., the function "stat" would come before the struct + // "stat"), but IdentifierResolver::AddDeclToIdentifierChain() + // adds declarations to the end of the list (so we need to see the + // struct "status" before the function "status"). + llvm::SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II), + IdentifierResolver::end()); + for (llvm::SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), + DEnd = Decls.rend(); + D != DEnd; ++D) + clang::io::Emit32(Out, Writer.getDeclID(*D)); + } +}; +} // end anonymous namespace + +/// \brief Write the identifier table into the PCH file. +/// +/// The identifier table consists of a blob containing string data +/// (the actual identifiers themselves) and a separate "offsets" index +/// that maps identifier IDs to locations within the blob. +void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { + using namespace llvm; + + // Create and write out the blob that contains the identifier + // strings. + { + OnDiskChainedHashTableGenerator<PCHIdentifierTableTrait> Generator; + + // Look for any identifiers that were named while processing the + // headers, but are otherwise not needed. We add these to the hash + // table to enable checking of the predefines buffer in the case + // where the user adds new macro definitions when building the PCH + // file. + for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), + IDEnd = PP.getIdentifierTable().end(); + ID != IDEnd; ++ID) + getIdentifierRef(ID->second); + + // Create the on-disk hash table representation. + IdentifierOffsets.resize(IdentifierIDs.size()); + for (llvm::DenseMap<const IdentifierInfo *, pch::IdentID>::iterator + ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end(); + ID != IDEnd; ++ID) { + assert(ID->first && "NULL identifier in identifier table"); + Generator.insert(ID->first, ID->second); + } + + // Create the on-disk hash table in a buffer. + llvm::SmallString<4096> IdentifierTable; + uint32_t BucketOffset; + { + PCHIdentifierTableTrait Trait(*this, PP); + llvm::raw_svector_ostream Out(IdentifierTable); + // Make sure that no bucket is at offset 0 + clang::io::Emit32(Out, 0); + BucketOffset = Generator.Emit(Out, Trait); + } + + // Create a blob abbreviation + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the identifier table + RecordData Record; + Record.push_back(pch::IDENTIFIER_TABLE); + Record.push_back(BucketOffset); + Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str()); + } + + // Write the offsets table for identifier IDs. + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_OFFSET)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + RecordData Record; + Record.push_back(pch::IDENTIFIER_OFFSET); + Record.push_back(IdentifierOffsets.size()); + Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, + (const char *)&IdentifierOffsets.front(), + IdentifierOffsets.size() * sizeof(uint32_t)); +} + +//===----------------------------------------------------------------------===// +// General Serialization Routines +//===----------------------------------------------------------------------===// + +/// \brief Write a record containing the given attributes. +void PCHWriter::WriteAttributeRecord(const Attr *Attr) { + RecordData Record; + for (; Attr; Attr = Attr->getNext()) { + Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs + Record.push_back(Attr->isInherited()); + switch (Attr->getKind()) { + default: + assert(0 && "Does not support PCH writing for this attribute yet!"); + break; + case Attr::Alias: + AddString(cast<AliasAttr>(Attr)->getAliasee(), Record); + break; + + case Attr::AlignMac68k: + break; + + case Attr::Aligned: + Record.push_back(cast<AlignedAttr>(Attr)->getAlignment()); + break; + + case Attr::AlwaysInline: + break; + + case Attr::AnalyzerNoReturn: + break; + + case Attr::Annotate: + AddString(cast<AnnotateAttr>(Attr)->getAnnotation(), Record); + break; + + case Attr::AsmLabel: + AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record); + break; + + case Attr::BaseCheck: + break; + + case Attr::Blocks: + Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable + break; + + case Attr::CDecl: + break; + + case Attr::Cleanup: + AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record); + break; + + case Attr::Const: + break; + + case Attr::Constructor: + Record.push_back(cast<ConstructorAttr>(Attr)->getPriority()); + break; + + case Attr::DLLExport: + case Attr::DLLImport: + case Attr::Deprecated: + break; + + case Attr::Destructor: + Record.push_back(cast<DestructorAttr>(Attr)->getPriority()); + break; + + case Attr::FastCall: + case Attr::Final: + break; + + case Attr::Format: { + const FormatAttr *Format = cast<FormatAttr>(Attr); + AddString(Format->getType(), Record); + Record.push_back(Format->getFormatIdx()); + Record.push_back(Format->getFirstArg()); + break; + } + + case Attr::FormatArg: { + const FormatArgAttr *Format = cast<FormatArgAttr>(Attr); + Record.push_back(Format->getFormatIdx()); + break; + } + + case Attr::Sentinel : { + const SentinelAttr *Sentinel = cast<SentinelAttr>(Attr); + Record.push_back(Sentinel->getSentinel()); + Record.push_back(Sentinel->getNullPos()); + break; + } + + case Attr::GNUInline: + case Attr::Hiding: + case Attr::IBActionKind: + case Attr::IBOutletKind: + case Attr::Malloc: + case Attr::NoDebug: + case Attr::NoInline: + case Attr::NoReturn: + case Attr::NoThrow: + break; + + case Attr::IBOutletCollectionKind: { + const IBOutletCollectionAttr *ICA = cast<IBOutletCollectionAttr>(Attr); + AddDeclRef(ICA->getClass(), Record); + break; + } + + case Attr::NonNull: { + const NonNullAttr *NonNull = cast<NonNullAttr>(Attr); + Record.push_back(NonNull->size()); + Record.insert(Record.end(), NonNull->begin(), NonNull->end()); + break; + } + + case Attr::CFReturnsNotRetained: + case Attr::CFReturnsRetained: + case Attr::NSReturnsNotRetained: + case Attr::NSReturnsRetained: + case Attr::ObjCException: + case Attr::ObjCNSObject: + case Attr::Overloadable: + case Attr::Override: + break; + + case Attr::MaxFieldAlignment: + Record.push_back(cast<MaxFieldAlignmentAttr>(Attr)->getAlignment()); + break; + + case Attr::Packed: + break; + + case Attr::Pure: + break; + + case Attr::Regparm: + Record.push_back(cast<RegparmAttr>(Attr)->getNumParams()); + break; + + case Attr::ReqdWorkGroupSize: + Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getXDim()); + Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getYDim()); + Record.push_back(cast<ReqdWorkGroupSizeAttr>(Attr)->getZDim()); + break; + + case Attr::Section: + AddString(cast<SectionAttr>(Attr)->getName(), Record); + break; + + case Attr::StdCall: + case Attr::TransparentUnion: + case Attr::Unavailable: + case Attr::Unused: + case Attr::Used: + break; + + case Attr::Visibility: + // FIXME: stable encoding + Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility()); + break; + + case Attr::WarnUnusedResult: + case Attr::Weak: + case Attr::WeakRef: + case Attr::WeakImport: + break; + } + } + + Stream.EmitRecord(pch::DECL_ATTR, Record); +} + +void PCHWriter::AddString(const std::string &Str, RecordData &Record) { + Record.push_back(Str.size()); + Record.insert(Record.end(), Str.begin(), Str.end()); +} + +/// \brief Note that the identifier II occurs at the given offset +/// within the identifier table. +void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { + IdentifierOffsets[IdentifierIDs[II] - 1] = Offset; +} + +/// \brief Note that the selector Sel occurs at the given offset +/// within the method pool/selector table. +void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { + unsigned ID = SelectorIDs[Sel]; + assert(ID && "Unknown selector"); + SelectorOffsets[ID - 1] = Offset; +} + +PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream) + : Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS), + NumStatements(0), NumMacros(0), NumLexicalDeclContexts(0), + NumVisibleDeclContexts(0) { } + +void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, + const char *isysroot) { + using namespace llvm; + + ASTContext &Context = SemaRef.Context; + Preprocessor &PP = SemaRef.PP; + + // Emit the file header. + Stream.Emit((unsigned)'C', 8); + Stream.Emit((unsigned)'P', 8); + Stream.Emit((unsigned)'C', 8); + Stream.Emit((unsigned)'H', 8); + + WriteBlockInfoBlock(); + + // The translation unit is the first declaration we'll emit. + DeclIDs[Context.getTranslationUnitDecl()] = 1; + DeclTypesToEmit.push(Context.getTranslationUnitDecl()); + + // Make sure that we emit IdentifierInfos (and any attached + // declarations) for builtins. + { + IdentifierTable &Table = PP.getIdentifierTable(); + llvm::SmallVector<const char *, 32> BuiltinNames; + Context.BuiltinInfo.GetBuiltinNames(BuiltinNames, + Context.getLangOptions().NoBuiltin); + for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I) + getIdentifierRef(&Table.get(BuiltinNames[I])); + } + + // Build a record containing all of the tentative definitions in this file, in + // TentativeDefinitions order. Generally, this record will be empty for + // headers. + RecordData TentativeDefinitions; + for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) { + AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions); + } + + // Build a record containing all of the static unused functions in this file. + RecordData UnusedStaticFuncs; + for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) + AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs); + + // Build a record containing all of the locally-scoped external + // declarations in this header file. Generally, this record will be + // empty. + RecordData LocallyScopedExternalDecls; + // FIXME: This is filling in the PCH file in densemap order which is + // nondeterminstic! + for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator + TD = SemaRef.LocallyScopedExternalDecls.begin(), + TDEnd = SemaRef.LocallyScopedExternalDecls.end(); + TD != TDEnd; ++TD) + AddDeclRef(TD->second, LocallyScopedExternalDecls); + + // Build a record containing all of the ext_vector declarations. + RecordData ExtVectorDecls; + for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) + AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls); + + // Write the remaining PCH contents. + RecordData Record; + Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); + WriteMetadata(Context, isysroot); + WriteLanguageOptions(Context.getLangOptions()); + if (StatCalls && !isysroot) + WriteStatCache(*StatCalls, isysroot); + WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); + // Write the record of special types. + Record.clear(); + + AddTypeRef(Context.getBuiltinVaListType(), Record); + AddTypeRef(Context.getObjCIdType(), Record); + AddTypeRef(Context.getObjCSelType(), Record); + AddTypeRef(Context.getObjCProtoType(), Record); + AddTypeRef(Context.getObjCClassType(), Record); + AddTypeRef(Context.getRawCFConstantStringType(), Record); + AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record); + AddTypeRef(Context.getFILEType(), Record); + AddTypeRef(Context.getjmp_bufType(), Record); + AddTypeRef(Context.getsigjmp_bufType(), Record); + AddTypeRef(Context.ObjCIdRedefinitionType, Record); + AddTypeRef(Context.ObjCClassRedefinitionType, Record); + AddTypeRef(Context.getRawBlockdescriptorType(), Record); + AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); + AddTypeRef(Context.ObjCSelRedefinitionType, Record); + AddTypeRef(Context.getRawNSConstantStringType(), Record); + Stream.EmitRecord(pch::SPECIAL_TYPES, Record); + + // Keep writing types and declarations until all types and + // declarations have been written. + Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3); + WriteDeclsBlockAbbrevs(); + while (!DeclTypesToEmit.empty()) { + DeclOrType DOT = DeclTypesToEmit.front(); + DeclTypesToEmit.pop(); + if (DOT.isType()) + WriteType(DOT.getType()); + else + WriteDecl(Context, DOT.getDecl()); + } + Stream.ExitBlock(); + + WritePreprocessor(PP); + WriteMethodPool(SemaRef); + WriteIdentifierTable(PP); + + // Write the type offsets array + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::TYPE_OFFSET)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block + unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + Record.clear(); + Record.push_back(pch::TYPE_OFFSET); + Record.push_back(TypeOffsets.size()); + Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, + (const char *)&TypeOffsets.front(), + TypeOffsets.size() * sizeof(TypeOffsets[0])); + + // Write the declaration offsets array + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block + unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + Record.clear(); + Record.push_back(pch::DECL_OFFSET); + Record.push_back(DeclOffsets.size()); + Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, + (const char *)&DeclOffsets.front(), + DeclOffsets.size() * sizeof(DeclOffsets[0])); + + // Write the record containing external, unnamed definitions. + if (!ExternalDefinitions.empty()) + Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions); + + // Write the record containing tentative definitions. + if (!TentativeDefinitions.empty()) + Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions); + + // Write the record containing unused static functions. + if (!UnusedStaticFuncs.empty()) + Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs); + + // Write the record containing locally-scoped external definitions. + if (!LocallyScopedExternalDecls.empty()) + Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS, + LocallyScopedExternalDecls); + + // Write the record containing ext_vector type names. + if (!ExtVectorDecls.empty()) + Stream.EmitRecord(pch::EXT_VECTOR_DECLS, ExtVectorDecls); + + // Some simple statistics + Record.clear(); + Record.push_back(NumStatements); + Record.push_back(NumMacros); + Record.push_back(NumLexicalDeclContexts); + Record.push_back(NumVisibleDeclContexts); + Stream.EmitRecord(pch::STATISTICS, Record); + Stream.ExitBlock(); +} + +void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) { + Record.push_back(Loc.getRawEncoding()); +} + +void PCHWriter::AddSourceRange(SourceRange Range, RecordData &Record) { + AddSourceLocation(Range.getBegin(), Record); + AddSourceLocation(Range.getEnd(), Record); +} + +void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) { + Record.push_back(Value.getBitWidth()); + unsigned N = Value.getNumWords(); + const uint64_t* Words = Value.getRawData(); + for (unsigned I = 0; I != N; ++I) + Record.push_back(Words[I]); +} + +void PCHWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) { + Record.push_back(Value.isUnsigned()); + AddAPInt(Value, Record); +} + +void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) { + AddAPInt(Value.bitcastToAPInt(), Record); +} + +void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) { + Record.push_back(getIdentifierRef(II)); +} + +pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) { + if (II == 0) + return 0; + + pch::IdentID &ID = IdentifierIDs[II]; + if (ID == 0) + ID = IdentifierIDs.size(); + return ID; +} + +pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) { + if (MD == 0) + return 0; + + pch::IdentID &ID = MacroDefinitions[MD]; + if (ID == 0) + ID = MacroDefinitions.size(); + return ID; +} + +void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { + if (SelRef.getAsOpaquePtr() == 0) { + Record.push_back(0); + return; + } + + pch::SelectorID &SID = SelectorIDs[SelRef]; + if (SID == 0) { + SID = SelectorIDs.size(); + SelVector.push_back(SelRef); + } + Record.push_back(SID); +} + +void PCHWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) { + AddDeclRef(Temp->getDestructor(), Record); +} + +void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordData &Record) { + switch (Arg.getArgument().getKind()) { + case TemplateArgument::Expression: + AddStmt(Arg.getLocInfo().getAsExpr()); + break; + case TemplateArgument::Type: + AddTypeSourceInfo(Arg.getLocInfo().getAsTypeSourceInfo(), Record); + break; + case TemplateArgument::Template: + Record.push_back( + Arg.getTemplateQualifierRange().getBegin().getRawEncoding()); + Record.push_back(Arg.getTemplateQualifierRange().getEnd().getRawEncoding()); + Record.push_back(Arg.getTemplateNameLoc().getRawEncoding()); + break; + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + break; + } +} + +void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { + if (TInfo == 0) { + AddTypeRef(QualType(), Record); + return; + } + + AddTypeRef(TInfo->getType(), Record); + TypeLocWriter TLW(*this, Record); + for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) + TLW.Visit(TL); +} + +void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { + if (T.isNull()) { + Record.push_back(pch::PREDEF_TYPE_NULL_ID); + return; + } + + unsigned FastQuals = T.getLocalFastQualifiers(); + T.removeFastQualifiers(); + + if (T.hasLocalNonFastQualifiers()) { + pch::TypeID &ID = TypeIDs[T]; + if (ID == 0) { + // We haven't seen these qualifiers applied to this type before. + // Assign it a new ID. This is the only time we enqueue a + // qualified type, and it has no CV qualifiers. + ID = NextTypeID++; + DeclTypesToEmit.push(T); + } + + // Encode the type qualifiers in the type reference. + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); + return; + } + + assert(!T.hasLocalQualifiers()); + + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr())) { + pch::TypeID ID = 0; + switch (BT->getKind()) { + case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break; + case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break; + case BuiltinType::Char_U: ID = pch::PREDEF_TYPE_CHAR_U_ID; break; + case BuiltinType::UChar: ID = pch::PREDEF_TYPE_UCHAR_ID; break; + case BuiltinType::UShort: ID = pch::PREDEF_TYPE_USHORT_ID; break; + case BuiltinType::UInt: ID = pch::PREDEF_TYPE_UINT_ID; break; + case BuiltinType::ULong: ID = pch::PREDEF_TYPE_ULONG_ID; break; + case BuiltinType::ULongLong: ID = pch::PREDEF_TYPE_ULONGLONG_ID; break; + case BuiltinType::UInt128: ID = pch::PREDEF_TYPE_UINT128_ID; break; + case BuiltinType::Char_S: ID = pch::PREDEF_TYPE_CHAR_S_ID; break; + case BuiltinType::SChar: ID = pch::PREDEF_TYPE_SCHAR_ID; break; + case BuiltinType::WChar: ID = pch::PREDEF_TYPE_WCHAR_ID; break; + case BuiltinType::Short: ID = pch::PREDEF_TYPE_SHORT_ID; break; + case BuiltinType::Int: ID = pch::PREDEF_TYPE_INT_ID; break; + case BuiltinType::Long: ID = pch::PREDEF_TYPE_LONG_ID; break; + case BuiltinType::LongLong: ID = pch::PREDEF_TYPE_LONGLONG_ID; break; + case BuiltinType::Int128: ID = pch::PREDEF_TYPE_INT128_ID; break; + case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break; + case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break; + case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break; + case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break; + case BuiltinType::Char16: ID = pch::PREDEF_TYPE_CHAR16_ID; break; + case BuiltinType::Char32: ID = pch::PREDEF_TYPE_CHAR32_ID; break; + case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break; + case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break; + case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break; + case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break; + case BuiltinType::ObjCSel: ID = pch::PREDEF_TYPE_OBJC_SEL; break; + case BuiltinType::UndeducedAuto: + assert(0 && "Should not see undeduced auto here"); + break; + } + + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); + return; + } + + pch::TypeID &ID = TypeIDs[T]; + if (ID == 0) { + // We haven't seen this type before. Assign it a new ID and put it + // into the queue of types to emit. + ID = NextTypeID++; + DeclTypesToEmit.push(T); + } + + // Encode the type qualifiers in the type reference. + Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); +} + +void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { + if (D == 0) { + Record.push_back(0); + return; + } + + pch::DeclID &ID = DeclIDs[D]; + if (ID == 0) { + // We haven't seen this declaration before. Give it a new ID and + // enqueue it in the list of declarations to emit. + ID = DeclIDs.size(); + DeclTypesToEmit.push(const_cast<Decl *>(D)); + } + + Record.push_back(ID); +} + +pch::DeclID PCHWriter::getDeclID(const Decl *D) { + if (D == 0) + return 0; + + assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!"); + return DeclIDs[D]; +} + +void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { + // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. + Record.push_back(Name.getNameKind()); + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + AddIdentifierRef(Name.getAsIdentifierInfo(), Record); + break; + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + AddSelectorRef(Name.getObjCSelector(), Record); + break; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + AddTypeRef(Name.getCXXNameType(), Record); + break; + + case DeclarationName::CXXOperatorName: + Record.push_back(Name.getCXXOverloadedOperator()); + break; + + case DeclarationName::CXXLiteralOperatorName: + AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record); + break; + + case DeclarationName::CXXUsingDirective: + // No extra data to emit + break; + } +} + +void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, + RecordData &Record) { + // Nested name specifiers usually aren't too long. I think that 8 would + // typically accomodate the vast majority. + llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames; + + // Push each of the NNS's onto a stack for serialization in reverse order. + while (NNS) { + NestedNames.push_back(NNS); + NNS = NNS->getPrefix(); + } + + Record.push_back(NestedNames.size()); + while(!NestedNames.empty()) { + NNS = NestedNames.pop_back_val(); + NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); + Record.push_back(Kind); + switch (Kind) { + case NestedNameSpecifier::Identifier: + AddIdentifierRef(NNS->getAsIdentifier(), Record); + break; + + case NestedNameSpecifier::Namespace: + AddDeclRef(NNS->getAsNamespace(), Record); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + AddTypeRef(QualType(NNS->getAsType(), 0), Record); + Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); + break; + + case NestedNameSpecifier::Global: + // Don't need to write an associated value. + break; + } + } +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp new file mode 100644 index 0000000..cc58e8e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterDecl.cpp @@ -0,0 +1,817 @@ +//===--- PCHWriterDecl.cpp - Declaration Serialization --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements serialization for Declarations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHWriter.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Declaration serialization +//===----------------------------------------------------------------------===// + +namespace { + class PCHDeclWriter : public DeclVisitor<PCHDeclWriter, void> { + + PCHWriter &Writer; + ASTContext &Context; + PCHWriter::RecordData &Record; + + public: + pch::DeclCode Code; + unsigned AbbrevToUse; + + PCHDeclWriter(PCHWriter &Writer, ASTContext &Context, + PCHWriter::RecordData &Record) + : Writer(Writer), Context(Context), Record(Record) { + } + + void VisitDecl(Decl *D); + void VisitTranslationUnitDecl(TranslationUnitDecl *D); + void VisitNamedDecl(NamedDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitTypeDecl(TypeDecl *D); + void VisitTypedefDecl(TypedefDecl *D); + void VisitUnresolvedUsingTypename(UnresolvedUsingTypenameDecl *D); + void VisitTagDecl(TagDecl *D); + void VisitEnumDecl(EnumDecl *D); + void VisitRecordDecl(RecordDecl *D); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); + void VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + void VisitValueDecl(ValueDecl *D); + void VisitEnumConstantDecl(EnumConstantDecl *D); + void VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D); + void VisitDeclaratorDecl(DeclaratorDecl *D); + void VisitFunctionDecl(FunctionDecl *D); + void VisitCXXMethodDecl(CXXMethodDecl *D); + void VisitCXXConstructorDecl(CXXConstructorDecl *D); + void VisitCXXDestructorDecl(CXXDestructorDecl *D); + void VisitCXXConversionDecl(CXXConversionDecl *D); + void VisitFieldDecl(FieldDecl *D); + void VisitVarDecl(VarDecl *D); + void VisitImplicitParamDecl(ImplicitParamDecl *D); + void VisitParmVarDecl(ParmVarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateDecl(TemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void visitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitUsing(UsingDecl *D); + void VisitUsingShadow(UsingShadowDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitFriendTemplateDecl(FriendTemplateDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); + void VisitBlockDecl(BlockDecl *D); + + void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, + uint64_t VisibleOffset); + + + // FIXME: Put in the same order is DeclNodes.def? + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCContainerDecl(ObjCContainerDecl *D); + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + void VisitObjCIvarDecl(ObjCIvarDecl *D); + void VisitObjCProtocolDecl(ObjCProtocolDecl *D); + void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); + void VisitObjCClassDecl(ObjCClassDecl *D); + void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + void VisitObjCCategoryDecl(ObjCCategoryDecl *D); + void VisitObjCImplDecl(ObjCImplDecl *D); + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + void VisitObjCImplementationDecl(ObjCImplementationDecl *D); + void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + }; +} + +void PCHDeclWriter::VisitDecl(Decl *D) { + Writer.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()), Record); + Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record); + Writer.AddSourceLocation(D->getLocation(), Record); + Record.push_back(D->isInvalidDecl()); + Record.push_back(D->hasAttrs()); + Record.push_back(D->isImplicit()); + Record.push_back(D->isUsed()); + Record.push_back(D->getAccess()); + Record.push_back(D->getPCHLevel()); +} + +void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + VisitDecl(D); + Writer.AddDeclRef(D->getAnonymousNamespace(), Record); + Code = pch::DECL_TRANSLATION_UNIT; +} + +void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) { + VisitDecl(D); + Writer.AddDeclarationName(D->getDeclName(), Record); +} + +void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { + VisitNamedDecl(D); + Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); +} + +void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { + VisitTypeDecl(D); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); + Code = pch::DECL_TYPEDEF; +} + +void PCHDeclWriter::VisitTagDecl(TagDecl *D) { + VisitTypeDecl(D); + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); + Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding + Record.push_back(D->isDefinition()); + Record.push_back(D->isEmbeddedInDeclarator()); + Writer.AddSourceLocation(D->getRBraceLoc(), Record); + Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); + // FIXME: maybe write optional qualifier and its range. + Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); +} + +void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { + VisitTagDecl(D); + Writer.AddTypeRef(D->getIntegerType(), Record); + Writer.AddTypeRef(D->getPromotionType(), Record); + Record.push_back(D->getNumPositiveBits()); + Record.push_back(D->getNumNegativeBits()); + // FIXME: C++ InstantiatedFrom + Code = pch::DECL_ENUM; +} + +void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) { + VisitTagDecl(D); + Record.push_back(D->hasFlexibleArrayMember()); + Record.push_back(D->isAnonymousStructOrUnion()); + Record.push_back(D->hasObjectMember()); + Code = pch::DECL_RECORD; +} + +void PCHDeclWriter::VisitValueDecl(ValueDecl *D) { + VisitNamedDecl(D); + Writer.AddTypeRef(D->getType(), Record); +} + +void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { + VisitValueDecl(D); + Record.push_back(D->getInitExpr()? 1 : 0); + if (D->getInitExpr()) + Writer.AddStmt(D->getInitExpr()); + Writer.AddAPSInt(D->getInitVal(), Record); + Code = pch::DECL_ENUM_CONSTANT; +} + +void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { + VisitValueDecl(D); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); + // FIXME: write optional qualifier and its range. +} + +void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { + VisitDeclaratorDecl(D); + + Record.push_back(D->isThisDeclarationADefinition()); + if (D->isThisDeclarationADefinition()) + Writer.AddStmt(D->getBody()); + + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); + Record.push_back(D->getStorageClass()); // FIXME: stable encoding + Record.push_back(D->getStorageClassAsWritten()); + Record.push_back(D->isInlineSpecified()); + Record.push_back(D->isVirtualAsWritten()); + Record.push_back(D->isPure()); + Record.push_back(D->hasInheritedPrototype()); + Record.push_back(D->hasWrittenPrototype()); + Record.push_back(D->isDeleted()); + Record.push_back(D->isTrivial()); + Record.push_back(D->isCopyAssignment()); + Record.push_back(D->hasImplicitReturnZero()); + // FIXME: C++ TemplateOrInstantiation??? + Writer.AddSourceLocation(D->getLocEnd(), Record); + + Record.push_back(D->param_size()); + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); + P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Code = pch::DECL_FUNCTION; +} + +void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { + VisitNamedDecl(D); + // FIXME: convert to LazyStmtPtr? + // Unlike C/C++, method bodies will never be in header files. + Record.push_back(D->getBody() != 0); + if (D->getBody() != 0) { + Writer.AddStmt(D->getBody()); + Writer.AddDeclRef(D->getSelfDecl(), Record); + Writer.AddDeclRef(D->getCmdDecl(), Record); + } + Record.push_back(D->isInstanceMethod()); + Record.push_back(D->isVariadic()); + Record.push_back(D->isSynthesized()); + // FIXME: stable encoding for @required/@optional + Record.push_back(D->getImplementationControl()); + // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway + Record.push_back(D->getObjCDeclQualifier()); + Record.push_back(D->getNumSelectorArgs()); + Writer.AddTypeRef(D->getResultType(), Record); + Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); + Writer.AddSourceLocation(D->getLocEnd(), Record); + Record.push_back(D->param_size()); + for (ObjCMethodDecl::param_iterator P = D->param_begin(), + PEnd = D->param_end(); P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Code = pch::DECL_OBJC_METHOD; +} + +void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceRange(D->getAtEndRange(), Record); + // Abstract class (no need to define a stable pch::DECL code). +} + +void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + VisitObjCContainerDecl(D); + Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); + Writer.AddDeclRef(D->getSuperClass(), Record); + Record.push_back(D->protocol_size()); + for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(), + PEnd = D->protocol_end(); + P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); + Record.push_back(D->ivar_size()); + for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(), + IEnd = D->ivar_end(); I != IEnd; ++I) + Writer.AddDeclRef(*I, Record); + Writer.AddDeclRef(D->getCategoryList(), Record); + Record.push_back(D->isForwardDecl()); + Record.push_back(D->isImplicitInterfaceDecl()); + Writer.AddSourceLocation(D->getClassLoc(), Record); + Writer.AddSourceLocation(D->getSuperClassLoc(), Record); + Writer.AddSourceLocation(D->getLocEnd(), Record); + Code = pch::DECL_OBJC_INTERFACE; +} + +void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { + VisitFieldDecl(D); + // FIXME: stable encoding for @public/@private/@protected/@package + Record.push_back(D->getAccessControl()); + Code = pch::DECL_OBJC_IVAR; +} + +void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + VisitObjCContainerDecl(D); + Record.push_back(D->isForwardDecl()); + Writer.AddSourceLocation(D->getLocEnd(), Record); + Record.push_back(D->protocol_size()); + for (ObjCProtocolDecl::protocol_iterator + I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) + Writer.AddDeclRef(*I, Record); + for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); + Code = pch::DECL_OBJC_PROTOCOL; +} + +void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { + VisitFieldDecl(D); + Code = pch::DECL_OBJC_AT_DEFS_FIELD; +} + +void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { + VisitDecl(D); + Record.push_back(D->size()); + for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) + Writer.AddDeclRef(I->getInterface(), Record); + for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) + Writer.AddSourceLocation(I->getLocation(), Record); + Code = pch::DECL_OBJC_CLASS; +} + +void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + VisitDecl(D); + Record.push_back(D->protocol_size()); + for (ObjCForwardProtocolDecl::protocol_iterator + I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) + Writer.AddDeclRef(*I, Record); + for (ObjCForwardProtocolDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); + Code = pch::DECL_OBJC_FORWARD_PROTOCOL; +} + +void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + VisitObjCContainerDecl(D); + Writer.AddDeclRef(D->getClassInterface(), Record); + Record.push_back(D->protocol_size()); + for (ObjCCategoryDecl::protocol_iterator + I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) + Writer.AddDeclRef(*I, Record); + for (ObjCCategoryDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); + Writer.AddDeclRef(D->getNextClassCategory(), Record); + Writer.AddSourceLocation(D->getAtLoc(), Record); + Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); + Code = pch::DECL_OBJC_CATEGORY; +} + +void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { + VisitNamedDecl(D); + Writer.AddDeclRef(D->getClassInterface(), Record); + Code = pch::DECL_OBJC_COMPATIBLE_ALIAS; +} + +void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAtLoc(), Record); + Writer.AddTypeRef(D->getType(), Record); + // FIXME: stable encoding + Record.push_back((unsigned)D->getPropertyAttributes()); + // FIXME: stable encoding + Record.push_back((unsigned)D->getPropertyImplementation()); + Writer.AddDeclarationName(D->getGetterName(), Record); + Writer.AddDeclarationName(D->getSetterName(), Record); + Writer.AddDeclRef(D->getGetterMethodDecl(), Record); + Writer.AddDeclRef(D->getSetterMethodDecl(), Record); + Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); + Code = pch::DECL_OBJC_PROPERTY; +} + +void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { + VisitObjCContainerDecl(D); + Writer.AddDeclRef(D->getClassInterface(), Record); + // Abstract class (no need to define a stable pch::DECL code). +} + +void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + VisitObjCImplDecl(D); + Writer.AddIdentifierRef(D->getIdentifier(), Record); + Code = pch::DECL_OBJC_CATEGORY_IMPL; +} + +void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + VisitObjCImplDecl(D); + Writer.AddDeclRef(D->getSuperClass(), Record); + // FIXME add writing of IvarInitializers and NumIvarInitializers. + Code = pch::DECL_OBJC_IMPLEMENTATION; +} + +void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + VisitDecl(D); + Writer.AddSourceLocation(D->getLocStart(), Record); + Writer.AddDeclRef(D->getPropertyDecl(), Record); + Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); + // FIXME. write GetterCXXConstructor and SetterCXXAssignment. + Code = pch::DECL_OBJC_PROPERTY_IMPL; +} + +void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { + VisitDeclaratorDecl(D); + Record.push_back(D->isMutable()); + Record.push_back(D->getBitWidth()? 1 : 0); + if (D->getBitWidth()) + Writer.AddStmt(D->getBitWidth()); + Code = pch::DECL_FIELD; +} + +void PCHDeclWriter::VisitVarDecl(VarDecl *D) { + VisitDeclaratorDecl(D); + Record.push_back(D->getStorageClass()); // FIXME: stable encoding + Record.push_back(D->getStorageClassAsWritten()); + Record.push_back(D->isThreadSpecified()); + Record.push_back(D->hasCXXDirectInitializer()); + Record.push_back(D->isDeclaredInCondition()); + Record.push_back(D->isExceptionVariable()); + Record.push_back(D->isNRVOVariable()); + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); + Record.push_back(D->getInit() ? 1 : 0); + if (D->getInit()) + Writer.AddStmt(D->getInit()); + Code = pch::DECL_VAR; +} + +void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { + VisitVarDecl(D); + Code = pch::DECL_IMPLICIT_PARAM; +} + +void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { + VisitVarDecl(D); + Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding + Record.push_back(D->hasInheritedDefaultArg()); + Code = pch::DECL_PARM_VAR; + + // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here + // we dynamically check for the properties that we optimize for, but don't + // know are true of all PARM_VAR_DECLs. + if (!D->getTypeSourceInfo() && + !D->hasAttrs() && + !D->isImplicit() && + !D->isUsed() && + D->getAccess() == AS_none && + D->getPCHLevel() == 0 && + D->getStorageClass() == 0 && + !D->hasCXXDirectInitializer() && // Can params have this ever? + D->getObjCDeclQualifier() == 0 && + !D->hasInheritedDefaultArg() && + D->getInit() == 0) // No default expr. + AbbrevToUse = Writer.getParmVarDeclAbbrev(); + + // Check things we know are true of *every* PARM_VAR_DECL, which is more than + // just us assuming it. + assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls"); + assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); + assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); + assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition"); + assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); + assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl"); +} + +void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { + VisitDecl(D); + Writer.AddStmt(D->getAsmString()); + Code = pch::DECL_FILE_SCOPE_ASM; +} + +void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) { + VisitDecl(D); + Writer.AddStmt(D->getBody()); + Record.push_back(D->param_size()); + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); + P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Code = pch::DECL_BLOCK; +} + +void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + VisitDecl(D); + // FIXME: It might be nice to serialize the brace locations for this + // declaration, which don't seem to be readily available in the AST. + Record.push_back(D->getLanguage()); + Record.push_back(D->hasBraces()); + Code = pch::DECL_LINKAGE_SPEC; +} + +void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getLBracLoc(), Record); + Writer.AddSourceLocation(D->getRBracLoc(), Record); + Writer.AddDeclRef(D->getNextNamespace(), Record); + + // Only write one reference--original or anonymous + Record.push_back(D->isOriginalNamespace()); + if (D->isOriginalNamespace()) + Writer.AddDeclRef(D->getAnonymousNamespace(), Record); + else + Writer.AddDeclRef(D->getOriginalNamespace(), Record); + Code = pch::DECL_NAMESPACE; +} + +void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAliasLoc(), Record); + Writer.AddSourceRange(D->getQualifierRange(), Record); + Writer.AddNestedNameSpecifier(D->getQualifier(), Record); + Writer.AddSourceLocation(D->getTargetNameLoc(), Record); + Writer.AddDeclRef(D->getNamespace(), Record); + Code = pch::DECL_NAMESPACE_ALIAS; +} + +void PCHDeclWriter::VisitUsing(UsingDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceRange(D->getNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLocation(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record); + Record.push_back(D->getNumShadowDecls()); + for (UsingDecl::shadow_iterator P = D->shadow_begin(), + PEnd = D->shadow_end(); P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Record.push_back(D->isTypeName()); + Code = pch::DECL_USING; +} + +void PCHDeclWriter::VisitUsingShadow(UsingShadowDecl *D) { + VisitNamedDecl(D); + Writer.AddDeclRef(D->getTargetDecl(), Record); + Writer.AddDeclRef(D->getUsingDecl(), Record); + Code = pch::DECL_USING_SHADOW; +} + +void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record); + Writer.AddSourceRange(D->getQualifierRange(), Record); + Writer.AddNestedNameSpecifier(D->getQualifier(), Record); + Writer.AddSourceLocation(D->getIdentLocation(), Record); + Writer.AddDeclRef(D->getNominatedNamespace(), Record); + Writer.AddDeclRef(dyn_cast<Decl>(D->getCommonAncestor()), Record); + Code = pch::DECL_USING_DIRECTIVE; +} + +void PCHDeclWriter::VisitUnresolvedUsingValue(UnresolvedUsingValueDecl *D) { + VisitValueDecl(D); + Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLoc(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); + Code = pch::DECL_UNRESOLVED_USING_VALUE; +} + +void PCHDeclWriter::VisitUnresolvedUsingTypename( + UnresolvedUsingTypenameDecl *D) { + VisitTypeDecl(D); + Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); + Writer.AddSourceLocation(D->getUsingLoc(), Record); + Writer.AddSourceLocation(D->getTypenameLoc(), Record); + Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); + Code = pch::DECL_UNRESOLVED_USING_TYPENAME; +} + +void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { + // assert(false && "cannot write CXXRecordDecl"); + VisitRecordDecl(D); + Code = pch::DECL_CXX_RECORD; +} + +void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { + // assert(false && "cannot write CXXMethodDecl"); + VisitFunctionDecl(D); + Code = pch::DECL_CXX_METHOD; +} + +void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + // assert(false && "cannot write CXXConstructorDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_CONSTRUCTOR; +} + +void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + // assert(false && "cannot write CXXDestructorDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_DESTRUCTOR; +} + +void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { + // assert(false && "cannot write CXXConversionDecl"); + VisitCXXMethodDecl(D); + Code = pch::DECL_CXX_CONVERSION; +} + +void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { + assert(false && "cannot write FriendTemplateDecl"); +} + +void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { + assert(false && "cannot write TemplateDecl"); +} + +void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { + assert(false && "cannot write ClassTemplateDecl"); +} + +void PCHDeclWriter::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + assert(false && "cannot write ClassTemplateSpecializationDecl"); +} + +void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + assert(false && "cannot write ClassTemplatePartialSpecializationDecl"); +} + +void PCHDeclWriter::visitFunctionTemplateDecl(FunctionTemplateDecl *D) { + assert(false && "cannot write FunctionTemplateDecl"); +} + +void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + assert(false && "cannot write TemplateTypeParmDecl"); +} + +void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + assert(false && "cannot write NonTypeTemplateParmDecl"); +} + +void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + assert(false && "cannot write TemplateTemplateParmDecl"); +} + +void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { + assert(false && "cannot write StaticAssertDecl"); +} + +/// \brief Emit the DeclContext part of a declaration context decl. +/// +/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL +/// block for this declaration context is stored. May be 0 to indicate +/// that there are no declarations stored within this context. +/// +/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE +/// block for this declaration context is stored. May be 0 to indicate +/// that there are no declarations visible from this context. Note +/// that this value will not be emitted for non-primary declaration +/// contexts. +void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, + uint64_t VisibleOffset) { + Record.push_back(LexicalOffset); + Record.push_back(VisibleOffset); +} + + +//===----------------------------------------------------------------------===// +// PCHWriter Implementation +//===----------------------------------------------------------------------===// + +void PCHWriter::WriteDeclsBlockAbbrevs() { + using namespace llvm; + // Abbreviation for DECL_PARM_VAR. + BitCodeAbbrev *Abv = new BitCodeAbbrev(); + Abv->Add(BitCodeAbbrevOp(pch::DECL_PARM_VAR)); + + // Decl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location + Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) + Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs + Abv->Add(BitCodeAbbrevOp(0)); // isImplicit + Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier + Abv->Add(BitCodeAbbrevOp(0)); // PCH level + + // NamedDecl + Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name + // ValueDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type + // DeclaratorDecl + Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType + // VarDecl + Abv->Add(BitCodeAbbrevOp(0)); // StorageClass + Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten + Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified + Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer + Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition + Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable + Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable + Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl + Abv->Add(BitCodeAbbrevOp(0)); // HasInit + // ParmVarDecl + Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier + Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg + + ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv); +} + +/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by +/// consumers of the AST. +/// +/// Such decls will always be deserialized from the PCH file, so we would like +/// this to be as restrictive as possible. Currently the predicate is driven by +/// code generation requirements, if other clients have a different notion of +/// what is "required" then we may have to consider an alternate scheme where +/// clients can iterate over the top-level decls and get information on them, +/// without necessary deserializing them. We could explicitly require such +/// clients to use a separate API call to "realize" the decl. This should be +/// relatively painless since they would presumably only do it for top-level +/// decls. +// +// FIXME: This predicate is essentially IRgen's predicate to determine whether a +// declaration can be deferred. Merge them somehow. +static bool isRequiredDecl(const Decl *D, ASTContext &Context) { + // File scoped assembly must be seen. + if (isa<FileScopeAsmDecl>(D)) + return true; + + // Otherwise if this isn't a function or a file scoped variable it doesn't + // need to be seen. + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!VD->isFileVarDecl()) + return false; + } else if (!isa<FunctionDecl>(D)) + return false; + + // Aliases and used decls must be seen. + if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>()) + return true; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Forward declarations don't need to be seen. + if (!FD->isThisDeclarationADefinition()) + return false; + + // Constructors and destructors must be seen. + if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) + return true; + + // Otherwise, this is required unless it is static. + // + // FIXME: Inlines. + return FD->getStorageClass() != FunctionDecl::Static; + } else { + const VarDecl *VD = cast<VarDecl>(D); + + // In C++, this doesn't need to be seen if it is marked "extern". + if (Context.getLangOptions().CPlusPlus && !VD->getInit() && + (VD->getStorageClass() == VarDecl::Extern || + VD->isExternC())) + return false; + + // In C, this doesn't need to be seen unless it is a definition. + if (!Context.getLangOptions().CPlusPlus && !VD->getInit()) + return false; + + // Otherwise, this is required unless it is static. + return VD->getStorageClass() != VarDecl::Static; + } +} + +void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { + RecordData Record; + PCHDeclWriter W(*this, Context, Record); + + // If this declaration is also a DeclContext, write blocks for the + // declarations that lexically stored inside its context and those + // declarations that are visible from its context. These blocks + // are written before the declaration itself so that we can put + // their offsets into the record for the declaration. + uint64_t LexicalOffset = 0; + uint64_t VisibleOffset = 0; + DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) { + LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); + VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); + } + + // Determine the ID for this declaration + pch::DeclID &ID = DeclIDs[D]; + if (ID == 0) + ID = DeclIDs.size(); + + unsigned Index = ID - 1; + + // Record the offset for this declaration + if (DeclOffsets.size() == Index) + DeclOffsets.push_back(Stream.GetCurrentBitNo()); + else if (DeclOffsets.size() < Index) { + DeclOffsets.resize(Index+1); + DeclOffsets[Index] = Stream.GetCurrentBitNo(); + } + + // Build and emit a record for this declaration + Record.clear(); + W.Code = (pch::DeclCode)0; + W.AbbrevToUse = 0; + W.Visit(D); + if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); + + if (!W.Code) + llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") + + D->getDeclKindName() + "'"); + Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); + + // If the declaration had any attributes, write them now. + if (D->hasAttrs()) + WriteAttributeRecord(D->getAttrs()); + + // Flush any expressions that were written as part of this declaration. + FlushStmts(); + + // Note "external" declarations so that we can add them to a record in the + // PCH file later. + // + // FIXME: This should be renamed, the predicate is much more complicated. + if (isRequiredDecl(D, Context)) + ExternalDefinitions.push_back(Index + 1); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp new file mode 100644 index 0000000..a9ee435 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PCHWriterStmt.cpp @@ -0,0 +1,1101 @@ +//===--- PCHWriterStmt.cpp - Statement and Expression Serialization -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements serialization for Statements and Expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PCHWriter.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/Bitcode/BitstreamWriter.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Statement/expression serialization +//===----------------------------------------------------------------------===// + +namespace { + class PCHStmtWriter : public StmtVisitor<PCHStmtWriter, void> { + PCHWriter &Writer; + PCHWriter::RecordData &Record; + + public: + pch::StmtCode Code; + + PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) + : Writer(Writer), Record(Record) { } + + void VisitStmt(Stmt *S); + void VisitNullStmt(NullStmt *S); + void VisitCompoundStmt(CompoundStmt *S); + void VisitSwitchCase(SwitchCase *S); + void VisitCaseStmt(CaseStmt *S); + void VisitDefaultStmt(DefaultStmt *S); + void VisitLabelStmt(LabelStmt *S); + void VisitIfStmt(IfStmt *S); + void VisitSwitchStmt(SwitchStmt *S); + void VisitWhileStmt(WhileStmt *S); + void VisitDoStmt(DoStmt *S); + void VisitForStmt(ForStmt *S); + void VisitGotoStmt(GotoStmt *S); + void VisitIndirectGotoStmt(IndirectGotoStmt *S); + void VisitContinueStmt(ContinueStmt *S); + void VisitBreakStmt(BreakStmt *S); + void VisitReturnStmt(ReturnStmt *S); + void VisitDeclStmt(DeclStmt *S); + void VisitAsmStmt(AsmStmt *S); + void VisitExpr(Expr *E); + void VisitPredefinedExpr(PredefinedExpr *E); + void VisitDeclRefExpr(DeclRefExpr *E); + void VisitIntegerLiteral(IntegerLiteral *E); + void VisitFloatingLiteral(FloatingLiteral *E); + void VisitImaginaryLiteral(ImaginaryLiteral *E); + void VisitStringLiteral(StringLiteral *E); + void VisitCharacterLiteral(CharacterLiteral *E); + void VisitParenExpr(ParenExpr *E); + void VisitUnaryOperator(UnaryOperator *E); + void VisitOffsetOfExpr(OffsetOfExpr *E); + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitArraySubscriptExpr(ArraySubscriptExpr *E); + void VisitCallExpr(CallExpr *E); + void VisitMemberExpr(MemberExpr *E); + void VisitCastExpr(CastExpr *E); + void VisitBinaryOperator(BinaryOperator *E); + void VisitCompoundAssignOperator(CompoundAssignOperator *E); + void VisitConditionalOperator(ConditionalOperator *E); + void VisitImplicitCastExpr(ImplicitCastExpr *E); + void VisitExplicitCastExpr(ExplicitCastExpr *E); + void VisitCStyleCastExpr(CStyleCastExpr *E); + void VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + void VisitExtVectorElementExpr(ExtVectorElementExpr *E); + void VisitInitListExpr(InitListExpr *E); + void VisitDesignatedInitExpr(DesignatedInitExpr *E); + void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); + void VisitVAArgExpr(VAArgExpr *E); + void VisitAddrLabelExpr(AddrLabelExpr *E); + void VisitStmtExpr(StmtExpr *E); + void VisitTypesCompatibleExpr(TypesCompatibleExpr *E); + void VisitChooseExpr(ChooseExpr *E); + void VisitGNUNullExpr(GNUNullExpr *E); + void VisitShuffleVectorExpr(ShuffleVectorExpr *E); + void VisitBlockExpr(BlockExpr *E); + void VisitBlockDeclRefExpr(BlockDeclRefExpr *E); + + // Objective-C Expressions + void VisitObjCStringLiteral(ObjCStringLiteral *E); + void VisitObjCEncodeExpr(ObjCEncodeExpr *E); + void VisitObjCSelectorExpr(ObjCSelectorExpr *E); + void VisitObjCProtocolExpr(ObjCProtocolExpr *E); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E); + void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); + void VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E); + void VisitObjCMessageExpr(ObjCMessageExpr *E); + void VisitObjCSuperExpr(ObjCSuperExpr *E); + void VisitObjCIsaExpr(ObjCIsaExpr *E); + + // Objective-C Statements + void VisitObjCForCollectionStmt(ObjCForCollectionStmt *); + void VisitObjCAtCatchStmt(ObjCAtCatchStmt *); + void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *); + void VisitObjCAtTryStmt(ObjCAtTryStmt *); + void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *); + void VisitObjCAtThrowStmt(ObjCAtThrowStmt *); + + // C++ Statements + void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); + void VisitCXXMemberCallExpr(CXXMemberCallExpr *E); + void VisitCXXConstructExpr(CXXConstructExpr *E); + void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + void VisitCXXConstCastExpr(CXXConstCastExpr *E); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); + void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); + void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void VisitCXXThisExpr(CXXThisExpr *E); + void VisitCXXThrowExpr(CXXThrowExpr *E); + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); + + void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + void VisitCXXNewExpr(CXXNewExpr *E); + + void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); + }; +} + +void PCHStmtWriter::VisitStmt(Stmt *S) { +} + +void PCHStmtWriter::VisitNullStmt(NullStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getSemiLoc(), Record); + Code = pch::STMT_NULL; +} + +void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); + Record.push_back(S->size()); + for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end(); + CS != CSEnd; ++CS) + Writer.WriteSubStmt(*CS); + Writer.AddSourceLocation(S->getLBracLoc(), Record); + Writer.AddSourceLocation(S->getRBracLoc(), Record); + Code = pch::STMT_COMPOUND; +} + +void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); + Record.push_back(Writer.RecordSwitchCaseID(S)); +} + +void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) { + VisitSwitchCase(S); + Writer.WriteSubStmt(S->getLHS()); + Writer.WriteSubStmt(S->getRHS()); + Writer.WriteSubStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getCaseLoc(), Record); + Writer.AddSourceLocation(S->getEllipsisLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); + Code = pch::STMT_CASE; +} + +void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) { + VisitSwitchCase(S); + Writer.WriteSubStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getDefaultLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); + Code = pch::STMT_DEFAULT; +} + +void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + Writer.AddIdentifierRef(S->getID(), Record); + Writer.WriteSubStmt(S->getSubStmt()); + Writer.AddSourceLocation(S->getIdentLoc(), Record); + Record.push_back(Writer.GetLabelID(S)); + Code = pch::STMT_LABEL; +} + +void PCHStmtWriter::VisitIfStmt(IfStmt *S) { + VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); + Writer.WriteSubStmt(S->getCond()); + Writer.WriteSubStmt(S->getThen()); + Writer.WriteSubStmt(S->getElse()); + Writer.AddSourceLocation(S->getIfLoc(), Record); + Writer.AddSourceLocation(S->getElseLoc(), Record); + Code = pch::STMT_IF; +} + +void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); + Writer.WriteSubStmt(S->getCond()); + Writer.WriteSubStmt(S->getBody()); + Writer.AddSourceLocation(S->getSwitchLoc(), Record); + for (SwitchCase *SC = S->getSwitchCaseList(); SC; + SC = SC->getNextSwitchCase()) + Record.push_back(Writer.getSwitchCaseID(SC)); + Code = pch::STMT_SWITCH; +} + +void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); + Writer.AddDeclRef(S->getConditionVariable(), Record); + Writer.WriteSubStmt(S->getCond()); + Writer.WriteSubStmt(S->getBody()); + Writer.AddSourceLocation(S->getWhileLoc(), Record); + Code = pch::STMT_WHILE; +} + +void PCHStmtWriter::VisitDoStmt(DoStmt *S) { + VisitStmt(S); + Writer.WriteSubStmt(S->getCond()); + Writer.WriteSubStmt(S->getBody()); + Writer.AddSourceLocation(S->getDoLoc(), Record); + Writer.AddSourceLocation(S->getWhileLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Code = pch::STMT_DO; +} + +void PCHStmtWriter::VisitForStmt(ForStmt *S) { + VisitStmt(S); + Writer.WriteSubStmt(S->getInit()); + Writer.WriteSubStmt(S->getCond()); + Writer.AddDeclRef(S->getConditionVariable(), Record); + Writer.WriteSubStmt(S->getInc()); + Writer.WriteSubStmt(S->getBody()); + Writer.AddSourceLocation(S->getForLoc(), Record); + Writer.AddSourceLocation(S->getLParenLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Code = pch::STMT_FOR; +} + +void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + Record.push_back(Writer.GetLabelID(S->getLabel())); + Writer.AddSourceLocation(S->getGotoLoc(), Record); + Writer.AddSourceLocation(S->getLabelLoc(), Record); + Code = pch::STMT_GOTO; +} + +void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getGotoLoc(), Record); + Writer.AddSourceLocation(S->getStarLoc(), Record); + Writer.WriteSubStmt(S->getTarget()); + Code = pch::STMT_INDIRECT_GOTO; +} + +void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getContinueLoc(), Record); + Code = pch::STMT_CONTINUE; +} + +void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getBreakLoc(), Record); + Code = pch::STMT_BREAK; +} + +void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); + Writer.WriteSubStmt(S->getRetValue()); + Writer.AddSourceLocation(S->getReturnLoc(), Record); + Writer.AddDeclRef(S->getNRVOCandidate(), Record); + Code = pch::STMT_RETURN; +} + +void PCHStmtWriter::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getStartLoc(), Record); + Writer.AddSourceLocation(S->getEndLoc(), Record); + DeclGroupRef DG = S->getDeclGroup(); + for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D) + Writer.AddDeclRef(*D, Record); + Code = pch::STMT_DECL; +} + +void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + Record.push_back(S->getNumOutputs()); + Record.push_back(S->getNumInputs()); + Record.push_back(S->getNumClobbers()); + Writer.AddSourceLocation(S->getAsmLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Record.push_back(S->isVolatile()); + Record.push_back(S->isSimple()); + Record.push_back(S->isMSAsm()); + Writer.WriteSubStmt(S->getAsmString()); + + // Outputs + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record); + Writer.WriteSubStmt(S->getOutputConstraintLiteral(I)); + Writer.WriteSubStmt(S->getOutputExpr(I)); + } + + // Inputs + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + Writer.AddIdentifierRef(S->getInputIdentifier(I), Record); + Writer.WriteSubStmt(S->getInputConstraintLiteral(I)); + Writer.WriteSubStmt(S->getInputExpr(I)); + } + + // Clobbers + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) + Writer.WriteSubStmt(S->getClobber(I)); + + Code = pch::STMT_ASM; +} + +void PCHStmtWriter::VisitExpr(Expr *E) { + VisitStmt(E); + Writer.AddTypeRef(E->getType(), Record); + Record.push_back(E->isTypeDependent()); + Record.push_back(E->isValueDependent()); +} + +void PCHStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->getIdentType()); // FIXME: stable encoding + Code = pch::EXPR_PREDEFINED; +} + +void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getDecl(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); + // FIXME: write qualifier + // FIXME: write explicit template arguments + Code = pch::EXPR_DECL_REF; +} + +void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Writer.AddAPInt(E->getValue(), Record); + Code = pch::EXPR_INTEGER_LITERAL; +} + +void PCHStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) { + VisitExpr(E); + Writer.AddAPFloat(E->getValue(), Record); + Record.push_back(E->isExact()); + Writer.AddSourceLocation(E->getLocation(), Record); + Code = pch::EXPR_FLOATING_LITERAL; +} + +void PCHStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_IMAGINARY_LITERAL; +} + +void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) { + VisitExpr(E); + Record.push_back(E->getByteLength()); + Record.push_back(E->getNumConcatenated()); + Record.push_back(E->isWide()); + // FIXME: String data should be stored as a blob at the end of the + // StringLiteral. However, we can't do so now because we have no + // provision for coping with abbreviations when we're jumping around + // the PCH file during deserialization. + Record.insert(Record.end(), + E->getStrData(), E->getStrData() + E->getByteLength()); + for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I) + Writer.AddSourceLocation(E->getStrTokenLoc(I), Record); + Code = pch::EXPR_STRING_LITERAL; +} + +void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->isWide()); + Code = pch::EXPR_CHARACTER_LITERAL; +} + +void PCHStmtWriter::VisitParenExpr(ParenExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLParen(), Record); + Writer.AddSourceLocation(E->getRParen(), Record); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_PAREN; +} + +void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getSubExpr()); + Record.push_back(E->getOpcode()); // FIXME: stable encoding + Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Code = pch::EXPR_UNARY_OPERATOR; +} + +void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumComponents()); + Record.push_back(E->getNumExpressions()); + Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I); + Record.push_back(ON.getKind()); // FIXME: Stable encoding + Writer.AddSourceLocation(ON.getRange().getBegin(), Record); + Writer.AddSourceLocation(ON.getRange().getEnd(), Record); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + Record.push_back(ON.getArrayExprIndex()); + break; + + case OffsetOfExpr::OffsetOfNode::Field: + Writer.AddDeclRef(ON.getField(), Record); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + Writer.AddIdentifierRef(ON.getFieldName(), Record); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // FIXME: Implement this! + llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); + break; + } + } + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + Writer.WriteSubStmt(E->getIndexExpr(I)); + Code = pch::EXPR_OFFSETOF; +} + +void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { + VisitExpr(E); + Record.push_back(E->isSizeOf()); + if (E->isArgumentType()) + Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); + else { + Record.push_back(0); + Writer.WriteSubStmt(E->getArgumentExpr()); + } + Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_SIZEOF_ALIGN_OF; +} + +void PCHStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getLHS()); + Writer.WriteSubStmt(E->getRHS()); + Writer.AddSourceLocation(E->getRBracketLoc(), Record); + Code = pch::EXPR_ARRAY_SUBSCRIPT; +} + +void PCHStmtWriter::VisitCallExpr(CallExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumArgs()); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Writer.WriteSubStmt(E->getCallee()); + for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) + Writer.WriteSubStmt(*Arg); + Code = pch::EXPR_CALL; +} + +void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getBase()); + Writer.AddDeclRef(E->getMemberDecl(), Record); + Writer.AddSourceLocation(E->getMemberLoc(), Record); + Record.push_back(E->isArrow()); + // FIXME: C++ nested-name-specifier + // FIXME: C++ template argument list + Code = pch::EXPR_MEMBER; +} + +void PCHStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getBase()); + Writer.AddSourceLocation(E->getIsaMemberLoc(), Record); + Record.push_back(E->isArrow()); + Code = pch::EXPR_OBJC_ISA; +} + +void PCHStmtWriter::VisitCastExpr(CastExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getSubExpr()); + Record.push_back(E->getCastKind()); // FIXME: stable encoding +} + +void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getLHS()); + Writer.WriteSubStmt(E->getRHS()); + Record.push_back(E->getOpcode()); // FIXME: stable encoding + Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Code = pch::EXPR_BINARY_OPERATOR; +} + +void PCHStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { + VisitBinaryOperator(E); + Writer.AddTypeRef(E->getComputationLHSType(), Record); + Writer.AddTypeRef(E->getComputationResultType(), Record); + Code = pch::EXPR_COMPOUND_ASSIGN_OPERATOR; +} + +void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getCond()); + Writer.WriteSubStmt(E->getLHS()); + Writer.WriteSubStmt(E->getRHS()); + Writer.AddSourceLocation(E->getQuestionLoc(), Record); + Writer.AddSourceLocation(E->getColonLoc(), Record); + Code = pch::EXPR_CONDITIONAL_OPERATOR; +} + +void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) { + VisitCastExpr(E); + Record.push_back(E->isLvalueCast()); + Code = pch::EXPR_IMPLICIT_CAST; +} + +void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) { + VisitCastExpr(E); + Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record); +} + +void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getLParenLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CSTYLE_CAST; +} + +void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLParenLoc(), Record); + Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); + Writer.WriteSubStmt(E->getInitializer()); + Record.push_back(E->isFileScope()); + Code = pch::EXPR_COMPOUND_LITERAL; +} + +void PCHStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getBase()); + Writer.AddIdentifierRef(&E->getAccessor(), Record); + Writer.AddSourceLocation(E->getAccessorLoc(), Record); + Code = pch::EXPR_EXT_VECTOR_ELEMENT; +} + +void PCHStmtWriter::VisitInitListExpr(InitListExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumInits()); + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) + Writer.WriteSubStmt(E->getInit(I)); + Writer.WriteSubStmt(E->getSyntacticForm()); + Writer.AddSourceLocation(E->getLBraceLoc(), Record); + Writer.AddSourceLocation(E->getRBraceLoc(), Record); + Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); + Record.push_back(E->hadArrayRangeDesignator()); + Code = pch::EXPR_INIT_LIST; +} + +void PCHStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumSubExprs()); + for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) + Writer.WriteSubStmt(E->getSubExpr(I)); + Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record); + Record.push_back(E->usesGNUSyntax()); + for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), + DEnd = E->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + if (FieldDecl *Field = D->getField()) { + Record.push_back(pch::DESIG_FIELD_DECL); + Writer.AddDeclRef(Field, Record); + } else { + Record.push_back(pch::DESIG_FIELD_NAME); + Writer.AddIdentifierRef(D->getFieldName(), Record); + } + Writer.AddSourceLocation(D->getDotLoc(), Record); + Writer.AddSourceLocation(D->getFieldLoc(), Record); + } else if (D->isArrayDesignator()) { + Record.push_back(pch::DESIG_ARRAY); + Record.push_back(D->getFirstExprIndex()); + Writer.AddSourceLocation(D->getLBracketLoc(), Record); + Writer.AddSourceLocation(D->getRBracketLoc(), Record); + } else { + assert(D->isArrayRangeDesignator() && "Unknown designator"); + Record.push_back(pch::DESIG_ARRAY_RANGE); + Record.push_back(D->getFirstExprIndex()); + Writer.AddSourceLocation(D->getLBracketLoc(), Record); + Writer.AddSourceLocation(D->getEllipsisLoc(), Record); + Writer.AddSourceLocation(D->getRBracketLoc(), Record); + } + } + Code = pch::EXPR_DESIGNATED_INIT; +} + +void PCHStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { + VisitExpr(E); + Code = pch::EXPR_IMPLICIT_VALUE_INIT; +} + +void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getSubExpr()); + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_VA_ARG; +} + +void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getAmpAmpLoc(), Record); + Writer.AddSourceLocation(E->getLabelLoc(), Record); + Record.push_back(Writer.GetLabelID(E->getLabel())); + Code = pch::EXPR_ADDR_LABEL; +} + +void PCHStmtWriter::VisitStmtExpr(StmtExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getSubStmt()); + Writer.AddSourceLocation(E->getLParenLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_STMT; +} + +void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { + VisitExpr(E); + Writer.AddTypeRef(E->getArgType1(), Record); + Writer.AddTypeRef(E->getArgType2(), Record); + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_TYPES_COMPATIBLE; +} + +void PCHStmtWriter::VisitChooseExpr(ChooseExpr *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getCond()); + Writer.WriteSubStmt(E->getLHS()); + Writer.WriteSubStmt(E->getRHS()); + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CHOOSE; +} + +void PCHStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getTokenLocation(), Record); + Code = pch::EXPR_GNU_NULL; +} + +void PCHStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumSubExprs()); + for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) + Writer.WriteSubStmt(E->getExpr(I)); + Writer.AddSourceLocation(E->getBuiltinLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_SHUFFLE_VECTOR; +} + +void PCHStmtWriter::VisitBlockExpr(BlockExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getBlockDecl(), Record); + Record.push_back(E->hasBlockDeclRefExprs()); + Code = pch::EXPR_BLOCK; +} + +void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getDecl(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->isByRef()); + Record.push_back(E->isConstQualAdded()); + Code = pch::EXPR_BLOCK_DECL_REF; +} + +//===----------------------------------------------------------------------===// +// Objective-C Expressions and Statements. +//===----------------------------------------------------------------------===// + +void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) { + VisitExpr(E); + Writer.WriteSubStmt(E->getString()); + Writer.AddSourceLocation(E->getAtLoc(), Record); + Code = pch::EXPR_OBJC_STRING_LITERAL; +} + +void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + VisitExpr(E); + Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record); + Writer.AddSourceLocation(E->getAtLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_OBJC_ENCODE; +} + +void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { + VisitExpr(E); + Writer.AddSelectorRef(E->getSelector(), Record); + Writer.AddSourceLocation(E->getAtLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_OBJC_SELECTOR_EXPR; +} + +void PCHStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getProtocol(), Record); + Writer.AddSourceLocation(E->getAtLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_OBJC_PROTOCOL_EXPR; +} + +void PCHStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getDecl(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); + Writer.WriteSubStmt(E->getBase()); + Record.push_back(E->isArrow()); + Record.push_back(E->isFreeIvar()); + Code = pch::EXPR_OBJC_IVAR_REF_EXPR; +} + +void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getProperty(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); + Writer.WriteSubStmt(E->getBase()); + Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR; +} + +void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getGetterMethod(), Record); + Writer.AddDeclRef(E->getSetterMethod(), Record); + + // NOTE: InterfaceDecl and Base are mutually exclusive. + Writer.AddDeclRef(E->getInterfaceDecl(), Record); + Writer.WriteSubStmt(E->getBase()); + Writer.AddSourceLocation(E->getLocation(), Record); + Writer.AddSourceLocation(E->getClassLoc(), Record); + Code = pch::EXPR_OBJC_KVC_REF_EXPR; +} + +void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumArgs()); + Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding + switch (E->getReceiverKind()) { + case ObjCMessageExpr::Instance: + Writer.WriteSubStmt(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + Writer.AddTypeRef(E->getSuperType(), Record); + Writer.AddSourceLocation(E->getSuperLoc(), Record); + break; + } + + if (E->getMethodDecl()) { + Record.push_back(1); + Writer.AddDeclRef(E->getMethodDecl(), Record); + } else { + Record.push_back(0); + Writer.AddSelectorRef(E->getSelector(), Record); + } + + Writer.AddSourceLocation(E->getLeftLoc(), Record); + Writer.AddSourceLocation(E->getRightLoc(), Record); + + for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) + Writer.WriteSubStmt(*Arg); + Code = pch::EXPR_OBJC_MESSAGE_EXPR; +} + +void PCHStmtWriter::VisitObjCSuperExpr(ObjCSuperExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLoc(), Record); + Code = pch::EXPR_OBJC_SUPER_EXPR; +} + +void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); + Writer.WriteSubStmt(S->getElement()); + Writer.WriteSubStmt(S->getCollection()); + Writer.WriteSubStmt(S->getBody()); + Writer.AddSourceLocation(S->getForLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Code = pch::STMT_OBJC_FOR_COLLECTION; +} + +void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + Writer.WriteSubStmt(S->getCatchBody()); + Writer.AddDeclRef(S->getCatchParamDecl(), Record); + Writer.AddSourceLocation(S->getAtCatchLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Code = pch::STMT_OBJC_CATCH; +} + +void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + Writer.WriteSubStmt(S->getFinallyBody()); + Writer.AddSourceLocation(S->getAtFinallyLoc(), Record); + Code = pch::STMT_OBJC_FINALLY; +} + +void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + Record.push_back(S->getNumCatchStmts()); + Record.push_back(S->getFinallyStmt() != 0); + Writer.WriteSubStmt(S->getTryBody()); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) + Writer.WriteSubStmt(S->getCatchStmt(I)); + if (S->getFinallyStmt()) + Writer.WriteSubStmt(S->getFinallyStmt()); + Writer.AddSourceLocation(S->getAtTryLoc(), Record); + Code = pch::STMT_OBJC_AT_TRY; +} + +void PCHStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + Writer.WriteSubStmt(S->getSynchExpr()); + Writer.WriteSubStmt(S->getSynchBody()); + Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record); + Code = pch::STMT_OBJC_AT_SYNCHRONIZED; +} + +void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + Writer.WriteSubStmt(S->getThrowExpr()); + Writer.AddSourceLocation(S->getThrowLoc(), Record); + Code = pch::STMT_OBJC_AT_THROW; +} + +//===----------------------------------------------------------------------===// +// C++ Expressions and Statements. +//===----------------------------------------------------------------------===// + +void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + VisitCallExpr(E); + Record.push_back(E->getOperator()); + Code = pch::EXPR_CXX_OPERATOR_CALL; +} + +void PCHStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { + VisitCallExpr(E); + Code = pch::EXPR_CXX_MEMBER_CALL; +} + +void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { + VisitExpr(E); + Writer.AddDeclRef(E->getConstructor(), Record); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->isElidable()); + Record.push_back(E->requiresZeroInitialization()); + Record.push_back(E->getNumArgs()); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) + Writer.WriteSubStmt(E->getArg(I)); + Record.push_back(E->getConstructionKind()); // FIXME: stable encoding + Code = pch::EXPR_CXX_CONSTRUCT; +} + +void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getOperatorLoc(), Record); +} + +void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_STATIC_CAST; +} + +void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_DYNAMIC_CAST; +} + +void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_REINTERPRET_CAST; +} + +void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_CONST_CAST; +} + +void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CXX_FUNCTIONAL_CAST; +} + +void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { + VisitExpr(E); + Record.push_back(E->getValue()); + Writer.AddSourceLocation(E->getLocation(), Record); + Code = pch::EXPR_CXX_BOOL_LITERAL; +} + +void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Code = pch::EXPR_CXX_NULL_PTR_LITERAL; +} + +void PCHStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + VisitExpr(E); + Writer.AddSourceRange(E->getSourceRange(), Record); + if (E->isTypeOperand()) { + Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record); + Code = pch::EXPR_CXX_TYPEID_TYPE; + } else { + Writer.WriteSubStmt(E->getExprOperand()); + Code = pch::EXPR_CXX_TYPEID_EXPR; + } +} + +void PCHStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getLocation(), Record); + Record.push_back(E->isImplicit()); + Code = pch::EXPR_CXX_THIS; +} + +void PCHStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getThrowLoc(), Record); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_THROW; +} + +void PCHStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getUsedLocation(), Record); + if (E->isExprStored()) { + Record.push_back(1); + Writer.WriteSubStmt(E->getExpr()); + } else { + Record.push_back(0); + } + + Code = pch::EXPR_CXX_DEFAULT_ARG; +} + +void PCHStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + VisitExpr(E); + Writer.AddCXXTemporary(E->getTemporary(), Record); + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_BIND_TEMPORARY; +} + +void PCHStmtWriter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + VisitExpr(E); + Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CXX_ZERO_INIT_VALUE; +} + +void PCHStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { + VisitExpr(E); + Record.push_back(E->isGlobalNew()); + Record.push_back(E->isParenTypeId()); + Record.push_back(E->hasInitializer()); + Record.push_back(E->isArray()); + Record.push_back(E->getNumPlacementArgs()); + Record.push_back(E->getNumConstructorArgs()); + Writer.AddDeclRef(E->getOperatorNew(), Record); + Writer.AddDeclRef(E->getOperatorDelete(), Record); + Writer.AddDeclRef(E->getConstructor(), Record); + Writer.AddSourceLocation(E->getStartLoc(), Record); + Writer.AddSourceLocation(E->getEndLoc(), Record); + for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end(); + I != e; ++I) + Writer.WriteSubStmt(*I); + + Code = pch::EXPR_CXX_NEW; +} + + +void PCHStmtWriter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { + VisitExpr(E); + Record.push_back(E->getNumTemporaries()); + for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i) + Writer.AddCXXTemporary(E->getTemporary(i), Record); + + Writer.WriteSubStmt(E->getSubExpr()); + Code = pch::EXPR_CXX_EXPR_WITH_TEMPORARIES; +} + + +//===----------------------------------------------------------------------===// +// PCHWriter Implementation +//===----------------------------------------------------------------------===// + +unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) { + assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() && + "SwitchCase recorded twice"); + unsigned NextID = SwitchCaseIDs.size(); + SwitchCaseIDs[S] = NextID; + return NextID; +} + +unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) { + assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() && + "SwitchCase hasn't been seen yet"); + return SwitchCaseIDs[S]; +} + +/// \brief Retrieve the ID for the given label statement, which may +/// or may not have been emitted yet. +unsigned PCHWriter::GetLabelID(LabelStmt *S) { + std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S); + if (Pos != LabelIDs.end()) + return Pos->second; + + unsigned NextID = LabelIDs.size(); + LabelIDs[S] = NextID; + return NextID; +} + +/// \brief Write the given substatement or subexpression to the +/// bitstream. +void PCHWriter::WriteSubStmt(Stmt *S) { + RecordData Record; + PCHStmtWriter Writer(*this, Record); + ++NumStatements; + + if (!S) { + Stream.EmitRecord(pch::STMT_NULL_PTR, Record); + return; + } + + Writer.Code = pch::STMT_NULL_PTR; + Writer.Visit(S); + +#ifndef NDEBUG + if (Writer.Code == pch::STMT_NULL_PTR) { + S->dump(); + assert(0 && "Unhandled sub statement writing PCH file"); + } +#endif + Stream.EmitRecord(Writer.Code, Record); +} + +/// \brief Flush all of the statements that have been added to the +/// queue via AddStmt(). +void PCHWriter::FlushStmts() { + RecordData Record; + PCHStmtWriter Writer(*this, Record); + + for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) { + ++NumStatements; + Stmt *S = StmtsToEmit[I]; + + if (!S) { + Stream.EmitRecord(pch::STMT_NULL_PTR, Record); + continue; + } + + Writer.Code = pch::STMT_NULL_PTR; + Writer.Visit(S); +#ifndef NDEBUG + if (Writer.Code == pch::STMT_NULL_PTR) { + S->dump(); + assert(0 && "Unhandled expression writing PCH file"); + } +#endif + Stream.EmitRecord(Writer.Code, Record); + + assert(N == StmtsToEmit.size() && + "Substatement writen via AddStmt rather than WriteSubStmt!"); + + // Note that we are at the end of a full expression. Any + // expression records that follow this one are part of a different + // expression. + Record.clear(); + Stream.EmitRecord(pch::STMT_STOP, Record); + } + + StmtsToEmit.clear(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PlistDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Frontend/PlistDiagnostics.cpp new file mode 100644 index 0000000..5706a07 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PlistDiagnostics.cpp @@ -0,0 +1,471 @@ +//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PlistDiagnostics object. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PathDiagnosticClients.h" +#include "clang/Checker/BugReporter/PathDiagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +using namespace clang; +using llvm::cast; + +typedef llvm::DenseMap<FileID, unsigned> FIDMap; + +namespace clang { + class Preprocessor; +} + +namespace { +struct CompareDiagnostics { + // Compare if 'X' is "<" than 'Y'. + bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { + // First compare by location + const FullSourceLoc &XLoc = X->getLocation().asLocation(); + const FullSourceLoc &YLoc = Y->getLocation().asLocation(); + if (XLoc < YLoc) + return true; + if (XLoc != YLoc) + return false; + + // Next, compare by bug type. + llvm::StringRef XBugType = X->getBugType(); + llvm::StringRef YBugType = Y->getBugType(); + if (XBugType < YBugType) + return true; + if (XBugType != YBugType) + return false; + + // Next, compare by bug description. + llvm::StringRef XDesc = X->getDescription(); + llvm::StringRef YDesc = Y->getDescription(); + if (XDesc < YDesc) + return true; + if (XDesc != YDesc) + return false; + + // FIXME: Further refine by comparing PathDiagnosticPieces? + return false; + } +}; +} + +namespace { + class PlistDiagnostics : public PathDiagnosticClient { + std::vector<const PathDiagnostic*> BatchedDiags; + const std::string OutputFile; + const LangOptions &LangOpts; + llvm::OwningPtr<PathDiagnosticClient> SubPD; + bool flushed; + public: + PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, + PathDiagnosticClient *subPD); + + ~PlistDiagnostics() { FlushDiagnostics(NULL); } + + void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); + + void HandlePathDiagnostic(const PathDiagnostic* D); + + virtual llvm::StringRef getName() const { + return "PlistDiagnostics"; + } + + PathGenerationScheme getGenerationScheme() const; + bool supportsLogicalOpControlFlow() const { return true; } + bool supportsAllBlockEdges() const { return true; } + virtual bool useVerboseDescription() const { return false; } + }; +} // end anonymous namespace + +PlistDiagnostics::PlistDiagnostics(const std::string& output, + const LangOptions &LO, + PathDiagnosticClient *subPD) + : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} + +PathDiagnosticClient* +clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP, + PathDiagnosticClient *subPD) { + return new PlistDiagnostics(s, PP.getLangOptions(), subPD); +} + +PathDiagnosticClient::PathGenerationScheme +PlistDiagnostics::getGenerationScheme() const { + if (const PathDiagnosticClient *PD = SubPD.get()) + return PD->getGenerationScheme(); + + return Extensive; +} + +static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V, + const SourceManager* SM, SourceLocation L) { + + FileID FID = SM->getFileID(SM->getInstantiationLoc(L)); + FIDMap::iterator I = FIDs.find(FID); + if (I != FIDs.end()) return; + FIDs[FID] = V.size(); + V.push_back(FID); +} + +static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, + SourceLocation L) { + FileID FID = SM.getFileID(SM.getInstantiationLoc(L)); + FIDMap::const_iterator I = FIDs.find(FID); + assert(I != FIDs.end()); + return I->second; +} + +static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) { + for (unsigned i = 0; i < indent; ++i) o << ' '; + return o; +} + +static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation L, const FIDMap &FM, + unsigned indent, bool extend = false) { + + FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<SourceManager&>(SM)); + + // Add in the length of the token, so that we cover multi-char tokens. + unsigned offset = + extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; + + Indent(o, indent) << "<dict>\n"; + Indent(o, indent) << " <key>line</key><integer>" + << Loc.getInstantiationLineNumber() << "</integer>\n"; + Indent(o, indent) << " <key>col</key><integer>" + << Loc.getInstantiationColumnNumber() + offset << "</integer>\n"; + Indent(o, indent) << " <key>file</key><integer>" + << GetFID(FM, SM, Loc) << "</integer>\n"; + Indent(o, indent) << "</dict>\n"; +} + +static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + const PathDiagnosticLocation &L, const FIDMap& FM, + unsigned indent, bool extend = false) { + EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); +} + +static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM, + const LangOptions &LangOpts, + PathDiagnosticRange R, const FIDMap &FM, + unsigned indent) { + Indent(o, indent) << "<array>\n"; + EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); + EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint); + Indent(o, indent) << "</array>\n"; +} + +static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, + const std::string& s) { + o << "<string>"; + for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { + char c = *I; + switch (c) { + default: o << c; break; + case '&': o << "&"; break; + case '<': o << "<"; break; + case '>': o << ">"; break; + case '\'': o << "'"; break; + case '\"': o << """; break; + } + } + o << "</string>"; + return o; +} + +static void ReportControlFlow(llvm::raw_ostream& o, + const PathDiagnosticControlFlowPiece& P, + const FIDMap& FM, + const SourceManager &SM, + const LangOptions &LangOpts, + unsigned indent) { + + Indent(o, indent) << "<dict>\n"; + ++indent; + + Indent(o, indent) << "<key>kind</key><string>control</string>\n"; + + // Emit edges. + Indent(o, indent) << "<key>edges</key>\n"; + ++indent; + Indent(o, indent) << "<array>\n"; + ++indent; + for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end(); + I!=E; ++I) { + Indent(o, indent) << "<dict>\n"; + ++indent; + Indent(o, indent) << "<key>start</key>\n"; + EmitRange(o, SM, LangOpts, I->getStart().asRange(), FM, indent+1); + Indent(o, indent) << "<key>end</key>\n"; + EmitRange(o, SM, LangOpts, I->getEnd().asRange(), FM, indent+1); + --indent; + Indent(o, indent) << "</dict>\n"; + } + --indent; + Indent(o, indent) << "</array>\n"; + --indent; + + // Output any helper text. + const std::string& s = P.getString(); + if (!s.empty()) { + Indent(o, indent) << "<key>alternate</key>"; + EmitString(o, s) << '\n'; + } + + --indent; + Indent(o, indent) << "</dict>\n"; +} + +static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, + const FIDMap& FM, + const SourceManager &SM, + const LangOptions &LangOpts, + unsigned indent) { + + Indent(o, indent) << "<dict>\n"; + ++indent; + + Indent(o, indent) << "<key>kind</key><string>event</string>\n"; + + // Output the location. + FullSourceLoc L = P.getLocation().asLocation(); + + Indent(o, indent) << "<key>location</key>\n"; + EmitLocation(o, SM, LangOpts, L, FM, indent); + + // Output the ranges (if any). + PathDiagnosticPiece::range_iterator RI = P.ranges_begin(), + RE = P.ranges_end(); + + if (RI != RE) { + Indent(o, indent) << "<key>ranges</key>\n"; + Indent(o, indent) << "<array>\n"; + ++indent; + for (; RI != RE; ++RI) + EmitRange(o, SM, LangOpts, *RI, FM, indent+1); + --indent; + Indent(o, indent) << "</array>\n"; + } + + // Output the text. + assert(!P.getString().empty()); + Indent(o, indent) << "<key>extended_message</key>\n"; + Indent(o, indent); + EmitString(o, P.getString()) << '\n'; + + // Output the short text. + // FIXME: Really use a short string. + Indent(o, indent) << "<key>message</key>\n"; + EmitString(o, P.getString()) << '\n'; + + // Finish up. + --indent; + Indent(o, indent); o << "</dict>\n"; +} + +static void ReportMacro(llvm::raw_ostream& o, + const PathDiagnosticMacroPiece& P, + const FIDMap& FM, const SourceManager &SM, + const LangOptions &LangOpts, + unsigned indent) { + + for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end(); + I!=E; ++I) { + + switch ((*I)->getKind()) { + default: + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, + indent); + break; + } + } +} + +static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, + const FIDMap& FM, const SourceManager &SM, + const LangOptions &LangOpts) { + + unsigned indent = 4; + + switch (P.getKind()) { + case PathDiagnosticPiece::ControlFlow: + ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, + LangOpts, indent); + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, + indent); + break; + } +} + +void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { + if (!D) + return; + + if (D->empty()) { + delete D; + return; + } + + // We need to flatten the locations (convert Stmt* to locations) because + // the referenced statements may be freed by the time the diagnostics + // are emitted. + const_cast<PathDiagnostic*>(D)->flattenLocations(); + BatchedDiags.push_back(D); +} + +void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> + *FilesMade) { + + if (flushed) + return; + + flushed = true; + + // Sort the diagnostics so that they are always emitted in a deterministic + // order. + if (!BatchedDiags.empty()) + std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); + + // Build up a set of FIDs that we use by scanning the locations and + // ranges of the diagnostics. + FIDMap FM; + llvm::SmallVector<FileID, 10> Fids; + const SourceManager* SM = 0; + + if (!BatchedDiags.empty()) + SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager(); + + for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(), + DE = BatchedDiags.end(); DI != DE; ++DI) { + + const PathDiagnostic *D = *DI; + + for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) { + AddFID(FM, Fids, SM, I->getLocation().asLocation()); + + for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(), + RE=I->ranges_end(); RI!=RE; ++RI) { + AddFID(FM, Fids, SM, RI->getBegin()); + AddFID(FM, Fids, SM, RI->getEnd()); + } + } + } + + // Open the file. + std::string ErrMsg; + llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg); + if (!ErrMsg.empty()) { + llvm::errs() << "warning: could not creat file: " << OutputFile << '\n'; + return; + } + + // Write the plist header. + o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "<plist version=\"1.0\">\n"; + + // Write the root object: a <dict> containing... + // - "files", an <array> mapping from FIDs to file names + // - "diagnostics", an <array> containing the path diagnostics + o << "<dict>\n" + " <key>files</key>\n" + " <array>\n"; + + for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); + I!=E; ++I) { + o << " "; + EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; + } + + o << " </array>\n" + " <key>diagnostics</key>\n" + " <array>\n"; + + for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(), + DE = BatchedDiags.end(); DI!=DE; ++DI) { + + o << " <dict>\n" + " <key>path</key>\n"; + + const PathDiagnostic *D = *DI; + // Create an owning smart pointer for 'D' just so that we auto-free it + // when we exit this method. + llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D)); + + o << " <array>\n"; + + for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) + ReportDiag(o, *I, FM, *SM, LangOpts); + + o << " </array>\n"; + + // Output the bug type and bug category. + o << " <key>description</key>"; + EmitString(o, D->getDescription()) << '\n'; + o << " <key>category</key>"; + EmitString(o, D->getCategory()) << '\n'; + o << " <key>type</key>"; + EmitString(o, D->getBugType()) << '\n'; + + // Output the location of the bug. + o << " <key>location</key>\n"; + EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); + + // Output the diagnostic to the sub-diagnostic client, if any. + if (SubPD) { + SubPD->HandlePathDiagnostic(OwnedD.take()); + llvm::SmallVector<std::string, 1> SubFilesMade; + SubPD->FlushDiagnostics(SubFilesMade); + + if (!SubFilesMade.empty()) { + o << " <key>" << SubPD->getName() << "_files</key>\n"; + o << " <array>\n"; + for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i) + o << " <string>" << SubFilesMade[i] << "</string>\n"; + o << " </array>\n"; + } + } + + // Close up the entry. + o << " </dict>\n"; + } + + o << " </array>\n"; + + // Finish. + o << "</dict>\n</plist>"; + + if (FilesMade) + FilesMade->push_back(OutputFile); + + BatchedDiags.clear(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp new file mode 100644 index 0000000..b032233 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintParserCallbacks.cpp @@ -0,0 +1,851 @@ +//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code simply runs the preprocessor on the input file and prints out the +// result. This is the traditional behavior of the -E option. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Parse/Action.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class ParserPrintActions : public MinimalAction { + llvm::raw_ostream& Out; + + public: + ParserPrintActions(Preprocessor &PP, llvm::raw_ostream& OS) + : MinimalAction(PP), Out(OS) {} + + // Printing Functions which also must call MinimalAction + + /// ActOnDeclarator - This callback is invoked when a declarator is parsed + /// and 'Init' specifies the initializer if any. This is for things like: + /// "int X = 4" or "typedef int foo". + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { + Out << __FUNCTION__ << " "; + if (IdentifierInfo *II = D.getIdentifier()) { + Out << "'" << II->getName() << "'"; + } else { + Out << "<anon>"; + } + Out << "\n"; + + // Pass up to EmptyActions so that the symbol table is maintained right. + return MinimalAction::ActOnDeclarator(S, D); + } + /// ActOnPopScope - This callback is called immediately before the specified + /// scope is popped and deleted. + virtual void ActOnPopScope(SourceLocation Loc, Scope *S) { + Out << __FUNCTION__ << "\n"; + return MinimalAction::ActOnPopScope(Loc, S); + } + + /// ActOnTranslationUnitScope - This callback is called once, immediately + /// after creating the translation unit scope (in Parser::Initialize). + virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { + Out << __FUNCTION__ << "\n"; + MinimalAction::ActOnTranslationUnitScope(Loc, S); + } + + + Action::DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + const DeclPtrTy *ProtoRefs, + unsigned NumProtocols, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, + AttributeList *AttrList) { + Out << __FUNCTION__ << "\n"; + return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc, + ClassName, ClassLoc, + SuperName, SuperLoc, + ProtoRefs, NumProtocols, + ProtoLocs, EndProtoLoc, + AttrList); + } + + /// ActOnForwardClassDeclaration - + /// Scope will always be top level file scope. + Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + unsigned NumElts) { + Out << __FUNCTION__ << "\n"; + return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList, + IdentLocs, NumElts); + } + + // Pure Printing + + /// ActOnParamDeclarator - This callback is invoked when a parameter + /// declarator is parsed. This callback only occurs for functions + /// with prototypes. S is the function prototype scope for the + /// parameters (C++ [basic.scope.proto]). + virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) { + Out << __FUNCTION__ << " "; + if (IdentifierInfo *II = D.getIdentifier()) { + Out << "'" << II->getName() << "'"; + } else { + Out << "<anon>"; + } + Out << "\n"; + return DeclPtrTy(); + } + + /// AddInitializerToDecl - This action is called immediately after + /// ParseDeclarator (when an initializer is present). The code is factored + /// this way to make sure we are able to handle the following: + /// void func() { int xx = xx; } + /// This allows ActOnDeclarator to register "xx" prior to parsing the + /// initializer. The declaration above should still result in a warning, + /// since the reference to "xx" is uninitialized. + virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) { + Out << __FUNCTION__ << "\n"; + } + + /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, + /// this gives the actions implementation a chance to process the group as + /// a whole. + virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS, + DeclPtrTy *Group, + unsigned NumDecls) { + Out << __FUNCTION__ << "\n"; + return DeclGroupPtrTy(); + } + + /// ActOnStartOfFunctionDef - This is called at the start of a function + /// definition, instead of calling ActOnDeclarator. The Declarator includes + /// information about formal arguments that are part of this function. + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, + Declarator &D){ + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + /// ActOnStartOfFunctionDef - This is called at the start of a function + /// definition, after the FunctionDecl has already been created. + virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { + Out << __FUNCTION__ << "\n"; + } + + /// ActOnFunctionDefBody - This is called when a function body has completed + /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef. + virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, + ExprArg AsmString) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with + /// no declarator (e.g. "struct foo;") is parsed. + virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + /// ActOnLinkageSpec - Parsed a C++ linkage-specification that + /// contained braces. Lang/StrSize contains the language string that + /// was parsed at location Loc. Decls/NumDecls provides the + /// declarations parsed inside the linkage specification. + virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, + SourceLocation LBrace, + SourceLocation RBrace, const char *Lang, + unsigned StrSize, + DeclPtrTy *Decls, unsigned NumDecls) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + /// ActOnLinkageSpec - Parsed a C++ linkage-specification without + /// braces. Lang/StrSize contains the language string that was + /// parsed at location Loc. D is the declaration parsed. + virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, const char *Lang, + unsigned StrSize, DeclPtrTy D) { + return DeclPtrTy(); + } + + //===------------------------------------------------------------------===// + // Type Parsing Callbacks. + //===------------------------------------------------------------------===// + + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { + Out << __FUNCTION__ << "\n"; + return TypeResult(); + } + + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent) { + // TagType is an instance of DeclSpec::TST, indicating what kind of tag this + // is (struct/union/enum/class). + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + /// Act on @defs() element found when parsing a structure. ClassName is the + /// name of the referenced class. + virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + llvm::SmallVectorImpl<DeclPtrTy> &Decls) { + Out << __FUNCTION__ << "\n"; + } + + virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD, + SourceLocation DeclStart, + Declarator &D, ExprTy *BitfieldWidth) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + DeclPtrTy IntfDecl, + Declarator &D, ExprTy *BitfieldWidth, + tok::ObjCKeywordKind visibility) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl, + DeclPtrTy *Fields, unsigned NumFields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *AttrList) { + Out << __FUNCTION__ << "\n"; + } + + virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, + DeclPtrTy LastEnumConstant, + SourceLocation IdLoc,IdentifierInfo *Id, + SourceLocation EqualLoc, ExprTy *Val) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, DeclPtrTy EnumDecl, + DeclPtrTy *Elements, unsigned NumElements, + Scope *S, AttributeList *AttrList) { + Out << __FUNCTION__ << "\n"; + } + + //===------------------------------------------------------------------===// + // Statement Parsing Callbacks. + //===------------------------------------------------------------------===// + + virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, + SourceLocation R, + MultiStmtArg Elts, + bool isStmtExpr) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) { + Out << __FUNCTION__ << "\n"; + return OwningStmtResult(*this, Expr->release()); + } + + /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension, + /// which can specify an RHS value. + virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, + ExprArg LHSVal, + SourceLocation DotDotDotLoc, + ExprArg RHSVal, + SourceLocation ColonLoc) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + StmtArg SubStmt, Scope *CurScope){ + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation ColonLoc, + StmtArg SubStmt) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, DeclPtrTy CondVar, + StmtArg ThenVal, + SourceLocation ElseLoc, + StmtArg ElseVal) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + ExprArg Cond, + DeclPtrTy CondVar) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + StmtArg Switch, + StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, + FullExprArg Cond, DeclPtrTy CondVar, + StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, + SourceLocation WhileLoc, + SourceLocation LPLoc, ExprArg Cond, + SourceLocation RPLoc){ + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg First, FullExprArg Second, + DeclPtrTy SecondVar, + FullExprArg Third, + SourceLocation RParenLoc, + StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnObjCForCollectionStmt( + SourceLocation ForColLoc, + SourceLocation LParenLoc, + StmtArg First, ExprArg Second, + SourceLocation RParenLoc, StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + IdentifierInfo *LabelII) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + ExprArg DestExp) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc, + Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc, + Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, + ExprArg RetValExp) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, + bool IsVolatile, + unsigned NumOutputs, + unsigned NumInputs, + IdentifierInfo **Names, + MultiExprArg Constraints, + MultiExprArg Exprs, + ExprArg AsmString, + MultiExprArg Clobbers, + SourceLocation RParenLoc, + bool MSAsm) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + // Objective-c statements + virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParen, + DeclPtrTy Parm, + StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, + StmtArg Body) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, + StmtArg Try, + MultiStmtArg CatchStmts, + StmtArg Finally) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw, + Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprArg SynchExpr, + StmtArg SynchBody) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + // C++ Statements + virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + DeclPtrTy ExceptionDecl, + StmtArg HandlerBlock) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, + StmtArg TryBlock, + MultiStmtArg Handlers) { + Out << __FUNCTION__ << "\n"; + return StmtEmpty(); + } + + //===------------------------------------------------------------------===// + // Expression Parsing Callbacks. + //===------------------------------------------------------------------===// + + // Primary Expressions. + + /// ActOnIdentifierExpr - Parse an identifier in expression context. + /// 'HasTrailingLParen' indicates whether or not the identifier has a '(' + /// token immediately after it. + virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, + IdentifierInfo &II, + bool HasTrailingLParen, + const CXXScopeSpec *SS, + bool isAddressOfOperand) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( + Scope *S, SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + bool HasTrailingLParen, const CXXScopeSpec &SS, + bool isAddressOfOperand) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXConversionFunctionExpr( + Scope *S, SourceLocation OperatorLoc, + TypeTy *Type, bool HasTrailingLParen, + const CXXScopeSpec &SS,bool isAddressOfOperand) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, + tok::TokenKind Kind) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCharacterConstant(const Token &) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnNumericConstant(const Token &) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + virtual OwningExprResult ActOnStringLiteral(const Token *Toks, + unsigned NumToks) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, + ExprArg Val) { + Out << __FUNCTION__ << "\n"; + return move(Val); // Default impl returns operand. + } + + // Postfix Expressions. + virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, + ExprArg Input) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base, + SourceLocation LLoc, + ExprArg Idx, + SourceLocation RLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation MemberLoc, + IdentifierInfo &Member, + DeclPtrTy ImplDecl, + const CXXScopeSpec *SS=0) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn, + SourceLocation LParenLoc, + MultiExprArg Args, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + // Unary Operators. 'Tok' is the token for the operator. + virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, ExprArg Input) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + virtual OwningExprResult + ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, + void *TyOrEx, const SourceRange &ArgRange) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen, + ExprArg Op) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, + MultiExprArg InitList, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + TypeTy *Ty, SourceLocation RParenLoc, + ExprArg Op) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, + ExprArg LHS, ExprArg RHS) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + ExprArg Cond, ExprArg LHS, + ExprArg RHS) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + //===--------------------- GNU Extension Expressions ------------------===// + + virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc, + SourceLocation LabLoc, + IdentifierInfo *LabelII) {// "&&foo" + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, + StmtArg SubStmt, + SourceLocation RPLoc) { // "({..})" + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *Arg1, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + // __builtin_types_compatible_p(type1, type2) + virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeTy *arg1,TypeTy *arg2, + SourceLocation RPLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + // __builtin_choose_expr(constExpr, expr1, expr2) + virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + ExprArg cond, ExprArg expr1, + ExprArg expr2, + SourceLocation RPLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + // __builtin_va_arg(expr, type) + virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprArg expr, TypeTy *type, + SourceLocation RPLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + } + + virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, + StmtArg Body, + Scope *CurScope) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace, + AttributeList *AttrList) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) { + Out << __FUNCTION__ << "\n"; + return; + } + +#if 0 + // FIXME: AttrList should be deleted by this function, but the definition + // would have to be available. + virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } +#endif + + virtual void ActOnParamDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc, + ExprArg defarg) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, + SourceLocation EqualLoc, + SourceLocation ArgLoc) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { + Out << __FUNCTION__ << "\n"; + } + + virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return; + } + + virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) { + Out << __FUNCTION__ << "\n"; + } + + virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, + DeclPtrTy Method) { + Out << __FUNCTION__ << "\n"; + } + + virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + ExprArg AssertExpr, + ExprArg AssertMessageExpr) { + Out << __FUNCTION__ << "\n"; + return DeclPtrTy(); + } + + virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + TypeTy *Ty, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + ExprArg Op, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, + bool isType, void *TyOrExpr, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, + tok::TokenKind Kind) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, + TypeTy *TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, + SourceLocation StartLoc, + Declarator &D, + SourceLocation EqualLoc, + ExprArg AssignExprVal) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, + bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + bool ParenTypeId, Declarator &D, + SourceLocation ConstructorLParen, + MultiExprArg ConstructorArgs, + SourceLocation ConstructorRParen) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + ExprArg Operand) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + + virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + SourceLocation LParen, + TypeTy *Ty, + SourceLocation RParen) { + Out << __FUNCTION__ << "\n"; + return ExprEmpty(); + } + }; +} + +MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP, + llvm::raw_ostream* OS) { + return new ParserPrintActions(PP, *OS); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp new file mode 100644 index 0000000..b6c18b7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -0,0 +1,520 @@ +//===--- PrintPreprocessedOutput.cpp - Implement the -E mode --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code simply runs the preprocessor on the input file and prints out the +// result. This is the traditional behavior of the -E option. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Pragma.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/TokenConcatenation.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> +using namespace clang; + +/// PrintMacroDefinition - Print a macro definition in a form that will be +/// properly accepted back as a definition. +static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, + Preprocessor &PP, llvm::raw_ostream &OS) { + OS << "#define " << II.getName(); + + if (MI.isFunctionLike()) { + OS << '('; + if (!MI.arg_empty()) { + MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); + for (; AI+1 != E; ++AI) { + OS << (*AI)->getName(); + OS << ','; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + OS << "..."; + else + OS << (*AI)->getName(); + } + + if (MI.isGNUVarargs()) + OS << "..."; // #define foo(x...) + + OS << ')'; + } + + // GCC always emits a space, even if the macro body is empty. However, do not + // want to emit two spaces if the first token has a leading space. + if (MI.tokens_empty() || !MI.tokens_begin()->hasLeadingSpace()) + OS << ' '; + + llvm::SmallString<128> SpellingBuffer; + for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end(); + I != E; ++I) { + if (I->hasLeadingSpace()) + OS << ' '; + + OS << PP.getSpelling(*I, SpellingBuffer); + } +} + +//===----------------------------------------------------------------------===// +// Preprocessed token printer +//===----------------------------------------------------------------------===// + +namespace { +class PrintPPOutputPPCallbacks : public PPCallbacks { + Preprocessor &PP; + SourceManager &SM; + TokenConcatenation ConcatInfo; +public: + llvm::raw_ostream &OS; +private: + unsigned CurLine; + bool EmittedTokensOnThisLine; + bool EmittedMacroOnThisLine; + SrcMgr::CharacteristicKind FileType; + llvm::SmallString<512> CurFilename; + bool Initialized; + bool DisableLineMarkers; + bool DumpDefines; + bool UseLineDirective; +public: + PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, + bool lineMarkers, bool defines) + : PP(pp), SM(PP.getSourceManager()), + ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), + DumpDefines(defines) { + CurLine = 0; + CurFilename += "<uninit>"; + EmittedTokensOnThisLine = false; + EmittedMacroOnThisLine = false; + FileType = SrcMgr::C_User; + Initialized = false; + + // If we're in microsoft mode, use normal #line instead of line markers. + UseLineDirective = PP.getLangOptions().Microsoft; + } + + void SetEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; } + bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType); + virtual void Ident(SourceLocation Loc, const std::string &str); + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str); + + + bool HandleFirstTokOnLine(Token &Tok); + bool MoveToLine(SourceLocation Loc) { + return MoveToLine(SM.getPresumedLoc(Loc).getLine()); + } + bool MoveToLine(unsigned LineNo); + + bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, + const Token &Tok) { + return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok); + } + void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0); + + void HandleNewlinesInToken(const char *TokStr, unsigned Len); + + /// MacroDefined - This hook is called whenever a macro definition is seen. + void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI); + +}; +} // end anonymous namespace + +void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, + const char *Extra, + unsigned ExtraLen) { + if (EmittedTokensOnThisLine || EmittedMacroOnThisLine) { + OS << '\n'; + EmittedTokensOnThisLine = false; + EmittedMacroOnThisLine = false; + } + + // Emit #line directives or GNU line markers depending on what mode we're in. + if (UseLineDirective) { + OS << "#line" << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + } else { + OS << '#' << ' ' << LineNo << ' ' << '"'; + OS.write(&CurFilename[0], CurFilename.size()); + OS << '"'; + + if (ExtraLen) + OS.write(Extra, ExtraLen); + + if (FileType == SrcMgr::C_System) + OS.write(" 3", 2); + else if (FileType == SrcMgr::C_ExternCSystem) + OS.write(" 3 4", 4); + } + OS << '\n'; +} + +/// MoveToLine - Move the output to the source line specified by the location +/// object. We can do this by emitting some number of \n's, or be emitting a +/// #line directive. This returns false if already at the specified line, true +/// if some newlines were emitted. +bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) { + if (DisableLineMarkers) { + if (LineNo == CurLine) return false; + + CurLine = LineNo; + + if (!EmittedTokensOnThisLine && !EmittedMacroOnThisLine) + return true; + + OS << '\n'; + EmittedTokensOnThisLine = false; + EmittedMacroOnThisLine = false; + return true; + } + + // If this line is "close enough" to the original line, just print newlines, + // otherwise print a #line directive. + if (LineNo-CurLine <= 8) { + if (LineNo-CurLine == 1) + OS << '\n'; + else if (LineNo == CurLine) + return false; // Spelling line moved, but instantiation line didn't. + else { + const char *NewLines = "\n\n\n\n\n\n\n\n"; + OS.write(NewLines, LineNo-CurLine); + } + } else { + WriteLineInfo(LineNo, 0, 0); + } + + CurLine = LineNo; + return true; +} + + +/// FileChanged - Whenever the preprocessor enters or exits a #include file +/// it invokes this handler. Update our conception of the current source +/// position. +void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, + FileChangeReason Reason, + SrcMgr::CharacteristicKind NewFileType) { + // Unless we are exiting a #include, make sure to skip ahead to the line the + // #include directive was at. + SourceManager &SourceMgr = SM; + + PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc); + unsigned NewLine = UserLoc.getLine(); + + if (Reason == PPCallbacks::EnterFile) { + SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc(); + if (IncludeLoc.isValid()) + MoveToLine(IncludeLoc); + } else if (Reason == PPCallbacks::SystemHeaderPragma) { + MoveToLine(NewLine); + + // TODO GCC emits the # directive for this directive on the line AFTER the + // directive and emits a bunch of spaces that aren't needed. Emulate this + // strange behavior. + } + + CurLine = NewLine; + + if (DisableLineMarkers) return; + + CurFilename.clear(); + CurFilename += UserLoc.getFilename(); + Lexer::Stringify(CurFilename); + FileType = NewFileType; + + if (!Initialized) { + WriteLineInfo(CurLine); + Initialized = true; + } + + switch (Reason) { + case PPCallbacks::EnterFile: + WriteLineInfo(CurLine, " 1", 2); + break; + case PPCallbacks::ExitFile: + WriteLineInfo(CurLine, " 2", 2); + break; + case PPCallbacks::SystemHeaderPragma: + case PPCallbacks::RenameFile: + WriteLineInfo(CurLine); + break; + } +} + +/// Ident - Handle #ident directives when read by the preprocessor. +/// +void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { + MoveToLine(Loc); + + OS.write("#ident ", strlen("#ident ")); + OS.write(&S[0], S.size()); + EmittedTokensOnThisLine = true; +} + +/// MacroDefined - This hook is called whenever a macro definition is seen. +void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II, + const MacroInfo *MI) { + // Only print out macro definitions in -dD mode. + if (!DumpDefines || + // Ignore __FILE__ etc. + MI->isBuiltinMacro()) return; + + MoveToLine(MI->getDefinitionLoc()); + PrintMacroDefinition(*II, *MI, PP, OS); + EmittedMacroOnThisLine = true; +} + + +void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, + const IdentifierInfo *Kind, + const std::string &Str) { + MoveToLine(Loc); + OS << "#pragma comment(" << Kind->getName(); + + if (!Str.empty()) { + OS << ", \""; + + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + unsigned char Char = Str[i]; + if (isprint(Char) && Char != '\\' && Char != '"') + OS << (char)Char; + else // Output anything hard as an octal escape. + OS << '\\' + << (char)('0'+ ((Char >> 6) & 7)) + << (char)('0'+ ((Char >> 3) & 7)) + << (char)('0'+ ((Char >> 0) & 7)); + } + OS << '"'; + } + + OS << ')'; + EmittedTokensOnThisLine = true; +} + + +/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this +/// is called for the first token on each new line. If this really is the start +/// of a new logical line, handle it and return true, otherwise return false. +/// This may not be the start of a logical line because the "start of line" +/// marker is set for spelling lines, not instantiation ones. +bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) { + // Figure out what line we went to and insert the appropriate number of + // newline characters. + if (!MoveToLine(Tok.getLocation())) + return false; + + // Print out space characters so that the first token on a line is + // indented for easy reading. + unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation()); + + // This hack prevents stuff like: + // #define HASH # + // HASH define foo bar + // From having the # character end up at column 1, which makes it so it + // is not handled as a #define next time through the preprocessor if in + // -fpreprocessed mode. + if (ColNo <= 1 && Tok.is(tok::hash)) + OS << ' '; + + // Otherwise, indent the appropriate number of spaces. + for (; ColNo > 1; --ColNo) + OS << ' '; + + return true; +} + +void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr, + unsigned Len) { + unsigned NumNewlines = 0; + for (; Len; --Len, ++TokStr) { + if (*TokStr != '\n' && + *TokStr != '\r') + continue; + + ++NumNewlines; + + // If we have \n\r or \r\n, skip both and count as one line. + if (Len != 1 && + (TokStr[1] == '\n' || TokStr[1] == '\r') && + TokStr[0] != TokStr[1]) + ++TokStr, --Len; + } + + if (NumNewlines == 0) return; + + CurLine += NumNewlines; +} + + +namespace { +struct UnknownPragmaHandler : public PragmaHandler { + const char *Prefix; + PrintPPOutputPPCallbacks *Callbacks; + + UnknownPragmaHandler(const char *prefix, PrintPPOutputPPCallbacks *callbacks) + : PragmaHandler(0), Prefix(prefix), Callbacks(callbacks) {} + virtual void HandlePragma(Preprocessor &PP, Token &PragmaTok) { + // Figure out what line we went to and insert the appropriate number of + // newline characters. + Callbacks->MoveToLine(PragmaTok.getLocation()); + Callbacks->OS.write(Prefix, strlen(Prefix)); + + // Read and print all of the pragma tokens. + while (PragmaTok.isNot(tok::eom)) { + if (PragmaTok.hasLeadingSpace()) + Callbacks->OS << ' '; + std::string TokSpell = PP.getSpelling(PragmaTok); + Callbacks->OS.write(&TokSpell[0], TokSpell.size()); + PP.LexUnexpandedToken(PragmaTok); + } + Callbacks->OS << '\n'; + } +}; +} // end anonymous namespace + + +static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, + PrintPPOutputPPCallbacks *Callbacks, + llvm::raw_ostream &OS) { + char Buffer[256]; + Token PrevPrevTok; + Token PrevTok; + while (1) { + + // If this token is at the start of a line, emit newlines if needed. + if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) { + // done. + } else if (Tok.hasLeadingSpace() || + // If we haven't emitted a token on this line yet, PrevTok isn't + // useful to look at and no concatenation could happen anyway. + (Callbacks->hasEmittedTokensOnThisLine() && + // Don't print "-" next to "-", it would form "--". + Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) { + OS << ' '; + } + + if (IdentifierInfo *II = Tok.getIdentifierInfo()) { + OS << II->getName(); + } else if (Tok.isLiteral() && !Tok.needsCleaning() && + Tok.getLiteralData()) { + OS.write(Tok.getLiteralData(), Tok.getLength()); + } else if (Tok.getLength() < 256) { + const char *TokPtr = Buffer; + unsigned Len = PP.getSpelling(Tok, TokPtr); + OS.write(TokPtr, Len); + + // Tokens that can contain embedded newlines need to adjust our current + // line number. + if (Tok.getKind() == tok::comment) + Callbacks->HandleNewlinesInToken(TokPtr, Len); + } else { + std::string S = PP.getSpelling(Tok); + OS.write(&S[0], S.size()); + + // Tokens that can contain embedded newlines need to adjust our current + // line number. + if (Tok.getKind() == tok::comment) + Callbacks->HandleNewlinesInToken(&S[0], S.size()); + } + Callbacks->SetEmittedTokensOnThisLine(); + + if (Tok.is(tok::eof)) break; + + PrevPrevTok = PrevTok; + PrevTok = Tok; + PP.Lex(Tok); + } +} + +typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; +static int MacroIDCompare(const void* a, const void* b) { + const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a); + const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b); + return LHS->first->getName().compare(RHS->first->getName()); +} + +static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { + // -dM mode just scans and ignores all tokens in the files, then dumps out + // the macro table at the end. + PP.EnterMainSourceFile(); + + Token Tok; + do PP.Lex(Tok); + while (Tok.isNot(tok::eof)); + + llvm::SmallVector<id_macro_pair, 128> + MacrosByID(PP.macro_begin(), PP.macro_end()); + llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); + + for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { + MacroInfo &MI = *MacrosByID[i].second; + // Ignore computed macros like __LINE__ and friends. + if (MI.isBuiltinMacro()) continue; + + PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS); + *OS << '\n'; + } +} + +/// DoPrintPreprocessedInput - This implements -E mode. +/// +void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, + const PreprocessorOutputOptions &Opts) { + // Show macros with no output is handled specially. + if (!Opts.ShowCPP) { + assert(Opts.ShowMacros && "Not yet implemented!"); + DoPrintMacros(PP, OS); + return; + } + + // Inform the preprocessor whether we want it to retain comments or not, due + // to -C or -CC. + PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); + + PrintPPOutputPPCallbacks *Callbacks = + new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, + Opts.ShowMacros); + PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks)); + PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC", + Callbacks)); + + PP.addPPCallbacks(Callbacks); + + // After we have configured the preprocessor, enter the main file. + PP.EnterMainSourceFile(); + + // Consume all of the tokens that come from the predefines buffer. Those + // should not be emitted into the output and are guaranteed to be at the + // start. + const SourceManager &SourceMgr = PP.getSourceManager(); + Token Tok; + do PP.Lex(Tok); + while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() && + !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(), + "<built-in>")); + + // Read all the preprocessed tokens, printing them out to the stream. + PrintPreprocessedTokens(PP, Tok, Callbacks, *OS); + *OS << '\n'; +} + diff --git a/contrib/llvm/tools/clang/lib/Frontend/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Frontend/RewriteMacros.cpp new file mode 100644 index 0000000..954e8e2 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/RewriteMacros.cpp @@ -0,0 +1,217 @@ +//===--- RewriteMacros.cpp - Rewrite macros into their expansions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This code rewrites macro invocations into their expansions. This gives you +// a macro expanded file that retains comments and #includes. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/OwningPtr.h" +#include <cstdio> + +using namespace clang; + +/// isSameToken - Return true if the two specified tokens start have the same +/// content. +static bool isSameToken(Token &RawTok, Token &PPTok) { + // If two tokens have the same kind and the same identifier info, they are + // obviously the same. + if (PPTok.getKind() == RawTok.getKind() && + PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) + return true; + + // Otherwise, if they are different but have the same identifier info, they + // are also considered to be the same. This allows keywords and raw lexed + // identifiers with the same name to be treated the same. + if (PPTok.getIdentifierInfo() && + PPTok.getIdentifierInfo() == RawTok.getIdentifierInfo()) + return true; + + return false; +} + + +/// GetNextRawTok - Return the next raw token in the stream, skipping over +/// comments if ReturnComment is false. +static const Token &GetNextRawTok(const std::vector<Token> &RawTokens, + unsigned &CurTok, bool ReturnComment) { + assert(CurTok < RawTokens.size() && "Overran eof!"); + + // If the client doesn't want comments and we have one, skip it. + if (!ReturnComment && RawTokens[CurTok].is(tok::comment)) + ++CurTok; + + return RawTokens[CurTok++]; +} + + +/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into +/// the specified vector. +static void LexRawTokensFromMainFile(Preprocessor &PP, + std::vector<Token> &RawTokens) { + SourceManager &SM = PP.getSourceManager(); + + // Create a lexer to lex all the tokens of the main file in raw mode. Even + // though it is in raw mode, it will not return comments. + const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); + + // Switch on comment lexing because we really do want them. + RawLex.SetCommentRetentionState(true); + + Token RawTok; + do { + RawLex.LexFromRawLexer(RawTok); + + // If we have an identifier with no identifier info for our raw token, look + // up the indentifier info. This is important for equality comparison of + // identifier tokens. + if (RawTok.is(tok::identifier) && !RawTok.getIdentifierInfo()) + PP.LookUpIdentifierInfo(RawTok); + + RawTokens.push_back(RawTok); + } while (RawTok.isNot(tok::eof)); +} + + +/// RewriteMacrosInInput - Implement -rewrite-macros mode. +void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { + SourceManager &SM = PP.getSourceManager(); + + Rewriter Rewrite; + Rewrite.setSourceMgr(SM, PP.getLangOptions()); + RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID()); + + std::vector<Token> RawTokens; + LexRawTokensFromMainFile(PP, RawTokens); + unsigned CurRawTok = 0; + Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + + + // Get the first preprocessing token. + PP.EnterMainSourceFile(); + Token PPTok; + PP.Lex(PPTok); + + // Preprocess the input file in parallel with raw lexing the main file. Ignore + // all tokens that are preprocessed from a file other than the main file (e.g. + // a header). If we see tokens that are in the preprocessed file but not the + // lexed file, we have a macro expansion. If we see tokens in the lexed file + // that aren't in the preprocessed view, we have macros that expand to no + // tokens, or macro arguments etc. + while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { + SourceLocation PPLoc = SM.getInstantiationLoc(PPTok.getLocation()); + + // If PPTok is from a different source file, ignore it. + if (!SM.isFromMainFile(PPLoc)) { + PP.Lex(PPTok); + continue; + } + + // If the raw file hits a preprocessor directive, they will be extra tokens + // in the raw file that don't exist in the preprocsesed file. However, we + // choose to preserve them in the output file and otherwise handle them + // specially. + if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) { + // If this is a #warning directive or #pragma mark (GNU extensions), + // comment the line out. + if (RawTokens[CurRawTok].is(tok::identifier)) { + const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); + if (II->getName() == "warning") { + // Comment out #warning. + RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); + } else if (II->getName() == "pragma" && + RawTokens[CurRawTok+1].is(tok::identifier) && + (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == + "mark")) { + // Comment out #pragma mark. + RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); + } + } + + // Otherwise, if this is a #include or some other directive, just leave it + // in the file by skipping over the line. + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof)) + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + continue; + } + + // Okay, both tokens are from the same file. Get their offsets from the + // start of the file. + unsigned PPOffs = SM.getFileOffset(PPLoc); + unsigned RawOffs = SM.getFileOffset(RawTok.getLocation()); + + // If the offsets are the same and the token kind is the same, ignore them. + if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) { + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + PP.Lex(PPTok); + continue; + } + + // If the PP token is farther along than the raw token, something was + // deleted. Comment out the raw token. + if (RawOffs <= PPOffs) { + // Comment out a whole run of tokens instead of bracketing each one with + // comments. Add a leading space if RawTok didn't have one. + bool HasSpace = RawTok.hasLeadingSpace(); + RB.InsertTextAfter(RawOffs, " /*"+HasSpace); + unsigned EndPos; + + do { + EndPos = RawOffs+RawTok.getLength(); + + RawTok = GetNextRawTok(RawTokens, CurRawTok, true); + RawOffs = SM.getFileOffset(RawTok.getLocation()); + + if (RawTok.is(tok::comment)) { + // Skip past the comment. + RawTok = GetNextRawTok(RawTokens, CurRawTok, false); + break; + } + + } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() && + (PPOffs != RawOffs || !isSameToken(RawTok, PPTok))); + + RB.InsertTextBefore(EndPos, "*/"); + continue; + } + + // Otherwise, there was a replacement an expansion. Insert the new token + // in the output buffer. Insert the whole run of new tokens at once to get + // them in the right order. + unsigned InsertPos = PPOffs; + std::string Expansion; + while (PPOffs < RawOffs) { + Expansion += ' ' + PP.getSpelling(PPTok); + PP.Lex(PPTok); + PPLoc = SM.getInstantiationLoc(PPTok.getLocation()); + PPOffs = SM.getFileOffset(PPLoc); + } + Expansion += ' '; + RB.InsertTextBefore(InsertPos, Expansion); + } + + // Get the buffer corresponding to MainFileID. If we haven't changed it, then + // we are done. + if (const RewriteBuffer *RewriteBuf = + Rewrite.getRewriteBufferFor(SM.getMainFileID())) { + //printf("Changed:\n"); + *OS << std::string(RewriteBuf->begin(), RewriteBuf->end()); + } else { + fprintf(stderr, "No changes\n"); + } + OS->flush(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Frontend/RewriteObjC.cpp new file mode 100644 index 0000000..5dd7bdf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/RewriteObjC.cpp @@ -0,0 +1,5778 @@ +//===--- RewriteObjC.cpp - Playground for the code rewriter ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Hacks and fun related to the code rewriter. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ParentMap.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/DenseSet.h" + +using namespace clang; +using llvm::utostr; + +namespace { + class RewriteObjC : public ASTConsumer { + enum { + BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), + block, ... */ + BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */ + BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the + __block variable */ + BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy + helpers */ + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose + support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 + }; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CXX_OBJ = (1 << 26), + BLOCK_IS_GC = (1 << 27), + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_DESCRIPTOR = (1 << 29) + }; + + Rewriter Rewrite; + Diagnostic &Diags; + const LangOptions &LangOpts; + unsigned RewriteFailedDiag; + unsigned TryFinallyContainsReturnDiag; + + ASTContext *Context; + SourceManager *SM; + TranslationUnitDecl *TUDecl; + FileID MainFileID; + const char *MainFileStart, *MainFileEnd; + SourceLocation LastIncLoc; + + llvm::SmallVector<ObjCImplementationDecl *, 8> ClassImplementation; + llvm::SmallVector<ObjCCategoryImplDecl *, 8> CategoryImplementation; + llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCSynthesizedStructs; + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> ObjCSynthesizedProtocols; + llvm::SmallPtrSet<ObjCInterfaceDecl*, 8> ObjCForwardDecls; + llvm::DenseMap<ObjCMethodDecl*, std::string> MethodInternalNames; + llvm::SmallVector<Stmt *, 32> Stmts; + llvm::SmallVector<int, 8> ObjCBcLabelNo; + // Remember all the @protocol(<expr>) expressions. + llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ProtocolExprDecls; + + llvm::DenseSet<uint64_t> CopyDestroyCache; + + unsigned NumObjCStringLiterals; + + FunctionDecl *MsgSendFunctionDecl; + FunctionDecl *MsgSendSuperFunctionDecl; + FunctionDecl *MsgSendStretFunctionDecl; + FunctionDecl *MsgSendSuperStretFunctionDecl; + FunctionDecl *MsgSendFpretFunctionDecl; + FunctionDecl *GetClassFunctionDecl; + FunctionDecl *GetMetaClassFunctionDecl; + FunctionDecl *GetSuperClassFunctionDecl; + FunctionDecl *SelGetUidFunctionDecl; + FunctionDecl *CFStringFunctionDecl; + FunctionDecl *SuperContructorFunctionDecl; + + // ObjC string constant support. + VarDecl *ConstantStringClassReference; + RecordDecl *NSStringRecord; + + // ObjC foreach break/continue generation support. + int BcLabelCount; + + // Needed for super. + ObjCMethodDecl *CurMethodDef; + RecordDecl *SuperStructDecl; + RecordDecl *ConstantStringDecl; + + TypeDecl *ProtocolTypeDecl; + QualType getProtocolType(); + + // Needed for header files being rewritten + bool IsHeader; + + std::string InFileName; + llvm::raw_ostream* OutFile; + + bool SilenceRewriteMacroWarning; + bool objc_impl_method; + + std::string Preamble; + + // Block expressions. + llvm::SmallVector<BlockExpr *, 32> Blocks; + llvm::SmallVector<int, 32> InnerDeclRefsCount; + llvm::SmallVector<BlockDeclRefExpr *, 32> InnerDeclRefs; + + llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs; + + // Block related declarations. + llvm::SmallVector<ValueDecl *, 8> BlockByCopyDecls; + llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet; + llvm::SmallVector<ValueDecl *, 8> BlockByRefDecls; + llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDeclsPtrSet; + llvm::DenseMap<ValueDecl *, unsigned> BlockByRefDeclNo; + llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls; + llvm::SmallPtrSet<VarDecl *, 8> ImportedLocalExternalDecls; + + llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; + + // This maps a property to it's assignment statement. + llvm::DenseMap<ObjCPropertyRefExpr *, BinaryOperator *> PropSetters; + // This maps a property to it's synthesied message expression. + // This allows us to rewrite chained getters (e.g. o.a.b.c). + llvm::DenseMap<ObjCPropertyRefExpr *, Stmt *> PropGetters; + + // This maps an original source AST to it's rewritten form. This allows + // us to avoid rewriting the same node twice (which is very uncommon). + // This is needed to support some of the exotic property rewriting. + llvm::DenseMap<Stmt *, Stmt *> ReplacedNodes; + + FunctionDecl *CurFunctionDef; + FunctionDecl *CurFunctionDeclToDeclareForBlock; + VarDecl *GlobalVarDecl; + + bool DisableReplaceStmt; + + static const int OBJC_ABI_VERSION =7 ; + public: + virtual void Initialize(ASTContext &context); + + // Top Level Driver code. + virtual void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) + HandleTopLevelSingleDecl(*I); + } + void HandleTopLevelSingleDecl(Decl *D); + void HandleDeclInMainFile(Decl *D); + RewriteObjC(std::string inFile, llvm::raw_ostream *OS, + Diagnostic &D, const LangOptions &LOpts, + bool silenceMacroWarn); + + ~RewriteObjC() {} + + virtual void HandleTranslationUnit(ASTContext &C); + + void ReplaceStmt(Stmt *Old, Stmt *New) { + Stmt *ReplacingStmt = ReplacedNodes[Old]; + + if (ReplacingStmt) + return; // We can't rewrite the same node twice. + + if (DisableReplaceStmt) + return; // Used when rewriting the assignment of a property setter. + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceStmt(Old, New)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void ReplaceStmtWithRange(Stmt *Old, Stmt *New, SourceRange SrcRange) { + // Measaure the old text. + int Size = Rewrite.getRangeSize(SrcRange); + if (Size == -1) { + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + return; + } + // Get the new text. + std::string SStr; + llvm::raw_string_ostream S(SStr); + New->printPretty(S, *Context, 0, PrintingPolicy(LangOpts)); + const std::string &Str = S.str(); + + // If replacement succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, Str)) { + ReplacedNodes[Old] = New; + return; + } + if (SilenceRewriteMacroWarning) + return; + Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag) + << Old->getSourceRange(); + } + + void InsertText(SourceLocation Loc, llvm::StringRef Str, + bool InsertAfter = true) { + // If insertion succeeded or warning disabled return with no warning. + if (!Rewrite.InsertText(Loc, Str, InsertAfter) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); + } + + void RemoveText(SourceLocation Loc, unsigned StrLen) { + // If removal succeeded or warning disabled return with no warning. + if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); + } + + void ReplaceText(SourceLocation Start, unsigned OrigLength, + llvm::StringRef Str) { + // If removal succeeded or warning disabled return with no warning. + if (!Rewrite.ReplaceText(Start, OrigLength, Str) || + SilenceRewriteMacroWarning) + return; + + Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag); + } + + // Syntactic Rewriting. + void RewritePrologue(SourceLocation Loc); + void RewriteInclude(); + void RewriteTabs(); + void RewriteForwardClassDecl(ObjCClassDecl *Dcl); + void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID); + void RewriteInterfaceDecl(ObjCInterfaceDecl *Dcl); + void RewriteImplementationDecl(Decl *Dcl); + void RewriteObjCMethodDecl(ObjCMethodDecl *MDecl, std::string &ResultStr); + void RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType); + void RewriteByRefString(std::string &ResultStr, const std::string &Name, + ValueDecl *VD); + void RewriteCategoryDecl(ObjCCategoryDecl *Dcl); + void RewriteProtocolDecl(ObjCProtocolDecl *Dcl); + void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl); + void RewriteMethodDeclaration(ObjCMethodDecl *Method); + void RewriteProperty(ObjCPropertyDecl *prop); + void RewriteFunctionDecl(FunctionDecl *FD); + void RewriteBlockLiteralFunctionDecl(FunctionDecl *FD); + void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl); + void RewriteTypeOfDecl(VarDecl *VD); + void RewriteObjCQualifiedInterfaceTypes(Expr *E); + bool needToScanForQualifiers(QualType T); + bool isSuperReceiver(Expr *recExpr); + QualType getSuperStructType(); + QualType getConstantStringStructType(); + QualType convertFunctionTypeOfBlocks(const FunctionType *FT); + bool BufferContainsPPDirectives(const char *startBuf, const char *endBuf); + + // Expression Rewriting. + Stmt *RewriteFunctionBodyOrGlobalInitializer(Stmt *S); + void CollectPropertySetters(Stmt *S); + + Stmt *CurrentBody; + ParentMap *PropParentMap; // created lazily. + + Stmt *RewriteAtEncode(ObjCEncodeExpr *Exp); + Stmt *RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation OrigStart, + bool &replaced); + Stmt *RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced); + Stmt *RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr); + Stmt *RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, + SourceRange SrcRange); + Stmt *RewriteAtSelector(ObjCSelectorExpr *Exp); + Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp); + Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp); + Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp); + void WarnAboutReturnGotoStmts(Stmt *S); + void HasReturnStmts(Stmt *S, bool &hasReturns); + void RewriteTryReturnStmts(Stmt *S); + void RewriteSyncReturnStmts(Stmt *S, std::string buf); + Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); + Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); + Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); + Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S); + Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); + Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd); + CallExpr *SynthesizeCallToFunctionDecl(FunctionDecl *FD, + Expr **args, unsigned nargs, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + Stmt *SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc=SourceLocation(), + SourceLocation EndLoc=SourceLocation()); + Stmt *RewriteBreakStmt(BreakStmt *S); + Stmt *RewriteContinueStmt(ContinueStmt *S); + void SynthCountByEnumWithState(std::string &buf); + + void SynthMsgSendFunctionDecl(); + void SynthMsgSendSuperFunctionDecl(); + void SynthMsgSendStretFunctionDecl(); + void SynthMsgSendFpretFunctionDecl(); + void SynthMsgSendSuperStretFunctionDecl(); + void SynthGetClassFunctionDecl(); + void SynthGetMetaClassFunctionDecl(); + void SynthGetSuperClassFunctionDecl(); + void SynthSelGetUidFunctionDecl(); + void SynthSuperContructorFunctionDecl(); + + // Metadata emission. + void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result); + + void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl, + std::string &Result); + + template<typename MethodIterator> + void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + const char *prefix, + const char *ClassName, + std::string &Result); + + void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, + const char *prefix, + const char *ClassName, + std::string &Result); + void RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Prots, + const char *prefix, + const char *ClassName, + std::string &Result); + void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result); + void SynthesizeIvarOffsetComputation(ObjCContainerDecl *IDecl, + ObjCIvarDecl *ivar, + std::string &Result); + void RewriteImplementations(); + void SynthesizeMetaDataIntoBuffer(std::string &Result); + + // Block rewriting. + void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D); + void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND); + + void InsertBlockLiteralsWithinFunction(FunctionDecl *FD); + void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); + + // Block specific rewrite rules. + void RewriteBlockCall(CallExpr *Exp); + void RewriteBlockPointerDecl(NamedDecl *VD); + void RewriteByRefVar(VarDecl *VD); + std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); + Stmt *RewriteBlockDeclRefExpr(Expr *VD); + Stmt *RewriteLocalVariableExternalStorage(DeclRefExpr *DRE); + void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); + + std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + const char *funcName, std::string Tag); + std::string SynthesizeBlockFunc(BlockExpr *CE, int i, + const char *funcName, std::string Tag); + std::string SynthesizeBlockImpl(BlockExpr *CE, + std::string Tag, std::string Desc); + std::string SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, + int i, const char *funcName, + unsigned hasCopy); + Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); + void SynthesizeBlockLiterals(SourceLocation FunLocStart, + const char *FunName); + void RewriteRecordBody(RecordDecl *RD); + + void CollectBlockDeclRefInfo(BlockExpr *Exp); + void GetBlockDeclRefExprs(Stmt *S); + void GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, + llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts); + + // We avoid calling Type::isBlockPointerType(), since it operates on the + // canonical type. We only care if the top-level type is a closure pointer. + bool isTopLevelBlockPointerType(QualType T) { + return isa<BlockPointerType>(T); + } + + /// convertBlockPointerToFunctionPointer - Converts a block-pointer type + /// to a function pointer type and upon success, returns true; false + /// otherwise. + bool convertBlockPointerToFunctionPointer(QualType &T) { + if (isTopLevelBlockPointerType(T)) { + const BlockPointerType *BPT = T->getAs<BlockPointerType>(); + T = Context->getPointerType(BPT->getPointeeType()); + return true; + } + return false; + } + + // FIXME: This predicate seems like it would be useful to add to ASTContext. + bool isObjCType(QualType T) { + if (!LangOpts.ObjC1 && !LangOpts.ObjC2) + return false; + + QualType OCT = Context->getCanonicalType(T).getUnqualifiedType(); + + if (OCT == Context->getCanonicalType(Context->getObjCIdType()) || + OCT == Context->getCanonicalType(Context->getObjCClassType())) + return true; + + if (const PointerType *PT = OCT->getAs<PointerType>()) { + if (isa<ObjCInterfaceType>(PT->getPointeeType()) || + PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + return false; + } + bool PointerTypeTakesAnyBlockArguments(QualType QT); + void GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen); + void RewriteCastExpr(CStyleCastExpr *CE); + + FunctionDecl *SynthBlockInitFunctionDecl(const char *name); + Stmt *SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs); + + void QuoteDoublequotes(std::string &From, std::string &To) { + for (unsigned i = 0; i < From.length(); i++) { + if (From[i] == '"') + To += "\\\""; + else + To += From[i]; + } + } + }; + + // Helper function: create a CStyleCastExpr with trivial type source info. + CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, + CastExpr::CastKind Kind, Expr *E) { + TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); + return new (Ctx) CStyleCastExpr(Ty, Kind, E, CXXBaseSpecifierArray(), TInfo, + SourceLocation(), SourceLocation()); + } +} + +void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, + NamedDecl *D) { + if (FunctionProtoType *fproto = dyn_cast<FunctionProtoType>(funcType)) { + for (FunctionProtoType::arg_type_iterator I = fproto->arg_type_begin(), + E = fproto->arg_type_end(); I && (I != E); ++I) + if (isTopLevelBlockPointerType(*I)) { + // All the args are checked/rewritten. Don't call twice! + RewriteBlockPointerDecl(D); + break; + } + } +} + +void RewriteObjC::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) { + const PointerType *PT = funcType->getAs<PointerType>(); + if (PT && PointerTypeTakesAnyBlockArguments(funcType)) + RewriteBlocksInFunctionProtoType(PT->getPointeeType(), ND); +} + +static bool IsHeaderFile(const std::string &Filename) { + std::string::size_type DotPos = Filename.rfind('.'); + + if (DotPos == std::string::npos) { + // no file extension + return false; + } + + std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); + // C header: .h + // C++ header: .hh or .H; + return Ext == "h" || Ext == "hh" || Ext == "H"; +} + +RewriteObjC::RewriteObjC(std::string inFile, llvm::raw_ostream* OS, + Diagnostic &D, const LangOptions &LOpts, + bool silenceMacroWarn) + : Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS), + SilenceRewriteMacroWarning(silenceMacroWarn) { + IsHeader = IsHeaderFile(inFile); + RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning, + "rewriting sub-expression within a macro (may not be correct)"); + TryFinallyContainsReturnDiag = Diags.getCustomDiagID(Diagnostic::Warning, + "rewriter doesn't support user-specified control flow semantics " + "for @try/@finally (code may not execute properly)"); +} + +ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, + llvm::raw_ostream* OS, + Diagnostic &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning) { + return new RewriteObjC(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning); +} + +void RewriteObjC::Initialize(ASTContext &context) { + Context = &context; + SM = &Context->getSourceManager(); + TUDecl = Context->getTranslationUnitDecl(); + MsgSendFunctionDecl = 0; + MsgSendSuperFunctionDecl = 0; + MsgSendStretFunctionDecl = 0; + MsgSendSuperStretFunctionDecl = 0; + MsgSendFpretFunctionDecl = 0; + GetClassFunctionDecl = 0; + GetMetaClassFunctionDecl = 0; + GetSuperClassFunctionDecl = 0; + SelGetUidFunctionDecl = 0; + CFStringFunctionDecl = 0; + ConstantStringClassReference = 0; + NSStringRecord = 0; + CurMethodDef = 0; + CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; + GlobalVarDecl = 0; + SuperStructDecl = 0; + ProtocolTypeDecl = 0; + ConstantStringDecl = 0; + BcLabelCount = 0; + SuperContructorFunctionDecl = 0; + NumObjCStringLiterals = 0; + PropParentMap = 0; + CurrentBody = 0; + DisableReplaceStmt = false; + objc_impl_method = false; + + // Get the ID and start/end of the main file. + MainFileID = SM->getMainFileID(); + const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); + MainFileStart = MainBuf->getBufferStart(); + MainFileEnd = MainBuf->getBufferEnd(); + + Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOptions()); + + // declaring objc_selector outside the parameter list removes a silly + // scope related warning... + if (IsHeader) + Preamble = "#pragma once\n"; + Preamble += "struct objc_selector; struct objc_class;\n"; + Preamble += "struct __rw_objc_super { struct objc_object *object; "; + Preamble += "struct objc_object *superClass; "; + if (LangOpts.Microsoft) { + // Add a constructor for creating temporary objects. + Preamble += "__rw_objc_super(struct objc_object *o, struct objc_object *s) " + ": "; + Preamble += "object(o), superClass(s) {} "; + } + Preamble += "};\n"; + Preamble += "#ifndef _REWRITER_typedef_Protocol\n"; + Preamble += "typedef struct objc_object Protocol;\n"; + Preamble += "#define _REWRITER_typedef_Protocol\n"; + Preamble += "#endif\n"; + if (LangOpts.Microsoft) { + Preamble += "#define __OBJC_RW_DLLIMPORT extern \"C\" __declspec(dllimport)\n"; + Preamble += "#define __OBJC_RW_STATICIMPORT extern \"C\"\n"; + } else + Preamble += "#define __OBJC_RW_DLLIMPORT extern\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper"; + Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSend_stret"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_msgSendSuper_stret"; + Preamble += "(struct objc_super *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT double objc_msgSend_fpret"; + Preamble += "(struct objc_object *, struct objc_selector *, ...);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass"; + Preamble += "(struct objc_class *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_getMetaClass"; + Preamble += "(const char *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_enter(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_try_exit(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT struct objc_object *objc_exception_extract(void *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match"; + Preamble += "(struct objc_class *, struct objc_object *);\n"; + // @synchronized hooks. + Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n"; + Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; + Preamble += "struct __objcFastEnumerationState {\n\t"; + Preamble += "unsigned long state;\n\t"; + Preamble += "void **itemsPtr;\n\t"; + Preamble += "unsigned long *mutationsPtr;\n\t"; + Preamble += "unsigned long extra[5];\n};\n"; + Preamble += "__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);\n"; + Preamble += "#define __FASTENUMERATIONSTATE\n"; + Preamble += "#endif\n"; + Preamble += "#ifndef __NSCONSTANTSTRINGIMPL\n"; + Preamble += "struct __NSConstantStringImpl {\n"; + Preamble += " int *isa;\n"; + Preamble += " int flags;\n"; + Preamble += " char *str;\n"; + Preamble += " long length;\n"; + Preamble += "};\n"; + Preamble += "#ifdef CF_EXPORT_CONSTANT_STRING\n"; + Preamble += "extern \"C\" __declspec(dllexport) int __CFConstantStringClassReference[];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];\n"; + Preamble += "#endif\n"; + Preamble += "#define __NSCONSTANTSTRINGIMPL\n"; + Preamble += "#endif\n"; + // Blocks preamble. + Preamble += "#ifndef BLOCK_IMPL\n"; + Preamble += "#define BLOCK_IMPL\n"; + Preamble += "struct __block_impl {\n"; + Preamble += " void *isa;\n"; + Preamble += " int Flags;\n"; + Preamble += " int Reserved;\n"; + Preamble += " void *FuncPtr;\n"; + Preamble += "};\n"; + Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n"; + Preamble += "#ifdef __OBJC_EXPORT_BLOCKS\n"; + Preamble += "extern \"C\" __declspec(dllexport) " + "void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void _Block_object_dispose(const void *, const int);\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "extern \"C\" __declspec(dllexport) void *_NSConcreteStackBlock[32];\n"; + Preamble += "#else\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];\n"; + Preamble += "__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];\n"; + Preamble += "#endif\n"; + Preamble += "#endif\n"; + if (LangOpts.Microsoft) { + Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; + Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; + Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. + Preamble += "#define __attribute__(X)\n"; + Preamble += "#endif\n"; + Preamble += "#define __weak\n"; + } + else { + Preamble += "#define __block\n"; + Preamble += "#define __weak\n"; + } + // NOTE! Windows uses LLP64 for 64bit mode. So, cast pointer to long long + // as this avoids warning in any 64bit/32bit compilation model. + Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; +} + + +//===----------------------------------------------------------------------===// +// Top Level Driver Code +//===----------------------------------------------------------------------===// + +void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { + if (Diags.hasErrorOccurred()) + return; + + // Two cases: either the decl could be in the main file, or it could be in a + // #included file. If the former, rewrite it now. If the later, check to see + // if we rewrote the #include/#import. + SourceLocation Loc = D->getLocation(); + Loc = SM->getInstantiationLoc(Loc); + + // If this is for a builtin, ignore it. + if (Loc.isInvalid()) return; + + // Look for built-in declarations that we need to refer during the rewrite. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + RewriteFunctionDecl(FD); + } else if (VarDecl *FVD = dyn_cast<VarDecl>(D)) { + // declared in <Foundation/NSString.h> + if (strcmp(FVD->getNameAsCString(), "_NSConstantStringClassReference") == 0) { + ConstantStringClassReference = FVD; + return; + } + } else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) { + RewriteInterfaceDecl(MD); + } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { + RewriteCategoryDecl(CD); + } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { + RewriteProtocolDecl(PD); + } else if (ObjCForwardProtocolDecl *FP = + dyn_cast<ObjCForwardProtocolDecl>(D)){ + RewriteForwardProtocolDecl(FP); + } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) { + // Recurse into linkage specifications + for (DeclContext::decl_iterator DI = LSD->decls_begin(), + DIEnd = LSD->decls_end(); + DI != DIEnd; ++DI) + HandleTopLevelSingleDecl(*DI); + } + // If we have a decl in the main file, see if we should rewrite it. + if (SM->isFromMainFile(Loc)) + return HandleDeclInMainFile(D); +} + +//===----------------------------------------------------------------------===// +// Syntactic (non-AST) Rewriting Code +//===----------------------------------------------------------------------===// + +void RewriteObjC::RewriteInclude() { + SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID); + llvm::StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); + size_t ImportLen = strlen("import"); + + // Loop over the whole file, looking for includes. + for (const char *BufPtr = MainBufStart; BufPtr < MainBufEnd; ++BufPtr) { + if (*BufPtr == '#') { + if (++BufPtr == MainBufEnd) + return; + while (*BufPtr == ' ' || *BufPtr == '\t') + if (++BufPtr == MainBufEnd) + return; + if (!strncmp(BufPtr, "import", ImportLen)) { + // replace import with include + SourceLocation ImportLoc = + LocStart.getFileLocWithOffset(BufPtr-MainBufStart); + ReplaceText(ImportLoc, ImportLen, "include"); + BufPtr += ImportLen; + } + } + } +} + +void RewriteObjC::RewriteTabs() { + llvm::StringRef MainBuf = SM->getBufferData(MainFileID); + const char *MainBufStart = MainBuf.begin(); + const char *MainBufEnd = MainBuf.end(); + + // Loop over the whole file, looking for tabs. + for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) { + if (*BufPtr != '\t') + continue; + + // Okay, we found a tab. This tab will turn into at least one character, + // but it depends on which 'virtual column' it is in. Compute that now. + unsigned VCol = 0; + while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' && + BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r') + ++VCol; + + // Okay, now that we know the virtual column, we know how many spaces to + // insert. We assume 8-character tab-stops. + unsigned Spaces = 8-(VCol & 7); + + // Get the location of the tab. + SourceLocation TabLoc = SM->getLocForStartOfFile(MainFileID); + TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart); + + // Rewrite the single tab character into a sequence of spaces. + ReplaceText(TabLoc, 1, llvm::StringRef(" ", Spaces)); + } +} + +static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl, + ObjCIvarDecl *OID) { + std::string S; + S = "((struct "; + S += ClassDecl->getIdentifier()->getName(); + S += "_IMPL *)self)->"; + S += OID->getName(); + return S; +} + +void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, + ObjCImplementationDecl *IMD, + ObjCCategoryImplDecl *CID) { + static bool objcGetPropertyDefined = false; + static bool objcSetPropertyDefined = false; + SourceLocation startLoc = PID->getLocStart(); + InsertText(startLoc, "// "); + const char *startBuf = SM->getCharacterData(startLoc); + assert((*startBuf == '@') && "bogus @synthesize location"); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@synthesize: can't find ';'"); + SourceLocation onePastSemiLoc = + startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return; // FIXME: is this correct? + + // Generate the 'getter' function. + ObjCPropertyDecl *PD = PID->getPropertyDecl(); + ObjCInterfaceDecl *ClassDecl = PD->getGetterMethodDecl()->getClassInterface(); + ObjCIvarDecl *OID = PID->getPropertyIvarDecl(); + + if (!OID) + return; + unsigned Attributes = PD->getPropertyAttributes(); + bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && + (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy)); + std::string Getr; + if (GenGetProperty && !objcGetPropertyDefined) { + objcGetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Getr = "\nextern \"C\" __declspec(dllimport) " + "id objc_getProperty(id, SEL, long, bool);\n"; + } + RewriteObjCMethodDecl(PD->getGetterMethodDecl(), Getr); + Getr += "{ "; + // Synthesize an explicit cast to gain access to the ivar. + // See objc-act.c:objc_synthesize_new_getter() for details. + if (GenGetProperty) { + // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) + Getr += "typedef "; + const FunctionType *FPRetType = 0; + RewriteTypeIntoString(PD->getGetterMethodDecl()->getResultType(), Getr, + FPRetType); + Getr += " _TYPE"; + if (FPRetType) { + Getr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) { + Getr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) Getr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString(); + Getr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) Getr += ", "; + Getr += "..."; + } + Getr += ")"; + } else + Getr += "()"; + } + Getr += ";\n"; + Getr += "return (_TYPE)"; + Getr += "objc_getProperty(self, _cmd, "; + SynthesizeIvarOffsetComputation(ClassDecl, OID, Getr); + Getr += ", 1)"; + } + else + Getr += "return " + getIvarAccessString(ClassDecl, OID); + Getr += "; }"; + InsertText(onePastSemiLoc, Getr); + if (PD->isReadOnly()) + return; + + // Generate the 'setter' function. + std::string Setr; + bool GenSetProperty = Attributes & (ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy); + if (GenSetProperty && !objcSetPropertyDefined) { + objcSetPropertyDefined = true; + // FIXME. Is this attribute correct in all cases? + Setr = "\nextern \"C\" __declspec(dllimport) " + "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; + } + + RewriteObjCMethodDecl(PD->getSetterMethodDecl(), Setr); + Setr += "{ "; + // Synthesize an explicit cast to initialize the ivar. + // See objc-act.c:objc_synthesize_new_setter() for details. + if (GenSetProperty) { + Setr += "objc_setProperty (self, _cmd, "; + SynthesizeIvarOffsetComputation(ClassDecl, OID, Setr); + Setr += ", (id)"; + Setr += PD->getNameAsCString(); + Setr += ", "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) + Setr += "0, "; + else + Setr += "1, "; + if (Attributes & ObjCPropertyDecl::OBJC_PR_copy) + Setr += "1)"; + else + Setr += "0)"; + } + else { + Setr += getIvarAccessString(ClassDecl, OID) + " = "; + Setr += PD->getNameAsCString(); + } + Setr += "; }"; + InsertText(onePastSemiLoc, Setr); +} + +void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { + // Get the start location and compute the semi location. + SourceLocation startLoc = ClassDecl->getLocation(); + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiPtr = strchr(startBuf, ';'); + + // Translate to typedef's that forward reference structs with the same name + // as the class. As a convenience, we include the original declaration + // as a comment. + std::string typedefString; + typedefString += "// @class "; + for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); + I != E; ++I) { + ObjCInterfaceDecl *ForwardDecl = I->getInterface(); + typedefString += ForwardDecl->getNameAsString(); + if (I+1 != E) + typedefString += ", "; + else + typedefString += ";\n"; + } + + for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end(); + I != E; ++I) { + ObjCInterfaceDecl *ForwardDecl = I->getInterface(); + typedefString += "#ifndef _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "#define _REWRITER_typedef_"; + typedefString += ForwardDecl->getNameAsString(); + typedefString += "\n"; + typedefString += "typedef struct objc_object "; + typedefString += ForwardDecl->getNameAsString(); + typedefString += ";\n#endif\n"; + } + + // Replace the @class with typedefs corresponding to the classes. + ReplaceText(startLoc, semiPtr-startBuf+1, typedefString); +} + +void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { + // When method is a synthesized one, such as a getter/setter there is + // nothing to rewrite. + if (Method->isSynthesized()) + return; + SourceLocation LocStart = Method->getLocStart(); + SourceLocation LocEnd = Method->getLocEnd(); + + if (SM->getInstantiationLineNumber(LocEnd) > + SM->getInstantiationLineNumber(LocStart)) { + InsertText(LocStart, "#if 0\n"); + ReplaceText(LocEnd, 1, ";\n#endif\n"); + } else { + InsertText(LocStart, "// "); + } +} + +void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { + SourceLocation Loc = prop->getAtLoc(); + + ReplaceText(Loc, 0, "// "); + // FIXME: handle properties that are declared across multiple lines. +} + +void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) { + SourceLocation LocStart = CatDecl->getLocStart(); + + // FIXME: handle category headers that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); + + for (ObjCCategoryDecl::prop_iterator I = CatDecl->prop_begin(), + E = CatDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + + for (ObjCCategoryDecl::instmeth_iterator + I = CatDecl->instmeth_begin(), E = CatDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCCategoryDecl::classmeth_iterator + I = CatDecl->classmeth_begin(), E = CatDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(CatDecl->getAtEndRange().getBegin(), + strlen("@end"), "/* @end */"); +} + +void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) { + SourceLocation LocStart = PDecl->getLocStart(); + + // FIXME: handle protocol headers that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); + + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + SourceLocation LocEnd = PDecl->getAtEndRange().getBegin(); + ReplaceText(LocEnd, strlen("@end"), "/* @end */"); + + // Must comment out @optional/@required + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + for (const char *p = startBuf; p < endBuf; p++) { + if (*p == '@' && !strncmp(p+1, "optional", strlen("optional"))) { + SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@optional"), "/* @optional */"); + + } + else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) { + SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf); + ReplaceText(OptionalLoc, strlen("@required"), "/* @required */"); + + } + } +} + +void RewriteObjC::RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *PDecl) { + SourceLocation LocStart = PDecl->getLocation(); + if (LocStart.isInvalid()) + assert(false && "Invalid SourceLocation"); + // FIXME: handle forward protocol that are declared across multiple lines. + ReplaceText(LocStart, 0, "// "); +} + +void RewriteObjC::RewriteTypeIntoString(QualType T, std::string &ResultStr, + const FunctionType *&FPRetType) { + if (T->isObjCQualifiedIdType()) + ResultStr += "id"; + else if (T->isFunctionPointerType() || + T->isBlockPointerType()) { + // needs special handling, since pointer-to-functions have special + // syntax (where a decaration models use). + QualType retType = T; + QualType PointeeTy; + if (const PointerType* PT = retType->getAs<PointerType>()) + PointeeTy = PT->getPointeeType(); + else if (const BlockPointerType *BPT = retType->getAs<BlockPointerType>()) + PointeeTy = BPT->getPointeeType(); + if ((FPRetType = PointeeTy->getAs<FunctionType>())) { + ResultStr += FPRetType->getResultType().getAsString(); + ResultStr += "(*"; + } + } else + ResultStr += T.getAsString(); +} + +void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD, + std::string &ResultStr) { + //fprintf(stderr,"In RewriteObjCMethodDecl\n"); + const FunctionType *FPRetType = 0; + ResultStr += "\nstatic "; + RewriteTypeIntoString(OMD->getResultType(), ResultStr, FPRetType); + ResultStr += " "; + + // Unique method name + std::string NameStr; + + if (OMD->isInstanceMethod()) + NameStr += "_I_"; + else + NameStr += "_C_"; + + NameStr += OMD->getClassInterface()->getNameAsString(); + NameStr += "_"; + + if (ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext())) { + NameStr += CID->getNameAsString(); + NameStr += "_"; + } + // Append selector names, replacing ':' with '_' + { + std::string selString = OMD->getSelector().getAsString(); + int len = selString.size(); + for (int i = 0; i < len; i++) + if (selString[i] == ':') + selString[i] = '_'; + NameStr += selString; + } + // Remember this name for metadata emission + MethodInternalNames[OMD] = NameStr; + ResultStr += NameStr; + + // Rewrite arguments + ResultStr += "("; + + // invisible arguments + if (OMD->isInstanceMethod()) { + QualType selfTy = Context->getObjCInterfaceType(OMD->getClassInterface()); + selfTy = Context->getPointerType(selfTy); + if (!LangOpts.Microsoft) { + if (ObjCSynthesizedStructs.count(OMD->getClassInterface())) + ResultStr += "struct "; + } + // When rewriting for Microsoft, explicitly omit the structure name. + ResultStr += OMD->getClassInterface()->getNameAsString(); + ResultStr += " *"; + } + else + ResultStr += Context->getObjCClassType().getAsString(); + + ResultStr += " self, "; + ResultStr += Context->getObjCSelType().getAsString(); + ResultStr += " _cmd"; + + // Method arguments. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + ParmVarDecl *PDecl = *PI; + ResultStr += ", "; + if (PDecl->getType()->isObjCQualifiedIdType()) { + ResultStr += "id "; + ResultStr += PDecl->getNameAsString(); + } else { + std::string Name = PDecl->getNameAsString(); + QualType QT = PDecl->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertBlockPointerToFunctionPointer(QT)) + QT.getAsStringInternal(Name, Context->PrintingPolicy); + else + PDecl->getType().getAsStringInternal(Name, Context->PrintingPolicy); + ResultStr += Name; + } + } + if (OMD->isVariadic()) + ResultStr += ", ..."; + ResultStr += ") "; + + if (FPRetType) { + ResultStr += ")"; // close the precedence "scope" for "*". + + // Now, emit the argument types (if any). + if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(FPRetType)) { + ResultStr += "("; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + if (i) ResultStr += ", "; + std::string ParamStr = FT->getArgType(i).getAsString(); + ResultStr += ParamStr; + } + if (FT->isVariadic()) { + if (FT->getNumArgs()) ResultStr += ", "; + ResultStr += "..."; + } + ResultStr += ")"; + } else { + ResultStr += "()"; + } + } +} +void RewriteObjC::RewriteImplementationDecl(Decl *OID) { + ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID); + ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID); + + InsertText(IMD ? IMD->getLocStart() : CID->getLocStart(), "// "); + + for (ObjCCategoryImplDecl::instmeth_iterator + I = IMD ? IMD->instmeth_begin() : CID->instmeth_begin(), + E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + + for (ObjCCategoryImplDecl::classmeth_iterator + I = IMD ? IMD->classmeth_begin() : CID->classmeth_begin(), + E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); + I != E; ++I) { + std::string ResultStr; + ObjCMethodDecl *OMD = *I; + RewriteObjCMethodDecl(OMD, ResultStr); + SourceLocation LocStart = OMD->getLocStart(); + SourceLocation LocEnd = OMD->getCompoundBody()->getLocStart(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + ReplaceText(LocStart, endBuf-startBuf, ResultStr); + } + for (ObjCCategoryImplDecl::propimpl_iterator + I = IMD ? IMD->propimpl_begin() : CID->propimpl_begin(), + E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); + I != E; ++I) { + RewritePropertyImplDecl(*I, IMD, CID); + } + + InsertText(IMD ? IMD->getLocEnd() : CID->getLocEnd(), "// "); +} + +void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { + std::string ResultStr; + if (!ObjCForwardDecls.count(ClassDecl)) { + // we haven't seen a forward decl - generate a typedef. + ResultStr = "#ifndef _REWRITER_typedef_"; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += "\n"; + ResultStr += "#define _REWRITER_typedef_"; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += "\n"; + ResultStr += "typedef struct objc_object "; + ResultStr += ClassDecl->getNameAsString(); + ResultStr += ";\n#endif\n"; + // Mark this typedef as having been generated. + ObjCForwardDecls.insert(ClassDecl); + } + SynthesizeObjCInternalStruct(ClassDecl, ResultStr); + + for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(), + E = ClassDecl->prop_end(); I != E; ++I) + RewriteProperty(*I); + for (ObjCInterfaceDecl::instmeth_iterator + I = ClassDecl->instmeth_begin(), E = ClassDecl->instmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + for (ObjCInterfaceDecl::classmeth_iterator + I = ClassDecl->classmeth_begin(), E = ClassDecl->classmeth_end(); + I != E; ++I) + RewriteMethodDeclaration(*I); + + // Lastly, comment out the @end. + ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"), + "/* @end */"); +} + +Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, + SourceRange SrcRange) { + // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr. + // This allows us to reuse all the fun and games in SynthMessageExpr(). + ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS()); + ObjCMessageExpr *MsgExpr; + ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); + llvm::SmallVector<Expr *, 1> ExprVec; + ExprVec.push_back(newStmt); + + Stmt *Receiver = PropRefExpr->getBase(); + ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver); + if (PRE && PropGetters[PRE]) { + // This allows us to handle chain/nested property getters. + Receiver = PropGetters[PRE]; + } + if (isa<ObjCSuperExpr>(Receiver)) + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME?*/SourceLocation(), + Receiver->getLocStart(), + /*IsInstanceSuper=*/true, + cast<Expr>(Receiver)->getType(), + PDecl->getSetterName(), + PDecl->getSetterMethodDecl(), + &ExprVec[0], 1, + /*FIXME:*/SourceLocation()); + else + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME: */SourceLocation(), + cast<Expr>(Receiver), + PDecl->getSetterName(), + PDecl->getSetterMethodDecl(), + &ExprVec[0], 1, + /*FIXME:*/SourceLocation()); + Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); + + // Now do the actual rewrite. + ReplaceStmtWithRange(BinOp, ReplacingStmt, SrcRange); + //delete BinOp; + // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references + // to things that stay around. + Context->Deallocate(MsgExpr); + return ReplacingStmt; +} + +Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { + // Synthesize a ObjCMessageExpr from a ObjCPropertyRefExpr. + // This allows us to reuse all the fun and games in SynthMessageExpr(). + ObjCMessageExpr *MsgExpr; + ObjCPropertyDecl *PDecl = PropRefExpr->getProperty(); + + Stmt *Receiver = PropRefExpr->getBase(); + + ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(Receiver); + if (PRE && PropGetters[PRE]) { + // This allows us to handle chain/nested property getters. + Receiver = PropGetters[PRE]; + } + + if (isa<ObjCSuperExpr>(Receiver)) + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME:*/SourceLocation(), + Receiver->getLocStart(), + /*IsInstanceSuper=*/true, + cast<Expr>(Receiver)->getType(), + PDecl->getGetterName(), + PDecl->getGetterMethodDecl(), + 0, 0, + /*FIXME:*/SourceLocation()); + else + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME:*/SourceLocation(), + cast<Expr>(Receiver), + PDecl->getGetterName(), + PDecl->getGetterMethodDecl(), + 0, 0, + /*FIXME:*/SourceLocation()); + + Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); + + if (!PropParentMap) + PropParentMap = new ParentMap(CurrentBody); + + Stmt *Parent = PropParentMap->getParent(PropRefExpr); + if (Parent && isa<ObjCPropertyRefExpr>(Parent)) { + // We stash away the ReplacingStmt since actually doing the + // replacement/rewrite won't work for nested getters (e.g. obj.p.i) + PropGetters[PropRefExpr] = ReplacingStmt; + // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references + // to things that stay around. + Context->Deallocate(MsgExpr); + return PropRefExpr; // return the original... + } else { + ReplaceStmt(PropRefExpr, ReplacingStmt); + // delete PropRefExpr; elsewhere... + // NOTE: We don't want to call MsgExpr->Destroy(), as it holds references + // to things that stay around. + Context->Deallocate(MsgExpr); + return ReplacingStmt; + } +} + +Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, + SourceLocation OrigStart, + bool &replaced) { + ObjCIvarDecl *D = IV->getDecl(); + const Expr *BaseExpr = IV->getBase(); + if (CurMethodDef) { + if (BaseExpr->getType()->isObjCObjectPointerType()) { + ObjCInterfaceType *iFaceDecl = + dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); + assert(iFaceDecl && "RewriteObjCIvarRefExpr - iFaceDecl is null"); + // lookup which class implements the instance variable. + ObjCInterfaceDecl *clsDeclared = 0; + iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), + clsDeclared); + assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); + + // Synthesize an explicit cast to gain access to the ivar. + std::string RecName = clsDeclared->getIdentifier()->getName(); + RecName += "_IMPL"; + IdentifierInfo *II = &Context->Idents.get(RecName); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), II); + assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), + IV->getBase()->getLocEnd(), + castExpr); + replaced = true; + if (IV->isFreeIvar() && + CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) { + MemberExpr *ME = new (Context) MemberExpr(PE, true, D, + IV->getLocation(), + D->getType()); + // delete IV; leak for now, see RewritePropertySetter() usage for more info. + return ME; + } + // Get the new text + // Cannot delete IV->getBase(), since PE points to it. + // Replace the old base with the cast. This is important when doing + // embedded rewrites. For example, [newInv->_container addObject:0]. + IV->setBase(PE); + return IV; + } + } else { // we are outside a method. + assert(!IV->isFreeIvar() && "Cannot have a free standing ivar outside a method"); + + // Explicit ivar refs need to have a cast inserted. + // FIXME: consider sharing some of this code with the code above. + if (BaseExpr->getType()->isObjCObjectPointerType()) { + ObjCInterfaceType *iFaceDecl = + dyn_cast<ObjCInterfaceType>(BaseExpr->getType()->getPointeeType()); + // lookup which class implements the instance variable. + ObjCInterfaceDecl *clsDeclared = 0; + iFaceDecl->getDecl()->lookupInstanceVariable(D->getIdentifier(), + clsDeclared); + assert(clsDeclared && "RewriteObjCIvarRefExpr(): Can't find class"); + + // Synthesize an explicit cast to gain access to the ivar. + std::string RecName = clsDeclared->getIdentifier()->getName(); + RecName += "_IMPL"; + IdentifierInfo *II = &Context->Idents.get(RecName); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), II); + assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), + IV->getBase()->getLocEnd(), castExpr); + replaced = true; + // Cannot delete IV->getBase(), since PE points to it. + // Replace the old base with the cast. This is important when doing + // embedded rewrites. For example, [newInv->_container addObject:0]. + IV->setBase(PE); + return IV; + } + } + return IV; +} + +Stmt *RewriteObjC::RewriteObjCNestedIvarRefExpr(Stmt *S, bool &replaced) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) { + if (*CI) { + Stmt *newStmt = RewriteObjCNestedIvarRefExpr(*CI, replaced); + if (newStmt) + *CI = newStmt; + } + } + if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { + SourceRange OrigStmtRange = S->getSourceRange(); + Stmt *newStmt = RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin(), + replaced); + return newStmt; + } + if (ObjCMessageExpr *MsgRefExpr = dyn_cast<ObjCMessageExpr>(S)) { + Stmt *newStmt = SynthMessageExpr(MsgRefExpr); + return newStmt; + } + return S; +} + +/// SynthCountByEnumWithState - To print: +/// ((unsigned int (*) +/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) +/// (void *)objc_msgSend)((id)l_collection, +/// sel_registerName( +/// "countByEnumeratingWithState:objects:count:"), +/// &enumState, +/// (id *)items, (unsigned int)16) +/// +void RewriteObjC::SynthCountByEnumWithState(std::string &buf) { + buf += "((unsigned int (*) (id, SEL, struct __objcFastEnumerationState *, " + "id *, unsigned int))(void *)objc_msgSend)"; + buf += "\n\t\t"; + buf += "((id)l_collection,\n\t\t"; + buf += "sel_registerName(\"countByEnumeratingWithState:objects:count:\"),"; + buf += "\n\t\t"; + buf += "&enumState, " + "(id *)items, (unsigned int)16)"; +} + +/// RewriteBreakStmt - Rewrite for a break-stmt inside an ObjC2's foreach +/// statement to exit to its outer synthesized loop. +/// +Stmt *RewriteObjC::RewriteBreakStmt(BreakStmt *S) { + if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) + return S; + // replace break with goto __break_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("break"), buf); + + return 0; +} + +/// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach +/// statement to continue with its inner synthesized loop. +/// +Stmt *RewriteObjC::RewriteContinueStmt(ContinueStmt *S) { + if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) + return S; + // replace continue with goto __continue_label + std::string buf; + + SourceLocation startLoc = S->getLocStart(); + buf = "goto __continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + ReplaceText(startLoc, strlen("continue"), buf); + + return 0; +} + +/// RewriteObjCForCollectionStmt - Rewriter for ObjC2's foreach statement. +/// It rewrites: +/// for ( type elem in collection) { stmts; } + +/// Into: +/// { +/// type elem; +/// struct __objcFastEnumerationState enumState = { 0 }; +/// id items[16]; +/// id l_collection = (id)collection; +/// unsigned long limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:items count:16]; +/// if (limit) { +/// unsigned long startMutations = *enumState.mutationsPtr; +/// do { +/// unsigned long counter = 0; +/// do { +/// if (startMutations != *enumState.mutationsPtr) +/// objc_enumerationMutation(l_collection); +/// elem = (type)enumState.itemsPtr[counter++]; +/// stmts; +/// __continue_label: ; +/// } while (counter < limit); +/// } while (limit = [l_collection countByEnumeratingWithState:&enumState +/// objects:items count:16]); +/// elem = nil; +/// __break_label: ; +/// } +/// else +/// elem = nil; +/// } +/// +Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, + SourceLocation OrigEnd) { + assert(!Stmts.empty() && "ObjCForCollectionStmt - Statement stack empty"); + assert(isa<ObjCForCollectionStmt>(Stmts.back()) && + "ObjCForCollectionStmt Statement stack mismatch"); + assert(!ObjCBcLabelNo.empty() && + "ObjCForCollectionStmt - Label No stack empty"); + + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + const char *elementName; + std::string elementTypeAsString; + std::string buf; + buf = "\n{\n\t"; + if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) { + // type elem; + NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); + QualType ElementType = cast<ValueDecl>(D)->getType(); + if (ElementType->isObjCQualifiedIdType() || + ElementType->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = ElementType.getAsString(); + buf += elementTypeAsString; + buf += " "; + elementName = D->getNameAsCString(); + buf += elementName; + buf += ";\n\t"; + } + else { + DeclRefExpr *DR = cast<DeclRefExpr>(S->getElement()); + elementName = DR->getDecl()->getNameAsCString(); + ValueDecl *VD = cast<ValueDecl>(DR->getDecl()); + if (VD->getType()->isObjCQualifiedIdType() || + VD->getType()->isObjCQualifiedInterfaceType()) + // Simply use 'id' for all qualified types. + elementTypeAsString = "id"; + else + elementTypeAsString = VD->getType().getAsString(); + } + + // struct __objcFastEnumerationState enumState = { 0 }; + buf += "struct __objcFastEnumerationState enumState = { 0 };\n\t"; + // id items[16]; + buf += "id items[16];\n\t"; + // id l_collection = (id) + buf += "id l_collection = (id)"; + // Find start location of 'collection' the hard way! + const char *startCollectionBuf = startBuf; + startCollectionBuf += 3; // skip 'for' + startCollectionBuf = strchr(startCollectionBuf, '('); + startCollectionBuf++; // skip '(' + // find 'in' and skip it. + while (*startCollectionBuf != ' ' || + *(startCollectionBuf+1) != 'i' || *(startCollectionBuf+2) != 'n' || + (*(startCollectionBuf+3) != ' ' && + *(startCollectionBuf+3) != '[' && *(startCollectionBuf+3) != '(')) + startCollectionBuf++; + startCollectionBuf += 3; + + // Replace: "for (type element in" with string constructed thus far. + ReplaceText(startLoc, startCollectionBuf - startBuf, buf); + // Replace ')' in for '(' type elem in collection ')' with ';' + SourceLocation rightParenLoc = S->getRParenLoc(); + const char *rparenBuf = SM->getCharacterData(rightParenLoc); + SourceLocation lparenLoc = startLoc.getFileLocWithOffset(rparenBuf-startBuf); + buf = ";\n\t"; + + // unsigned long limit = [l_collection countByEnumeratingWithState:&enumState + // objects:items count:16]; + // which is synthesized into: + // unsigned int limit = + // ((unsigned int (*) + // (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int)) + // (void *)objc_msgSend)((id)l_collection, + // sel_registerName( + // "countByEnumeratingWithState:objects:count:"), + // (struct __objcFastEnumerationState *)&state, + // (id *)items, (unsigned int)16); + buf += "unsigned long limit =\n\t\t"; + SynthCountByEnumWithState(buf); + buf += ";\n\t"; + /// if (limit) { + /// unsigned long startMutations = *enumState.mutationsPtr; + /// do { + /// unsigned long counter = 0; + /// do { + /// if (startMutations != *enumState.mutationsPtr) + /// objc_enumerationMutation(l_collection); + /// elem = (type)enumState.itemsPtr[counter++]; + buf += "if (limit) {\n\t"; + buf += "unsigned long startMutations = *enumState.mutationsPtr;\n\t"; + buf += "do {\n\t\t"; + buf += "unsigned long counter = 0;\n\t\t"; + buf += "do {\n\t\t\t"; + buf += "if (startMutations != *enumState.mutationsPtr)\n\t\t\t\t"; + buf += "objc_enumerationMutation(l_collection);\n\t\t\t"; + buf += elementName; + buf += " = ("; + buf += elementTypeAsString; + buf += ")enumState.itemsPtr[counter++];"; + // Replace ')' in for '(' type elem in collection ')' with all of these. + ReplaceText(lparenLoc, 1, buf); + + /// __continue_label: ; + /// } while (counter < limit); + /// } while (limit = [l_collection countByEnumeratingWithState:&enumState + /// objects:items count:16]); + /// elem = nil; + /// __break_label: ; + /// } + /// else + /// elem = nil; + /// } + /// + buf = ";\n\t"; + buf += "__continue_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;"; + buf += "\n\t\t"; + buf += "} while (counter < limit);\n\t"; + buf += "} while (limit = "; + SynthCountByEnumWithState(buf); + buf += ");\n\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "__break_label_"; + buf += utostr(ObjCBcLabelNo.back()); + buf += ": ;\n\t"; + buf += "}\n\t"; + buf += "else\n\t\t"; + buf += elementName; + buf += " = (("; + buf += elementTypeAsString; + buf += ")0);\n\t"; + buf += "}\n"; + + // Insert all these *after* the statement body. + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (isa<CompoundStmt>(S->getBody())) { + SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1); + InsertText(endBodyLoc, buf); + } else { + /* Need to treat single statements specially. For example: + * + * for (A *a in b) if (stuff()) break; + * for (A *a in b) xxxyy; + * + * The following code simply scans ahead to the semi to find the actual end. + */ + const char *stmtBuf = SM->getCharacterData(OrigEnd); + const char *semiBuf = strchr(stmtBuf, ';'); + assert(semiBuf && "Can't find ';'"); + SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(semiBuf-stmtBuf+1); + InsertText(endBodyLoc, buf); + } + Stmts.pop_back(); + ObjCBcLabelNo.pop_back(); + return 0; +} + +/// RewriteObjCSynchronizedStmt - +/// This routine rewrites @synchronized(expr) stmt; +/// into: +/// objc_sync_enter(expr); +/// @try stmt @finally { objc_sync_exit(expr); } +/// +Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @synchronized location"); + + std::string buf; + buf = "objc_sync_enter((id)"; + const char *lparenBuf = startBuf; + while (*lparenBuf != '(') lparenBuf++; + ReplaceText(startLoc, lparenBuf-startBuf+1, buf); + // We can't use S->getSynchExpr()->getLocEnd() to find the end location, since + // the sync expression is typically a message expression that's already + // been rewritten! (which implies the SourceLocation's are invalid). + SourceLocation endLoc = S->getSynchBody()->getLocStart(); + const char *endBuf = SM->getCharacterData(endLoc); + while (*endBuf != ')') endBuf--; + SourceLocation rparenLoc = startLoc.getFileLocWithOffset(endBuf-startBuf); + buf = ");\n"; + // declare a new scope with two variables, _stack and _rethrow. + buf += "/* @try scope begin */ \n{ struct _objc_exception_data {\n"; + buf += "int buf[18/*32-bit i386*/];\n"; + buf += "char *pointers[4];} _stack;\n"; + buf += "id volatile _rethrow = 0;\n"; + buf += "objc_exception_try_enter(&_stack);\n"; + buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; + ReplaceText(rparenLoc, 1, buf); + startLoc = S->getSynchBody()->getLocEnd(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '}') && "bogus @synchronized block"); + SourceLocation lastCurlyLoc = startLoc; + buf = "}\nelse {\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += "}\n"; + buf += "{ /* implicit finally clause */\n"; + buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; + + std::string syncBuf; + syncBuf += " objc_sync_exit("; + Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + S->getSynchExpr()); + std::string syncExprBufS; + llvm::raw_string_ostream syncExprBuf(syncExprBufS); + syncExpr->printPretty(syncExprBuf, *Context, 0, + PrintingPolicy(LangOpts)); + syncBuf += syncExprBuf.str(); + syncBuf += ");"; + + buf += syncBuf; + buf += "\n if (_rethrow) objc_exception_throw(_rethrow);\n"; + buf += "}\n"; + buf += "}"; + + ReplaceText(lastCurlyLoc, 1, buf); + + bool hasReturns = false; + HasReturnStmts(S->getSynchBody(), hasReturns); + if (hasReturns) + RewriteSyncReturnStmts(S->getSynchBody(), syncBuf); + + return 0; +} + +void RewriteObjC::WarnAboutReturnGotoStmts(Stmt *S) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + WarnAboutReturnGotoStmts(*CI); + + if (isa<ReturnStmt>(S) || isa<GotoStmt>(S)) { + Diags.Report(Context->getFullLoc(S->getLocStart()), + TryFinallyContainsReturnDiag); + } + return; +} + +void RewriteObjC::HasReturnStmts(Stmt *S, bool &hasReturns) +{ + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + HasReturnStmts(*CI, hasReturns); + + if (isa<ReturnStmt>(S)) + hasReturns = true; + return; +} + +void RewriteObjC::RewriteTryReturnStmts(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteTryReturnStmts(*CI); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteTryReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack); return"; + + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); + } + return; +} + +void RewriteObjC::RewriteSyncReturnStmts(Stmt *S, std::string syncExitBuf) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + RewriteSyncReturnStmts(*CI, syncExitBuf); + } + if (isa<ReturnStmt>(S)) { + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteSyncReturnStmts: can't find ';'"); + SourceLocation onePastSemiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf+1); + + std::string buf; + buf = "{ objc_exception_try_exit(&_stack);"; + buf += syncExitBuf; + buf += " return"; + + ReplaceText(startLoc, 6, buf); + InsertText(onePastSemiLoc, "}"); + } + return; +} + +Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @try location"); + + std::string buf; + // declare a new scope with two variables, _stack and _rethrow. + buf = "/* @try scope begin */ { struct _objc_exception_data {\n"; + buf += "int buf[18/*32-bit i386*/];\n"; + buf += "char *pointers[4];} _stack;\n"; + buf += "id volatile _rethrow = 0;\n"; + buf += "objc_exception_try_enter(&_stack);\n"; + buf += "if (!_setjmp(_stack.buf)) /* @try block continue */\n"; + + ReplaceText(startLoc, 4, buf); + + startLoc = S->getTryBody()->getLocEnd(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '}') && "bogus @try block"); + + SourceLocation lastCurlyLoc = startLoc; + if (S->getNumCatchStmts()) { + startLoc = startLoc.getFileLocWithOffset(1); + buf = " /* @catch begin */ else {\n"; + buf += " id _caught = objc_exception_extract(&_stack);\n"; + buf += " objc_exception_try_enter (&_stack);\n"; + buf += " if (_setjmp(_stack.buf))\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += " else { /* @catch continue */"; + + InsertText(startLoc, buf); + } else { /* no catch list */ + buf = "}\nelse {\n"; + buf += " _rethrow = objc_exception_extract(&_stack);\n"; + buf += "}"; + ReplaceText(lastCurlyLoc, 1, buf); + } + bool sawIdTypedCatch = false; + Stmt *lastCatchBody = 0; + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *Catch = S->getCatchStmt(I); + VarDecl *catchDecl = Catch->getCatchParamDecl(); + + if (I == 0) + buf = "if ("; // we are generating code for the first catch clause + else + buf = "else if ("; + startLoc = Catch->getLocStart(); + startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @catch location"); + + const char *lParenLoc = strchr(startBuf, '('); + + if (Catch->hasEllipsis()) { + // Now rewrite the body... + lastCatchBody = Catch->getCatchBody(); + SourceLocation bodyLoc = lastCatchBody->getLocStart(); + const char *bodyBuf = SM->getCharacterData(bodyLoc); + assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' && + "bogus @catch paren location"); + assert((*bodyBuf == '{') && "bogus @catch body location"); + + buf += "1) { id _tmp = _caught;"; + Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1, buf); + } else if (catchDecl) { + QualType t = catchDecl->getType(); + if (t == Context->getObjCIdType()) { + buf += "1) { "; + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); + sawIdTypedCatch = true; + } else if (const ObjCObjectPointerType *Ptr = + t->getAs<ObjCObjectPointerType>()) { + // Should be a pointer to a class. + ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); + if (IDecl) { + buf += "objc_exception_match((struct objc_class *)objc_getClass(\""; + buf += IDecl->getNameAsString(); + buf += "\"), (struct objc_object *)_caught)) { "; + ReplaceText(startLoc, lParenLoc-startBuf+1, buf); + } + } + // Now rewrite the body... + lastCatchBody = Catch->getCatchBody(); + SourceLocation rParenLoc = Catch->getRParenLoc(); + SourceLocation bodyLoc = lastCatchBody->getLocStart(); + const char *bodyBuf = SM->getCharacterData(bodyLoc); + const char *rParenBuf = SM->getCharacterData(rParenLoc); + assert((*rParenBuf == ')') && "bogus @catch paren location"); + assert((*bodyBuf == '{') && "bogus @catch body location"); + + // Here we replace ") {" with "= _caught;" (which initializes and + // declares the @catch parameter). + ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, " = _caught;"); + } else { + assert(false && "@catch rewrite bug"); + } + } + // Complete the catch list... + if (lastCatchBody) { + SourceLocation bodyLoc = lastCatchBody->getLocEnd(); + assert(*SM->getCharacterData(bodyLoc) == '}' && + "bogus @catch body location"); + + // Insert the last (implicit) else clause *before* the right curly brace. + bodyLoc = bodyLoc.getFileLocWithOffset(-1); + buf = "} /* last catch end */\n"; + buf += "else {\n"; + buf += " _rethrow = _caught;\n"; + buf += " objc_exception_try_exit(&_stack);\n"; + buf += "} } /* @catch end */\n"; + if (!S->getFinallyStmt()) + buf += "}\n"; + InsertText(bodyLoc, buf); + + // Set lastCurlyLoc + lastCurlyLoc = lastCatchBody->getLocEnd(); + } + if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) { + startLoc = finalStmt->getLocStart(); + startBuf = SM->getCharacterData(startLoc); + assert((*startBuf == '@') && "bogus @finally start"); + + ReplaceText(startLoc, 8, "/* @finally */"); + + Stmt *body = finalStmt->getFinallyBody(); + SourceLocation startLoc = body->getLocStart(); + SourceLocation endLoc = body->getLocEnd(); + assert(*SM->getCharacterData(startLoc) == '{' && + "bogus @finally body location"); + assert(*SM->getCharacterData(endLoc) == '}' && + "bogus @finally body location"); + + startLoc = startLoc.getFileLocWithOffset(1); + InsertText(startLoc, " if (!_rethrow) objc_exception_try_exit(&_stack);\n"); + endLoc = endLoc.getFileLocWithOffset(-1); + InsertText(endLoc, " if (_rethrow) objc_exception_throw(_rethrow);\n"); + + // Set lastCurlyLoc + lastCurlyLoc = body->getLocEnd(); + + // Now check for any return/continue/go statements within the @try. + WarnAboutReturnGotoStmts(S->getTryBody()); + } else { /* no finally clause - make sure we synthesize an implicit one */ + buf = "{ /* implicit finally clause */\n"; + buf += " if (!_rethrow) objc_exception_try_exit(&_stack);\n"; + buf += " if (_rethrow) objc_exception_throw(_rethrow);\n"; + buf += "}"; + ReplaceText(lastCurlyLoc, 1, buf); + + // Now check for any return/continue/go statements within the @try. + // The implicit finally clause won't called if the @try contains any + // jump statements. + bool hasReturns = false; + HasReturnStmts(S->getTryBody(), hasReturns); + if (hasReturns) + RewriteTryReturnStmts(S->getTryBody()); + } + // Now emit the final closing curly brace... + lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1); + InsertText(lastCurlyLoc, " } /* @try scope end */\n"); + return 0; +} + +Stmt *RewriteObjC::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) { + return 0; +} + +Stmt *RewriteObjC::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) { + return 0; +} + +// This can't be done with ReplaceStmt(S, ThrowExpr), since +// the throw expression is typically a message expression that's already +// been rewritten! (which implies the SourceLocation's are invalid). +Stmt *RewriteObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) { + // Get the start location and compute the semi location. + SourceLocation startLoc = S->getLocStart(); + const char *startBuf = SM->getCharacterData(startLoc); + + assert((*startBuf == '@') && "bogus @throw location"); + + std::string buf; + /* void objc_exception_throw(id) __attribute__((noreturn)); */ + if (S->getThrowExpr()) + buf = "objc_exception_throw("; + else // add an implicit argument + buf = "objc_exception_throw(_caught"; + + // handle "@ throw" correctly. + const char *wBuf = strchr(startBuf, 'w'); + assert((*wBuf == 'w') && "@throw: can't find 'w'"); + ReplaceText(startLoc, wBuf-startBuf+1, buf); + + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "@throw: can't find ';'"); + SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf); + ReplaceText(semiLoc, 1, ");"); + return 0; +} + +Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { + // Create a new string expression. + QualType StrType = Context->getPointerType(Context->CharTy); + std::string StrEncoding; + Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); + Expr *Replacement = StringLiteral::Create(*Context,StrEncoding.c_str(), + StrEncoding.length(), false,StrType, + SourceLocation()); + ReplaceStmt(Exp, Replacement); + + // Replace this subexpr in the parent. + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return Replacement; +} + +Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + assert(SelGetUidFunctionDecl && "Can't find sel_registerName() decl"); + // Create a call to sel_registerName("selName"). + llvm::SmallVector<Expr*, 8> SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString().c_str(), + Exp->getSelector().getAsString().size(), + false, argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size()); + ReplaceStmt(Exp, SelExp); + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return SelExp; +} + +CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( + FunctionDecl *FD, Expr **args, unsigned nargs, SourceLocation StartLoc, + SourceLocation EndLoc) { + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = FD->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, msgSendType, SourceLocation()); + + // Now, we cast the reference to a pointer to the objc_msgSend type. + QualType pToFunc = Context->getPointerType(msgSendType); + ImplicitCastExpr *ICE = + new (Context) ImplicitCastExpr(pToFunc, CastExpr::CK_Unknown, + DRE, CXXBaseSpecifierArray(), + /*isLvalue=*/false); + + const FunctionType *FT = msgSendType->getAs<FunctionType>(); + + CallExpr *Exp = + new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(), + EndLoc); + return Exp; +} + +static bool scanForProtocolRefs(const char *startBuf, const char *endBuf, + const char *&startRef, const char *&endRef) { + while (startBuf < endBuf) { + if (*startBuf == '<') + startRef = startBuf; // mark the start. + if (*startBuf == '>') { + if (startRef && *startRef == '<') { + endRef = startBuf; // mark the end. + return true; + } + return false; + } + startBuf++; + } + return false; +} + +static void scanToNextArgument(const char *&argRef) { + int angle = 0; + while (*argRef != ')' && (*argRef != ',' || angle > 0)) { + if (*argRef == '<') + angle++; + else if (*argRef == '>') + angle--; + argRef++; + } + assert(angle == 0 && "scanToNextArgument - bad protocol type syntax"); +} + +bool RewriteObjC::needToScanForQualifiers(QualType T) { + if (T->isObjCQualifiedIdType()) + return true; + if (const PointerType *PT = T->getAs<PointerType>()) { + if (PT->getPointeeType()->isObjCQualifiedIdType()) + return true; + } + if (T->isObjCObjectPointerType()) { + T = T->getPointeeType(); + return T->isObjCQualifiedInterfaceType(); + } + return false; +} + +void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Expr *E) { + QualType Type = E->getType(); + if (needToScanForQualifiers(Type)) { + SourceLocation Loc, EndLoc; + + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) { + Loc = ECE->getLParenLoc(); + EndLoc = ECE->getRParenLoc(); + } else { + Loc = E->getLocStart(); + EndLoc = E->getLocEnd(); + } + // This will defend against trying to rewrite synthesized expressions. + if (Loc.isInvalid() || EndLoc.isInvalid()) + return; + + const char *startBuf = SM->getCharacterData(Loc); + const char *endBuf = SM->getCharacterData(EndLoc); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-startBuf); + SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-startBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } +} + +void RewriteObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) { + SourceLocation Loc; + QualType Type; + const FunctionProtoType *proto = 0; + if (VarDecl *VD = dyn_cast<VarDecl>(Dcl)) { + Loc = VD->getLocation(); + Type = VD->getType(); + } + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Dcl)) { + Loc = FD->getLocation(); + // Check for ObjC 'id' and class types that have been adorned with protocol + // information (id<p>, C<p>*). The protocol references need to be rewritten! + const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); + assert(funcType && "missing function type"); + proto = dyn_cast<FunctionProtoType>(funcType); + if (!proto) + return; + Type = proto->getResultType(); + } + else if (FieldDecl *FD = dyn_cast<FieldDecl>(Dcl)) { + Loc = FD->getLocation(); + Type = FD->getType(); + } + else + return; + + if (needToScanForQualifiers(Type)) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = SM->getCharacterData(Loc); + const char *startBuf = endBuf; + while (*startBuf != ';' && *startBuf != '<' && startBuf != MainFileStart) + startBuf--; // scan backward (from the decl location) for return type. + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = Loc.getFileLocWithOffset(startRef-endBuf); + SourceLocation GreaterLoc = Loc.getFileLocWithOffset(endRef-endBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + } + if (!proto) + return; // most likely, was a variable + // Now check arguments. + const char *startBuf = SM->getCharacterData(Loc); + const char *startFuncBuf = startBuf; + for (unsigned i = 0; i < proto->getNumArgs(); i++) { + if (needToScanForQualifiers(proto->getArgType(i))) { + // Since types are unique, we need to scan the buffer. + + const char *endBuf = startBuf; + // scan forward (from the decl location) for argument types. + scanToNextArgument(endBuf); + const char *startRef = 0, *endRef = 0; + if (scanForProtocolRefs(startBuf, endBuf, startRef, endRef)) { + // Get the locations of the startRef, endRef. + SourceLocation LessLoc = + Loc.getFileLocWithOffset(startRef-startFuncBuf); + SourceLocation GreaterLoc = + Loc.getFileLocWithOffset(endRef-startFuncBuf+1); + // Comment out the protocol references. + InsertText(LessLoc, "/*"); + InsertText(GreaterLoc, "*/"); + } + startBuf = ++endBuf; + } + else { + // If the function name is derived from a macro expansion, then the + // argument buffer will not follow the name. Need to speak with Chris. + while (*startBuf && *startBuf != ')' && *startBuf != ',') + startBuf++; // scan forward (from the decl location) for argument types. + startBuf++; + } + } +} + +void RewriteObjC::RewriteTypeOfDecl(VarDecl *ND) { + QualType QT = ND->getType(); + const Type* TypePtr = QT->getAs<Type>(); + if (!isa<TypeOfExprType>(TypePtr)) + return; + while (isa<TypeOfExprType>(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + TypePtr = QT->getAs<Type>(); + } + // FIXME. This will not work for multiple declarators; as in: + // __typeof__(a) b,c,d; + std::string TypeAsString(QT.getAsString()); + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + const char *startBuf = SM->getCharacterData(DeclLoc); + if (ND->getInit()) { + std::string Name(ND->getNameAsString()); + TypeAsString += " " + Name + " = "; + Expr *E = ND->getInit(); + SourceLocation startLoc; + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getInstantiationLoc(startLoc); + const char *endBuf = SM->getCharacterData(startLoc); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } + else { + SourceLocation X = ND->getLocEnd(); + X = SM->getInstantiationLoc(X); + const char *endBuf = SM->getCharacterData(X); + ReplaceText(DeclLoc, endBuf-startBuf-1, TypeAsString); + } +} + +// SynthSelGetUidFunctionDecl - SEL sel_registerName(const char *str); +void RewriteObjC::SynthSelGetUidFunctionDecl() { + IdentifierInfo *SelGetUidIdent = &Context->Idents.get("sel_registerName"); + llvm::SmallVector<QualType, 16> ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + SelGetUidIdent, getFuncType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { + // declared in <objc/objc.h> + if (FD->getIdentifier() && + strcmp(FD->getNameAsCString(), "sel_registerName") == 0) { + SelGetUidFunctionDecl = FD; + return; + } + RewriteObjCQualifiedInterfaceTypes(FD); +} + +static void RewriteBlockPointerType(std::string& Str, QualType Type) { + std::string TypeString(Type.getAsString()); + const char *argPtr = TypeString.c_str(); + if (!strchr(argPtr, '^')) { + Str += TypeString; + return; + } + while (*argPtr) { + Str += (*argPtr == '^' ? '*' : *argPtr); + argPtr++; + } +} + +// FIXME. Consolidate this routine with RewriteBlockPointerType. +static void RewriteBlockPointerTypeVariable(std::string& Str, ValueDecl *VD) { + QualType Type = VD->getType(); + std::string TypeString(Type.getAsString()); + const char *argPtr = TypeString.c_str(); + int paren = 0; + while (*argPtr) { + switch (*argPtr) { + case '(': + Str += *argPtr; + paren++; + break; + case ')': + Str += *argPtr; + paren--; + break; + case '^': + Str += '*'; + if (paren == 1) + Str += VD->getNameAsString(); + break; + default: + Str += *argPtr; + break; + } + argPtr++; + } +} + + +void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + const FunctionType *funcType = FD->getType()->getAs<FunctionType>(); + const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType); + if (!proto) + return; + QualType Type = proto->getResultType(); + std::string FdStr = Type.getAsString(); + FdStr += " "; + FdStr += FD->getNameAsCString(); + FdStr += "("; + unsigned numArgs = proto->getNumArgs(); + for (unsigned i = 0; i < numArgs; i++) { + QualType ArgType = proto->getArgType(i); + RewriteBlockPointerType(FdStr, ArgType); + if (i+1 < numArgs) + FdStr += ", "; + } + FdStr += ");\n"; + InsertText(FunLocStart, FdStr); + CurFunctionDeclToDeclareForBlock = 0; +} + +// SynthSuperContructorFunctionDecl - id objc_super(id obj, id super); +void RewriteObjC::SynthSuperContructorFunctionDecl() { + if (SuperContructorFunctionDecl) + return; + IdentifierInfo *msgSendIdent = &Context->Idents.get("__rw_objc_super"); + llvm::SmallVector<QualType, 16> ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + false, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend"); + llvm::SmallVector<QualType, 16> ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); +void RewriteObjC::SynthMsgSendSuperFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); + llvm::SmallVector<QualType, 16> ArgTys; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), + &Context->Idents.get("objc_super")); + QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); + assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendStretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_stret"); + llvm::SmallVector<QualType, 16> ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthMsgSendSuperStretFunctionDecl - +// id objc_msgSendSuper_stret(struct objc_super *, SEL op, ...); +void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { + IdentifierInfo *msgSendIdent = + &Context->Idents.get("objc_msgSendSuper_stret"); + llvm::SmallVector<QualType, 16> ArgTys; + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), + &Context->Idents.get("objc_super")); + QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); + assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); +void RewriteObjC::SynthMsgSendFpretFunctionDecl() { + IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSend_fpret"); + llvm::SmallVector<QualType, 16> ArgTys; + QualType argT = Context->getObjCIdType(); + assert(!argT.isNull() && "Can't find 'id' type"); + ArgTys.push_back(argT); + argT = Context->getObjCSelType(); + assert(!argT.isNull() && "Can't find 'SEL' type"); + ArgTys.push_back(argT); + QualType msgSendType = Context->getFunctionType(Context->DoubleTy, + &ArgTys[0], ArgTys.size(), + true /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + msgSendIdent, msgSendType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthGetClassFunctionDecl - id objc_getClass(const char *name); +void RewriteObjC::SynthGetClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getClass"); + llvm::SmallVector<QualType, 16> ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + getClassIdent, getClassType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); +void RewriteObjC::SynthGetSuperClassFunctionDecl() { + IdentifierInfo *getSuperClassIdent = + &Context->Idents.get("class_getSuperclass"); + llvm::SmallVector<QualType, 16> ArgTys; + ArgTys.push_back(Context->getObjCClassType()); + QualType getClassType = Context->getFunctionType(Context->getObjCClassType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + getSuperClassIdent, + getClassType, 0, + FunctionDecl::Extern, + FunctionDecl::None, + false); +} + +// SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); +void RewriteObjC::SynthGetMetaClassFunctionDecl() { + IdentifierInfo *getClassIdent = &Context->Idents.get("objc_getMetaClass"); + llvm::SmallVector<QualType, 16> ArgTys; + ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst())); + QualType getClassType = Context->getFunctionType(Context->getObjCIdType(), + &ArgTys[0], ArgTys.size(), + false /*isVariadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, + SourceLocation(), + getClassIdent, getClassType, 0, + FunctionDecl::Extern, + FunctionDecl::None, false); +} + +Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { + QualType strType = getConstantStringStructType(); + + std::string S = "__NSConstantStringImpl_"; + + std::string tmpName = InFileName; + unsigned i; + for (i=0; i < tmpName.length(); i++) { + char c = tmpName.at(i); + // replace any non alphanumeric characters with '_'. + if (!isalpha(c) && (c < '0' || c > '9')) + tmpName[i] = '_'; + } + S += tmpName; + S += "_"; + S += utostr(NumObjCStringLiterals++); + + Preamble += "static __NSConstantStringImpl " + S; + Preamble += " __attribute__ ((section (\"__DATA, __cfstring\"))) = {__CFConstantStringClassReference,"; + Preamble += "0x000007c8,"; // utf8_str + // The pretty printer for StringLiteral handles escape characters properly. + std::string prettyBufS; + llvm::raw_string_ostream prettyBuf(prettyBufS); + Exp->getString()->printPretty(prettyBuf, *Context, 0, + PrintingPolicy(LangOpts)); + Preamble += prettyBuf.str(); + Preamble += ","; + Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + &Context->Idents.get(S), strType, 0, + VarDecl::Static, VarDecl::None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation()); + Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, + Context->getPointerType(DRE->getType()), + SourceLocation()); + // cast to NSConstantString * + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), + CastExpr::CK_Unknown, Unop); + ReplaceStmt(Exp, cast); + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return cast; +} + +bool RewriteObjC::isSuperReceiver(Expr *recExpr) { + // check if we are sending a message to 'super' + if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return false; + return isa<ObjCSuperExpr>(recExpr); +} + +// struct objc_super { struct objc_object *receiver; struct objc_class *super; }; +QualType RewriteObjC::getSuperStructType() { + if (!SuperStructDecl) { + SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), + &Context->Idents.get("objc_super")); + QualType FieldTypes[2]; + + // struct objc_object *receiver; + FieldTypes[0] = Context->getObjCIdType(); + // struct objc_class *super; + FieldTypes[1] = Context->getObjCClassType(); + + // Create fields + for (unsigned i = 0; i < 2; ++i) { + SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/false)); + } + + SuperStructDecl->completeDefinition(); + } + return Context->getTagDeclType(SuperStructDecl); +} + +QualType RewriteObjC::getConstantStringStructType() { + if (!ConstantStringDecl) { + ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), + &Context->Idents.get("__NSConstantStringImpl")); + QualType FieldTypes[4]; + + // struct objc_object *receiver; + FieldTypes[0] = Context->getObjCIdType(); + // int flags; + FieldTypes[1] = Context->IntTy; + // char *str; + FieldTypes[2] = Context->getPointerType(Context->CharTy); + // long length; + FieldTypes[3] = Context->LongTy; + + // Create fields + for (unsigned i = 0; i < 4; ++i) { + ConstantStringDecl->addDecl(FieldDecl::Create(*Context, + ConstantStringDecl, + SourceLocation(), 0, + FieldTypes[i], 0, + /*BitWidth=*/0, + /*Mutable=*/true)); + } + + ConstantStringDecl->completeDefinition(); + } + return Context->getTagDeclType(ConstantStringDecl); +} + +Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!SelGetUidFunctionDecl) + SynthSelGetUidFunctionDecl(); + if (!MsgSendFunctionDecl) + SynthMsgSendFunctionDecl(); + if (!MsgSendSuperFunctionDecl) + SynthMsgSendSuperFunctionDecl(); + if (!MsgSendStretFunctionDecl) + SynthMsgSendStretFunctionDecl(); + if (!MsgSendSuperStretFunctionDecl) + SynthMsgSendSuperStretFunctionDecl(); + if (!MsgSendFpretFunctionDecl) + SynthMsgSendFpretFunctionDecl(); + if (!GetClassFunctionDecl) + SynthGetClassFunctionDecl(); + if (!GetSuperClassFunctionDecl) + SynthGetSuperClassFunctionDecl(); + if (!GetMetaClassFunctionDecl) + SynthGetMetaClassFunctionDecl(); + + // default to objc_msgSend(). + FunctionDecl *MsgSendFlavor = MsgSendFunctionDecl; + // May need to use objc_msgSend_stret() as well. + FunctionDecl *MsgSendStretFlavor = 0; + if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { + QualType resultType = mDecl->getResultType(); + if (resultType->isRecordType()) + MsgSendStretFlavor = MsgSendStretFunctionDecl; + else if (resultType->isRealFloatingType()) + MsgSendFlavor = MsgSendFpretFunctionDecl; + } + + // Synthesize a call to objc_msgSend(). + llvm::SmallVector<Expr*, 8> MsgExprs; + switch (Exp->getReceiverKind()) { + case ObjCMessageExpr::SuperClass: { + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + + llvm::SmallVector<Expr*, 4> InitExprs; + + // set the receiver to self, the first argument to all methods. + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + Context->getObjCIdType(), + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, + EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.Microsoft) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + superType, SourceLocation()); + SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], + InitExprs.size(), + superType, SourceLocation()); + // The code for super is a little tricky to prevent collision with + // the structure definition in the header. The rewriter has it's own + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); + } else { + // (struct objc_super) { <exprs from above> } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), + &InitExprs[0], InitExprs.size(), + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); + // struct objc_super * + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Class: { + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ObjCInterfaceDecl *Class + = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface(); + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getNameStart(), + clsName->getLength(), + false, argType, + SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + break; + } + + case ObjCMessageExpr::SuperInstance:{ + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + llvm::SmallVector<Expr*, 4> InitExprs; + + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + Context->getObjCIdType(), + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( + // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.Microsoft) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + superType, SourceLocation()); + SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], + InitExprs.size(), + superType, SourceLocation()); + // The code for super is a little tricky to prevent collision with + // the structure definition in the header. The rewriter has it's own + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); + } else { + // (struct objc_super) { <exprs from above> } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), + &InitExprs[0], InitExprs.size(), + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); + } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Instance: { + // Remove all type-casts because it may contain objc-style types; e.g. + // Foo<Proto> *. + Expr *recExpr = Exp->getInstanceReceiver(); + while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) + recExpr = CE->getSubExpr(); + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, recExpr); + MsgExprs.push_back(recExpr); + break; + } + } + + // Create a call to sel_registerName("selName"), it will be the 2nd argument. + llvm::SmallVector<Expr*, 8> SelExprs; + QualType argType = Context->getPointerType(Context->CharTy); + SelExprs.push_back(StringLiteral::Create(*Context, + Exp->getSelector().getAsString().c_str(), + Exp->getSelector().getAsString().size(), + false, argType, SourceLocation())); + CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, + &SelExprs[0], SelExprs.size(), + StartLoc, + EndLoc); + MsgExprs.push_back(SelExp); + + // Now push any user supplied arguments. + for (unsigned i = 0; i < Exp->getNumArgs(); i++) { + Expr *userExpr = Exp->getArg(i); + // Make all implicit casts explicit...ICE comes in handy:-) + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) { + // Reuse the ICE type, it is exactly what the doctor ordered. + QualType type = ICE->getType()->isObjCQualifiedIdType() + ? Context->getObjCIdType() + : ICE->getType(); + // Make sure we convert "type (^)(...)" to "type (*)(...)". + (void)convertBlockPointerToFunctionPointer(type); + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown, + userExpr); + } + // Make id<P...> cast into an 'id' cast. + else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { + if (CE->getType()->isObjCQualifiedIdType()) { + while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) + userExpr = CE->getSubExpr(); + userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, userExpr); + } + } + MsgExprs.push_back(userExpr); + // We've transferred the ownership to MsgExprs. For now, we *don't* null + // out the argument in the original expression (since we aren't deleting + // the ObjCMessageExpr). See RewritePropertySetter() usage for more info. + //Exp->setArg(i, 0); + } + // Generate the funky cast. + CastExpr *cast; + llvm::SmallVector<QualType, 8> ArgTypes; + QualType returnType; + + // Push 'id' and 'SEL', the 2 implicit arguments. + if (MsgSendFlavor == MsgSendSuperFunctionDecl) + ArgTypes.push_back(Context->getPointerType(getSuperStructType())); + else + ArgTypes.push_back(Context->getObjCIdType()); + ArgTypes.push_back(Context->getObjCSelType()); + if (ObjCMethodDecl *OMD = Exp->getMethodDecl()) { + // Push any user argument types. + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + QualType t = (*PI)->getType()->isObjCQualifiedIdType() + ? Context->getObjCIdType() + : (*PI)->getType(); + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(t); + ArgTypes.push_back(t); + } + returnType = OMD->getResultType()->isObjCQualifiedIdType() + ? Context->getObjCIdType() : OMD->getResultType(); + (void)convertBlockPointerToFunctionPointer(returnType); + } else { + returnType = Context->getObjCIdType(); + } + // Get the type, we will need to reference it in a couple spots. + QualType msgSendType = MsgSendFlavor->getType(); + + // Create a reference to the objc_msgSend() declaration. + DeclRefExpr *DRE = new (Context) DeclRefExpr(MsgSendFlavor, msgSendType, + SourceLocation()); + + // Need to cast objc_msgSend to "void *" (to workaround a GCC bandaid). + // If we don't do this cast, we get the following bizarre warning/note: + // xx.m:13: warning: function called through a non-compatible type + // xx.m:13: note: if this code is reached, the program will abort + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, DRE); + + // Now do the "normal" pointer to function cast. + QualType castType = Context->getFunctionType(returnType, + &ArgTypes[0], ArgTypes.size(), + // If we don't have a method decl, force a variadic cast. + Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); + + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); + + const FunctionType *FT = msgSendType->getAs<FunctionType>(); + CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], + MsgExprs.size(), + FT->getResultType(), EndLoc); + Stmt *ReplacingStmt = CE; + if (MsgSendStretFlavor) { + // We have the method which returns a struct/union. Must also generate + // call to objc_msgSend_stret and hang both varieties on a conditional + // expression which dictate which one to envoke depending on size of + // method's return type. + + // Create a reference to the objc_msgSend_stret() declaration. + DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType, + SourceLocation()); + // Need to cast objc_msgSend_stret to "void *" (see above comment). + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, STDRE); + // Now do the "normal" pointer to function cast. + castType = Context->getFunctionType(returnType, + &ArgTypes[0], ArgTypes.size(), + Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + castType = Context->getPointerType(castType); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); + + // Don't forget the parens to enforce the proper binding. + PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); + + FT = msgSendType->getAs<FunctionType>(); + CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], + MsgExprs.size(), + FT->getResultType(), SourceLocation()); + + // Build sizeof(returnType) + SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, + Context->getTrivialTypeSourceInfo(returnType), + Context->getSizeType(), + SourceLocation(), SourceLocation()); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. + // For X86 it is more complicated and some kind of target specific routine + // is needed to decide what to do. + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8), + Context->IntTy, + SourceLocation()); + BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit, + BinaryOperator::LE, + Context->IntTy, + SourceLocation()); + // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(lessThanExpr, + SourceLocation(), CE, + SourceLocation(), STCE, returnType); + ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr); + } + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return ReplacingStmt; +} + +Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) { + Stmt *ReplacingStmt = SynthMessageExpr(Exp, Exp->getLocStart(), + Exp->getLocEnd()); + + // Now do the actual rewrite. + ReplaceStmt(Exp, ReplacingStmt); + + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return ReplacingStmt; +} + +// typedef struct objc_object Protocol; +QualType RewriteObjC::getProtocolType() { + if (!ProtocolTypeDecl) { + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); + ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, + SourceLocation(), + &Context->Idents.get("Protocol"), + TInfo); + } + return Context->getTypeDeclType(ProtocolTypeDecl); +} + +/// RewriteObjCProtocolExpr - Rewrite a protocol expression into +/// a synthesized/forward data reference (to the protocol's metadata). +/// The forward references (and metadata) are generated in +/// RewriteObjC::HandleTranslationUnit(). +Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { + std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); + IdentifierInfo *ID = &Context->Idents.get(Name); + VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + ID, getProtocolType(), 0, + VarDecl::Extern, VarDecl::None); + DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation()); + Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, + Context->getPointerType(DRE->getType()), + SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), + CastExpr::CK_Unknown, + DerefExpr); + ReplaceStmt(Exp, castExpr); + ProtocolExprDecls.insert(Exp->getProtocol()); + // delete Exp; leak for now, see RewritePropertySetter() usage for more info. + return castExpr; + +} + +bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, + const char *endBuf) { + while (startBuf < endBuf) { + if (*startBuf == '#') { + // Skip whitespace. + for (++startBuf; startBuf[0] == ' ' || startBuf[0] == '\t'; ++startBuf) + ; + if (!strncmp(startBuf, "if", strlen("if")) || + !strncmp(startBuf, "ifdef", strlen("ifdef")) || + !strncmp(startBuf, "ifndef", strlen("ifndef")) || + !strncmp(startBuf, "define", strlen("define")) || + !strncmp(startBuf, "undef", strlen("undef")) || + !strncmp(startBuf, "else", strlen("else")) || + !strncmp(startBuf, "elif", strlen("elif")) || + !strncmp(startBuf, "endif", strlen("endif")) || + !strncmp(startBuf, "pragma", strlen("pragma")) || + !strncmp(startBuf, "include", strlen("include")) || + !strncmp(startBuf, "import", strlen("import")) || + !strncmp(startBuf, "include_next", strlen("include_next"))) + return true; + } + startBuf++; + } + return false; +} + +/// SynthesizeObjCInternalStruct - Rewrite one internal struct corresponding to +/// an objective-c class with ivars. +void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, + std::string &Result) { + assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); + assert(CDecl->getNameAsCString() && + "Name missing in SynthesizeObjCInternalStruct"); + // Do not synthesize more than once. + if (ObjCSynthesizedStructs.count(CDecl)) + return; + ObjCInterfaceDecl *RCDecl = CDecl->getSuperClass(); + int NumIvars = CDecl->ivar_size(); + SourceLocation LocStart = CDecl->getLocStart(); + SourceLocation LocEnd = CDecl->getLocEnd(); + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + + // If no ivars and no root or if its root, directly or indirectly, + // have no ivars (thus not synthesized) then no need to synthesize this class. + if ((CDecl->isForwardDecl() || NumIvars == 0) && + (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + ReplaceText(LocStart, endBuf-startBuf, Result); + return; + } + + // FIXME: This has potential of causing problem. If + // SynthesizeObjCInternalStruct is ever called recursively. + Result += "\nstruct "; + Result += CDecl->getNameAsString(); + if (LangOpts.Microsoft) + Result += "_IMPL"; + + if (NumIvars > 0) { + const char *cursor = strchr(startBuf, '{'); + assert((cursor && endBuf) + && "SynthesizeObjCInternalStruct - malformed @interface"); + // If the buffer contains preprocessor directives, we do more fine-grained + // rewrites. This is intended to fix code that looks like (which occurs in + // NSURL.h, for example): + // + // #ifdef XYZ + // @interface Foo : NSObject + // #else + // @interface FooBar : NSObject + // #endif + // { + // int i; + // } + // @end + // + // This clause is segregated to avoid breaking the common case. + if (BufferContainsPPDirectives(startBuf, cursor)) { + SourceLocation L = RCDecl ? CDecl->getSuperClassLoc() : + CDecl->getClassLoc(); + const char *endHeader = SM->getCharacterData(L); + endHeader += Lexer::MeasureTokenLength(L, *SM, LangOpts); + + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + // advance to the end of the referenced protocols. + while (endHeader < cursor && *endHeader != '>') endHeader++; + endHeader++; + } + // rewrite the original header + ReplaceText(LocStart, endHeader-startBuf, Result); + } else { + // rewrite the original header *without* disturbing the '{' + ReplaceText(LocStart, cursor-startBuf, Result); + } + if (RCDecl && ObjCSynthesizedStructs.count(RCDecl)) { + Result = "\n struct "; + Result += RCDecl->getNameAsString(); + Result += "_IMPL "; + Result += RCDecl->getNameAsString(); + Result += "_IVARS;\n"; + + // insert the super class structure definition. + SourceLocation OnePastCurly = + LocStart.getFileLocWithOffset(cursor-startBuf+1); + InsertText(OnePastCurly, Result); + } + cursor++; // past '{' + + // Now comment out any visibility specifiers. + while (cursor < endBuf) { + if (*cursor == '@') { + SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + // Skip whitespace. + for (++cursor; cursor[0] == ' ' || cursor[0] == '\t'; ++cursor) + /*scan*/; + + // FIXME: presence of @public, etc. inside comment results in + // this transformation as well, which is still correct c-code. + if (!strncmp(cursor, "public", strlen("public")) || + !strncmp(cursor, "private", strlen("private")) || + !strncmp(cursor, "package", strlen("package")) || + !strncmp(cursor, "protected", strlen("protected"))) + InsertText(atLoc, "// "); + } + // FIXME: If there are cases where '<' is used in ivar declaration part + // of user code, then scan the ivar list and use needToScanForQualifiers + // for type checking. + else if (*cursor == '<') { + SourceLocation atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + InsertText(atLoc, "/* "); + cursor = strchr(cursor, '>'); + cursor++; + atLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + InsertText(atLoc, " */"); + } else if (*cursor == '^') { // rewrite block specifier. + SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf); + ReplaceText(caretLoc, 1, "*"); + } + cursor++; + } + // Don't forget to add a ';'!! + InsertText(LocEnd.getFileLocWithOffset(1), ";"); + } else { // we don't have any instance variables - insert super struct. + endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); + Result += " {\n struct "; + Result += RCDecl->getNameAsString(); + Result += "_IMPL "; + Result += RCDecl->getNameAsString(); + Result += "_IVARS;\n};\n"; + ReplaceText(LocStart, endBuf-startBuf, Result); + } + // Mark this struct as having been generated. + if (!ObjCSynthesizedStructs.insert(CDecl)) + assert(false && "struct already synthesize- SynthesizeObjCInternalStruct"); +} + +// RewriteObjCMethodsMetaData - Rewrite methods metadata for instance or +/// class methods. +template<typename MethodIterator> +void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, + MethodIterator MethodEnd, + bool IsInstanceMethod, + const char *prefix, + const char *ClassName, + std::string &Result) { + if (MethodBegin == MethodEnd) return; + + if (!objc_impl_method) { + /* struct _objc_method { + SEL _cmd; + char *method_types; + void *_imp; + } + */ + Result += "\nstruct _objc_method {\n"; + Result += "\tSEL _cmd;\n"; + Result += "\tchar *method_types;\n"; + Result += "\tvoid *_imp;\n"; + Result += "};\n"; + + objc_impl_method = true; + } + + // Build _objc_method_list for class's methods if needed + + /* struct { + struct _objc_method_list *next_method; + int method_count; + struct _objc_method method_list[]; + } + */ + unsigned NumMethods = std::distance(MethodBegin, MethodEnd); + Result += "\nstatic struct {\n"; + Result += "\tstruct _objc_method_list *next_method;\n"; + Result += "\tint method_count;\n"; + Result += "\tstruct _objc_method method_list["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += IsInstanceMethod ? "INSTANCE" : "CLASS"; + Result += "_METHODS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __"; + Result += IsInstanceMethod ? "inst" : "cls"; + Result += "_meth\")))= "; + Result += "{\n\t0, " + utostr(NumMethods) + "\n"; + + Result += "\t,{{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + for (++MethodBegin; MethodBegin != MethodEnd; ++MethodBegin) { + Result += "\t ,{(SEL)\""; + Result += (*MethodBegin)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl(*MethodBegin, MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\", (void *)"; + Result += MethodInternalNames[*MethodBegin]; + Result += "}\n"; + } + Result += "\t }\n};\n"; +} + +/// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. +void RewriteObjC:: +RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix, + const char *ClassName, std::string &Result) { + static bool objc_protocol_methods = false; + + // Output struct protocol_methods holder of method selector and type. + if (!objc_protocol_methods && !PDecl->isForwardDecl()) { + /* struct protocol_methods { + SEL _cmd; + char *method_types; + } + */ + Result += "\nstruct _protocol_methods {\n"; + Result += "\tstruct objc_selector *_cmd;\n"; + Result += "\tchar *method_types;\n"; + Result += "};\n"; + + objc_protocol_methods = true; + } + // Do not synthesize the protocol more than once. + if (ObjCSynthesizedProtocols.count(PDecl)) + return; + + if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { + unsigned NumMethods = std::distance(PDecl->instmeth_begin(), + PDecl->instmeth_end()); + /* struct _objc_protocol_method_list { + int protocol_method_count; + struct protocol_methods protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tint protocol_method_count;\n"; + Result += "\tstruct _protocol_methods protocol_methods["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= " + "{\n\t" + utostr(NumMethods) + "\n"; + + // Output instance methods declared in this protocol. + for (ObjCProtocolDecl::instmeth_iterator + I = PDecl->instmeth_begin(), E = PDecl->instmeth_end(); + I != E; ++I) { + if (I == PDecl->instmeth_begin()) + Result += "\t ,{{(struct objc_selector *)\""; + else + Result += "\t ,{(struct objc_selector *)\""; + Result += (*I)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\"}\n"; + } + Result += "\t }\n};\n"; + } + + // Output class methods declared in this protocol. + unsigned NumMethods = std::distance(PDecl->classmeth_begin(), + PDecl->classmeth_end()); + if (NumMethods > 0) { + /* struct _objc_protocol_method_list { + int protocol_method_count; + struct protocol_methods protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tint protocol_method_count;\n"; + Result += "\tstruct _protocol_methods protocol_methods["; + Result += utostr(NumMethods); + Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " + "{\n\t"; + Result += utostr(NumMethods); + Result += "\n"; + + // Output instance methods declared in this protocol. + for (ObjCProtocolDecl::classmeth_iterator + I = PDecl->classmeth_begin(), E = PDecl->classmeth_end(); + I != E; ++I) { + if (I == PDecl->classmeth_begin()) + Result += "\t ,{{(struct objc_selector *)\""; + else + Result += "\t ,{(struct objc_selector *)\""; + Result += (*I)->getSelector().getAsString().c_str(); + std::string MethodTypeString; + Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); + Result += "\", \""; + Result += MethodTypeString; + Result += "\"}\n"; + } + Result += "\t }\n};\n"; + } + + // Output: + /* struct _objc_protocol { + // Objective-C 1.0 extensions + struct _objc_protocol_extension *isa; + char *protocol_name; + struct _objc_protocol **protocol_list; + struct _objc_protocol_method_list *instance_methods; + struct _objc_protocol_method_list *class_methods; + }; + */ + static bool objc_protocol = false; + if (!objc_protocol) { + Result += "\nstruct _objc_protocol {\n"; + Result += "\tstruct _objc_protocol_extension *isa;\n"; + Result += "\tchar *protocol_name;\n"; + Result += "\tstruct _objc_protocol **protocol_list;\n"; + Result += "\tstruct _objc_protocol_method_list *instance_methods;\n"; + Result += "\tstruct _objc_protocol_method_list *class_methods;\n"; + Result += "};\n"; + + objc_protocol = true; + } + + Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_"; + Result += PDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= " + "{\n\t0, \""; + Result += PDecl->getNameAsString(); + Result += "\", 0, "; + if (PDecl->instmeth_begin() != PDecl->instmeth_end()) { + Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_"; + Result += PDecl->getNameAsString(); + Result += ", "; + } + else + Result += "0, "; + if (PDecl->classmeth_begin() != PDecl->classmeth_end()) { + Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_"; + Result += PDecl->getNameAsString(); + Result += "\n"; + } + else + Result += "0\n"; + Result += "};\n"; + + // Mark this protocol as having been generated. + if (!ObjCSynthesizedProtocols.insert(PDecl)) + assert(false && "protocol already synthesized"); + +} + +void RewriteObjC:: +RewriteObjCProtocolListMetaData(const ObjCList<ObjCProtocolDecl> &Protocols, + const char *prefix, const char *ClassName, + std::string &Result) { + if (Protocols.empty()) return; + + for (unsigned i = 0; i != Protocols.size(); i++) + RewriteObjCProtocolMetaData(Protocols[i], prefix, ClassName, Result); + + // Output the top lovel protocol meta-data for the class. + /* struct _objc_protocol_list { + struct _objc_protocol_list *next; + int protocol_count; + struct _objc_protocol *class_protocols[]; + } + */ + Result += "\nstatic struct {\n"; + Result += "\tstruct _objc_protocol_list *next;\n"; + Result += "\tint protocol_count;\n"; + Result += "\tstruct _objc_protocol *class_protocols["; + Result += utostr(Protocols.size()); + Result += "];\n} _OBJC_"; + Result += prefix; + Result += "_PROTOCOLS_"; + Result += ClassName; + Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= " + "{\n\t0, "; + Result += utostr(Protocols.size()); + Result += "\n"; + + Result += "\t,{&_OBJC_PROTOCOL_"; + Result += Protocols[0]->getNameAsString(); + Result += " \n"; + + for (unsigned i = 1; i != Protocols.size(); i++) { + Result += "\t ,&_OBJC_PROTOCOL_"; + Result += Protocols[i]->getNameAsString(); + Result += "\n"; + } + Result += "\t }\n};\n"; +} + + +/// RewriteObjCCategoryImplDecl - Rewrite metadata for each category +/// implementation. +void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, + std::string &Result) { + ObjCInterfaceDecl *ClassDecl = IDecl->getClassInterface(); + // Find category declaration for this implementation. + ObjCCategoryDecl *CDecl; + for (CDecl = ClassDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->getIdentifier() == IDecl->getIdentifier()) + break; + + std::string FullCategoryName = ClassDecl->getNameAsString(); + FullCategoryName += '_'; + FullCategoryName += IDecl->getNameAsString(); + + // Build _objc_method_list for class's instance methods if needed + llvm::SmallVector<ObjCMethodDecl *, 32> + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!(*Prop)->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + InstanceMethods.push_back(Setter); + } + RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), + true, "CATEGORY_", FullCategoryName.c_str(), + Result); + + // Build _objc_method_list for class's class methods if needed + RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), + false, "CATEGORY_", FullCategoryName.c_str(), + Result); + + // Protocols referenced in class declaration? + // Null CDecl is case of a category implementation with no category interface + if (CDecl) + RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY", + FullCategoryName.c_str(), Result); + /* struct _objc_category { + char *category_name; + char *class_name; + struct _objc_method_list *instance_methods; + struct _objc_method_list *class_methods; + struct _objc_protocol_list *protocols; + // Objective-C 1.0 extensions + uint32_t size; // sizeof (struct _objc_category) + struct _objc_property_list *instance_properties; // category's own + // @property decl. + }; + */ + + static bool objc_category = false; + if (!objc_category) { + Result += "\nstruct _objc_category {\n"; + Result += "\tchar *category_name;\n"; + Result += "\tchar *class_name;\n"; + Result += "\tstruct _objc_method_list *instance_methods;\n"; + Result += "\tstruct _objc_method_list *class_methods;\n"; + Result += "\tstruct _objc_protocol_list *protocols;\n"; + Result += "\tunsigned int size;\n"; + Result += "\tstruct _objc_property_list *instance_properties;\n"; + Result += "};\n"; + objc_category = true; + } + Result += "\nstatic struct _objc_category _OBJC_CATEGORY_"; + Result += FullCategoryName; + Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\""; + Result += IDecl->getNameAsString(); + Result += "\"\n\t, \""; + Result += ClassDecl->getNameAsString(); + Result += "\"\n"; + + if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { + Result += "\t, (struct _objc_method_list *)" + "&_OBJC_CATEGORY_INSTANCE_METHODS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { + Result += "\t, (struct _objc_method_list *)" + "&_OBJC_CATEGORY_CLASS_METHODS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + + if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_"; + Result += FullCategoryName; + Result += "\n"; + } + else + Result += "\t, 0\n"; + Result += "\t, sizeof(struct _objc_category), 0\n};\n"; +} + +/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of +/// ivar offset. +void RewriteObjC::SynthesizeIvarOffsetComputation(ObjCContainerDecl *IDecl, + ObjCIvarDecl *ivar, + std::string &Result) { + if (ivar->isBitField()) { + // FIXME: The hack below doesn't work for bitfields. For now, we simply + // place all bitfields at offset 0. + Result += "0"; + } else { + Result += "__OFFSETOFIVAR__(struct "; + Result += IDecl->getNameAsString(); + if (LangOpts.Microsoft) + Result += "_IMPL"; + Result += ", "; + Result += ivar->getNameAsString(); + Result += ")"; + } +} + +//===----------------------------------------------------------------------===// +// Meta Data Emission +//===----------------------------------------------------------------------===// + +void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, + std::string &Result) { + ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); + + // Explictly declared @interface's are already synthesized. + if (CDecl->isImplicitInterfaceDecl()) { + // FIXME: Implementation of a class with no @interface (legacy) doese not + // produce correct synthesis as yet. + SynthesizeObjCInternalStruct(CDecl, Result); + } + + // Build _objc_ivar_list metadata for classes ivars if needed + unsigned NumIvars = !IDecl->ivar_empty() + ? IDecl->ivar_size() + : (CDecl ? CDecl->ivar_size() : 0); + if (NumIvars > 0) { + static bool objc_ivar = false; + if (!objc_ivar) { + /* struct _objc_ivar { + char *ivar_name; + char *ivar_type; + int ivar_offset; + }; + */ + Result += "\nstruct _objc_ivar {\n"; + Result += "\tchar *ivar_name;\n"; + Result += "\tchar *ivar_type;\n"; + Result += "\tint ivar_offset;\n"; + Result += "};\n"; + + objc_ivar = true; + } + + /* struct { + int ivar_count; + struct _objc_ivar ivar_list[nIvars]; + }; + */ + Result += "\nstatic struct {\n"; + Result += "\tint ivar_count;\n"; + Result += "\tstruct _objc_ivar ivar_list["; + Result += utostr(NumIvars); + Result += "];\n} _OBJC_INSTANCE_VARIABLES_"; + Result += IDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= " + "{\n\t"; + Result += utostr(NumIvars); + Result += "\n"; + + ObjCInterfaceDecl::ivar_iterator IVI, IVE; + llvm::SmallVector<ObjCIvarDecl *, 8> IVars; + if (!IDecl->ivar_empty()) { + for (ObjCInterfaceDecl::ivar_iterator + IV = IDecl->ivar_begin(), IVEnd = IDecl->ivar_end(); + IV != IVEnd; ++IV) + IVars.push_back(*IV); + IVI = IDecl->ivar_begin(); + IVE = IDecl->ivar_end(); + } else { + IVI = CDecl->ivar_begin(); + IVE = CDecl->ivar_end(); + } + Result += "\t,{{\""; + Result += (*IVI)->getNameAsString(); + Result += "\", \""; + std::string TmpString, StrEncoding; + Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI); + QuoteDoublequotes(TmpString, StrEncoding); + Result += StrEncoding; + Result += "\", "; + SynthesizeIvarOffsetComputation(IDecl, *IVI, Result); + Result += "}\n"; + for (++IVI; IVI != IVE; ++IVI) { + Result += "\t ,{\""; + Result += (*IVI)->getNameAsString(); + Result += "\", \""; + std::string TmpString, StrEncoding; + Context->getObjCEncodingForType((*IVI)->getType(), TmpString, *IVI); + QuoteDoublequotes(TmpString, StrEncoding); + Result += StrEncoding; + Result += "\", "; + SynthesizeIvarOffsetComputation(IDecl, (*IVI), Result); + Result += "}\n"; + } + + Result += "\t }\n};\n"; + } + + // Build _objc_method_list for class's instance methods if needed + llvm::SmallVector<ObjCMethodDecl *, 32> + InstanceMethods(IDecl->instmeth_begin(), IDecl->instmeth_end()); + + // If any of our property implementations have associated getters or + // setters, produce metadata for them as well. + for (ObjCImplDecl::propimpl_iterator Prop = IDecl->propimpl_begin(), + PropEnd = IDecl->propimpl_end(); + Prop != PropEnd; ++Prop) { + if ((*Prop)->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + continue; + if (!(*Prop)->getPropertyIvarDecl()) + continue; + ObjCPropertyDecl *PD = (*Prop)->getPropertyDecl(); + if (!PD) + continue; + if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + InstanceMethods.push_back(Getter); + if (PD->isReadOnly()) + continue; + if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + InstanceMethods.push_back(Setter); + } + RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), + true, "", IDecl->getNameAsCString(), Result); + + // Build _objc_method_list for class's class methods if needed + RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), + false, "", IDecl->getNameAsCString(), Result); + + // Protocols referenced in class declaration? + RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), + "CLASS", CDecl->getNameAsCString(), Result); + + // Declaration of class/meta-class metadata + /* struct _objc_class { + struct _objc_class *isa; // or const char *root_class_name when metadata + const char *super_class_name; + char *name; + long version; + long info; + long instance_size; + struct _objc_ivar_list *ivars; + struct _objc_method_list *methods; + struct objc_cache *cache; + struct objc_protocol_list *protocols; + const char *ivar_layout; + struct _objc_class_ext *ext; + }; + */ + static bool objc_class = false; + if (!objc_class) { + Result += "\nstruct _objc_class {\n"; + Result += "\tstruct _objc_class *isa;\n"; + Result += "\tconst char *super_class_name;\n"; + Result += "\tchar *name;\n"; + Result += "\tlong version;\n"; + Result += "\tlong info;\n"; + Result += "\tlong instance_size;\n"; + Result += "\tstruct _objc_ivar_list *ivars;\n"; + Result += "\tstruct _objc_method_list *methods;\n"; + Result += "\tstruct objc_cache *cache;\n"; + Result += "\tstruct _objc_protocol_list *protocols;\n"; + Result += "\tconst char *ivar_layout;\n"; + Result += "\tstruct _objc_class_ext *ext;\n"; + Result += "};\n"; + objc_class = true; + } + + // Meta-class metadata generation. + ObjCInterfaceDecl *RootClass = 0; + ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass(); + while (SuperClass) { + RootClass = SuperClass; + SuperClass = SuperClass->getSuperClass(); + } + SuperClass = CDecl->getSuperClass(); + + Result += "\nstatic struct _objc_class _OBJC_METACLASS_"; + Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= " + "{\n\t(struct _objc_class *)\""; + Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString()); + Result += "\""; + + if (SuperClass) { + Result += ", \""; + Result += SuperClass->getNameAsString(); + Result += "\", \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + else { + Result += ", 0, \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it. + // 'info' field is initialized to CLS_META(2) for metaclass + Result += ", 0,2, sizeof(struct _objc_class), 0"; + if (IDecl->classmeth_begin() != IDecl->classmeth_end()) { + Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_"; + Result += IDecl->getNameAsString(); + Result += "\n"; + } + else + Result += ", 0\n"; + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_"; + Result += CDecl->getNameAsString(); + Result += ",0,0\n"; + } + else + Result += "\t,0,0,0,0\n"; + Result += "};\n"; + + // class metadata generation. + Result += "\nstatic struct _objc_class _OBJC_CLASS_"; + Result += CDecl->getNameAsString(); + Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= " + "{\n\t&_OBJC_METACLASS_"; + Result += CDecl->getNameAsString(); + if (SuperClass) { + Result += ", \""; + Result += SuperClass->getNameAsString(); + Result += "\", \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + else { + Result += ", 0, \""; + Result += CDecl->getNameAsString(); + Result += "\""; + } + // 'info' field is initialized to CLS_CLASS(1) for class + Result += ", 0,1"; + if (!ObjCSynthesizedStructs.count(CDecl)) + Result += ",0"; + else { + // class has size. Must synthesize its size. + Result += ",sizeof(struct "; + Result += CDecl->getNameAsString(); + if (LangOpts.Microsoft) + Result += "_IMPL"; + Result += ")"; + } + if (NumIvars > 0) { + Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_"; + Result += CDecl->getNameAsString(); + Result += "\n\t"; + } + else + Result += ",0"; + if (IDecl->instmeth_begin() != IDecl->instmeth_end()) { + Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_"; + Result += CDecl->getNameAsString(); + Result += ", 0\n\t"; + } + else + Result += ",0,0"; + if (CDecl->protocol_begin() != CDecl->protocol_end()) { + Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_"; + Result += CDecl->getNameAsString(); + Result += ", 0,0\n"; + } + else + Result += ",0,0,0\n"; + Result += "};\n"; +} + +/// RewriteImplementations - This routine rewrites all method implementations +/// and emits meta-data. + +void RewriteObjC::RewriteImplementations() { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // Rewrite implemented methods + for (int i = 0; i < ClsDefCount; i++) + RewriteImplementationDecl(ClassImplementation[i]); + + for (int i = 0; i < CatDefCount; i++) + RewriteImplementationDecl(CategoryImplementation[i]); +} + +void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) { + int ClsDefCount = ClassImplementation.size(); + int CatDefCount = CategoryImplementation.size(); + + // For each implemented class, write out all its meta data. + for (int i = 0; i < ClsDefCount; i++) + RewriteObjCClassMetaData(ClassImplementation[i], Result); + + // For each implemented category, write out all its meta data. + for (int i = 0; i < CatDefCount; i++) + RewriteObjCCategoryImplDecl(CategoryImplementation[i], Result); + + // Write objc_symtab metadata + /* + struct _objc_symtab + { + long sel_ref_cnt; + SEL *refs; + short cls_def_cnt; + short cat_def_cnt; + void *defs[cls_def_cnt + cat_def_cnt]; + }; + */ + + Result += "\nstruct _objc_symtab {\n"; + Result += "\tlong sel_ref_cnt;\n"; + Result += "\tSEL *refs;\n"; + Result += "\tshort cls_def_cnt;\n"; + Result += "\tshort cat_def_cnt;\n"; + Result += "\tvoid *defs[" + utostr(ClsDefCount + CatDefCount)+ "];\n"; + Result += "};\n\n"; + + Result += "static struct _objc_symtab " + "_OBJC_SYMBOLS __attribute__((used, section (\"__OBJC, __symbols\")))= {\n"; + Result += "\t0, 0, " + utostr(ClsDefCount) + + ", " + utostr(CatDefCount) + "\n"; + for (int i = 0; i < ClsDefCount; i++) { + Result += "\t,&_OBJC_CLASS_"; + Result += ClassImplementation[i]->getNameAsString(); + Result += "\n"; + } + + for (int i = 0; i < CatDefCount; i++) { + Result += "\t,&_OBJC_CATEGORY_"; + Result += CategoryImplementation[i]->getClassInterface()->getNameAsString(); + Result += "_"; + Result += CategoryImplementation[i]->getNameAsString(); + Result += "\n"; + } + + Result += "};\n\n"; + + // Write objc_module metadata + + /* + struct _objc_module { + long version; + long size; + const char *name; + struct _objc_symtab *symtab; + } + */ + + Result += "\nstruct _objc_module {\n"; + Result += "\tlong version;\n"; + Result += "\tlong size;\n"; + Result += "\tconst char *name;\n"; + Result += "\tstruct _objc_symtab *symtab;\n"; + Result += "};\n\n"; + Result += "static struct _objc_module " + "_OBJC_MODULES __attribute__ ((used, section (\"__OBJC, __module_info\")))= {\n"; + Result += "\t" + utostr(OBJC_ABI_VERSION) + + ", sizeof(struct _objc_module), \"\", &_OBJC_SYMBOLS\n"; + Result += "};\n\n"; + + if (LangOpts.Microsoft) { + if (ProtocolExprDecls.size()) { + Result += "#pragma section(\".objc_protocol$B\",long,read,write)\n"; + Result += "#pragma data_seg(push, \".objc_protocol$B\")\n"; + for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(), + E = ProtocolExprDecls.end(); I != E; ++I) { + Result += "static struct _objc_protocol *_POINTER_OBJC_PROTOCOL_"; + Result += (*I)->getNameAsString(); + Result += " = &_OBJC_PROTOCOL_"; + Result += (*I)->getNameAsString(); + Result += ";\n"; + } + Result += "#pragma data_seg(pop)\n\n"; + } + Result += "#pragma section(\".objc_module_info$B\",long,read,write)\n"; + Result += "#pragma data_seg(push, \".objc_module_info$B\")\n"; + Result += "static struct _objc_module *_POINTER_OBJC_MODULES = "; + Result += "&_OBJC_MODULES;\n"; + Result += "#pragma data_seg(pop)\n\n"; + } +} + +void RewriteObjC::RewriteByRefString(std::string &ResultStr, + const std::string &Name, + ValueDecl *VD) { + assert(BlockByRefDeclNo.count(VD) && + "RewriteByRefString: ByRef decl missing"); + ResultStr += "struct __Block_byref_" + Name + + "_" + utostr(BlockByRefDeclNo[VD]) ; +} + +static bool HasLocalVariableExternalStorage(ValueDecl *VD) { + if (VarDecl *Var = dyn_cast<VarDecl>(VD)) + return (Var->isFunctionOrMethodVarDecl() && !Var->hasLocalStorage()); + return false; +} + +std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, + const char *funcName, + std::string Tag) { + const FunctionType *AFT = CE->getFunctionType(); + QualType RT = AFT->getResultType(); + std::string StructRef = "struct " + Tag; + std::string S = "static " + RT.getAsString() + " __" + + funcName + "_" + "block_func_" + utostr(i); + + BlockDecl *BD = CE->getBlockDecl(); + + if (isa<FunctionNoProtoType>(AFT)) { + // No user-supplied arguments. Still need to pass in a pointer to the + // block (to reference imported block decl refs). + S += "(" + StructRef + " *__cself)"; + } else if (BD->param_empty()) { + S += "(" + StructRef + " *__cself)"; + } else { + const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); + assert(FT && "SynthesizeBlockFunc: No function proto"); + S += '('; + // first add the implicit argument. + S += StructRef + " *__cself, "; + std::string ParamStr; + for (BlockDecl::param_iterator AI = BD->param_begin(), + E = BD->param_end(); AI != E; ++AI) { + if (AI != BD->param_begin()) S += ", "; + ParamStr = (*AI)->getNameAsString(); + QualType QT = (*AI)->getType(); + if (convertBlockPointerToFunctionPointer(QT)) + QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); + else + QT.getAsStringInternal(ParamStr, Context->PrintingPolicy); + S += ParamStr; + } + if (FT->isVariadic()) { + if (!BD->param_empty()) S += ", "; + S += "..."; + } + S += ')'; + } + S += " {\n"; + + // Create local declarations to avoid rewriting all closure decl ref exprs. + // First, emit a declaration for all "by ref" decls. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string Name = (*I)->getNameAsString(); + std::string TypeString; + RewriteByRefString(TypeString, Name, (*I)); + TypeString += " *"; + Name = TypeString + Name; + S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; + } + // Next, emit a declaration for all "by copy" declarations. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + // Handle nested closure invocation. For example: + // + // void (^myImportedClosure)(void); + // myImportedClosure = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherClosure)(void); + // anotherClosure = ^(void) { + // myImportedClosure(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + RewriteBlockPointerTypeVariable(S, (*I)); + S += " = ("; + RewriteBlockPointerType(S, (*I)->getType()); + S += ")"; + S += "__cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; + } + else { + std::string Name = (*I)->getNameAsString(); + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(Name, Context->PrintingPolicy); + S += Name + " = __cself->" + + (*I)->getNameAsString() + "; // bound by copy\n"; + } + } + std::string RewrittenStr = RewrittenBlockExprs[CE]; + const char *cstr = RewrittenStr.c_str(); + while (*cstr++ != '{') ; + S += cstr; + S += "\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, + const char *funcName, + std::string Tag) { + std::string StructRef = "struct " + Tag; + std::string S = "static void __"; + + S += funcName; + S += "_block_copy_" + utostr(i); + S += "(" + StructRef; + S += "*dst, " + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + S += "_Block_object_assign((void*)&dst->"; + S += (*I)->getNameAsString(); + S += ", (void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + + S += "\nstatic void __"; + S += funcName; + S += "_block_dispose_" + utostr(i); + S += "(" + StructRef; + S += "*src) {"; + for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), + E = ImportedBlockDecls.end(); I != E; ++I) { + S += "_Block_object_dispose((void*)src->"; + S += (*I)->getNameAsString(); + if (BlockByRefDeclsPtrSet.count((*I))) + S += ", " + utostr(BLOCK_FIELD_IS_BYREF) + "/*BLOCK_FIELD_IS_BYREF*/);"; + else + S += ", " + utostr(BLOCK_FIELD_IS_OBJECT) + "/*BLOCK_FIELD_IS_OBJECT*/);"; + } + S += "}\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, + std::string Desc) { + std::string S = "\nstruct " + Tag; + std::string Constructor = " " + Tag; + + S += " {\n struct __block_impl impl;\n"; + S += " struct " + Desc; + S += "* Desc;\n"; + + Constructor += "(void *fp, "; // Invoke function pointer. + Constructor += "struct " + Desc; // Descriptor pointer. + Constructor += " *desc"; + + if (BlockDeclRefs.size()) { + // Output all "by copy" declarations. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + // Handle nested closure invocation. For example: + // + // void (^myImportedBlock)(void); + // myImportedBlock = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherBlock)(void); + // anotherBlock = ^(void) { + // myImportedBlock(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + S += "struct __block_impl *"; + Constructor += ", void *" + ArgName; + } else { + QualType QT = (*I)->getType(); + if (HasLocalVariableExternalStorage(*I)) + QT = Context->getPointerType(QT); + QT.getAsStringInternal(FieldName, Context->PrintingPolicy); + QT.getAsStringInternal(ArgName, Context->PrintingPolicy); + Constructor += ", " + ArgName; + } + S += FieldName + ";\n"; + } + // Output all "by ref" declarations. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + S += " "; + std::string FieldName = (*I)->getNameAsString(); + std::string ArgName = "_" + FieldName; + // Handle nested closure invocation. For example: + // + // void (^myImportedBlock)(void); + // myImportedBlock = ^(void) { setGlobalInt(x + y); }; + // + // void (^anotherBlock)(void); + // anotherBlock = ^(void) { + // myImportedBlock(); // import and invoke the closure + // }; + // + if (isTopLevelBlockPointerType((*I)->getType())) { + S += "struct __block_impl *"; + Constructor += ", void *" + ArgName; + } else { + std::string TypeString; + RewriteByRefString(TypeString, FieldName, (*I)); + TypeString += " *"; + FieldName = TypeString + FieldName; + ArgName = TypeString + ArgName; + Constructor += ", " + ArgName; + } + S += FieldName + "; // by ref\n"; + } + // Finish writing the constructor. + Constructor += ", int flags=0) {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + + Constructor += " Desc = desc;\n"; + + // Initialize all "by copy" arguments. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + Constructor += " "; + if (isTopLevelBlockPointerType((*I)->getType())) + Constructor += Name + " = (struct __block_impl *)_"; + else + Constructor += Name + " = _"; + Constructor += Name + ";\n"; + } + // Initialize all "by ref" arguments. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + std::string Name = (*I)->getNameAsString(); + Constructor += " "; + if (isTopLevelBlockPointerType((*I)->getType())) + Constructor += Name + " = (struct __block_impl *)_"; + else + Constructor += Name + " = _"; + Constructor += Name + "->__forwarding;\n"; + } + } else { + // Finish writing the constructor. + Constructor += ", int flags=0) {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + Constructor += " Desc = desc;\n"; + } + Constructor += " "; + Constructor += "}\n"; + S += Constructor; + S += "};\n"; + return S; +} + +std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, + std::string ImplTag, int i, + const char *FunName, + unsigned hasCopy) { + std::string S = "\nstatic struct " + DescTag; + + S += " {\n unsigned long reserved;\n"; + S += " unsigned long Block_size;\n"; + if (hasCopy) { + S += " void (*copy)(struct "; + S += ImplTag; S += "*, struct "; + S += ImplTag; S += "*);\n"; + + S += " void (*dispose)(struct "; + S += ImplTag; S += "*);\n"; + } + S += "} "; + + S += DescTag + "_DATA = { 0, sizeof(struct "; + S += ImplTag + ")"; + if (hasCopy) { + S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i); + S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i); + } + S += "};\n"; + return S; +} + +void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, + const char *FunName) { + // Insert declaration for the function in which block literal is used. + if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); + bool RewriteSC = (GlobalVarDecl && + !Blocks.empty() && + GlobalVarDecl->getStorageClass() == VarDecl::Static && + GlobalVarDecl->getType().getCVRQualifiers()); + if (RewriteSC) { + std::string SC(" void __"); + SC += GlobalVarDecl->getNameAsString(); + SC += "() {}"; + InsertText(FunLocStart, SC); + } + + // Insert closures that were part of the function. + for (unsigned i = 0, count=0; i < Blocks.size(); i++) { + CollectBlockDeclRefInfo(Blocks[i]); + // Need to copy-in the inner copied-in variables not actually used in this + // block. + for (int j = 0; j < InnerDeclRefsCount[i]; j++) { + BlockDeclRefExpr *Exp = InnerDeclRefs[count++]; + ValueDecl *VD = Exp->getDecl(); + BlockDeclRefs.push_back(Exp); + if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) { + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + } + + std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); + std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); + + std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); + + InsertText(FunLocStart, CI); + + std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, ImplTag); + + InsertText(FunLocStart, CF); + + if (ImportedBlockDecls.size()) { + std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, ImplTag); + InsertText(FunLocStart, HF); + } + std::string BD = SynthesizeBlockDescriptor(DescTag, ImplTag, i, FunName, + ImportedBlockDecls.size() > 0); + InsertText(FunLocStart, BD); + + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + } + if (RewriteSC) { + // Must insert any 'const/volatile/static here. Since it has been + // removed as result of rewriting of block literals. + std::string SC; + if (GlobalVarDecl->getStorageClass() == VarDecl::Static) + SC = "static "; + if (GlobalVarDecl->getType().isConstQualified()) + SC += "const "; + if (GlobalVarDecl->getType().isVolatileQualified()) + SC += "volatile "; + if (GlobalVarDecl->getType().isRestrictQualified()) + SC += "restrict "; + InsertText(FunLocStart, SC); + } + + Blocks.clear(); + InnerDeclRefsCount.clear(); + InnerDeclRefs.clear(); + RewrittenBlockExprs.clear(); +} + +void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { + SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); + const char *FuncName = FD->getNameAsCString(); + + SynthesizeBlockLiterals(FunLocStart, FuncName); +} + +static void BuildUniqueMethodName(std::string &Name, + ObjCMethodDecl *MD) { + ObjCInterfaceDecl *IFace = MD->getClassInterface(); + Name = IFace->getNameAsCString(); + Name += "__" + MD->getSelector().getAsString(); + // Convert colons to underscores. + std::string::size_type loc = 0; + while ((loc = Name.find(":", loc)) != std::string::npos) + Name.replace(loc, 1, "_"); +} + +void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { + //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n"); + //SourceLocation FunLocStart = MD->getLocStart(); + SourceLocation FunLocStart = MD->getLocStart(); + std::string FuncName; + BuildUniqueMethodName(FuncName, MD); + SynthesizeBlockLiterals(FunLocStart, FuncName.c_str()); +} + +void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) + GetBlockDeclRefExprs(CBE->getBody()); + else + GetBlockDeclRefExprs(*CI); + } + // Handle specific things. + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { + // FIXME: Handle enums. + if (!isa<FunctionDecl>(CDRE->getDecl())) + BlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) + if (HasLocalVariableExternalStorage(DRE->getDecl())) { + BlockDeclRefExpr *BDRE = + new (Context)BlockDeclRefExpr(DRE->getDecl(), DRE->getType(), + DRE->getLocation(), false); + BlockDeclRefs.push_back(BDRE); + } + + return; +} + +void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, + llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs, + llvm::SmallPtrSet<const DeclContext *, 8> &InnerContexts) { + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) { + InnerContexts.insert(cast<DeclContext>(CBE->getBlockDecl())); + GetInnerBlockDeclRefExprs(CBE->getBody(), + InnerBlockDeclRefs, + InnerContexts); + } + else + GetInnerBlockDeclRefExprs(*CI, + InnerBlockDeclRefs, + InnerContexts); + + } + // Handle specific things. + if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(S)) { + if (!isa<FunctionDecl>(CDRE->getDecl()) && + !InnerContexts.count(CDRE->getDecl()->getDeclContext())) + InnerBlockDeclRefs.push_back(CDRE); + } + else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { + if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) + if (Var->isFunctionOrMethodVarDecl()) + ImportedLocalExternalDecls.insert(Var); + } + + return; +} + +/// convertFunctionTypeOfBlocks - This routine converts a function type +/// whose result type may be a block pointer or whose argument type(s) +/// might be block pointers to an equivalent funtion type replacing +/// all block pointers to function pointers. +QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { + const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); + // FTP will be null for closures that don't take arguments. + // Generate a funky cast. + llvm::SmallVector<QualType, 8> ArgTypes; + QualType Res = FT->getResultType(); + bool HasBlockType = convertBlockPointerToFunctionPointer(Res); + + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + if (convertBlockPointerToFunctionPointer(t)) + HasBlockType = true; + ArgTypes.push_back(t); + } + } + QualType FuncType; + // FIXME. Does this work if block takes no argument but has a return type + // which is of block type? + if (HasBlockType) + FuncType = Context->getFunctionType(Res, + &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0, + false, false, 0, 0, FunctionType::ExtInfo()); + else FuncType = QualType(FT, 0); + return FuncType; +} + +Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { + // Navigate to relevant type information. + const BlockPointerType *CPT = 0; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BlockExp)) { + CPT = DRE->getType()->getAs<BlockPointerType>(); + } else if (const BlockDeclRefExpr *CDRE = + dyn_cast<BlockDeclRefExpr>(BlockExp)) { + CPT = CDRE->getType()->getAs<BlockPointerType>(); + } else if (const MemberExpr *MExpr = dyn_cast<MemberExpr>(BlockExp)) { + CPT = MExpr->getType()->getAs<BlockPointerType>(); + } + else if (const ParenExpr *PRE = dyn_cast<ParenExpr>(BlockExp)) { + return SynthesizeBlockCall(Exp, PRE->getSubExpr()); + } + else if (const ImplicitCastExpr *IEXPR = dyn_cast<ImplicitCastExpr>(BlockExp)) + CPT = IEXPR->getType()->getAs<BlockPointerType>(); + else if (const ConditionalOperator *CEXPR = + dyn_cast<ConditionalOperator>(BlockExp)) { + Expr *LHSExp = CEXPR->getLHS(); + Stmt *LHSStmt = SynthesizeBlockCall(Exp, LHSExp); + Expr *RHSExp = CEXPR->getRHS(); + Stmt *RHSStmt = SynthesizeBlockCall(Exp, RHSExp); + Expr *CONDExp = CEXPR->getCond(); + ConditionalOperator *CondExpr = + new (Context) ConditionalOperator(CONDExp, + SourceLocation(), cast<Expr>(LHSStmt), + SourceLocation(), cast<Expr>(RHSStmt), + Exp->getType()); + return CondExpr; + } else if (const ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(BlockExp)) { + CPT = IRE->getType()->getAs<BlockPointerType>(); + } else { + assert(1 && "RewriteBlockClass: Bad type"); + } + assert(CPT && "RewriteBlockClass: Bad type"); + const FunctionType *FT = CPT->getPointeeType()->getAs<FunctionType>(); + assert(FT && "RewriteBlockClass: Bad type"); + const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); + // FTP will be null for closures that don't take arguments. + + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), + &Context->Idents.get("__block_impl")); + QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); + + // Generate a funky cast. + llvm::SmallVector<QualType, 8> ArgTypes; + + // Push the block argument type. + ArgTypes.push_back(PtrBlock); + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I && (I != E); ++I) { + QualType t = *I; + // Make sure we convert "t (^)(...)" to "t (*)(...)". + (void)convertBlockPointerToFunctionPointer(t); + ArgTypes.push_back(t); + } + } + // Now do the pointer to function cast. + QualType PtrToFuncCastType = Context->getFunctionType(Exp->getType(), + &ArgTypes[0], ArgTypes.size(), false/*no variadic*/, 0, + false, false, 0, 0, + FunctionType::ExtInfo()); + + PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); + + CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, + CastExpr::CK_Unknown, + const_cast<Expr*>(BlockExp)); + // Don't forget the parens to enforce the proper binding. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + BlkCast); + //PE->dump(); + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), + FD->getType()); + + CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, + CastExpr::CK_Unknown, ME); + PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); + + llvm::SmallVector<Expr*, 8> BlkExprs; + // Add the implicit argument. + BlkExprs.push_back(BlkCast); + // Add the user arguments. + for (CallExpr::arg_iterator I = Exp->arg_begin(), + E = Exp->arg_end(); I != E; ++I) { + BlkExprs.push_back(*I); + } + CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0], + BlkExprs.size(), + Exp->getType(), SourceLocation()); + return CE; +} + +void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { + Stmt *BlockCall = SynthesizeBlockCall(Exp, Exp->getCallee()); + ReplaceStmt(Exp, BlockCall); +} + +// We need to return the rewritten expression to handle cases where the +// BlockDeclRefExpr is embedded in another expression being rewritten. +// For example: +// +// int main() { +// __block Foo *f; +// __block int i; +// +// void (^myblock)() = ^() { +// [f test]; // f is a BlockDeclRefExpr embedded in a message (which is being rewritten). +// i = 77; +// }; +//} +Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { + // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR + // for each DeclRefExp where BYREFVAR is name of the variable. + ValueDecl *VD; + bool isArrow = true; + if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(DeclRefExp)) + VD = BDRE->getDecl(); + else { + VD = cast<DeclRefExpr>(DeclRefExp)->getDecl(); + isArrow = false; + } + + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get("__forwarding"), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, + FD, SourceLocation(), + FD->getType()); + + const char *Name = VD->getNameAsCString(); + FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get(Name), + Context->VoidPtrTy, 0, + /*BitWidth=*/0, /*Mutable=*/true); + ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), + DeclRefExp->getType()); + + + + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + ME); + ReplaceStmt(DeclRefExp, PE); + return PE; +} + +// Rewrites the imported local variable V with external storage +// (static, extern, etc.) as *V +// +Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { + ValueDecl *VD = DRE->getDecl(); + if (VarDecl *Var = dyn_cast<VarDecl>(VD)) + if (!ImportedLocalExternalDecls.count(Var)) + return DRE; + Expr *Exp = new (Context) UnaryOperator(DRE, UnaryOperator::Deref, + DRE->getType(), DRE->getLocation()); + // Need parens to enforce precedence. + ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + Exp); + ReplaceStmt(DRE, PE); + return PE; +} + +void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { + SourceLocation LocStart = CE->getLParenLoc(); + SourceLocation LocEnd = CE->getRParenLoc(); + + // Need to avoid trying to rewrite synthesized casts. + if (LocStart.isInvalid()) + return; + // Need to avoid trying to rewrite casts contained in macros. + if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd)) + return; + + const char *startBuf = SM->getCharacterData(LocStart); + const char *endBuf = SM->getCharacterData(LocEnd); + QualType QT = CE->getType(); + const Type* TypePtr = QT->getAs<Type>(); + if (isa<TypeOfExprType>(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + std::string TypeAsString = "("; + RewriteBlockPointerType(TypeAsString, QT); + TypeAsString += ")"; + ReplaceText(LocStart, endBuf-startBuf+1, TypeAsString); + return; + } + // advance the location to startArgList. + const char *argPtr = startBuf; + + while (*argPtr++ && (argPtr < endBuf)) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); + ReplaceText(LocStart, 1, "*"); + break; + } + } + return; +} + +void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { + SourceLocation DeclLoc = FD->getLocation(); + unsigned parenCount = 0; + + // We have 1 or more arguments that have closure pointers. + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *startArgList = strchr(startBuf, '('); + + assert((*startArgList == '(') && "Rewriter fuzzy parser confused"); + + parenCount++; + // advance the location to startArgList. + DeclLoc = DeclLoc.getFileLocWithOffset(startArgList-startBuf); + assert((DeclLoc.isValid()) && "Invalid DeclLoc"); + + const char *argPtr = startArgList; + + while (*argPtr++ && parenCount) { + switch (*argPtr) { + case '^': + // Replace the '^' with '*'. + DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); + ReplaceText(DeclLoc, 1, "*"); + break; + case '(': + parenCount++; + break; + case ')': + parenCount--; + break; + } + } + return; +} + +bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) { + const FunctionProtoType *FTP; + const PointerType *PT = QT->getAs<PointerType>(); + if (PT) { + FTP = PT->getPointeeType()->getAs<FunctionProtoType>(); + } else { + const BlockPointerType *BPT = QT->getAs<BlockPointerType>(); + assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type"); + FTP = BPT->getPointeeType()->getAs<FunctionProtoType>(); + } + if (FTP) { + for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(), + E = FTP->arg_type_end(); I != E; ++I) + if (isTopLevelBlockPointerType(*I)) + return true; + } + return false; +} + +void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, + const char *&RParen) { + const char *argPtr = strchr(Name, '('); + assert((*argPtr == '(') && "Rewriter fuzzy parser confused"); + + LParen = argPtr; // output the start. + argPtr++; // skip past the left paren. + unsigned parenCount = 1; + + while (*argPtr && parenCount) { + switch (*argPtr) { + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; + } + if (parenCount) argPtr++; + } + assert((*argPtr == ')') && "Rewriter fuzzy parser confused"); + RParen = argPtr; // output the end +} + +void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { + RewriteBlockPointerFunctionArgs(FD); + return; + } + // Handle Variables and Typedefs. + SourceLocation DeclLoc = ND->getLocation(); + QualType DeclT; + if (VarDecl *VD = dyn_cast<VarDecl>(ND)) + DeclT = VD->getType(); + else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) + DeclT = TDD->getUnderlyingType(); + else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) + DeclT = FD->getType(); + else + assert(0 && "RewriteBlockPointerDecl(): Decl type not yet handled"); + + const char *startBuf = SM->getCharacterData(DeclLoc); + const char *endBuf = startBuf; + // scan backward (from the decl location) for the end of the previous decl. + while (*startBuf != '^' && *startBuf != ';' && startBuf != MainFileStart) + startBuf--; + + // *startBuf != '^' if we are dealing with a pointer to function that + // may take block argument types (which will be handled below). + if (*startBuf == '^') { + // Replace the '^' with '*', computing a negative offset. + DeclLoc = DeclLoc.getFileLocWithOffset(startBuf-endBuf); + ReplaceText(DeclLoc, 1, "*"); + } + if (PointerTypeTakesAnyBlockArguments(DeclT)) { + // Replace the '^' with '*' for arguments. + DeclLoc = ND->getLocation(); + startBuf = SM->getCharacterData(DeclLoc); + const char *argListBegin, *argListEnd; + GetExtentOfArgList(startBuf, argListBegin, argListEnd); + while (argListBegin < argListEnd) { + if (*argListBegin == '^') { + SourceLocation CaretLoc = DeclLoc.getFileLocWithOffset(argListBegin-startBuf); + ReplaceText(CaretLoc, 1, "*"); + } + argListBegin++; + } + } + return; +} + + +/// SynthesizeByrefCopyDestroyHelper - This routine synthesizes: +/// void __Block_byref_id_object_copy(struct Block_byref_id_object *dst, +/// struct Block_byref_id_object *src) { +/// _Block_object_assign (&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_assign(&_dest->object, _src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } +/// And: +/// void __Block_byref_id_object_dispose(struct Block_byref_id_object *_src) { +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT +/// [|BLOCK_FIELD_IS_WEAK]) // object +/// _Block_object_dispose(_src->object, +/// BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK +/// [|BLOCK_FIELD_IS_WEAK]) // block +/// } + +std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, + int flag) { + std::string S; + if (CopyDestroyCache.count(flag)) + return S; + CopyDestroyCache.insert(flag); + S = "static void __Block_byref_id_object_copy_"; + S += utostr(flag); + S += "(void *dst, void *src) {\n"; + + // offset into the object pointer is computed as: + // void * + void* + int + int + void* + void * + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + unsigned VoidPtrSize = + static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy)); + + unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8; + S += " _Block_object_assign((char*)dst + "; + S += utostr(offset); + S += ", *(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + + S += "static void __Block_byref_id_object_dispose_"; + S += utostr(flag); + S += "(void *src) {\n"; + S += " _Block_object_dispose(*(void * *) ((char*)src + "; + S += utostr(offset); + S += "), "; + S += utostr(flag); + S += ");\n}\n"; + return S; +} + +/// RewriteByRefVar - For each __block typex ND variable this routine transforms +/// the declaration into: +/// struct __Block_byref_ND { +/// void *__isa; // NULL for everything except __weak pointers +/// struct __Block_byref_ND *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__Block_byref_id_object_copy; // If variable is __block ObjC object +/// void *__Block_byref_id_object_dispose; // If variable is __block ObjC object +/// typex ND; +/// }; +/// +/// It then replaces declaration of ND variable with: +/// struct __Block_byref_ND ND = {__isa=0B, __forwarding=&ND, __flags=some_flag, +/// __size=sizeof(struct __Block_byref_ND), +/// ND=initializer-if-any}; +/// +/// +void RewriteObjC::RewriteByRefVar(VarDecl *ND) { + // Insert declaration for the function in which block literal is + // used. + if (CurFunctionDeclToDeclareForBlock) + RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); + int flag = 0; + int isa = 0; + SourceLocation DeclLoc = ND->getTypeSpecStartLoc(); + if (DeclLoc.isInvalid()) + // If type location is missing, it is because of missing type (a warning). + // Use variable's location which is good for this case. + DeclLoc = ND->getLocation(); + const char *startBuf = SM->getCharacterData(DeclLoc); + SourceLocation X = ND->getLocEnd(); + X = SM->getInstantiationLoc(X); + const char *endBuf = SM->getCharacterData(X); + std::string Name(ND->getNameAsString()); + std::string ByrefType; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += " {\n"; + ByrefType += " void *__isa;\n"; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += " *__forwarding;\n"; + ByrefType += " int __flags;\n"; + ByrefType += " int __size;\n"; + // Add void *__Block_byref_id_object_copy; + // void *__Block_byref_id_object_dispose; if needed. + QualType Ty = ND->getType(); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; + ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; + } + + Ty.getAsStringInternal(Name, Context->PrintingPolicy); + ByrefType += " " + Name + ";\n"; + ByrefType += "};\n"; + // Insert this type in global scope. It is needed by helper function. + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + else { + assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } + InsertText(FunLocStart, ByrefType); + if (Ty.isObjCGCWeak()) { + flag |= BLOCK_FIELD_IS_WEAK; + isa = 1; + } + + if (HasCopyAndDispose) { + flag = BLOCK_BYREF_CALLER; + QualType Ty = ND->getType(); + // FIXME. Handle __weak variable (BLOCK_FIELD_IS_WEAK) as well. + if (Ty->isBlockPointerType()) + flag |= BLOCK_FIELD_IS_BLOCK; + else + flag |= BLOCK_FIELD_IS_OBJECT; + std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag); + if (!HF.empty()) + InsertText(FunLocStart, HF); + } + + // struct __Block_byref_ND ND = + // {0, &ND, some_flag, __size=sizeof(struct __Block_byref_ND), + // initializer-if-any}; + bool hasInit = (ND->getInit() != 0); + unsigned flags = 0; + if (HasCopyAndDispose) + flags |= BLOCK_HAS_COPY_DISPOSE; + Name = ND->getNameAsString(); + ByrefType.clear(); + RewriteByRefString(ByrefType, Name, ND); + std::string ForwardingCastType("("); + ForwardingCastType += ByrefType + " *)"; + if (!hasInit) { + ByrefType += " " + Name + " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += ")"; + if (HasCopyAndDispose) { + ByrefType += ", __Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + } + ByrefType += "};\n"; + ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType); + } + else { + SourceLocation startLoc; + Expr *E = ND->getInit(); + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); + startLoc = SM->getInstantiationLoc(startLoc); + endBuf = SM->getCharacterData(startLoc); + + ByrefType += " " + Name; + ByrefType += " = {(void*)"; + ByrefType += utostr(isa); + ByrefType += "," + ForwardingCastType + "&" + Name + ", "; + ByrefType += utostr(flags); + ByrefType += ", "; + ByrefType += "sizeof("; + RewriteByRefString(ByrefType, Name, ND); + ByrefType += "), "; + if (HasCopyAndDispose) { + ByrefType += "__Block_byref_id_object_copy_"; + ByrefType += utostr(flag); + ByrefType += ", __Block_byref_id_object_dispose_"; + ByrefType += utostr(flag); + ByrefType += ", "; + } + ReplaceText(DeclLoc, endBuf-startBuf, ByrefType); + + // Complete the newly synthesized compound expression by inserting a right + // curly brace before the end of the declaration. + // FIXME: This approach avoids rewriting the initializer expression. It + // also assumes there is only one declarator. For example, the following + // isn't currently supported by this routine (in general): + // + // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; + // + const char *startBuf = SM->getCharacterData(startLoc); + const char *semiBuf = strchr(startBuf, ';'); + assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); + SourceLocation semiLoc = + startLoc.getFileLocWithOffset(semiBuf-startBuf); + + InsertText(semiLoc, "}"); + } + return; +} + +void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { + // Add initializers for any closure decl refs. + GetBlockDeclRefExprs(Exp->getBody()); + if (BlockDeclRefs.size()) { + // Unique all "by copy" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (!BlockDeclRefs[i]->isByRef()) { + if (!BlockByCopyDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByCopyDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByCopyDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Unique all "by ref" declarations. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->isByRef()) { + if (!BlockByRefDeclsPtrSet.count(BlockDeclRefs[i]->getDecl())) { + BlockByRefDeclsPtrSet.insert(BlockDeclRefs[i]->getDecl()); + BlockByRefDecls.push_back(BlockDeclRefs[i]->getDecl()); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < BlockDeclRefs.size(); i++) + if (BlockDeclRefs[i]->isByRef() || + BlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + BlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl()); + } +} + +FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) { + IdentifierInfo *ID = &Context->Idents.get(name); + QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); + return FunctionDecl::Create(*Context, TUDecl,SourceLocation(), + ID, FType, 0, FunctionDecl::Extern, + FunctionDecl::None, false, false); +} + +Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, + const llvm::SmallVector<BlockDeclRefExpr *, 8> &InnerBlockDeclRefs) { + Blocks.push_back(Exp); + + CollectBlockDeclRefInfo(Exp); + + // Add inner imported variables now used in current block. + int countOfInnerDecls = 0; + if (!InnerBlockDeclRefs.empty()) { + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) { + BlockDeclRefExpr *Exp = InnerBlockDeclRefs[i]; + ValueDecl *VD = Exp->getDecl(); + if (!Exp->isByRef() && !BlockByCopyDeclsPtrSet.count(VD)) { + // We need to save the copied-in variables in nested + // blocks because it is needed at the end for some of the API generations. + // See SynthesizeBlockLiterals routine. + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByCopyDeclsPtrSet.insert(VD); + BlockByCopyDecls.push_back(VD); + } + if (Exp->isByRef() && !BlockByRefDeclsPtrSet.count(VD)) { + InnerDeclRefs.push_back(Exp); countOfInnerDecls++; + BlockDeclRefs.push_back(Exp); + BlockByRefDeclsPtrSet.insert(VD); + BlockByRefDecls.push_back(VD); + } + } + // Find any imported blocks...they will need special attention. + for (unsigned i = 0; i < InnerBlockDeclRefs.size(); i++) + if (InnerBlockDeclRefs[i]->isByRef() || + InnerBlockDeclRefs[i]->getType()->isObjCObjectPointerType() || + InnerBlockDeclRefs[i]->getType()->isBlockPointerType()) + ImportedBlockDecls.insert(InnerBlockDeclRefs[i]->getDecl()); + } + InnerDeclRefsCount.push_back(countOfInnerDecls); + + std::string FuncName; + + if (CurFunctionDef) + FuncName = CurFunctionDef->getNameAsString(); + else if (CurMethodDef) + BuildUniqueMethodName(FuncName, CurMethodDef); + else if (GlobalVarDecl) + FuncName = std::string(GlobalVarDecl->getNameAsString()); + + std::string BlockNumber = utostr(Blocks.size()-1); + + std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; + std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; + + // Get a pointer to the function type so we can cast appropriately. + QualType BFT = convertFunctionTypeOfBlocks(Exp->getFunctionType()); + QualType FType = Context->getPointerType(BFT); + + FunctionDecl *FD; + Expr *NewRep; + + // Simulate a contructor call... + FD = SynthBlockInitFunctionDecl(Tag.c_str()); + DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, SourceLocation()); + + llvm::SmallVector<Expr*, 4> InitExprs; + + // Initialize the block function. + FD = SynthBlockInitFunctionDecl(Func.c_str()); + DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), + SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); + InitExprs.push_back(castExpr); + + // Initialize the block descriptor. + std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; + + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + VarDecl::Static, VarDecl::None); + UnaryOperator *DescRefExpr = new (Context) UnaryOperator( + new (Context) DeclRefExpr(NewVD, + Context->VoidPtrTy, SourceLocation()), + UnaryOperator::AddrOf, + Context->getPointerType(Context->VoidPtrTy), + SourceLocation()); + InitExprs.push_back(DescRefExpr); + + // Add initializers for any closure decl refs. + if (BlockDeclRefs.size()) { + Expr *Exp; + // Output all "by copy" declarations. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), + E = BlockByCopyDecls.end(); I != E; ++I) { + if (isObjCType((*I)->getType())) { + // FIXME: Conform to ABI ([[obj retain] autorelease]). + FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + SourceLocation()); + } + } else if (isTopLevelBlockPointerType((*I)->getType())) { + FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); + } else { + FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + if (HasLocalVariableExternalStorage(*I)) { + QualType QT = (*I)->getType(); + QT = Context->getPointerType(QT); + Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + SourceLocation()); + } + + } + InitExprs.push_back(Exp); + } + // Output all "by ref" declarations. + for (llvm::SmallVector<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), + E = BlockByRefDecls.end(); I != E; ++I) { + ValueDecl *ND = (*I); + std::string Name(ND->getNameAsString()); + std::string RecName; + RewriteByRefString(RecName, Name, ND); + IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + + sizeof("struct")); + RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, + SourceLocation(), II); + assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); + QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); + + FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); + Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, + Context->getPointerType(Exp->getType()), + SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, castT, CastExpr::CK_Unknown, Exp); + InitExprs.push_back(Exp); + } + } + if (ImportedBlockDecls.size()) { + // generate BLOCK_HAS_COPY_DISPOSE(have helper funcs) | BLOCK_HAS_DESCRIPTOR + int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); + unsigned IntSize = + static_cast<unsigned>(Context->getTypeSize(Context->IntTy)); + Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); + InitExprs.push_back(FlagExp); + } + NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), + FType, SourceLocation()); + NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, + Context->getPointerType(NewRep->getType()), + SourceLocation()); + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown, + NewRep); + BlockDeclRefs.clear(); + BlockByRefDecls.clear(); + BlockByRefDeclsPtrSet.clear(); + BlockByCopyDecls.clear(); + BlockByCopyDeclsPtrSet.clear(); + ImportedBlockDecls.clear(); + return NewRep; +} + +//===----------------------------------------------------------------------===// +// Function Body / Expression rewriting +//===----------------------------------------------------------------------===// + +// This is run as a first "pass" prior to RewriteFunctionBodyOrGlobalInitializer(). +// The allows the main rewrite loop to associate all ObjCPropertyRefExprs with +// their respective BinaryOperator. Without this knowledge, we'd need to rewrite +// the ObjCPropertyRefExpr twice (once as a getter, and later as a setter). +// Since the rewriter isn't capable of rewriting rewritten code, it's important +// we get this right. +void RewriteObjC::CollectPropertySetters(Stmt *S) { + // Perform a bottom up traversal of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) + CollectPropertySetters(*CI); + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + if (BinOp->isAssignmentOp()) { + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(BinOp->getLHS())) + PropSetters[PRE] = BinOp; + } + } +} + +Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { + if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || + isa<DoStmt>(S) || isa<ForStmt>(S)) + Stmts.push_back(S); + else if (isa<ObjCForCollectionStmt>(S)) { + Stmts.push_back(S); + ObjCBcLabelNo.push_back(++BcLabelCount); + } + + SourceRange OrigStmtRange = S->getSourceRange(); + + // Perform a bottom up rewrite of all children. + for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); + CI != E; ++CI) + if (*CI) { + Stmt *newStmt; + Stmt *S = (*CI); + if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { + Expr *OldBase = IvarRefExpr->getBase(); + bool replaced = false; + newStmt = RewriteObjCNestedIvarRefExpr(S, replaced); + if (replaced) { + if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt)) + ReplaceStmt(OldBase, IRE->getBase()); + else + ReplaceStmt(S, newStmt); + } + } + else + newStmt = RewriteFunctionBodyOrGlobalInitializer(S); + if (newStmt) + *CI = newStmt; + } + + if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) { + llvm::SmallVector<BlockDeclRefExpr *, 8> InnerBlockDeclRefs; + llvm::SmallPtrSet<const DeclContext *, 8> InnerContexts; + InnerContexts.insert(BE->getBlockDecl()); + ImportedLocalExternalDecls.clear(); + GetInnerBlockDeclRefExprs(BE->getBody(), + InnerBlockDeclRefs, InnerContexts); + // Rewrite the block body in place. + RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); + ImportedLocalExternalDecls.clear(); + // Now we snarf the rewritten text and stash it away for later use. + std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); + RewrittenBlockExprs[BE] = Str; + + Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); + + //blockTranscribed->dump(); + ReplaceStmt(S, blockTranscribed); + return blockTranscribed; + } + // Handle specific things. + if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S)) + return RewriteAtEncode(AtEncode); + + if (ObjCPropertyRefExpr *PropRefExpr = dyn_cast<ObjCPropertyRefExpr>(S)) { + BinaryOperator *BinOp = PropSetters[PropRefExpr]; + if (BinOp) { + // Because the rewriter doesn't allow us to rewrite rewritten code, + // we need to rewrite the right hand side prior to rewriting the setter. + DisableReplaceStmt = true; + // Save the source range. Even if we disable the replacement, the + // rewritten node will have been inserted into the tree. If the synthesized + // node is at the 'end', the rewriter will fail. Consider this: + // self.errorHandler = handler ? handler : + // ^(NSURL *errorURL, NSError *error) { return (BOOL)1; }; + SourceRange SrcRange = BinOp->getSourceRange(); + Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(BinOp->getRHS()); + DisableReplaceStmt = false; + // + // Unlike the main iterator, we explicily avoid changing 'BinOp'. If + // we changed the RHS of BinOp, the rewriter would fail (since it needs + // to see the original expression). Consider this example: + // + // Foo *obj1, *obj2; + // + // obj1.i = [obj2 rrrr]; + // + // 'BinOp' for the previous expression looks like: + // + // (BinaryOperator 0x231ccf0 'int' '=' + // (ObjCPropertyRefExpr 0x231cc70 'int' Kind=PropertyRef Property="i" + // (DeclRefExpr 0x231cc50 'Foo *' Var='obj1' 0x231cbb0)) + // (ObjCMessageExpr 0x231ccb0 'int' selector=rrrr + // (DeclRefExpr 0x231cc90 'Foo *' Var='obj2' 0x231cbe0))) + // + // 'newStmt' represents the rewritten message expression. For example: + // + // (CallExpr 0x231d300 'id':'struct objc_object *' + // (ParenExpr 0x231d2e0 'int (*)(id, SEL)' + // (CStyleCastExpr 0x231d2c0 'int (*)(id, SEL)' + // (CStyleCastExpr 0x231d220 'void *' + // (DeclRefExpr 0x231d200 'id (id, SEL, ...)' FunctionDecl='objc_msgSend' 0x231cdc0)))) + // + // Note that 'newStmt' is passed to RewritePropertySetter so that it + // can be used as the setter argument. ReplaceStmt() will still 'see' + // the original RHS (since we haven't altered BinOp). + // + // This implies the Rewrite* routines can no longer delete the original + // node. As a result, we now leak the original AST nodes. + // + return RewritePropertySetter(BinOp, dyn_cast<Expr>(newStmt), SrcRange); + } else { + return RewritePropertyGetter(PropRefExpr); + } + } + if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S)) + return RewriteAtSelector(AtSelector); + + if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S)) + return RewriteObjCStringLiteral(AtString); + + if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) { +#if 0 + // Before we rewrite it, put the original message expression in a comment. + SourceLocation startLoc = MessExpr->getLocStart(); + SourceLocation endLoc = MessExpr->getLocEnd(); + + const char *startBuf = SM->getCharacterData(startLoc); + const char *endBuf = SM->getCharacterData(endLoc); + + std::string messString; + messString += "// "; + messString.append(startBuf, endBuf-startBuf+1); + messString += "\n"; + + // FIXME: Missing definition of + // InsertText(clang::SourceLocation, char const*, unsigned int). + // InsertText(startLoc, messString.c_str(), messString.size()); + // Tried this, but it didn't work either... + // ReplaceText(startLoc, 0, messString.c_str(), messString.size()); +#endif + return RewriteMessageExpr(MessExpr); + } + + if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S)) + return RewriteObjCTryStmt(StmtTry); + + if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S)) + return RewriteObjCSynchronizedStmt(StmtTry); + + if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S)) + return RewriteObjCThrowStmt(StmtThrow); + + if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S)) + return RewriteObjCProtocolExpr(ProtocolExp); + + if (ObjCForCollectionStmt *StmtForCollection = + dyn_cast<ObjCForCollectionStmt>(S)) + return RewriteObjCForCollectionStmt(StmtForCollection, + OrigStmtRange.getEnd()); + if (BreakStmt *StmtBreakStmt = + dyn_cast<BreakStmt>(S)) + return RewriteBreakStmt(StmtBreakStmt); + if (ContinueStmt *StmtContinueStmt = + dyn_cast<ContinueStmt>(S)) + return RewriteContinueStmt(StmtContinueStmt); + + // Need to check for protocol refs (id <P>, Foo <P> *) in variable decls + // and cast exprs. + if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + // FIXME: What we're doing here is modifying the type-specifier that + // precedes the first Decl. In the future the DeclGroup should have + // a separate type-specifier that we can rewrite. + // NOTE: We need to avoid rewriting the DeclStmt if it is within + // the context of an ObjCForCollectionStmt. For example: + // NSArray *someArray; + // for (id <FooProtocol> index in someArray) ; + // This is because RewriteObjCForCollectionStmt() does textual rewriting + // and it depends on the original text locations/positions. + if (Stmts.empty() || !isa<ObjCForCollectionStmt>(Stmts.back())) + RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin()); + + // Blocks rewrite rules. + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl *SD = *DI; + if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) { + if (isTopLevelBlockPointerType(ND->getType())) + RewriteBlockPointerDecl(ND); + else if (ND->getType()->isFunctionPointerType()) + CheckFunctionPointerDecl(ND->getType(), ND); + if (VarDecl *VD = dyn_cast<VarDecl>(SD)) { + if (VD->hasAttr<BlocksAttr>()) { + static unsigned uniqueByrefDeclCount = 0; + assert(!BlockByRefDeclNo.count(ND) && + "RewriteFunctionBodyOrGlobalInitializer: Duplicate byref decl"); + BlockByRefDeclNo[ND] = uniqueByrefDeclCount++; + RewriteByRefVar(VD); + } + else + RewriteTypeOfDecl(VD); + } + } + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + } + } + } + + if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) + RewriteObjCQualifiedInterfaceTypes(CE); + + if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || + isa<DoStmt>(S) || isa<ForStmt>(S)) { + assert(!Stmts.empty() && "Statement stack is empty"); + assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) || + isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back())) + && "Statement stack mismatch"); + Stmts.pop_back(); + } + // Handle blocks rewriting. + if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + if (BDRE->isByRef()) + return RewriteBlockDeclRefExpr(BDRE); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(S)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<BlocksAttr>()) + return RewriteBlockDeclRefExpr(DRE); + if (HasLocalVariableExternalStorage(VD)) + return RewriteLocalVariableExternalStorage(DRE); + } + + if (CallExpr *CE = dyn_cast<CallExpr>(S)) { + if (CE->getCallee()->getType()->isBlockPointerType()) { + Stmt *BlockCall = SynthesizeBlockCall(CE, CE->getCallee()); + ReplaceStmt(S, BlockCall); + return BlockCall; + } + } + if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S)) { + RewriteCastExpr(CE); + } +#if 0 + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) { + CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation()); + // Get the new text. + std::string SStr; + llvm::raw_string_ostream Buf(SStr); + Replacement->printPretty(Buf, *Context); + const std::string &Str = Buf.str(); + + printf("CAST = %s\n", &Str[0]); + InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size()); + delete S; + return Replacement; + } +#endif + // Return this stmt unmodified. + return S; +} + +void RewriteObjC::RewriteRecordBody(RecordDecl *RD) { + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) { + FieldDecl *FD = *i; + if (isTopLevelBlockPointerType(FD->getType())) + RewriteBlockPointerDecl(FD); + if (FD->getType()->isObjCQualifiedIdType() || + FD->getType()->isObjCQualifiedInterfaceType()) + RewriteObjCQualifiedInterfaceTypes(FD); + } +} + +/// HandleDeclInMainFile - This is called for each top-level decl defined in the +/// main file of the input. +void RewriteObjC::HandleDeclInMainFile(Decl *D) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isOverloadedOperator()) + return; + + // Since function prototypes don't have ParmDecl's, we check the function + // prototype. This enables us to rewrite function declarations and + // definitions using the same code. + RewriteBlocksInFunctionProtoType(FD->getType(), FD); + + // FIXME: If this should support Obj-C++, support CXXTryStmt + if (CompoundStmt *Body = FD->getCompoundBody()) { + CurFunctionDef = FD; + CurFunctionDeclToDeclareForBlock = FD; + CollectPropertySetters(Body); + CurrentBody = Body; + Body = + cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); + FD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + // This synthesizes and inserts the block "impl" struct, invoke function, + // and any copy/dispose helper functions. + InsertBlockLiteralsWithinFunction(FD); + CurFunctionDef = 0; + CurFunctionDeclToDeclareForBlock = 0; + } + return; + } + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (CompoundStmt *Body = MD->getCompoundBody()) { + CurMethodDef = MD; + CollectPropertySetters(Body); + CurrentBody = Body; + Body = + cast_or_null<CompoundStmt>(RewriteFunctionBodyOrGlobalInitializer(Body)); + MD->setBody(Body); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + InsertBlockLiteralsWithinMethod(MD); + CurMethodDef = 0; + } + } + if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D)) + ClassImplementation.push_back(CI); + else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D)) + CategoryImplementation.push_back(CI); + else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D)) + RewriteForwardClassDecl(CD); + else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + RewriteObjCQualifiedInterfaceTypes(VD); + if (isTopLevelBlockPointerType(VD->getType())) + RewriteBlockPointerDecl(VD); + else if (VD->getType()->isFunctionPointerType()) { + CheckFunctionPointerDecl(VD->getType(), VD); + if (VD->getInit()) { + if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { + RewriteCastExpr(CE); + } + } + } else if (VD->getType()->isRecordType()) { + RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl(); + if (RD->isDefinition()) + RewriteRecordBody(RD); + } + if (VD->getInit()) { + GlobalVarDecl = VD; + CollectPropertySetters(VD->getInit()); + CurrentBody = VD->getInit(); + RewriteFunctionBodyOrGlobalInitializer(VD->getInit()); + CurrentBody = 0; + if (PropParentMap) { + delete PropParentMap; + PropParentMap = 0; + } + SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), + VD->getNameAsCString()); + GlobalVarDecl = 0; + + // This is needed for blocks. + if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(VD->getInit())) { + RewriteCastExpr(CE); + } + } + return; + } + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + if (isTopLevelBlockPointerType(TD->getUnderlyingType())) + RewriteBlockPointerDecl(TD); + else if (TD->getUnderlyingType()->isFunctionPointerType()) + CheckFunctionPointerDecl(TD->getUnderlyingType(), TD); + return; + } + if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) { + if (RD->isDefinition()) + RewriteRecordBody(RD); + return; + } + // Nothing yet. +} + +void RewriteObjC::HandleTranslationUnit(ASTContext &C) { + if (Diags.hasErrorOccurred()) + return; + + RewriteInclude(); + + // Here's a great place to add any extra declarations that may be needed. + // Write out meta data for each @protocol(<expr>). + for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(), + E = ProtocolExprDecls.end(); I != E; ++I) + RewriteObjCProtocolMetaData(*I, "", "", Preamble); + + InsertText(SM->getLocForStartOfFile(MainFileID), Preamble, false); + if (ClassImplementation.size() || CategoryImplementation.size()) + RewriteImplementations(); + + // Get the buffer corresponding to MainFileID. If we haven't changed it, then + // we are done. + if (const RewriteBuffer *RewriteBuf = + Rewrite.getRewriteBufferFor(MainFileID)) { + //printf("Changed:\n"); + *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); + } else { + llvm::errs() << "No changes\n"; + } + + if (ClassImplementation.size() || CategoryImplementation.size() || + ProtocolExprDecls.size()) { + // Rewrite Objective-c meta data* + std::string ResultStr; + SynthesizeMetaDataIntoBuffer(ResultStr); + // Emit metadata. + *OutFile << ResultStr; + } + OutFile->flush(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/RewriteTest.cpp b/contrib/llvm/tools/clang/lib/Frontend/RewriteTest.cpp new file mode 100644 index 0000000..0414678 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/RewriteTest.cpp @@ -0,0 +1,39 @@ +//===--- RewriteTest.cpp - Rewriter playground ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a testbed. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/TokenRewriter.h" +#include "llvm/Support/raw_ostream.h" + +void clang::DoRewriteTest(Preprocessor &PP, llvm::raw_ostream* OS) { + SourceManager &SM = PP.getSourceManager(); + const LangOptions &LangOpts = PP.getLangOptions(); + + TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts); + + // Throw <i> </i> tags around comments. + for (TokenRewriter::token_iterator I = Rewriter.token_begin(), + E = Rewriter.token_end(); I != E; ++I) { + if (I->isNot(tok::comment)) continue; + + Rewriter.AddTokenBefore(I, "<i>"); + Rewriter.AddTokenAfter(I, "</i>"); + } + + + // Print out the output. + for (TokenRewriter::token_iterator I = Rewriter.token_begin(), + E = Rewriter.token_end(); I != E; ++I) + *OS << PP.getSpelling(*I); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp new file mode 100644 index 0000000..21dc0ba --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp @@ -0,0 +1,453 @@ +//===--- StmtXML.cpp - XML implementation for Stmt ASTs ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dumpXML methods, which dump out the +// AST to an XML document. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtXML Visitor +//===----------------------------------------------------------------------===// + +namespace { + class StmtXML : public StmtVisitor<StmtXML> { + DocumentXML& Doc; + + //static const char *getOpcodeStr(UnaryOperator::Opcode Op); + //static const char *getOpcodeStr(BinaryOperator::Opcode Op); + + + void addSpecialAttribute(const char* pName, StringLiteral* Str) { + Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength())); + } + + void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) { + if (S->isArgumentType()) + Doc.addAttribute(pName, S->getArgumentType()); + } + + void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) { + if (S->isTypeOperand()) + Doc.addAttribute(pName, S->getTypeOperand()); + } + + + public: + StmtXML(DocumentXML& doc) + : Doc(doc) { + } + + void DumpSubTree(Stmt *S) { + if (S) { + Visit(S); + if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) { + for (DeclStmt::decl_iterator DI = DS->decl_begin(), + DE = DS->decl_end(); DI != DE; ++DI) { + Doc.PrintDecl(*DI); + } + } else { + for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); + i != e; ++i) + DumpSubTree(*i); + } + Doc.toParent(); + } else { + Doc.addSubNode("NULL").toParent(); + } + } + + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* S) \ + { \ + typedef CLASS tStmtType; \ + Doc.addSubNode(NAME); + +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN); +#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN); +#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S); +#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange()); + + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (S->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (S->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#define ID_ATTRIBUTE_XML Doc.addAttribute("id", S); +#define SUB_NODE_XML( CLASS ) +#define SUB_NODE_SEQUENCE_XML( CLASS ) +#define SUB_NODE_OPT_XML( CLASS ) + +#include "clang/Frontend/StmtXML.def" + +#if (0) + // Stmts. + void VisitStmt(Stmt *Node); + void VisitDeclStmt(DeclStmt *Node); + void VisitLabelStmt(LabelStmt *Node); + void VisitGotoStmt(GotoStmt *Node); + + // Exprs + void VisitExpr(Expr *Node); + void VisitDeclRefExpr(DeclRefExpr *Node); + void VisitPredefinedExpr(PredefinedExpr *Node); + void VisitCharacterLiteral(CharacterLiteral *Node); + void VisitIntegerLiteral(IntegerLiteral *Node); + void VisitFloatingLiteral(FloatingLiteral *Node); + void VisitStringLiteral(StringLiteral *Str); + void VisitUnaryOperator(UnaryOperator *Node); + void VisitOffsetOfExpr(OffsetOfExpr *Node); + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); + void VisitBinaryOperator(BinaryOperator *Node); + void VisitCompoundAssignOperator(CompoundAssignOperator *Node); + void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); + + // C++ + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); + void VisitCXXThisExpr(CXXThisExpr *Node); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); + + // ObjC + void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(ObjCMessageExpr* Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); + void VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + void VisitObjCSuperExpr(ObjCSuperExpr *Node); +#endif + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// +#if (0) +void StmtXML::VisitStmt(Stmt *Node) { + // nothing special to do +} + +void StmtXML::VisitDeclStmt(DeclStmt *Node) { + for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); + DI != DE; ++DI) { + Doc.PrintDecl(*DI); + } +} + +void StmtXML::VisitLabelStmt(LabelStmt *Node) { + Doc.addAttribute("name", Node->getName()); +} + +void StmtXML::VisitGotoStmt(GotoStmt *Node) { + Doc.addAttribute("name", Node->getLabel()->getName()); +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtXML::VisitExpr(Expr *Node) { + DumpExpr(Node); +} + +void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { + DumpExpr(Node); + + const char* pKind; + switch (Node->getDecl()->getKind()) { + case Decl::Function: pKind = "FunctionDecl"; break; + case Decl::Var: pKind = "Var"; break; + case Decl::ParmVar: pKind = "ParmVar"; break; + case Decl::EnumConstant: pKind = "EnumConstant"; break; + case Decl::Typedef: pKind = "Typedef"; break; + case Decl::Record: pKind = "Record"; break; + case Decl::Enum: pKind = "Enum"; break; + case Decl::CXXRecord: pKind = "CXXRecord"; break; + case Decl::ObjCInterface: pKind = "ObjCInterface"; break; + case Decl::ObjCClass: pKind = "ObjCClass"; break; + default: pKind = "Decl"; break; + } + + Doc.addAttribute("kind", pKind); + Doc.addAttribute("name", Node->getDecl()->getNameAsString()); + Doc.addRefAttribute(Node->getDecl()); +} + +void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) { + DumpExpr(Node); + switch (Node->getIdentType()) { + default: assert(0 && "unknown case"); + case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; + case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; + case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; + } +} + +void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) { + DumpExpr(Node); + Doc.addAttribute("value", Node->getValue()); +} + +void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) { + DumpExpr(Node); + bool isSigned = Node->getType()->isSignedIntegerType(); + Doc.addAttribute("value", Node->getValue().toString(10, isSigned)); +} + +void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) { + DumpExpr(Node); + // FIXME: output float as written in source (no approximation or the like) + //Doc.addAttribute("value", Node->getValueAsApproximateDouble())); + Doc.addAttribute("value", "FIXME"); +} + +void StmtXML::VisitStringLiteral(StringLiteral *Str) { + DumpExpr(Str); + if (Str->isWide()) + Doc.addAttribute("is_wide", "1"); + + Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength())); +} + + +const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown unary operator"); + case UnaryOperator::PostInc: return "postinc"; + case UnaryOperator::PostDec: return "postdec"; + case UnaryOperator::PreInc: return "preinc"; + case UnaryOperator::PreDec: return "predec"; + case UnaryOperator::AddrOf: return "addrof"; + case UnaryOperator::Deref: return "deref"; + case UnaryOperator::Plus: return "plus"; + case UnaryOperator::Minus: return "minus"; + case UnaryOperator::Not: return "not"; + case UnaryOperator::LNot: return "lnot"; + case UnaryOperator::Real: return "__real"; + case UnaryOperator::Imag: return "__imag"; + case UnaryOperator::Extension: return "__extension__"; + case UnaryOperator::OffsetOf: return "__builtin_offsetof"; + } +} + + +const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown binary operator"); + case BinaryOperator::PtrMemD: return "ptrmemd"; + case BinaryOperator::PtrMemI: return "ptrmemi"; + case BinaryOperator::Mul: return "mul"; + case BinaryOperator::Div: return "div"; + case BinaryOperator::Rem: return "rem"; + case BinaryOperator::Add: return "add"; + case BinaryOperator::Sub: return "sub"; + case BinaryOperator::Shl: return "shl"; + case BinaryOperator::Shr: return "shr"; + case BinaryOperator::LT: return "lt"; + case BinaryOperator::GT: return "gt"; + case BinaryOperator::LE: return "le"; + case BinaryOperator::GE: return "ge"; + case BinaryOperator::EQ: return "eq"; + case BinaryOperator::NE: return "ne"; + case BinaryOperator::And: return "and"; + case BinaryOperator::Xor: return "xor"; + case BinaryOperator::Or: return "or"; + case BinaryOperator::LAnd: return "land"; + case BinaryOperator::LOr: return "lor"; + case BinaryOperator::Assign: return "assign"; + case BinaryOperator::MulAssign: return "mulassign"; + case BinaryOperator::DivAssign: return "divassign"; + case BinaryOperator::RemAssign: return "remassign"; + case BinaryOperator::AddAssign: return "addassign"; + case BinaryOperator::SubAssign: return "subassign"; + case BinaryOperator::ShlAssign: return "shlassign"; + case BinaryOperator::ShrAssign: return "shrassign"; + case BinaryOperator::AndAssign: return "andassign"; + case BinaryOperator::XorAssign: return "xorassign"; + case BinaryOperator::OrAssign: return "orassign"; + case BinaryOperator::Comma: return "comma"; + } +} + +void StmtXML::VisitUnaryOperator(UnaryOperator *Node) { + DumpExpr(Node); + Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); +} + +void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) { + DumpExpr(Node); +} + +void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof"); + Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0"); + if (Node->isArgumentType()) + DumpTypeExpr(Node->getArgumentType()); +} + +void StmtXML::VisitMemberExpr(MemberExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0"); + Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString()); + Doc.addRefAttribute(Node->getMemberDecl()); +} + +void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("name", Node->getAccessor().getName()); +} + +void StmtXML::VisitBinaryOperator(BinaryOperator *Node) { + DumpExpr(Node); + Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); +} + +void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + VisitBinaryOperator(Node); +/* FIXME: is this needed in the AST? + DumpExpr(Node); + CurrentNode = CurrentNode->addSubNode("ComputeLHSTy"); + DumpType(Node->getComputationLHSType()); + CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy"); + DumpType(Node->getComputationResultType()); + Doc.toParent(); +*/ +} + +// GNU extensions. + +void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("name", Node->getLabel()->getName()); +} + +void StmtXML::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { + DumpExpr(Node); + DumpTypeExpr(Node->getArgType1()); + DumpTypeExpr(Node->getArgType2()); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions +//===----------------------------------------------------------------------===// + +void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("kind", Node->getCastName()); + DumpTypeExpr(Node->getTypeAsWritten()); +} + +void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("value", Node->getValue() ? "true" : "false"); +} + +void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) { + DumpExpr(Node); +} + +void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { + DumpExpr(Node); + DumpTypeExpr(Node->getTypeAsWritten()); +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) { + DumpExpr(Node); + Doc.addAttribute("selector", Node->getSelector().getAsString()); + IdentifierInfo* clsName = Node->getClassName(); + if (clsName) + Doc.addAttribute("class", clsName->getName()); +} + +void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + DumpExpr(Node); + DumpTypeExpr(Node->getEncodedType()); +} + +void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("selector", Node->getSelector().getAsString()); +} + +void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString()); +} + +void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("property", Node->getProperty()->getNameAsString()); +} + +void StmtXML::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node) { + DumpExpr(Node); + ObjCMethodDecl *Getter = Node->getGetterMethod(); + ObjCMethodDecl *Setter = Node->getSetterMethod(); + Doc.addAttribute("Getter", Getter->getSelector().getAsString()); + Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); +} + +void StmtXML::VisitObjCSuperExpr(ObjCSuperExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("super", "1"); +} + +void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + DumpExpr(Node); + Doc.addAttribute("kind", Node->getDecl()->getDeclKindName()); + Doc.addAttribute("decl", Node->getDecl()->getNameAsString()); + if (Node->isFreeIvar()) + Doc.addAttribute("isFreeIvar", "1"); +} +#endif +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void DocumentXML::PrintStmt(const Stmt *S) { + StmtXML P(*this); + P.DumpSubTree(const_cast<Stmt*>(S)); +} + diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp new file mode 100644 index 0000000..fdf2ec8 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp @@ -0,0 +1,48 @@ +//===--- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +/// HandleDiagnostic - Store the errors, warnings, and notes that are +/// reported. +/// +void TextDiagnosticBuffer::HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) { + llvm::SmallString<100> Buf; + Info.FormatDiagnostic(Buf); + switch (Level) { + default: assert(0 && "Diagnostic not handled during diagnostic buffering!"); + case Diagnostic::Note: + Notes.push_back(std::make_pair(Info.getLocation(), Buf.str())); + break; + case Diagnostic::Warning: + Warnings.push_back(std::make_pair(Info.getLocation(), Buf.str())); + break; + case Diagnostic::Error: + case Diagnostic::Fatal: + Errors.push_back(std::make_pair(Info.getLocation(), Buf.str())); + break; + } +} + +void TextDiagnosticBuffer::FlushDiagnostics(Diagnostic &Diags) const { + // FIXME: Flush the diagnostics in order. + for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, it->second.c_str())); + for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Warning,it->second.c_str())); + for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it) + Diags.Report(Diags.getCustomDiagID(Diagnostic::Note, it->second.c_str())); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp new file mode 100644 index 0000000..6ccf4f1 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -0,0 +1,948 @@ +//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This diagnostic client prints out their diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Lex/Lexer.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include <algorithm> +using namespace clang; + +static const enum llvm::raw_ostream::Colors noteColor = + llvm::raw_ostream::BLACK; +static const enum llvm::raw_ostream::Colors fixitColor = + llvm::raw_ostream::GREEN; +static const enum llvm::raw_ostream::Colors caretColor = + llvm::raw_ostream::GREEN; +static const enum llvm::raw_ostream::Colors warningColor = + llvm::raw_ostream::MAGENTA; +static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; +static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; +// Used for changing only the bold attribute. +static const enum llvm::raw_ostream::Colors savedColor = + llvm::raw_ostream::SAVEDCOLOR; + +/// \brief Number of spaces to indent when word-wrapping. +const unsigned WordWrapIndentation = 6; + +TextDiagnosticPrinter::TextDiagnosticPrinter(llvm::raw_ostream &os, + const DiagnosticOptions &diags, + bool _OwnsOutputStream) + : OS(os), LangOpts(0), DiagOpts(&diags), + LastCaretDiagnosticWasNote(0), + OwnsOutputStream(_OwnsOutputStream) { +} + +TextDiagnosticPrinter::~TextDiagnosticPrinter() { + if (OwnsOutputStream) + delete &OS; +} + +void TextDiagnosticPrinter:: +PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { + if (Loc.isInvalid()) return; + + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // Print out the other include frames first. + PrintIncludeStack(PLoc.getIncludeLoc(), SM); + + if (DiagOpts->ShowLocation) + OS << "In file included from " << PLoc.getFilename() + << ':' << PLoc.getLine() << ":\n"; + else + OS << "In included file:\n"; +} + +/// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s) +/// any characters in LineNo that intersect the SourceRange. +void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, + const SourceManager &SM, + unsigned LineNo, FileID FID, + std::string &CaretLine, + const std::string &SourceLine) { + assert(CaretLine.size() == SourceLine.size() && + "Expect a correspondence between source and caret line!"); + if (!R.isValid()) return; + + SourceLocation Begin = SM.getInstantiationLoc(R.getBegin()); + SourceLocation End = SM.getInstantiationLoc(R.getEnd()); + + // If the End location and the start location are the same and are a macro + // location, then the range was something that came from a macro expansion + // or _Pragma. If this is an object-like macro, the best we can do is to + // highlight the range. If this is a function-like macro, we'd also like to + // highlight the arguments. + if (Begin == End && R.getEnd().isMacroID()) + End = SM.getInstantiationRange(R.getEnd()).second; + + unsigned StartLineNo = SM.getInstantiationLineNumber(Begin); + if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) + return; // No intersection. + + unsigned EndLineNo = SM.getInstantiationLineNumber(End); + if (EndLineNo < LineNo || SM.getFileID(End) != FID) + return; // No intersection. + + // Compute the column number of the start. + unsigned StartColNo = 0; + if (StartLineNo == LineNo) { + StartColNo = SM.getInstantiationColumnNumber(Begin); + if (StartColNo) --StartColNo; // Zero base the col #. + } + + // Compute the column number of the end. + unsigned EndColNo = CaretLine.size(); + if (EndLineNo == LineNo) { + EndColNo = SM.getInstantiationColumnNumber(End); + if (EndColNo) { + --EndColNo; // Zero base the col #. + + // Add in the length of the token, so that we cover multi-char tokens. + EndColNo += Lexer::MeasureTokenLength(End, SM, *LangOpts); + } else { + EndColNo = CaretLine.size(); + } + } + + assert(StartColNo <= EndColNo && "Invalid range!"); + + // Pick the first non-whitespace column. + while (StartColNo < SourceLine.size() && + (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t')) + ++StartColNo; + + // Pick the last non-whitespace column. + if (EndColNo > SourceLine.size()) + EndColNo = SourceLine.size(); + while (EndColNo-1 && + (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t')) + --EndColNo; + + // If the start/end passed each other, then we are trying to highlight a range + // that just exists in whitespace, which must be some sort of other bug. + assert(StartColNo <= EndColNo && "Trying to highlight whitespace??"); + + // Fill the range with ~'s. + for (unsigned i = StartColNo; i < EndColNo; ++i) + CaretLine[i] = '~'; +} + +/// \brief When the source code line we want to print is too long for +/// the terminal, select the "interesting" region. +static void SelectInterestingSourceRegion(std::string &SourceLine, + std::string &CaretLine, + std::string &FixItInsertionLine, + unsigned EndOfCaretToken, + unsigned Columns) { + unsigned MaxSize = std::max(SourceLine.size(), + std::max(CaretLine.size(), + FixItInsertionLine.size())); + if (MaxSize > SourceLine.size()) + SourceLine.resize(MaxSize, ' '); + if (MaxSize > CaretLine.size()) + CaretLine.resize(MaxSize, ' '); + if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) + FixItInsertionLine.resize(MaxSize, ' '); + + // Find the slice that we need to display the full caret line + // correctly. + unsigned CaretStart = 0, CaretEnd = CaretLine.size(); + for (; CaretStart != CaretEnd; ++CaretStart) + if (!isspace(CaretLine[CaretStart])) + break; + + for (; CaretEnd != CaretStart; --CaretEnd) + if (!isspace(CaretLine[CaretEnd - 1])) + break; + + // Make sure we don't chop the string shorter than the caret token + // itself. + if (CaretEnd < EndOfCaretToken) + CaretEnd = EndOfCaretToken; + + // If we have a fix-it line, make sure the slice includes all of the + // fix-it information. + if (!FixItInsertionLine.empty()) { + unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size(); + for (; FixItStart != FixItEnd; ++FixItStart) + if (!isspace(FixItInsertionLine[FixItStart])) + break; + + for (; FixItEnd != FixItStart; --FixItEnd) + if (!isspace(FixItInsertionLine[FixItEnd - 1])) + break; + + if (FixItStart < CaretStart) + CaretStart = FixItStart; + if (FixItEnd > CaretEnd) + CaretEnd = FixItEnd; + } + + // CaretLine[CaretStart, CaretEnd) contains all of the interesting + // parts of the caret line. While this slice is smaller than the + // number of columns we have, try to grow the slice to encompass + // more context. + + // If the end of the interesting region comes before we run out of + // space in the terminal, start at the beginning of the line. + if (Columns > 3 && CaretEnd < Columns - 3) + CaretStart = 0; + + unsigned TargetColumns = Columns; + if (TargetColumns > 8) + TargetColumns -= 8; // Give us extra room for the ellipses. + unsigned SourceLength = SourceLine.size(); + while ((CaretEnd - CaretStart) < TargetColumns) { + bool ExpandedRegion = false; + // Move the start of the interesting region left until we've + // pulled in something else interesting. + if (CaretStart == 1) + CaretStart = 0; + else if (CaretStart > 1) { + unsigned NewStart = CaretStart - 1; + + // Skip over any whitespace we see here; we're looking for + // another bit of interesting text. + while (NewStart && isspace(SourceLine[NewStart])) + --NewStart; + + // Skip over this bit of "interesting" text. + while (NewStart && !isspace(SourceLine[NewStart])) + --NewStart; + + // Move up to the non-whitespace character we just saw. + if (NewStart) + ++NewStart; + + // If we're still within our limit, update the starting + // position within the source/caret line. + if (CaretEnd - NewStart <= TargetColumns) { + CaretStart = NewStart; + ExpandedRegion = true; + } + } + + // Move the end of the interesting region right until we've + // pulled in something else interesting. + if (CaretEnd != SourceLength) { + assert(CaretEnd < SourceLength && "Unexpected caret position!"); + unsigned NewEnd = CaretEnd; + + // Skip over any whitespace we see here; we're looking for + // another bit of interesting text. + while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1])) + ++NewEnd; + + // Skip over this bit of "interesting" text. + while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1])) + ++NewEnd; + + if (NewEnd - CaretStart <= TargetColumns) { + CaretEnd = NewEnd; + ExpandedRegion = true; + } + } + + if (!ExpandedRegion) + break; + } + + // [CaretStart, CaretEnd) is the slice we want. Update the various + // output lines to show only this slice, with two-space padding + // before the lines so that it looks nicer. + if (CaretEnd < SourceLine.size()) + SourceLine.replace(CaretEnd, std::string::npos, "..."); + if (CaretEnd < CaretLine.size()) + CaretLine.erase(CaretEnd, std::string::npos); + if (FixItInsertionLine.size() > CaretEnd) + FixItInsertionLine.erase(CaretEnd, std::string::npos); + + if (CaretStart > 2) { + SourceLine.replace(0, CaretStart, " ..."); + CaretLine.replace(0, CaretStart, " "); + if (FixItInsertionLine.size() >= CaretStart) + FixItInsertionLine.replace(0, CaretStart, " "); + } +} + +void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, + SourceRange *Ranges, + unsigned NumRanges, + const SourceManager &SM, + const FixItHint *Hints, + unsigned NumHints, + unsigned Columns, + unsigned OnMacroInst, + unsigned MacroSkipStart, + unsigned MacroSkipEnd) { + assert(LangOpts && "Unexpected diagnostic outside source file processing"); + assert(!Loc.isInvalid() && "must have a valid source location here"); + + // If this is a macro ID, first emit information about where this was + // instantiated (recursively) then emit information about where the token was + // spelled from. + if (!Loc.isFileID()) { + // Whether to suppress printing this macro instantiation. + bool Suppressed + = OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd; + + + SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; + // FIXME: Map ranges? + EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns, + OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); + + // Map the location. + Loc = SM.getImmediateSpellingLoc(Loc); + + // Map the ranges. + for (unsigned i = 0; i != NumRanges; ++i) { + SourceLocation S = Ranges[i].getBegin(), E = Ranges[i].getEnd(); + if (S.isMacroID()) S = SM.getImmediateSpellingLoc(S); + if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); + Ranges[i] = SourceRange(S, E); + } + + if (!Suppressed) { + // Get the pretty name, according to #line directives etc. + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + // If this diagnostic is not in the main file, print out the + // "included from" lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + } + + if (DiagOpts->ShowLocation) { + // Emit the file/line/column that this expansion came from. + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; + if (DiagOpts->ShowColumn) + OS << PLoc.getColumn() << ':'; + OS << ' '; + } + OS << "note: instantiated from:\n"; + + EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns, + OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); + return; + } + + if (OnMacroInst == MacroSkipStart) { + // Tell the user that we've skipped contexts. + OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart) + << " contexts in backtrace; use -fmacro-backtrace-limit=0 to see " + "all)\n"; + } + + return; + } + + // Decompose the location into a FID/Offset pair. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + // Get information about the buffer it points into. + bool Invalid = false; + const char *BufStart = SM.getBufferData(FID, &Invalid).data(); + if (Invalid) + return; + + unsigned ColNo = SM.getColumnNumber(FID, FileOffset); + unsigned CaretEndColNo + = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); + + // Rewind from the current position to the start of the line. + const char *TokPtr = BufStart+FileOffset; + const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. + + + // Compute the line end. Scan forward from the error position to the end of + // the line. + const char *LineEnd = TokPtr; + while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') + ++LineEnd; + + // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past + // the source line length as currently being computed. See + // test/Misc/message-length.c. + CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); + + // Copy the line of code into an std::string for ease of manipulation. + std::string SourceLine(LineStart, LineEnd); + + // Create a line for the caret that is filled with spaces that is the same + // length as the line of source code. + std::string CaretLine(LineEnd-LineStart, ' '); + + // Highlight all of the characters covered by Ranges with ~ characters. + if (NumRanges) { + unsigned LineNo = SM.getLineNumber(FID, FileOffset); + + for (unsigned i = 0, e = NumRanges; i != e; ++i) + HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); + } + + // Next, insert the caret itself. + if (ColNo-1 < CaretLine.size()) + CaretLine[ColNo-1] = '^'; + else + CaretLine.push_back('^'); + + // Scan the source line, looking for tabs. If we find any, manually expand + // them to spaces and update the CaretLine to match. + for (unsigned i = 0; i != SourceLine.size(); ++i) { + if (SourceLine[i] != '\t') continue; + + // Replace this tab with at least one space. + SourceLine[i] = ' '; + + // Compute the number of spaces we need to insert. + unsigned TabStop = DiagOpts->TabStop; + assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && + "Invalid -ftabstop value"); + unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); + assert(NumSpaces < TabStop && "Invalid computation of space amt"); + + // Insert spaces into the SourceLine. + SourceLine.insert(i+1, NumSpaces, ' '); + + // Insert spaces or ~'s into CaretLine. + CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); + } + + // If we are in -fdiagnostics-print-source-range-info mode, we are trying to + // produce easily machine parsable output. Add a space before the source line + // and the caret to make it trivial to tell the main diagnostic line from what + // the user is intended to see. + if (DiagOpts->ShowSourceRanges) { + SourceLine = ' ' + SourceLine; + CaretLine = ' ' + CaretLine; + } + + std::string FixItInsertionLine; + if (NumHints && DiagOpts->ShowFixits) { + for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; + Hint != LastHint; ++Hint) { + if (Hint->InsertionLoc.isValid()) { + // We have an insertion hint. Determine whether the inserted + // code is on the same line as the caret. + std::pair<FileID, unsigned> HintLocInfo + = SM.getDecomposedInstantiationLoc(Hint->InsertionLoc); + if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == + SM.getLineNumber(FID, FileOffset)) { + // Insert the new code into the line just below the code + // that the user wrote. + unsigned HintColNo + = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); + unsigned LastColumnModified + = HintColNo - 1 + Hint->CodeToInsert.size(); + if (LastColumnModified > FixItInsertionLine.size()) + FixItInsertionLine.resize(LastColumnModified, ' '); + std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), + FixItInsertionLine.begin() + HintColNo - 1); + } else { + FixItInsertionLine.clear(); + break; + } + } + } + // Now that we have the entire fixit line, expand the tabs in it. + // Since we don't want to insert spaces in the middle of a word, + // find each word and the column it should line up with and insert + // spaces until they match. + if (!FixItInsertionLine.empty()) { + unsigned FixItPos = 0; + unsigned LinePos = 0; + unsigned TabExpandedCol = 0; + unsigned LineLength = LineEnd - LineStart; + + while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { + // Find the next word in the FixIt line. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] == ' ') + ++FixItPos; + unsigned CharDistance = FixItPos - TabExpandedCol; + + // Walk forward in the source line, keeping track of + // the tab-expanded column. + for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) + if (LinePos >= LineLength || LineStart[LinePos] != '\t') + ++TabExpandedCol; + else + TabExpandedCol = + (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; + + // Adjust the fixit line to match this column. + FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); + FixItPos = TabExpandedCol; + + // Walk to the end of the word. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] != ' ') + ++FixItPos; + } + } + } + + // If the source line is too long for our terminal, select only the + // "interesting" source region within that line. + if (Columns && SourceLine.size() > Columns) + SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, + CaretEndColNo, Columns); + + // Finally, remove any blank spaces from the end of CaretLine. + while (CaretLine[CaretLine.size()-1] == ' ') + CaretLine.erase(CaretLine.end()-1); + + // Emit what we have computed. + OS << SourceLine << '\n'; + + if (DiagOpts->ShowColors) + OS.changeColor(caretColor, true); + OS << CaretLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + + if (!FixItInsertionLine.empty()) { + if (DiagOpts->ShowColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); + if (DiagOpts->ShowSourceRanges) + OS << ' '; + OS << FixItInsertionLine << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + } +} + +/// \brief Skip over whitespace in the string, starting at the given +/// index. +/// +/// \returns The index of the first non-whitespace character that is +/// greater than or equal to Idx or, if no such character exists, +/// returns the end of the string. +static unsigned skipWhitespace(unsigned Idx, + const llvm::SmallVectorImpl<char> &Str, + unsigned Length) { + while (Idx < Length && isspace(Str[Idx])) + ++Idx; + return Idx; +} + +/// \brief If the given character is the start of some kind of +/// balanced punctuation (e.g., quotes or parentheses), return the +/// character that will terminate the punctuation. +/// +/// \returns The ending punctuation character, if any, or the NULL +/// character if the input character does not start any punctuation. +static inline char findMatchingPunctuation(char c) { + switch (c) { + case '\'': return '\''; + case '`': return '\''; + case '"': return '"'; + case '(': return ')'; + case '[': return ']'; + case '{': return '}'; + default: break; + } + + return 0; +} + +/// \brief Find the end of the word starting at the given offset +/// within a string. +/// +/// \returns the index pointing one character past the end of the +/// word. +static unsigned findEndOfWord(unsigned Start, + const llvm::SmallVectorImpl<char> &Str, + unsigned Length, unsigned Column, + unsigned Columns) { + assert(Start < Str.size() && "Invalid start position!"); + unsigned End = Start + 1; + + // If we are already at the end of the string, take that as the word. + if (End == Str.size()) + return End; + + // Determine if the start of the string is actually opening + // punctuation, e.g., a quote or parentheses. + char EndPunct = findMatchingPunctuation(Str[Start]); + if (!EndPunct) { + // This is a normal word. Just find the first space character. + while (End < Length && !isspace(Str[End])) + ++End; + return End; + } + + // We have the start of a balanced punctuation sequence (quotes, + // parentheses, etc.). Determine the full sequence is. + llvm::SmallString<16> PunctuationEndStack; + PunctuationEndStack.push_back(EndPunct); + while (End < Length && !PunctuationEndStack.empty()) { + if (Str[End] == PunctuationEndStack.back()) + PunctuationEndStack.pop_back(); + else if (char SubEndPunct = findMatchingPunctuation(Str[End])) + PunctuationEndStack.push_back(SubEndPunct); + + ++End; + } + + // Find the first space character after the punctuation ended. + while (End < Length && !isspace(Str[End])) + ++End; + + unsigned PunctWordLength = End - Start; + if (// If the word fits on this line + Column + PunctWordLength <= Columns || + // ... or the word is "short enough" to take up the next line + // without too much ugly white space + PunctWordLength < Columns/3) + return End; // Take the whole thing as a single "word". + + // The whole quoted/parenthesized string is too long to print as a + // single "word". Instead, find the "word" that starts just after + // the punctuation and use that end-point instead. This will recurse + // until it finds something small enough to consider a word. + return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns); +} + +/// \brief Print the given string to a stream, word-wrapping it to +/// some number of columns in the process. +/// +/// \brief OS the stream to which the word-wrapping string will be +/// emitted. +/// +/// \brief Str the string to word-wrap and output. +/// +/// \brief Columns the number of columns to word-wrap to. +/// +/// \brief Column the column number at which the first character of \p +/// Str will be printed. This will be non-zero when part of the first +/// line has already been printed. +/// +/// \brief Indentation the number of spaces to indent any lines beyond +/// the first line. +/// +/// \returns true if word-wrapping was required, or false if the +/// string fit on the first line. +static bool PrintWordWrapped(llvm::raw_ostream &OS, + const llvm::SmallVectorImpl<char> &Str, + unsigned Columns, + unsigned Column = 0, + unsigned Indentation = WordWrapIndentation) { + unsigned Length = Str.size(); + + // If there is a newline in this message somewhere, find that + // newline and split the message into the part before the newline + // (which will be word-wrapped) and the part from the newline one + // (which will be emitted unchanged). + for (unsigned I = 0; I != Length; ++I) + if (Str[I] == '\n') { + Length = I; + break; + } + + // The string used to indent each line. + llvm::SmallString<16> IndentStr; + IndentStr.assign(Indentation, ' '); + bool Wrapped = false; + for (unsigned WordStart = 0, WordEnd; WordStart < Length; + WordStart = WordEnd) { + // Find the beginning of the next word. + WordStart = skipWhitespace(WordStart, Str, Length); + if (WordStart == Length) + break; + + // Find the end of this word. + WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns); + + // Does this word fit on the current line? + unsigned WordLength = WordEnd - WordStart; + if (Column + WordLength < Columns) { + // This word fits on the current line; print it there. + if (WordStart) { + OS << ' '; + Column += 1; + } + OS.write(&Str[WordStart], WordLength); + Column += WordLength; + continue; + } + + // This word does not fit on the current line, so wrap to the next + // line. + OS << '\n'; + OS.write(&IndentStr[0], Indentation); + OS.write(&Str[WordStart], WordLength); + Column = Indentation + WordLength; + Wrapped = true; + } + + if (Length == Str.size()) + return Wrapped; // We're done. + + // There is a newline in the message, followed by something that + // will not be word-wrapped. Print that. + OS.write(&Str[Length], Str.size() - Length); + return true; +} + +void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) { + // Keeps track of the the starting position of the location + // information (e.g., "foo.c:10:4:") that precedes the error + // message. We use this information to determine how long the + // file+line+column number prefix is. + uint64_t StartOfLocationInfo = OS.tell(); + + if (!Prefix.empty()) + OS << Prefix << ": "; + + // If the location is specified, print out a file/line/col and include trace + // if enabled. + if (Info.getLocation().isValid()) { + const SourceManager &SM = Info.getLocation().getManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); + unsigned LineNo = PLoc.getLine(); + + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + if (LastWarningLoc != PLoc.getIncludeLoc()) { + LastWarningLoc = PLoc.getIncludeLoc(); + PrintIncludeStack(LastWarningLoc, SM); + StartOfLocationInfo = OS.tell(); + } + + // Compute the column number. + if (DiagOpts->ShowLocation) { + if (DiagOpts->ShowColors) + OS.changeColor(savedColor, true); + + // Emit a Visual Studio compatible line number syntax. + if (LangOpts && LangOpts->Microsoft) { + OS << PLoc.getFilename() << '(' << LineNo << ')'; + OS << " : "; + } else { + OS << PLoc.getFilename() << ':' << LineNo << ':'; + if (DiagOpts->ShowColumn) + if (unsigned ColNo = PLoc.getColumn()) + OS << ColNo << ':'; + } + if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { + FileID CaretFileID = + SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); + bool PrintedRange = false; + + for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { + // Ignore invalid ranges. + if (!Info.getRange(i).isValid()) continue; + + SourceLocation B = Info.getRange(i).getBegin(); + SourceLocation E = Info.getRange(i).getEnd(); + B = SM.getInstantiationLoc(B); + E = SM.getInstantiationLoc(E); + + // If the End location and the start location are the same and are a + // macro location, then the range was something that came from a macro + // expansion or _Pragma. If this is an object-like macro, the best we + // can do is to highlight the range. If this is a function-like + // macro, we'd also like to highlight the arguments. + if (B == E && Info.getRange(i).getEnd().isMacroID()) + E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; + + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); + + // If the start or end of the range is in another file, just discard + // it. + if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) + continue; + + // Add in the length of the token, so that we cover multi-char tokens. + unsigned TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); + + OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; + PrintedRange = true; + } + + if (PrintedRange) + OS << ':'; + } + OS << ' '; + if (DiagOpts->ShowColors) + OS.resetColor(); + } + } + + if (DiagOpts->ShowColors) { + // Print diagnostic category in bold and color + switch (Level) { + case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); + case Diagnostic::Note: OS.changeColor(noteColor, true); break; + case Diagnostic::Warning: OS.changeColor(warningColor, true); break; + case Diagnostic::Error: OS.changeColor(errorColor, true); break; + case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; + } + } + + switch (Level) { + case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); + case Diagnostic::Note: OS << "note: "; break; + case Diagnostic::Warning: OS << "warning: "; break; + case Diagnostic::Error: OS << "error: "; break; + case Diagnostic::Fatal: OS << "fatal error: "; break; + } + + if (DiagOpts->ShowColors) + OS.resetColor(); + + llvm::SmallString<100> OutStr; + Info.FormatDiagnostic(OutStr); + + std::string OptionName; + if (DiagOpts->ShowOptionNames) { + if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { + OptionName = "-W"; + OptionName += Opt; + } else if (Info.getID() == diag::fatal_too_many_errors) { + OptionName = "-ferror-limit="; + } else { + // If the diagnostic is an extension diagnostic and not enabled by default + // then it must have been turned on with -pedantic. + bool EnabledByDefault; + if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && + !EnabledByDefault) + OptionName = "-pedantic"; + } + } + + // If the user wants to see category information, include it too. + unsigned DiagCategory = 0; + if (DiagOpts->ShowCategories) + DiagCategory = Diagnostic::getCategoryNumberForDiag(Info.getID()); + + // If there is any categorization information, include it. + if (!OptionName.empty() || DiagCategory != 0) { + bool NeedsComma = false; + OutStr += " ["; + + if (!OptionName.empty()) { + OutStr += OptionName; + NeedsComma = true; + } + + if (DiagCategory) { + if (NeedsComma) OutStr += ','; + if (DiagOpts->ShowCategories == 1) + OutStr += llvm::utostr(DiagCategory); + else { + assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); + OutStr += Diagnostic::getCategoryNameFromID(DiagCategory); + } + } + + OutStr += "]"; + } + + + if (DiagOpts->ShowColors) { + // Print warnings, errors and fatal errors in bold, no color + switch (Level) { + case Diagnostic::Warning: OS.changeColor(savedColor, true); break; + case Diagnostic::Error: OS.changeColor(savedColor, true); break; + case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; + default: break; //don't bold notes + } + } + + if (DiagOpts->MessageLength) { + // We will be word-wrapping the error message, so compute the + // column number where we currently are (after printing the + // location information). + unsigned Column = OS.tell() - StartOfLocationInfo; + PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); + } else { + OS.write(OutStr.begin(), OutStr.size()); + } + OS << '\n'; + if (DiagOpts->ShowColors) + OS.resetColor(); + + // If caret diagnostics are enabled and we have location, we want to + // emit the caret. However, we only do this if the location moved + // from the last diagnostic, if the last diagnostic was a note that + // was part of a different warning or error diagnostic, or if the + // diagnostic has ranges. We don't want to emit the same caret + // multiple times if one loc has multiple diagnostics. + if (DiagOpts->ShowCarets && Info.getLocation().isValid() && + ((LastLoc != Info.getLocation()) || Info.getNumRanges() || + (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || + Info.getNumFixItHints())) { + // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. + LastLoc = Info.getLocation(); + LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); + + // Get the ranges into a local array we can hack on. + SourceRange Ranges[20]; + unsigned NumRanges = Info.getNumRanges(); + assert(NumRanges < 20 && "Out of space"); + for (unsigned i = 0; i != NumRanges; ++i) + Ranges[i] = Info.getRange(i); + + unsigned NumHints = Info.getNumFixItHints(); + for (unsigned idx = 0; idx < NumHints; ++idx) { + const FixItHint &Hint = Info.getFixItHint(idx); + if (Hint.RemoveRange.isValid()) { + assert(NumRanges < 20 && "Out of space"); + Ranges[NumRanges++] = Hint.RemoveRange; + } + } + + unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; + if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { + // Compute the length of the macro-instantiation backtrace, so that we + // can establish which steps in the macro backtrace we'll skip. + SourceLocation Loc = LastLoc; + unsigned Depth = 0; + do { + ++Depth; + Loc = LastLoc.getManager().getImmediateInstantiationRange(Loc).first; + } while (!Loc.isFileID()); + + if (Depth > DiagOpts->MacroBacktraceLimit) { + MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + + DiagOpts->MacroBacktraceLimit % 2; + MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; + } + } + + EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), + Info.getFixItHints(), + Info.getNumFixItHints(), + DiagOpts->MessageLength, + 0, MacroInstSkipStart, MacroInstSkipEnd); + } + + OS.flush(); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp new file mode 100644 index 0000000..be9db42 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp @@ -0,0 +1,119 @@ +//===--- DocumentXML.cpp - XML document for ASTs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the XML document class, which provides the means to +// dump out the AST in a XML form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/DocumentXML.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" + +namespace clang { + namespace XML { + namespace { + +//--------------------------------------------------------- +class TypeWriter : public TypeVisitor<TypeWriter> { + DocumentXML& Doc; + +public: + TypeWriter(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) { \ + Doc.addSubNode(NAME); + +#define ID_ATTRIBUTE_XML // done by the Document class itself +#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); +#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") +#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context") +#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); + +#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = false; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ + { \ + const char* pAttributeName = NAME; \ + const bool optional = true; \ + switch (T->FN) { \ + default: assert(0 && "unknown enum value"); + +#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; +#define END_ENUM_XML } } +#define END_NODE_XML } + +#include "clang/Frontend/TypeXML.def" + +}; + +//--------------------------------------------------------- + } // anon clang + } // NS XML + +//--------------------------------------------------------- +class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> { + DocumentXML& Doc; + + void addIfType(const Type* pType) { + Doc.addTypeRecursively(pType); + } + + void addIfType(const QualType& pType) { + Doc.addTypeRecursively(pType); + } + + template<class T> void addIfType(T) {} + +public: + TypeAdder(DocumentXML& doc) : Doc(doc) {} + +#define NODE_XML( CLASS, NAME ) \ + void Visit##CLASS(CLASS* T) \ + { + +#define ID_ATTRIBUTE_XML +#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN); +#define CONTEXT_ATTRIBUTE_XML( FN ) +#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN); +#define ATTRIBUTE_OPT_XML( FN, NAME ) +#define ATTRIBUTE_ENUM_XML( FN, NAME ) +#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) +#define ENUM_XML( VALUE, NAME ) +#define END_ENUM_XML +#define END_NODE_XML } + +#include "clang/Frontend/TypeXML.def" +}; + +//--------------------------------------------------------- +void DocumentXML::addParentTypes(const Type* pType) { + TypeAdder(*this).Visit(const_cast<Type*>(pType)); +} + +//--------------------------------------------------------- +void DocumentXML::writeTypeToXML(const Type* pType) { + XML::TypeWriter(*this).Visit(const_cast<Type*>(pType)); +} + +//--------------------------------------------------------- +void DocumentXML::writeTypeToXML(const QualType& pType) { + XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType)); +} + +//--------------------------------------------------------- +} // NS clang + diff --git a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp new file mode 100644 index 0000000..ae36481 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -0,0 +1,521 @@ +//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags, + DiagnosticClient *_Primary) + : Diags(_Diags), PrimaryClient(_Primary), + Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), NumErrors(0) { +} + +VerifyDiagnosticsClient::~VerifyDiagnosticsClient() { + CheckDiagnostics(); +} + +// DiagnosticClient interface. + +void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP) { + // FIXME: Const hack, we screw up the preprocessor but in practice its ok + // because it doesn't get reused. It would be better if we could make a copy + // though. + CurrentPreprocessor = const_cast<Preprocessor*>(PP); + + PrimaryClient->BeginSourceFile(LangOpts, PP); +} + +void VerifyDiagnosticsClient::EndSourceFile() { + CheckDiagnostics(); + + PrimaryClient->EndSourceFile(); + + CurrentPreprocessor = 0; +} + +void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel, + const DiagnosticInfo &Info) { + // Send the diagnostic to the buffer, we will check it once we reach the end + // of the source file (or are destructed). + Buffer->HandleDiagnostic(DiagLevel, Info); +} + +// FIXME: It would be nice to just get this from the primary diagnostic client +// or something. +bool VerifyDiagnosticsClient::HadErrors() { + CheckDiagnostics(); + + return NumErrors != 0; +} + +//===----------------------------------------------------------------------===// +// Checking diagnostics implementation. +//===----------------------------------------------------------------------===// + +typedef TextDiagnosticBuffer::DiagList DiagList; +typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; + +namespace { + +/// Directive - Abstract class representing a parsed verify directive. +/// +class Directive { +public: + static Directive* Create(bool RegexKind, const SourceLocation &Location, + const std::string &Text, unsigned Count); +public: + SourceLocation Location; + const std::string Text; + unsigned Count; + + virtual ~Directive() { } + + // Returns true if directive text is valid. + // Otherwise returns false and populates E. + virtual bool isValid(std::string &Error) = 0; + + // Returns true on match. + virtual bool Match(const std::string &S) = 0; + +protected: + Directive(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Location(Location), Text(Text), Count(Count) { } + +private: + Directive(const Directive&); // DO NOT IMPLEMENT + void operator=(const Directive&); // DO NOT IMPLEMENT +}; + +/// StandardDirective - Directive with string matching. +/// +class StandardDirective : public Directive { +public: + StandardDirective(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Directive(Location, Text, Count) { } + + virtual bool isValid(std::string &Error) { + // all strings are considered valid; even empty ones + return true; + } + + virtual bool Match(const std::string &S) { + return S.find(Text) != std::string::npos || + Text.find(S) != std::string::npos; + } +}; + +/// RegexDirective - Directive with regular-expression matching. +/// +class RegexDirective : public Directive { +public: + RegexDirective(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Directive(Location, Text, Count), Regex(Text) { } + + virtual bool isValid(std::string &Error) { + if (Regex.isValid(Error)) + return true; + return false; + } + + virtual bool Match(const std::string &S) { + return Regex.match(S); + } + +private: + llvm::Regex Regex; +}; + +typedef std::vector<Directive*> DirectiveList; + +/// ExpectedData - owns directive objects and deletes on destructor. +/// +struct ExpectedData { + DirectiveList Errors; + DirectiveList Warnings; + DirectiveList Notes; + + ~ExpectedData() { + DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; + for (DirectiveList **PL = Lists; *PL; ++PL) { + DirectiveList * const L = *PL; + for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) + delete *I; + } + } +}; + +class ParseHelper +{ +public: + ParseHelper(const char *Begin, const char *End) + : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } + + // Return true if string literal is next. + bool Next(const std::string &S) { + std::string::size_type LEN = S.length(); + P = C; + PEnd = C + LEN; + if (PEnd > End) + return false; + return !memcmp(P, S.c_str(), LEN); + } + + // Return true if number is next. + // Output N only if number is next. + bool Next(unsigned &N) { + unsigned TMP = 0; + P = C; + for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) { + TMP *= 10; + TMP += P[0] - '0'; + } + if (P == C) + return false; + PEnd = P; + N = TMP; + return true; + } + + // Return true if string literal is found. + // When true, P marks begin-position of S in content. + bool Search(const std::string &S) { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.length(); + return P != End; + } + + // Advance 1-past previous next/search. + // Behavior is undefined if previous next/search failed. + bool Advance() { + C = PEnd; + return C < End; + } + + // Skip zero or more whitespace. + void SkipWhitespace() { + for (; C < End && isspace(*C); ++C) + ; + } + + // Return true if EOF reached. + bool Done() { + return !(C < End); + } + + const char * const Begin; // beginning of expected content + const char * const End; // end of expected content (1-past) + const char *C; // position of next char in content + const char *P; + +private: + const char *PEnd; // previous next/search subject end (1-past) +}; + +} // namespace anonymous + +/// ParseDirective - Go through the comment and see if it indicates expected +/// diagnostics. If so, then put them in the appropriate directive list. +/// +static void ParseDirective(const char *CommentStart, unsigned CommentLen, + ExpectedData &ED, Preprocessor &PP, + SourceLocation Pos) { + // A single comment may contain multiple directives. + for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { + // search for token: expected + if (!PH.Search("expected")) + break; + PH.Advance(); + + // next token: - + if (!PH.Next("-")) + continue; + PH.Advance(); + + // next token: { error | warning | note } + DirectiveList* DL = NULL; + if (PH.Next("error")) + DL = &ED.Errors; + else if (PH.Next("warning")) + DL = &ED.Warnings; + else if (PH.Next("note")) + DL = &ED.Notes; + else + continue; + PH.Advance(); + + // default directive kind + bool RegexKind = false; + const char* KindStr = "string"; + + // next optional token: - + if (PH.Next("-re")) { + PH.Advance(); + RegexKind = true; + KindStr = "regex"; + } + + // skip optional whitespace + PH.SkipWhitespace(); + + // next optional token: positive integer + unsigned Count = 1; + if (PH.Next(Count)) + PH.Advance(); + + // skip optional whitespace + PH.SkipWhitespace(); + + // next token: {{ + if (!PH.Next("{{")) { + PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_start) << KindStr; + continue; + } + PH.Advance(); + const char* const ContentBegin = PH.C; // mark content begin + + // search for token: }} + if (!PH.Search("}}")) { + PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_end) << KindStr; + continue; + } + const char* const ContentEnd = PH.P; // mark content end + PH.Advance(); + + // build directive text; convert \n to newlines + std::string Text; + llvm::StringRef NewlineStr = "\\n"; + llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); + size_t CPos = 0; + size_t FPos; + while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { + Text += Content.substr(CPos, FPos-CPos); + Text += '\n'; + CPos = FPos + NewlineStr.size(); + } + if (Text.empty()) + Text.assign(ContentBegin, ContentEnd); + + // construct new directive + Directive *D = Directive::Create(RegexKind, Pos, Text, Count); + std::string Error; + if (D->isValid(Error)) + DL->push_back(D); + else { + PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), + diag::err_verify_invalid_content) + << KindStr << Error; + } + } +} + +/// FindExpectedDiags - Lex the main source file to find all of the +// expected errors and warnings. +static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { + // Create a raw lexer to pull all the comments out of the main file. We don't + // want to look in #include'd headers for expected-error strings. + SourceManager &SM = PP.getSourceManager(); + FileID FID = SM.getMainFileID(); + if (SM.getMainFileID().isInvalid()) + return; + + // Create a lexer to lex all the tokens of the main file in raw mode. + const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); + + // Return comments as tokens, this is how we find expected diagnostics. + RawLex.SetCommentRetentionState(true); + + Token Tok; + Tok.setKind(tok::comment); + while (Tok.isNot(tok::eof)) { + RawLex.Lex(Tok); + if (!Tok.is(tok::comment)) continue; + + std::string Comment = PP.getSpelling(Tok); + if (Comment.empty()) continue; + + // Find all expected errors/warnings/notes. + ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); + }; +} + +/// PrintProblem - This takes a diagnostic map of the delta between expected and +/// seen diagnostics. If there's anything in it, then something unexpected +/// happened. Print the map out in a nice format and return "true". If the map +/// is empty and we're not going to print things, then return "false". +/// +static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, + const_diag_iterator diag_begin, + const_diag_iterator diag_end, + const char *Kind, bool Expected) { + if (diag_begin == diag_end) return 0; + + llvm::SmallString<256> Fmt; + llvm::raw_svector_ostream OS(Fmt); + for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { + if (I->first.isInvalid() || !SourceMgr) + OS << "\n (frontend)"; + else + OS << "\n Line " << SourceMgr->getInstantiationLineNumber(I->first); + OS << ": " << I->second; + } + + Diags.Report(diag::err_verify_inconsistent_diags) + << Kind << !Expected << OS.str(); + return std::distance(diag_begin, diag_end); +} + +static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, + DirectiveList &DL, const char *Kind, + bool Expected) { + if (DL.empty()) + return 0; + + llvm::SmallString<256> Fmt; + llvm::raw_svector_ostream OS(Fmt); + for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { + Directive& D = **I; + if (D.Location.isInvalid() || !SourceMgr) + OS << "\n (frontend)"; + else + OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location); + OS << ": " << D.Text; + } + + Diags.Report(diag::err_verify_inconsistent_diags) + << Kind << !Expected << OS.str(); + return DL.size(); +} + +/// CheckLists - Compare expected to seen diagnostic lists and return the +/// the difference between them. +/// +static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, + const char *Label, + DirectiveList &Left, + const_diag_iterator d2_begin, + const_diag_iterator d2_end) { + DirectiveList LeftOnly; + DiagList Right(d2_begin, d2_end); + + for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { + Directive& D = **I; + unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location); + + for (unsigned i = 0; i < D.Count; ++i) { + DiagList::iterator II, IE; + for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { + unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); + if (LineNo1 != LineNo2) + continue; + + const std::string &RightText = II->second; + if (D.Match(RightText)) + break; + } + if (II == IE) { + // Not found. + LeftOnly.push_back(*I); + } else { + // Found. The same cannot be found twice. + Right.erase(II); + } + } + } + // Now all that's left in Right are those that were not matched. + + return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) + + PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), + Label, false)); +} + +/// CheckResults - This compares the expected results to those that +/// were actually reported. It emits any discrepencies. Return "true" if there +/// were problems. Return "false" otherwise. +/// +static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, + const TextDiagnosticBuffer &Buffer, + ExpectedData &ED) { + // We want to capture the delta between what was expected and what was + // seen. + // + // Expected \ Seen - set expected but not seen + // Seen \ Expected - set seen but not expected + unsigned NumProblems = 0; + + // See if there are error mismatches. + NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors, + Buffer.err_begin(), Buffer.err_end()); + + // See if there are warning mismatches. + NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings, + Buffer.warn_begin(), Buffer.warn_end()); + + // See if there are note mismatches. + NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes, + Buffer.note_begin(), Buffer.note_end()); + + return NumProblems; +} + +void VerifyDiagnosticsClient::CheckDiagnostics() { + ExpectedData ED; + + // Ensure any diagnostics go to the primary client. + DiagnosticClient *CurClient = Diags.getClient(); + Diags.setClient(PrimaryClient.get()); + + // If we have a preprocessor, scan the source for expected diagnostic + // markers. If not then any diagnostics are unexpected. + if (CurrentPreprocessor) { + FindExpectedDiags(*CurrentPreprocessor, ED); + + // Check that the expected diagnostics occurred. + NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), + *Buffer, ED); + } else { + NumErrors += (PrintProblem(Diags, 0, + Buffer->err_begin(), Buffer->err_end(), + "error", false) + + PrintProblem(Diags, 0, + Buffer->warn_begin(), Buffer->warn_end(), + "warn", false) + + PrintProblem(Diags, 0, + Buffer->note_begin(), Buffer->note_end(), + "note", false)); + } + + Diags.setClient(CurClient); + + // Reset the buffer, we have processed all the diagnostics in it. + Buffer.reset(new TextDiagnosticBuffer()); +} + +Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, + const std::string &Text, unsigned Count) { + if (RegexKind) + return new RegexDirective(Location, Text, Count); + return new StandardDirective(Location, Text, Count); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp new file mode 100644 index 0000000..84c4f5d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp @@ -0,0 +1,131 @@ +//===--- Warnings.cpp - C-Language Front-end ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Command line warning options handler. +// +//===----------------------------------------------------------------------===// +// +// This file is responsible for handling all warning options. This includes +// a number of -Wfoo options and their variants, which are driven by TableGen- +// generated data, and the special cases -pedantic, -pedantic-errors, -w, +// -Werror and -Wfatal-errors. +// +// Each warning option controls any number of actual warnings. +// Given a warning option 'foo', the following are valid: +// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo +// +#include "clang/Frontend/Utils.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include <cstring> +#include <utility> +#include <algorithm> +using namespace clang; + +void clang::ProcessWarningOptions(Diagnostic &Diags, + const DiagnosticOptions &Opts) { + Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers + Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); + + // Handle -ferror-limit + if (Opts.ErrorLimit) + Diags.setErrorLimit(Opts.ErrorLimit); + if (Opts.TemplateBacktraceLimit) + Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit); + + // If -pedantic or -pedantic-errors was specified, then we want to map all + // extension diagnostics onto WARNING or ERROR unless the user has futz'd + // around with them explicitly. + if (Opts.PedanticErrors) + Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error); + else if (Opts.Pedantic) + Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn); + else + Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore); + + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { + const std::string &Opt = Opts.Warnings[i]; + const char *OptStart = &Opt[0]; + const char *OptEnd = OptStart+Opt.size(); + assert(*OptEnd == 0 && "Expect null termination for lower-bound search"); + + // Check to see if this warning starts with "no-", if so, this is a negative + // form of the option. + bool isPositive = true; + if (OptEnd-OptStart > 3 && memcmp(OptStart, "no-", 3) == 0) { + isPositive = false; + OptStart += 3; + } + + // Figure out how this option affects the warning. If -Wfoo, map the + // diagnostic to a warning, if -Wno-foo, map it to ignore. + diag::Mapping Mapping = isPositive ? diag::MAP_WARNING : diag::MAP_IGNORE; + + // -Wsystem-headers is a special case, not driven by the option table. It + // cannot be controlled with -Werror. + if (OptEnd-OptStart == 14 && memcmp(OptStart, "system-headers", 14) == 0) { + Diags.setSuppressSystemWarnings(!isPositive); + continue; + } + + // -Werror/-Wno-error is a special case, not controlled by the option table. + // It also has the "specifier" form of -Werror=foo and -Werror-foo. + if (OptEnd-OptStart >= 5 && memcmp(OptStart, "error", 5) == 0) { + const char *Specifier = 0; + if (OptEnd-OptStart != 5) { // Specifier must be present. + if ((OptStart[5] != '=' && OptStart[5] != '-') || + OptEnd-OptStart == 6) { + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Werror" << ("-W" + Opt); + continue; + } + Specifier = OptStart+6; + } + + if (Specifier == 0) { + Diags.setWarningsAsErrors(isPositive); + continue; + } + + // -Werror=foo maps foo to Error, -Wno-error=foo maps it to Warning. + Mapping = isPositive ? diag::MAP_ERROR : diag::MAP_WARNING_NO_WERROR; + OptStart = Specifier; + } + + // -Wfatal-errors is yet another special case. + if (OptEnd-OptStart >= 12 && memcmp(OptStart, "fatal-errors", 12) == 0) { + const char* Specifier = 0; + if (OptEnd-OptStart != 12) { + if ((OptStart[12] != '=' && OptStart[12] != '-') || + OptEnd-OptStart == 13) { + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Wfatal-errors" << ("-W" + Opt); + continue; + } + Specifier = OptStart + 13; + } + + if (Specifier == 0) { + Diags.setErrorsAsFatal(isPositive); + continue; + } + + // -Wfatal-errors=foo maps foo to Fatal, -Wno-fatal-errors=foo + // maps it to Error. + Mapping = isPositive ? diag::MAP_FATAL : diag::MAP_ERROR_NO_WFATAL; + OptStart = Specifier; + } + + if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) + Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); + } +} |