summaryrefslogtreecommitdiffstats
path: root/lib/Frontend
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Frontend')
-rw-r--r--lib/Frontend/ASTConsumers.cpp451
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp659
-rw-r--r--lib/Frontend/Backend.cpp415
-rw-r--r--lib/Frontend/CMakeLists.txt35
-rw-r--r--lib/Frontend/CacheTokens.cpp658
-rw-r--r--lib/Frontend/DependencyFile.cpp169
-rw-r--r--lib/Frontend/DiagChecker.cpp302
-rw-r--r--lib/Frontend/DocumentXML.cpp579
-rw-r--r--lib/Frontend/FixItRewriter.cpp199
-rw-r--r--lib/Frontend/GeneratePCH.cpp78
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp602
-rw-r--r--lib/Frontend/HTMLPrint.cpp92
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp327
-rw-r--r--lib/Frontend/InitPreprocessor.cpp495
-rw-r--r--lib/Frontend/Makefile18
-rw-r--r--lib/Frontend/ManagerRegistry.cpp20
-rw-r--r--lib/Frontend/PCHReader.cpp2260
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp712
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp1136
-rw-r--r--lib/Frontend/PCHWriter.cpp1966
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp532
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp829
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp389
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp831
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp470
-rw-r--r--lib/Frontend/RewriteBlocks.cpp1162
-rw-r--r--lib/Frontend/RewriteMacros.cpp215
-rw-r--r--lib/Frontend/RewriteObjC.cpp4693
-rw-r--r--lib/Frontend/RewriteTest.cpp39
-rw-r--r--lib/Frontend/StmtXML.cpp409
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp39
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp710
-rw-r--r--lib/Frontend/Warnings.cpp106
33 files changed, 21597 insertions, 0 deletions
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
new file mode 100644
index 0000000..11c9251
--- /dev/null
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -0,0 +1,451 @@
+//===--- 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/PrettyPrinter.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Streams.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, Context, 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(Ctx),
+ DEnd = Ctx.getTranslationUnitDecl()->decls_end(Ctx);
+ 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(), *Context);
+
+ if (FD->getBodyIfAvailable()) {
+ llvm::cerr << '\n';
+ FD->getBodyIfAvailable()->viewAST();
+ llvm::cerr << '\n';
+ }
+ return;
+ }
+
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ MD->print(llvm::errs(), *Context);
+
+ if (MD->getBody()) {
+ llvm::cerr << '\n';
+ MD->getBody()->viewAST();
+ llvm::cerr << '\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->getNameAsString();
+ break;
+ }
+ case Decl::Enum: {
+ const EnumDecl* ED = cast<EnumDecl>(DC);
+ if (ED->isDefinition())
+ Out << "[enum] ";
+ else
+ Out << "<enum> ";
+ Out << ED->getNameAsString();
+ break;
+ }
+ case Decl::Record: {
+ const RecordDecl* RD = cast<RecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[struct] ";
+ else
+ Out << "<struct> ";
+ Out << RD->getNameAsString();
+ break;
+ }
+ case Decl::CXXRecord: {
+ const CXXRecordDecl* RD = cast<CXXRecordDecl>(DC);
+ if (RD->isDefinition())
+ Out << "[class] ";
+ else
+ Out << "<class> ";
+ Out << RD->getNameAsString() << " " << 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->getNameAsString();
+ // 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)->getNameAsString();
+ }
+ Out << ")";
+ break;
+ }
+ case Decl::CXXMethod: {
+ const CXXMethodDecl* D = cast<CXXMethodDecl>(DC);
+ if (D->isOutOfLineDefinition())
+ Out << "[c++ method] ";
+ else if (D->isImplicit())
+ Out << "(c++ method) ";
+ else
+ Out << "<c++ method> ";
+ Out << D->getNameAsString();
+ // 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)->getNameAsString();
+ }
+ 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->isOutOfLineDefinition())
+ Out << "[c++ ctor] ";
+ else if (D->isImplicit())
+ Out << "(c++ ctor) ";
+ else
+ Out << "<c++ ctor> ";
+ Out << D->getNameAsString();
+ // 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)->getNameAsString();
+ }
+ 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->isOutOfLineDefinition())
+ Out << "[c++ dtor] ";
+ else if (D->isImplicit())
+ Out << "(c++ dtor) ";
+ else
+ Out << "<c++ dtor> ";
+ Out << D->getNameAsString();
+ // 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->isOutOfLineDefinition())
+ Out << "[c++ conversion] ";
+ else if (D->isImplicit())
+ Out << "(c++ conversion) ";
+ else
+ Out << "<c++ conversion> ";
+ Out << D->getNameAsString();
+ // 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.
+ // FIXME: Should not use a NULL DeclContext!
+ ASTContext *Context = 0;
+ for (DeclContext::decl_iterator I = DC->decls_begin(*Context),
+ E = DC->decls_end(*Context);
+ 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->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::Typedef: {
+ TypedefDecl* TD = cast<TypedefDecl>(*I);
+ Out << "<typedef> " << TD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::EnumConstant: {
+ EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I);
+ Out << "<enum constant> " << ECD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::Var: {
+ VarDecl* VD = cast<VarDecl>(*I);
+ Out << "<var> " << VD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ImplicitParam: {
+ ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I);
+ Out << "<implicit parameter> " << IPD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ParmVar: {
+ ParmVarDecl* PVD = cast<ParmVarDecl>(*I);
+ Out << "<parameter> " << PVD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::OriginalParmVar: {
+ OriginalParmVarDecl* OPVD = cast<OriginalParmVarDecl>(*I);
+ Out << "<original parameter> " << OPVD->getNameAsString() << "\n";
+ break;
+ }
+ case Decl::ObjCProperty: {
+ ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
+ Out << "<objc property> " << OPD->getNameAsString() << "\n";
+ break;
+ }
+ default:
+ fprintf(stderr, "DeclKind: %d \"%s\"\n", DK, I->getDeclKindName());
+ 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/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
new file mode 100644
index 0000000..ae90594
--- /dev/null
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -0,0 +1,659 @@
+//===--- 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/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+
+using namespace clang;
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz();
+
+//===----------------------------------------------------------------------===//
+// Basic type definitions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class AnalysisManager;
+ typedef void (*CodeAction)(AnalysisManager& Mgr);
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer declaration.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+ class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ typedef std::vector<CodeAction> Actions;
+ Actions FunctionActions;
+ Actions ObjCMethodActions;
+ Actions ObjCImplementationActions;
+ Actions TranslationUnitActions;
+
+ public:
+ const LangOptions& LOpts;
+ Diagnostic &Diags;
+ ASTContext* Ctx;
+ Preprocessor* PP;
+ PreprocessorFactory* PPF;
+ const std::string OutDir;
+ AnalyzerOptions Opts;
+ llvm::OwningPtr<PathDiagnosticClient> PD;
+
+ AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& outdir,
+ const AnalyzerOptions& opts)
+ : LOpts(lopts), Diags(diags),
+ Ctx(0), PP(pp), PPF(ppf),
+ OutDir(outdir), Opts(opts) {}
+
+ void addCodeAction(CodeAction action) {
+ FunctionActions.push_back(action);
+ ObjCMethodActions.push_back(action);
+ }
+
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
+
+ void addTranslationUnitAction(CodeAction action) {
+ TranslationUnitActions.push_back(action);
+ }
+
+ virtual void Initialize(ASTContext &Context) {
+ Ctx = &Context;
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+
+ void HandleTopLevelSingleDecl(Decl *D);
+ virtual void HandleTranslationUnit(ASTContext &C);
+
+ void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+ };
+
+
+ class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
+ Decl* D; Stmt* Body;
+
+ enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+
+ AnalysisConsumer& C;
+ bool DisplayedFunction;
+
+ llvm::OwningPtr<CFG> cfg;
+ llvm::OwningPtr<LiveVariables> liveness;
+ llvm::OwningPtr<ParentMap> PM;
+
+ // Configurable components creators.
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ public:
+ AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b, bool displayProgress)
+ : D(d), Body(b), AScope(ScopeDecl), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ AnalysisManager(AnalysisConsumer& c, bool displayProgress)
+ : D(0), Body(0), AScope(ScopeTU), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ Decl* getCodeDecl() const {
+ assert (AScope == ScopeDecl);
+ return D;
+ }
+
+ Stmt* getBody() const {
+ assert (AScope == ScopeDecl);
+ return Body;
+ }
+
+ StoreManagerCreator getStoreManagerCreator() {
+ return CreateStoreMgr;
+ };
+
+ ConstraintManagerCreator getConstraintManagerCreator() {
+ return CreateConstraintMgr;
+ }
+
+ virtual CFG* getCFG() {
+ if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
+ return cfg.get();
+ }
+
+ virtual ParentMap& getParentMap() {
+ if (!PM)
+ PM.reset(new ParentMap(getBody()));
+ return *PM.get();
+ }
+
+ virtual ASTContext& getContext() {
+ return *C.Ctx;
+ }
+
+ virtual SourceManager& getSourceManager() {
+ return getContext().getSourceManager();
+ }
+
+ virtual Diagnostic& getDiagnostic() {
+ return C.Diags;
+ }
+
+ const LangOptions& getLangOptions() const {
+ return C.LOpts;
+ }
+
+ virtual PathDiagnosticClient* getPathDiagnosticClient() {
+ if (C.PD.get() == 0 && !C.OutDir.empty()) {
+ switch (C.Opts.AnalysisDiagOpt) {
+ default:
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: C.PD.reset(CREATEFN(C.OutDir, C.PP, C.PPF)); break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+ return C.PD.get();
+ }
+
+ virtual LiveVariables* getLiveVariables() {
+ if (!liveness) {
+ CFG* c = getCFG();
+ if (!c) return 0;
+
+ liveness.reset(new LiveVariables(getContext(), *c));
+ liveness->runOnCFG(*c);
+ liveness->runOnAllBlocks(*c, 0, true);
+ }
+
+ return liveness.get();
+ }
+
+ bool shouldVisualizeGraphviz() const { return C.Opts.VisualizeEGDot; }
+
+ bool shouldVisualizeUbigraph() const { return C.Opts.VisualizeEGUbi; }
+
+ bool shouldVisualize() const {
+ return C.Opts.VisualizeEGDot || C.Opts.VisualizeEGUbi;
+ }
+
+ bool shouldTrimGraph() const { return C.Opts.TrimGraph; }
+
+ bool shouldPurgeDead() const { return C.Opts.PurgeDead; }
+
+ bool shouldEagerlyAssume() const { return C.Opts.EagerlyAssume; }
+
+ void DisplayFunction() {
+
+ if (DisplayedFunction)
+ return;
+
+ DisplayedFunction = true;
+
+ // FIXME: Is getCodeDecl() always a named decl?
+ if (isa<FunctionDecl>(getCodeDecl()) ||
+ isa<ObjCMethodDecl>(getCodeDecl())) {
+ NamedDecl *ND = cast<NamedDecl>(getCodeDecl());
+ SourceManager &SM = getContext().getSourceManager();
+ llvm::cerr << "ANALYZE: "
+ << SM.getPresumedLoc(ND->getLocation()).getFilename()
+ << ' ' << ND->getNameAsString() << '\n';
+ }
+ }
+
+ private:
+ /// Set configurable analyzer components creators. First check if there are
+ /// components registered at runtime. Otherwise fall back to builtin
+ /// components.
+ void setManagerCreators() {
+ if (ManagerRegistry::StoreMgrCreator != 0) {
+ CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+ }
+ else {
+ switch (C.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 (C.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"
+ }
+ }
+
+
+ // Some DiagnosticClients should be created all the time instead of
+ // lazily. Create those now.
+ switch (C.Opts.AnalysisDiagOpt) {
+ default: break;
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: if (AUTOCREATE) getPathDiagnosticClient(); break;
+#include "clang/Frontend/Analyses.def"
+ }
+ }
+
+ };
+
+} // end anonymous namespace
+
+namespace llvm {
+ template <> struct FoldingSetTrait<CodeAction> {
+ static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+ ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer implementation.
+//===----------------------------------------------------------------------===//
+
+void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
+
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
+ break;
+
+ Stmt* Body = FD->getBody(*Ctx);
+ if (Body) HandleCode(FD, Body, FunctionActions);
+ break;
+ }
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ return;
+
+ Stmt* Body = MD->getBody();
+ if (Body) HandleCode(MD, Body, ObjCMethodActions);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
+
+ if(!TranslationUnitActions.empty()) {
+ AnalysisManager mgr(*this, Opts.AnalyzerDisplayProgress);
+ for (Actions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I)
+ (*I)(mgr);
+ }
+
+ if (!ObjCImplementationActions.empty()) {
+ TranslationUnitDecl *TUD = C.getTranslationUnitDecl();
+
+ for (DeclContext::decl_iterator I = TUD->decls_begin(C),
+ E = TUD->decls_end(C);
+ I != E; ++I)
+ if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I))
+ HandleCode(ID, 0, ObjCImplementationActions);
+ }
+
+ // Delete the PathDiagnosticClient here just in case the AnalysisConsumer
+ // object doesn't get released. This will cause any side-effects in the
+ // destructor of the PathDiagnosticClient to get executed.
+ PD.reset();
+}
+
+void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions& actions) {
+
+ // Don't run the actions if an error has occured with parsing the file.
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Don't run the actions on declarations in header files unless
+ // otherwise specified.
+ if (!Opts.AnalyzeAll &&
+ !Ctx->getSourceManager().isFromMainFile(D->getLocation()))
+ return;
+
+ // Create an AnalysisManager that will manage the state for analyzing
+ // this method/function.
+ AnalysisManager mgr(*this, D, Body, Opts.AnalyzerDisplayProgress);
+
+ // Dispatch on the actions.
+ for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
+ (*I)(mgr);
+}
+
+//===----------------------------------------------------------------------===//
+// Analyses
+//===----------------------------------------------------------------------===//
+
+static void ActionWarnDeadStores(AnalysisManager& mgr) {
+ if (LiveVariables* L = mgr.getLiveVariables()) {
+ BugReporter BR(mgr);
+ CheckDeadStores(*L, BR);
+ }
+}
+
+static void ActionWarnUninitVals(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG())
+ CheckUninitializedValues(*c, mgr.getContext(), mgr.getDiagnostic());
+}
+
+
+static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
+ bool StandardWarnings = true) {
+
+
+ llvm::OwningPtr<GRTransferFuncs> TF(tf);
+
+ // Display progress.
+ mgr.DisplayFunction();
+
+ // Construct the analysis engine.
+ LiveVariables* L = mgr.getLiveVariables();
+ if (!L) return;
+
+ GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L, mgr,
+ mgr.shouldPurgeDead(), mgr.shouldEagerlyAssume(),
+ mgr.getStoreManagerCreator(),
+ mgr.getConstraintManagerCreator());
+
+ Eng.setTransferFunctions(tf);
+
+ if (StandardWarnings) {
+ Eng.RegisterInternalChecks();
+ RegisterAppleChecks(Eng);
+ }
+
+ // Set the graph auditor.
+ llvm::OwningPtr<ExplodedNodeImpl::Auditor> Auditor;
+ if (mgr.shouldVisualizeUbigraph()) {
+ Auditor.reset(CreateUbiViz());
+ ExplodedNodeImpl::SetAuditor(Auditor.get());
+ }
+
+ // Execute the worklist algorithm.
+ Eng.ExecuteWorkList();
+
+ // Release the auditor (if any) so that it doesn't monitor the graph
+ // created BugReporter.
+ ExplodedNodeImpl::SetAuditor(0);
+
+ // Visualize the exploded graph.
+ if (mgr.shouldVisualizeGraphviz())
+ Eng.ViewGraph(mgr.shouldTrimGraph());
+
+ // Display warnings.
+ Eng.getBugReporter().FlushReports();
+}
+
+static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
+ bool StandardWarnings) {
+
+ GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
+ GCEnabled,
+ mgr.getLangOptions());
+
+ ActionGRExprEngine(mgr, TF, StandardWarnings);
+}
+
+static void ActionCheckerCFRef(AnalysisManager& mgr) {
+
+ switch (mgr.getLangOptions().getGCMode()) {
+ default:
+ assert (false && "Invalid GC mode.");
+ case LangOptions::NonGC:
+ ActionCheckerCFRefAux(mgr, false, true);
+ break;
+
+ case LangOptions::GCOnly:
+ ActionCheckerCFRefAux(mgr, true, true);
+ break;
+
+ case LangOptions::HybridGC:
+ ActionCheckerCFRefAux(mgr, false, true);
+ ActionCheckerCFRefAux(mgr, true, false);
+ break;
+ }
+}
+
+static void ActionCheckerSimple(AnalysisManager& mgr) {
+ ActionGRExprEngine(mgr, MakeGRSimpleValsTF());
+}
+
+static void ActionDisplayLiveVariables(AnalysisManager& mgr) {
+ if (LiveVariables* L = mgr.getLiveVariables()) {
+ mgr.DisplayFunction();
+ L->dumpBlockLiveness(mgr.getSourceManager());
+ }
+}
+
+static void ActionCFGDump(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG()) {
+ mgr.DisplayFunction();
+ c->dump();
+ }
+}
+
+static void ActionCFGView(AnalysisManager& mgr) {
+ if (CFG* c = mgr.getCFG()) {
+ mgr.DisplayFunction();
+ c->viewCFG();
+ }
+}
+
+static void ActionWarnObjCDealloc(AnalysisManager& mgr) {
+ if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
+ return;
+
+ BugReporter BR(mgr);
+
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
+ mgr.getLangOptions(), BR);
+}
+
+static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr) {
+ BugReporter BR(mgr);
+ CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(mgr.getCodeDecl()), BR);
+}
+
+static void ActionWarnObjCMethSigs(AnalysisManager& mgr) {
+ BugReporter BR(mgr);
+
+ CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(mgr.getCodeDecl()),
+ BR);
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer creation.
+//===----------------------------------------------------------------------===//
+
+ASTConsumer* clang::CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& OutDir,
+ const AnalyzerOptions& Opts) {
+
+ llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(diags, pp, ppf,
+ lopts, 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.
+ diags.setWarningsAsErrors(false);
+
+ return C.take();
+}
+
+//===----------------------------------------------------------------------===//
+// Ubigraph Visualization. FIXME: Move to separate file.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class UbigraphViz : public ExplodedNodeImpl::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(ExplodedNodeImpl* Src, ExplodedNodeImpl* Dst);
+};
+
+} // end anonymous namespace
+
+static ExplodedNodeImpl::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::cerr << "Writing '" << Filename << "'.\n";
+
+ llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
+ std::string filename = Filename.toString();
+ Stream.reset(new llvm::raw_fd_ostream(filename.c_str(), false, ErrMsg));
+
+ if (!ErrMsg.empty())
+ return 0;
+
+ return new UbigraphViz(Stream.take(), Dir, Filename);
+}
+
+void UbigraphViz::AddEdge(ExplodedNodeImpl* Src, ExplodedNodeImpl* 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::cerr << "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::cerr << "Error viewing graph: " << ErrMsg << "\n";
+ }
+
+ // Delete the directory.
+ Dir.eraseFromDisk(true);
+}
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
new file mode 100644
index 0000000..44aa3a8
--- /dev/null
+++ b/lib/Frontend/Backend.cpp
@@ -0,0 +1,415 @@
+//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.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/raw_ostream.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
+#include "llvm/Target/SubtargetFeature.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetMachineRegistry.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/IPO.h"
+using namespace clang;
+using namespace llvm;
+
+namespace {
+ class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
+ BackendAction Action;
+ CompileOptions CompileOpts;
+ llvm::raw_ostream *AsmOutStream;
+ ASTContext *Context;
+
+ Timer LLVMIRGeneration;
+ Timer CodeGenerationTime;
+
+ llvm::OwningPtr<CodeGenerator> Gen;
+
+ llvm::Module *TheModule;
+ llvm::TargetData *TheTargetData;
+
+ mutable llvm::ModuleProvider *ModuleProvider;
+ 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. On failure \arg Error will be set to
+ /// a user readable error message.
+ bool AddEmitPasses(std::string &Error);
+
+ void EmitAssembly();
+
+ public:
+ BackendConsumer(BackendAction action, Diagnostic &Diags,
+ const LangOptions &langopts, const CompileOptions &compopts,
+ const std::string &infile, llvm::raw_ostream* OS) :
+ Action(action),
+ CompileOpts(compopts),
+ AsmOutStream(OS),
+ LLVMIRGeneration("LLVM IR Generation Time"),
+ CodeGenerationTime("Code Generation Time"),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts)),
+ TheModule(0), TheTargetData(0), ModuleProvider(0),
+ CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
+
+ // Enable -time-passes if -ftime-report is enabled.
+ llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
+ }
+
+ ~BackendConsumer() {
+ delete TheTargetData;
+ delete ModuleProvider;
+ delete CodeGenPasses;
+ delete PerModulePasses;
+ delete PerFunctionPasses;
+ }
+
+ virtual void Initialize(ASTContext &Ctx) {
+ Context = &Ctx;
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->Initialize(Ctx);
+
+ TheModule = Gen->GetModule();
+ ModuleProvider = new ExistingModuleProvider(TheModule);
+ TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
+ Context->getSourceManager(),
+ "LLVM IR generation of declaration");
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTopLevelDecl(D);
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &C) {
+ {
+ PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTranslationUnit(C);
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ // EmitAssembly times and registers crash info itself.
+ EmitAssembly();
+
+ // Force a flush here in case we never get released.
+ if (AsmOutStream)
+ AsmOutStream->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);
+ }
+ };
+}
+
+FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
+ if (!CodeGenPasses) {
+ CodeGenPasses = new FunctionPassManager(ModuleProvider);
+ 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(ModuleProvider);
+ PerFunctionPasses->add(new TargetData(*TheTargetData));
+ }
+
+ return PerFunctionPasses;
+}
+
+bool BackendConsumer::AddEmitPasses(std::string &Error) {
+ if (Action == Backend_EmitNothing)
+ return true;
+
+ if (Action == Backend_EmitBC) {
+ getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
+ } else if (Action == Backend_EmitLL) {
+ getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
+ } else {
+ bool Fast = CompileOpts.OptimizationLevel == 0;
+
+ // Create the TargetMachine for generating code.
+ const TargetMachineRegistry::entry *TME =
+ TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
+ if (!TME) {
+ Error = std::string("Unable to get target machine: ") + Error;
+ return false;
+ }
+
+ std::string FeaturesStr;
+ if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
+ SubtargetFeatures Features;
+ Features.setCPU(CompileOpts.CPU);
+ for (std::vector<std::string>::iterator
+ it = CompileOpts.Features.begin(),
+ ie = CompileOpts.Features.end(); it != ie; ++it)
+ Features.AddFeature(*it);
+ FeaturesStr = Features.getString();
+ }
+ TargetMachine *TM = TME->CtorFn(*TheModule, FeaturesStr);
+
+ // Set register scheduler & allocation policy.
+ RegisterScheduler::setDefault(createDefaultScheduler);
+ RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
+ createLinearScanRegisterAllocator);
+
+ // From llvm-gcc:
+ // If there are passes we have to run on the entire module, we do codegen
+ // as a separate "pass" after that happens.
+ // FIXME: This is disabled right now until bugs can be worked out. Reenable
+ // this for fast -O0 compiles!
+ FunctionPassManager *PM = getCodeGenPasses();
+ CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
+
+ switch (CompileOpts.OptimizationLevel) {
+ default: break;
+ case 0: OptLevel = CodeGenOpt::None; break;
+ case 3: OptLevel = CodeGenOpt::Aggressive; break;
+ }
+
+ // Normal mode, emit a .s file by running the code generator.
+ // Note, this also adds codegenerator level optimization passes.
+ switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
+ TargetMachine::AssemblyFile, OptLevel)) {
+ default:
+ case FileModel::Error:
+ Error = "Unable to interface with target machine!\n";
+ return false;
+ case FileModel::AsmFile:
+ break;
+ }
+
+ if (TM->addPassesToEmitFileFinish(*CodeGenPasses, (MachineCodeEmitter *)0,
+ OptLevel)) {
+ Error = "Unable to interface with target machine!\n";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void BackendConsumer::CreatePasses() {
+ // In -O0 if checking is disabled, we don't even have per-function passes.
+ if (CompileOpts.VerifyModule)
+ getPerFunctionPasses()->add(createVerifierPass());
+
+ if (CompileOpts.OptimizationLevel > 0) {
+ FunctionPassManager *PM = getPerFunctionPasses();
+ PM->add(createCFGSimplificationPass());
+ if (CompileOpts.OptimizationLevel == 1)
+ PM->add(createPromoteMemoryToRegisterPass());
+ else
+ PM->add(createScalarReplAggregatesPass());
+ PM->add(createInstructionCombiningPass());
+ }
+
+ // For now we always create per module passes.
+ PassManager *PM = getPerModulePasses();
+ if (CompileOpts.OptimizationLevel > 0) {
+ if (CompileOpts.UnitAtATime)
+ PM->add(createRaiseAllocationsPass()); // call %malloc -> malloc inst
+ PM->add(createCFGSimplificationPass()); // Clean up disgusting code
+ PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createGlobalOptimizerPass()); // Optimize out global vars
+ PM->add(createGlobalDCEPass()); // Remove unused fns and globs
+ PM->add(createIPConstantPropagationPass()); // IP Constant Propagation
+ PM->add(createDeadArgEliminationPass()); // Dead argument elimination
+ }
+ PM->add(createInstructionCombiningPass()); // Clean up after IPCP & DAE
+ PM->add(createCFGSimplificationPass()); // Clean up after IPCP & DAE
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createPruneEHPass()); // Remove dead EH info
+ PM->add(createFunctionAttrsPass()); // Set readonly/readnone attrs
+ }
+ if (CompileOpts.InlineFunctions)
+ PM->add(createFunctionInliningPass()); // Inline small functions
+ else
+ PM->add(createAlwaysInlinerPass()); // Respect always_inline
+ if (CompileOpts.OptimizationLevel > 2)
+ PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args
+ if (CompileOpts.SimplifyLibCalls)
+ PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations
+ PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl.
+ PM->add(createJumpThreadingPass()); // Thread jumps.
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+ PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas
+ PM->add(createInstructionCombiningPass()); // Combine silly seq's
+ PM->add(createCondPropagationPass()); // Propagate conditionals
+ PM->add(createTailCallEliminationPass()); // Eliminate tail calls
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+ PM->add(createReassociatePass()); // Reassociate expressions
+ PM->add(createLoopRotatePass()); // Rotate Loop
+ PM->add(createLICMPass()); // Hoist loop invariants
+ PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false));
+// PM->add(createLoopIndexSplitPass()); // Split loop index
+ PM->add(createInstructionCombiningPass());
+ PM->add(createIndVarSimplifyPass()); // Canonicalize indvars
+ PM->add(createLoopDeletionPass()); // Delete dead loops
+ if (CompileOpts.UnrollLoops)
+ PM->add(createLoopUnrollPass()); // Unroll small loops
+ PM->add(createInstructionCombiningPass()); // Clean up after the unroller
+ PM->add(createGVNPass()); // Remove redundancies
+ PM->add(createMemCpyOptPass()); // Remove memcpy / form memset
+ PM->add(createSCCPPass()); // Constant prop with SCCP
+
+ // Run instcombine after redundancy elimination to exploit opportunities
+ // opened up by them.
+ PM->add(createInstructionCombiningPass());
+ PM->add(createCondPropagationPass()); // Propagate conditionals
+ PM->add(createDeadStoreEliminationPass()); // Delete dead stores
+ PM->add(createAggressiveDCEPass()); // Delete dead instructions
+ PM->add(createCFGSimplificationPass()); // Merge & remove BBs
+
+ if (CompileOpts.UnitAtATime) {
+ PM->add(createStripDeadPrototypesPass()); // Get rid of dead prototypes
+ PM->add(createDeadTypeEliminationPass()); // Eliminate dead types
+ }
+
+ if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
+ PM->add(createConstantMergePass()); // Merge dup global constants
+ } else {
+ PM->add(createAlwaysInlinerPass());
+ }
+}
+
+/// 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(CompileOpts.TimePasses ? &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.
+ ModuleProvider->releaseModule();
+ TheModule = 0;
+ return;
+ }
+
+ assert(TheModule == M && "Unexpected module change during IR generation");
+
+ CreatePasses();
+
+ std::string Error;
+ if (!AddEmitPasses(Error)) {
+ // FIXME: Don't fail this way.
+ llvm::cerr << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+
+ // 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");
+ CodeGenPasses->doInitialization();
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+ if (!I->isDeclaration())
+ CodeGenPasses->run(*I);
+ CodeGenPasses->doFinalization();
+ }
+}
+
+ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts,
+ const CompileOptions &CompileOpts,
+ const std::string& InFile,
+ llvm::raw_ostream* OS) {
+ return new BackendConsumer(Action, Diags, LangOpts, CompileOpts, InFile, OS);
+}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
new file mode 100644
index 0000000..649f9da
--- /dev/null
+++ b/lib/Frontend/CMakeLists.txt
@@ -0,0 +1,35 @@
+set(LLVM_NO_RTTI 1)
+
+add_clang_library(clangFrontend
+ AnalysisConsumer.cpp
+ ASTConsumers.cpp
+ Backend.cpp
+ CacheTokens.cpp
+ DependencyFile.cpp
+ DiagChecker.cpp
+ DocumentXML.cpp
+ FixItRewriter.cpp
+ GeneratePCH.cpp
+ HTMLDiagnostics.cpp
+ HTMLPrint.cpp
+ InitHeaderSearch.cpp
+ InitPreprocessor.cpp
+ ManagerRegistry.cpp
+ PCHReader.cpp
+ PCHReaderDecl.cpp
+ PCHReaderStmt.cpp
+ PCHWriter.cpp
+ PCHWriterDecl.cpp
+ PCHWriterStmt.cpp
+ PlistDiagnostics.cpp
+ PrintParserCallbacks.cpp
+ PrintPreprocessedOutput.cpp
+ RewriteBlocks.cpp
+ RewriteMacros.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+ StmtXML.cpp
+ TextDiagnosticBuffer.cpp
+ TextDiagnosticPrinter.cpp
+ Warnings.cpp
+ )
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
new file mode 100644
index 0000000..0065828
--- /dev/null
+++ b/lib/Frontend/CacheTokens.cpp
@@ -0,0 +1,658 @@
+//===--- 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/StringMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Streams.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 VISIBILITY_HIDDEN 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 VISIBILITY_HIDDEN 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)) {}
+
+ PTHEntryKeyVariant(const char* path)
+ : Path(path), Kind(IsNoExist), StatBuf(0) {}
+
+ bool isFile() const { return Kind == IsFE; }
+
+ const char* getCString() 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 VISIBILITY_HIDDEN 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 BernsteinHash(V.getCString());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, PTHEntryKeyVariant V,
+ const PTHEntry& E) {
+
+ unsigned n = strlen(V.getCString()) + 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.getCString(), 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;
+typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
+typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
+
+namespace {
+class VISIBILITY_HIDDEN PTHWriter {
+ 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) {
+ Out << (unsigned char)(V);
+ }
+
+ void Emit16(uint32_t V) { ::Emit16(Out, V); }
+
+ void Emit24(uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ assert((V >> 24) == 0);
+ }
+
+ void Emit32(uint32_t V) { ::Emit32(Out, V); }
+
+ void EmitBuf(const char *Ptr, unsigned NumBytes) {
+ Out.write(Ptr, NumBytes);
+ }
+
+ /// 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 = 0);
+};
+} // 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 off = (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)) {
+ Tok.setIdentifierInfo(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.setIdentifierInfo(II);
+ 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))
+ Tok.setIdentifierInfo(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 - off);
+ 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(off, 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 && !MainFile->empty()) {
+ Emit16(MainFile->length());
+ EmitBuf(MainFile->data(), MainFile->length());
+ } 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();
+ if (!B) continue;
+
+ FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
+ Lexer L(FID, 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 = ::stat(path, buf);
+
+ if (result != 0) // Failed 'stat'.
+ PM.insert(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());
+ std::string MainFileName;
+
+ if (!MainFilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(MainFilePath.toString());
+ MainFileName = P.toString();
+ } else {
+ MainFileName = MainFilePath.toString();
+ }
+
+ // Create the PTHWriter.
+ PTHWriter PW(*OS, PP);
+
+ // Install the 'stat' system call listener in the FileManager.
+ PP.getFileManager().setStatCache(new StatListener(PW.getPM()));
+
+ // 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().setStatCache(0);
+ PW.GeneratePTH(&MainFileName);
+}
+
+//===----------------------------------------------------------------------===//
+
+class PTHIdKey {
+public:
+ const IdentifierInfo* II;
+ uint32_t FileOffset;
+};
+
+namespace {
+class VISIBILITY_HIDDEN 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 BernsteinHash(key->II->getName());
+ }
+
+ static std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const PTHIdKey* key, uint32_t) {
+ unsigned n = strlen(key->II->getName()) + 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->getName(), 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/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
new file mode 100644
index 0000000..c8a654c
--- /dev/null
+++ b/lib/Frontend/DependencyFile.cpp
@@ -0,0 +1,169 @@
+//===--- 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/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN 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 std::vector<std::string> &_Targets,
+ bool _IncludeSystemHeaders,
+ bool _PhonyTarget)
+ : PP(_PP), Targets(_Targets), OS(_OS),
+ IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
+
+ ~DependencyFileCallback() {
+ OutputDependencyFile();
+ OS->flush();
+ delete OS;
+ }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+};
+}
+
+
+
+void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
+ std::vector<std::string> &Targets,
+ bool IncludeSystemHeaders,
+ bool PhonyTarget) {
+ assert(!Targets.empty() && "Target required for dependency generation");
+
+ DependencyFileCallback *PPDep =
+ new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
+ PhonyTarget);
+ PP->setPPCallbacks(PPDep);
+}
+
+/// 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/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp
new file mode 100644
index 0000000..c0f5d14
--- /dev/null
+++ b/lib/Frontend/DiagChecker.cpp
@@ -0,0 +1,302 @@
+//===--- 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 <cstdio>
+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.
+ Lexer RawLex(FID, 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;
+
+ fprintf(stderr, "%s\n", Msg);
+
+ for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I)
+ fprintf(stderr, " Line %d: %s\n",
+ SourceMgr.getInstantiationLineNumber(I->first),
+ I->second.c_str());
+
+ 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/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
new file mode 100644
index 0000000..7562d2a
--- /dev/null
+++ b/lib/Frontend/DocumentXML.cpp
@@ -0,0 +1,579 @@
+//===--- 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/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
+
+namespace clang {
+
+//---------------------------------------------------------
+struct DocumentXML::NodeXML
+{
+ std::string Name;
+ NodeXML* Parent;
+
+ NodeXML(const std::string& name, NodeXML* parent) :
+ Name(name),
+ Parent(parent)
+ {}
+};
+
+//---------------------------------------------------------
+DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) :
+ Root(new NodeXML(rootName, 0)),
+ CurrentNode(Root),
+ Out(out),
+ Ctx(0),
+ CurrentIndent(0),
+ HasCurrentNodeSubNodes(false)
+{
+ Out << "<?xml version=\"1.0\"?>\n<" << rootName;
+}
+
+//---------------------------------------------------------
+DocumentXML::~DocumentXML()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+ delete Root;
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::addSubNode(const std::string& name)
+{
+ if (!HasCurrentNodeSubNodes)
+ {
+ Out << ">\n";
+ }
+ CurrentNode = new NodeXML(name, CurrentNode);
+ HasCurrentNodeSubNodes = false;
+ CurrentIndent += 2;
+ Indent();
+ Out << "<" << CurrentNode->Name;
+ return *this;
+}
+
+//---------------------------------------------------------
+void DocumentXML::Indent()
+{
+ for (int i = 0; i < CurrentIndent; ++i)
+ Out << ' ';
+}
+
+//---------------------------------------------------------
+DocumentXML& DocumentXML::toParent()
+{
+ assert(CurrentNode != Root && "to much backtracking");
+
+ if (HasCurrentNodeSubNodes)
+ {
+ Indent();
+ Out << "</" << CurrentNode->Name << ">\n";
+ }
+ else
+ {
+ Out << "/>\n";
+ }
+ NodeXML* NodeToDelete = CurrentNode;
+ CurrentNode = CurrentNode->Parent;
+ delete NodeToDelete;
+ HasCurrentNodeSubNodes = true;
+ CurrentIndent -= 2;
+ return *this;
+}
+
+//---------------------------------------------------------
+namespace {
+
+enum tIdType { ID_NORMAL, ID_FILE, 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' };
+ 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 += "&amp;"; break;
+ case '<': value += "&lt;"; break;
+ case '>': value += "&gt;"; break;
+ case '"': value += "&quot;"; break;
+ case '\'': value += "&apos;"; break;
+
+ }
+ }
+ return value;
+}
+
+//---------------------------------------------------------
+void DocumentXML::finalize()
+{
+ assert(CurrentNode == Root && "not completely backtracked");
+
+ addSubNode("ReferenceSection");
+ addSubNode("Types");
+
+ for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); i != e; ++i)
+ {
+ if (i->first.getCVRQualifiers() != 0)
+ {
+ addSubNode("CvQualifiedType");
+ addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
+ addAttribute("type", getPrefixedId(BasicTypes[i->first.getTypePtr()], ID_NORMAL));
+ if (i->first.isConstQualified()) addAttribute("const", "1");
+ if (i->first.isVolatileQualified()) addAttribute("volatile", "1");
+ if (i->first.isRestrictQualified()) addAttribute("restrict", "1");
+ toParent();
+ }
+ }
+
+ for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), e = BasicTypes.end(); i != e; ++i)
+ {
+ // don't use the get methods as they strip of typedef infos
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(i->first)) {
+ addSubNode("FundamentalType");
+ addAttribute("name", BT->getName(Ctx->getLangOptions().CPlusPlus));
+ }
+ else if (const PointerType *PT = dyn_cast<PointerType>(i->first)) {
+ addSubNode("PointerType");
+ addTypeAttribute(PT->getPointeeType());
+ }
+ else if (dyn_cast<FunctionType>(i->first) != 0) {
+ addSubNode("FunctionType");
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(i->first)) {
+ addSubNode("ReferenceType");
+ addTypeAttribute(RT->getPointeeType());
+ }
+ else if (const TypedefType * TT = dyn_cast<TypedefType>(i->first)) {
+ addSubNode("Typedef");
+ addAttribute("name", TT->getDecl()->getNameAsString());
+ addTypeAttribute(TT->getDecl()->getUnderlyingType());
+ addContextAttribute(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(i->first)) {
+ addSubNode("QualifiedNameType");
+ addTypeAttribute(QT->getNamedType());
+ }
+ else if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(i->first)) {
+ addSubNode("ArrayType");
+ addAttribute("min", 0);
+ addAttribute("max", (CAT->getSize() - 1).toString(10, false));
+ addTypeAttribute(CAT->getElementType());
+ }
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(i->first)) {
+ addSubNode("VariableArrayType");
+ addTypeAttribute(VAT->getElementType());
+ }
+ else if (const TagType *RET = dyn_cast<TagType>(i->first)) {
+ const TagDecl *tagDecl = RET->getDecl();
+ std::string tagKind = tagDecl->getKindName();
+ tagKind[0] = std::toupper(tagKind[0]);
+ addSubNode(tagKind);
+ addAttribute("name", tagDecl->getNameAsString());
+ addContextAttribute(tagDecl->getDeclContext());
+ }
+ else if (const VectorType* VT = dyn_cast<VectorType>(i->first)) {
+ addSubNode("VectorType");
+ addTypeAttribute(VT->getElementType());
+ addAttribute("num_elements", VT->getNumElements());
+ }
+ else
+ {
+ addSubNode("FIXMEType");
+ }
+ 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()->getAsFunctionType()], ID_NORMAL));
+ }
+
+ if (const DeclContext* parent = i->first->getParent())
+ {
+ addContextAttribute(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 << "</" << CurrentNode->Name << ">\n";
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeAttribute(const QualType& pType)
+{
+ addTypeRecursively(pType);
+ addAttribute("type", getPrefixedId(Types[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeIdAttribute(const Type* pType)
+{
+ addBasicTypeRecursively(pType);
+ addAttribute("id", getPrefixedId(BasicTypes[pType], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::addTypeRecursively(const QualType& pType)
+{
+ if (addToMap(Types, pType))
+ {
+ addBasicTypeRecursively(pType.getTypePtr());
+ // beautifier: a non-qualified type shall be transparent
+ if (pType.getCVRQualifiers() == 0)
+ {
+ Types[pType] = BasicTypes[pType.getTypePtr()];
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addBasicTypeRecursively(const Type* pType)
+{
+ if (addToMap(BasicTypes, pType))
+ {
+ if (const PointerType *PT = dyn_cast<PointerType>(pType)) {
+ addTypeRecursively(PT->getPointeeType());
+ }
+ else if (const ReferenceType *RT = dyn_cast<ReferenceType>(pType)) {
+ addTypeRecursively(RT->getPointeeType());
+ }
+ else if (const TypedefType *TT = dyn_cast<TypedefType>(pType)) {
+ addTypeRecursively(TT->getDecl()->getUnderlyingType());
+ addContextsRecursively(TT->getDecl()->getDeclContext());
+ }
+ else if (const QualifiedNameType *QT = dyn_cast<QualifiedNameType>(pType)) {
+ addTypeRecursively(QT->getNamedType());
+ // FIXME: what to do with NestedNameSpecifier or shall this type be transparent?
+ }
+ else if (const ArrayType *AT = dyn_cast<ArrayType>(pType)) {
+ addTypeRecursively(AT->getElementType());
+ // FIXME: doesn't work in the immediate streaming approach
+ /*if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ {
+ addSubNode("VariableArraySizeExpression");
+ PrintStmt(VAT->getSizeExpr());
+ toParent();
+ }*/
+ }
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addContextAttribute(const DeclContext *DC, tContextUsage usage)
+{
+ addContextsRecursively(DC);
+ const char* pAttributeTags[2] = { "context", "id" };
+ addAttribute(pAttributeTags[usage], getPrefixedId(Contexts[DC], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+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));
+}
+
+//---------------------------------------------------------
+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::PrintFunctionDecl(FunctionDecl *FD)
+{
+ switch (FD->getStorageClass()) {
+ default: assert(0 && "Unknown storage class");
+ case FunctionDecl::None: break;
+ case FunctionDecl::Extern: addAttribute("storage_class", "extern"); break;
+ case FunctionDecl::Static: addAttribute("storage_class", "static"); break;
+ case FunctionDecl::PrivateExtern: addAttribute("storage_class", "__private_extern__"); break;
+ }
+
+ if (FD->isInline())
+ addAttribute("inline", "1");
+
+ const FunctionType *AFT = FD->getType()->getAsFunctionType();
+ addTypeAttribute(AFT->getResultType());
+ addBasicTypeRecursively(AFT);
+
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) {
+ addAttribute("num_args", FD->getNumParams());
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ addSubNode("Argument");
+ ParmVarDecl *argDecl = FD->getParamDecl(i);
+ addAttribute("name", argDecl->getNameAsString());
+ addTypeAttribute(FT->getArgType(i));
+ addDeclIdAttribute(argDecl);
+ if (argDecl->getDefaultArg())
+ {
+ addAttribute("default_arg", "1");
+ PrintStmt(argDecl->getDefaultArg());
+ }
+ toParent();
+ }
+
+ if (FT->isVariadic()) {
+ addSubNode("Ellipsis").toParent();
+ }
+ } else {
+ assert(isa<FunctionNoProtoType>(AFT));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addRefAttribute(const NamedDecl* D)
+{
+ // FIXME: in case of CXX inline member functions referring to a member defined
+ // after the function it needs to be tested, if the ids are already there
+ // (should work, but I couldn't test it)
+ if (const DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addAttribute("ref", getPrefixedId(Contexts[DC], ID_NORMAL));
+ }
+ else
+ {
+ addAttribute("ref", getPrefixedId(Decls[D], ID_NORMAL));
+ }
+}
+
+//---------------------------------------------------------
+void DocumentXML::addDeclIdAttribute(const NamedDecl* D)
+{
+ addToMap(Decls, D);
+ addAttribute("id", getPrefixedId(Decls[D], ID_NORMAL));
+}
+
+//---------------------------------------------------------
+void DocumentXML::PrintDecl(Decl *D)
+{
+ addSubNode(D->getDeclKindName());
+ addContextAttribute(D->getDeclContext());
+ addLocation(D->getLocation());
+ if (DeclContext* DC = dyn_cast<DeclContext>(D))
+ {
+ addContextAttribute(DC, CONTEXT_AS_ID);
+ }
+
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ addAttribute("name", ND->getNameAsString());
+
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ PrintFunctionDecl(FD);
+ if (Stmt *Body = FD->getBody(*Ctx)) {
+ addSubNode("Body");
+ PrintStmt(Body);
+ toParent();
+ }
+ } else if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ addBasicTypeRecursively(RD->getTypeForDecl());
+ addAttribute("type", getPrefixedId(BasicTypes[RD->getTypeForDecl()], ID_NORMAL));
+ if (!RD->isDefinition())
+ {
+ addAttribute("forward", "1");
+ }
+
+ for (RecordDecl::field_iterator i = RD->field_begin(*Ctx), e = RD->field_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ const QualType& enumType = ED->getIntegerType();
+ if (!enumType.isNull())
+ {
+ addTypeAttribute(enumType);
+ for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(*Ctx), e = ED->enumerator_end(*Ctx); i != e; ++i)
+ {
+ PrintDecl(*i);
+ }
+ }
+ } else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) {
+ addTypeAttribute(ECD->getType());
+ addAttribute("value", ECD->getInitVal().toString(10, true));
+ if (ECD->getInitExpr())
+ {
+ PrintStmt(ECD->getInitExpr());
+ }
+ } else if (FieldDecl *FdD = dyn_cast<FieldDecl>(D)) {
+ addTypeAttribute(FdD->getType());
+ addDeclIdAttribute(ND);
+ if (FdD->isMutable())
+ addAttribute("mutable", "1");
+ if (FdD->isBitField())
+ {
+ addAttribute("bitfield", "1");
+ PrintStmt(FdD->getBitWidth());
+ }
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ addTypeIdAttribute(Ctx->getTypedefType(TD).getTypePtr());
+ addTypeAttribute(TD->getUnderlyingType());
+ } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ addTypeAttribute(VD->getType());
+ addDeclIdAttribute(ND);
+
+ VarDecl *V = dyn_cast<VarDecl>(VD);
+ if (V && V->getStorageClass() != VarDecl::None)
+ {
+ addAttribute("storage_class", VarDecl::getStorageClassSpecifierString(V->getStorageClass()));
+ }
+
+ if (V && V->getInit())
+ {
+ PrintStmt(V->getInit());
+ }
+ }
+ } else if (LinkageSpecDecl* LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ switch (LSD->getLanguage())
+ {
+ case LinkageSpecDecl::lang_c: addAttribute("lang", "C"); break;
+ case LinkageSpecDecl::lang_cxx: addAttribute("lang", "CXX"); break;
+ default: assert(0 && "Unexpected lang id");
+ }
+ } else if (isa<FileScopeAsmDecl>(D)) {
+ // FIXME: Implement this
+ } else {
+ assert(0 && "Unexpected decl");
+ }
+ toParent();
+}
+
+//---------------------------------------------------------
+} // NS clang
+
diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp
new file mode 100644
index 0000000..1ed89d7
--- /dev/null
+++ b/lib/Frontend/FixItRewriter.cpp
@@ -0,0 +1,199 @@
+//===--- 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/SourceManager.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr,
+ const LangOptions &LangOpts)
+ : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) {
+ Client = Diags.getClient();
+ Diags.setClient(this);
+}
+
+FixItRewriter::~FixItRewriter() {
+ Diags.setClient(Client);
+}
+
+bool FixItRewriter::WriteFixedFile(const std::string &InFileName,
+ const std::string &OutFileName) {
+ if (NumFailures > 0) {
+ Diag(FullSourceLoc(), diag::warn_fixit_no_changes);
+ return true;
+ }
+
+ llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
+ llvm::raw_ostream *OutFile;
+ if (!OutFileName.empty()) {
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ } else if (InFileName == "-") {
+ OutFile = &llvm::outs();
+ } else {
+ llvm::sys::Path Path(InFileName);
+ std::string Suffix = Path.getSuffix();
+ Path.eraseSuffix();
+ Path.appendSuffix("fixit." + Suffix);
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ }
+
+ FileID MainFileID = Rewrite.getSourceMgr().getMainFileID();
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ std::fprintf(stderr, "Main file is unchanged\n");
+ }
+ OutFile->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.
+ if (DiagLevel == Diagnostic::Ignored)
+ return;
+
+ if (!FixItLocations.empty()) {
+ // The user has specified the locations where we should perform
+ // the various fix-it modifications.
+
+ // If this diagnostic does not have any code modifications,
+ // completely ignore it, even if it's an error: fix-it locations
+ // are meant to perform specific fix-ups even in the presence of
+ // other errors.
+ if (Info.getNumCodeModificationHints() == 0)
+ return;
+
+ // See if the location of the error is one that matches what the
+ // user requested.
+ bool AcceptableLocation = false;
+ const FileEntry *File
+ = Rewrite.getSourceMgr().getFileEntryForID(
+ Info.getLocation().getFileID());
+ unsigned Line = Info.getLocation().getSpellingLineNumber();
+ unsigned Column = Info.getLocation().getSpellingColumnNumber();
+ for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator
+ Loc = FixItLocations.begin(), LocEnd = FixItLocations.end();
+ Loc != LocEnd; ++Loc) {
+ if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) {
+ AcceptableLocation = true;
+ break;
+ }
+ }
+
+ if (!AcceptableLocation)
+ return;
+ }
+
+ // Make sure that we can perform all of the modifications we
+ // in this diagnostic.
+ bool CanRewrite = Info.getNumCodeModificationHints() > 0;
+ for (unsigned Idx = 0, Last = Info.getNumCodeModificationHints();
+ Idx < Last; ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(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.getNumCodeModificationHints() > 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.getNumCodeModificationHints();
+ Idx < Last; ++Idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(Idx);
+ if (!Hint.RemoveRange.isValid()) {
+ // We're adding code.
+ if (Rewrite.InsertStrBefore(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.c_str(),
+ Hint.CodeToInsert.size()))
+ 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);
+}
diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp
new file mode 100644
index 0000000..8be88ce
--- /dev/null
+++ b/lib/Frontend/GeneratePCH.cpp
@@ -0,0 +1,78 @@
+//===--- 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/System/Path.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Streams.h"
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+ class VISIBILITY_HIDDEN PCHGenerator : public SemaConsumer {
+ const Preprocessor &PP;
+ llvm::raw_ostream *Out;
+ Sema *SemaPtr;
+ MemorizeStatCalls *StatCalls; // owned by the FileManager
+
+ public:
+ explicit PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *Out);
+ virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
+ virtual void HandleTranslationUnit(ASTContext &Ctx);
+ };
+}
+
+PCHGenerator::PCHGenerator(const Preprocessor &PP, llvm::raw_ostream *OS)
+ : PP(PP), Out(OS), SemaPtr(0), StatCalls(0) {
+
+ // Install a stat() listener to keep track of all of the stat()
+ // calls.
+ StatCalls = new MemorizeStatCalls;
+ PP.getFileManager().setStatCache(StatCalls);
+}
+
+void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
+ if (PP.getDiagnostics().hasErrorOccurred())
+ return;
+
+ // Write the PCH contents into a buffer
+ std::vector<unsigned char> Buffer;
+ BitstreamWriter Stream(Buffer);
+ PCHWriter Writer(Stream);
+
+ // Emit the PCH file
+ assert(SemaPtr && "No Sema?");
+ Writer.WritePCH(*SemaPtr, StatCalls);
+
+ // 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) {
+ return new PCHGenerator(PP, OS);
+}
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
new file mode 100644
index 0000000..9cfe0b2
--- /dev/null
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -0,0 +1,602 @@
+//===--- 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/Analysis/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/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include <fstream>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Boilerplate.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN HTMLDiagnostics : public PathDiagnosticClient {
+ llvm::sys::Path Directory, FilePrefix;
+ bool createdDir, noDir;
+ Preprocessor* PP;
+ std::vector<const PathDiagnostic*> BatchedDiags;
+public:
+ HTMLDiagnostics(const std::string& prefix, Preprocessor* pp);
+
+ virtual ~HTMLDiagnostics();
+
+ virtual void SetPreprocessor(Preprocessor *pp) { PP = pp; }
+
+ virtual void HandlePathDiagnostic(const PathDiagnostic* D);
+
+ 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);
+};
+
+} // end anonymous namespace
+
+HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix, 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, Preprocessor* PP,
+ PreprocessorFactory*) {
+ 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);
+}
+
+HTMLDiagnostics::~HTMLDiagnostics() {
+ while (!BatchedDiags.empty()) {
+ const PathDiagnostic* D = BatchedDiags.back();
+ BatchedDiags.pop_back();
+ ReportDiag(*D);
+ delete D;
+ }
+}
+
+void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D) {
+ // Create the HTML directory if it is missing.
+ if (!createdDir) {
+ createdDir = true;
+ std::string ErrorMsg;
+ Directory.createDirectoryOnDisk(true, &ErrorMsg);
+
+ if (!Directory.isDirectory()) {
+ llvm::cerr << "warning: could not create directory '"
+ << Directory.toString() << "'\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.
+
+ if (PP) html::SyntaxHighlight(R, FID, *PP);
+
+ // FIXME: We eventually want to use PPF to create a fresh Preprocessor,
+ // once we have worked out the bugs.
+ //
+ // if (PPF) html::HighlightMacros(R, FID, *PPF);
+ //
+ if (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.toString() + "/";
+ }
+
+ // 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.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ // Embed meta-data tags.
+
+ const std::string& BugDesc = D.getDescription();
+
+ if (!BugDesc.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ const std::string& BugType = D.getBugType();
+ if (!BugType.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGTYPE " << BugType << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ const std::string& BugCategory = D.getCategory();
+
+ if (!BugCategory.empty()) {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGLINE "
+ << D.back()->getLocation().asLocation().getInstantiationLineNumber()
+ << " -->\n";
+ R.InsertStrBefore(SMgr.getLocForStartOfFile(FID), os.str());
+ }
+
+ {
+ std::string s;
+ llvm::raw_string_ostream os(s);
+ os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
+ R.InsertStrBefore(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::cerr << "warning: no diagnostics generated for main file.\n";
+ return;
+ }
+
+ // Create the stream to write out the HTML.
+ std::ofstream os;
+
+ {
+ // 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);
+
+ os.open(H.toString().c_str());
+
+ if (!os) {
+ llvm::cerr << "warning: could not create file '" << F.toString() << "'\n";
+ return;
+ }
+ }
+
+ // 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());
+ std::pair<const char*, const char*> BufferInfo = L.getBufferData();
+ const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first;
+ Lexer rawLexer(L, PP->getLangOptions(), BufferInfo.first,
+ MacroName, BufferInfo.second);
+
+ 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.InsertStrBefore(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 CodeModificationHint *Hint = P.code_modifications_begin(),
+ *HintEnd = P.code_modifications_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.InsertStrBefore(Hint->InsertionLoc, EscapedCode);
+ }
+ }
+#endif
+}
+
+static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
+ llvm::SmallVector<char, 10> buf;
+
+ do {
+ unsigned x = n % ('z' - 'a');
+ buf.push_back('a' + x);
+ n = n / ('z' - 'a');
+ } while (n);
+
+ assert(!buf.empty());
+
+ for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(),
+ E=buf.rend(); I!=E; ++I)
+ os << *I;
+}
+
+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/lib/Frontend/HTMLPrint.cpp b/lib/Frontend/HTMLPrint.cpp
new file mode 100644
index 0000000..d5eb9fb
--- /dev/null
+++ b/lib/Frontend/HTMLPrint.cpp
@@ -0,0 +1,92 @@
+//===--- 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/Decl.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Rewrite/HTMLRewrite.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Functional HTML pretty-printing.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class HTMLPrinter : public ASTConsumer {
+ Rewriter R;
+ llvm::raw_ostream *Out;
+ Diagnostic &Diags;
+ Preprocessor *PP;
+ PreprocessorFactory *PPF;
+ public:
+ HTMLPrinter(llvm::raw_ostream *OS, Diagnostic &D, Preprocessor *pp,
+ PreprocessorFactory* ppf)
+ : Out(OS), Diags(D), PP(pp), PPF(ppf) {}
+ virtual ~HTMLPrinter();
+
+ void Initialize(ASTContext &context);
+ };
+}
+
+ASTConsumer* clang::CreateHTMLPrinter(llvm::raw_ostream *OS,
+ Diagnostic &D, Preprocessor *PP,
+ PreprocessorFactory* PPF) {
+
+ return new HTMLPrinter(OS, D, PP, PPF);
+}
+
+void HTMLPrinter::Initialize(ASTContext &context) {
+ R.setSourceMgr(context.getSourceManager(), context.getLangOptions());
+}
+
+HTMLPrinter::~HTMLPrinter() {
+ if (Diags.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 (PP) html::SyntaxHighlight(R, FID, *PP);
+ if (PPF) 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/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
new file mode 100644
index 0000000..6383c20
--- /dev/null
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -0,0 +1,327 @@
+//===--- 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/InitHeaderSearch.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/System/Path.h"
+#include "llvm/Config/config.h"
+#include <cstdio>
+#include <vector>
+using namespace clang;
+
+void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
+ bool isCXXAware, bool isUserSupplied,
+ bool isFramework, bool IgnoreSysRoot) {
+ assert(!Path.empty() && "can't handle empty path here");
+ FileManager &FM = Headers.getFileMgr();
+
+ // Compute the actual path, taking into consideration -isysroot.
+ llvm::SmallString<256> MappedPath;
+
+ // 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.append(isysroot.begin(), isysroot.end());
+ }
+
+ MappedPath.append(Path.begin(), Path.end());
+
+ // 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[0],
+ &MappedPath[0]+
+ MappedPath.size())) {
+ 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[0],
+ &MappedPath[0]+MappedPath.size())) {
+ 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)
+ fprintf(stderr, "ignoring nonexistent directory \"%s\"\n",
+ MappedPath.c_str());
+}
+
+
+void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
+ const char* at = getenv(Name);
+ if (!at || *at == 0) // Empty string should not add '.' path.
+ return;
+
+ const char* delim = strchr(at, llvm::sys::PathSeparator);
+ while (delim != 0) {
+ if (delim-at == 0)
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
+ true, false);
+ at = delim + 1;
+ delim = strchr(at, llvm::sys::PathSeparator);
+ }
+ if (*at == 0)
+ AddPath(".", Angled, false, true, false);
+ else
+ AddPath(at, Angled, false, true, false);
+}
+
+
+void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) {
+ // FIXME: temporary hack: hard-coded paths.
+ // FIXME: get these from the target?
+
+#ifdef LLVM_ON_WIN32
+ if (Lang.CPlusPlus) {
+ // Mingw32 GCC version 4
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++",
+ System, true, false, false);
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/mingw32",
+ System, true, false, false);
+ AddPath("c:/mingw/lib/gcc/mingw32/4.3.0/include/c++/backward",
+ System, true, false, false);
+ }
+
+ // Mingw32 GCC version 4
+ AddPath("C:/mingw/include", System, false, false, false);
+#else
+
+ if (Lang.CPlusPlus) {
+ AddPath("/usr/include/c++/4.2.1", System, true, false, false);
+ AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false);
+
+ AddPath("/usr/include/c++/4.0.0", System, true, false, false);
+ AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false);
+
+ // Ubuntu 7.10 - Gutsy Gibbon
+ AddPath("/usr/include/c++/4.1.3", System, true, false, false);
+ AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false);
+
+ // Fedora 8
+ AddPath("/usr/include/c++/4.1.2", System, true, false, false);
+ AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false);
+
+ // Fedora 9
+ AddPath("/usr/include/c++/4.3.0", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false);
+
+ // Fedora 10
+ AddPath("/usr/include/c++/4.3.2", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.2/i386-redhat-linux", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.2/backward", System, true, false, false);
+
+ // Arch Linux 2008-06-24
+ AddPath("/usr/include/c++/4.3.1", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
+ false);
+ AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false);
+ AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
+ false, false);
+
+ // Gentoo x86 stable
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", System,
+ true, false, false);
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/"
+ "i686-pc-linux-gnu", System, true, false, false);
+ AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4/backward",
+ System, true, false, false);
+
+ // DragonFly
+ AddPath("/usr/include/c++/4.1", System, true, false, false);
+
+ // FreeBSD
+ AddPath("/usr/include/c++/4.2", System, true, false, false);
+ }
+
+ AddPath("/usr/local/include", System, false, false, false);
+
+ AddPath("/usr/include", System, false, false, false);
+ AddPath("/System/Library/Frameworks", System, true, false, true);
+ AddPath("/Library/Frameworks", System, true, false, true);
+#endif
+}
+
+void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
+ AddEnvVarPaths("CPATH");
+ if (Lang.CPlusPlus && Lang.ObjC1)
+ AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
+ else if (Lang.CPlusPlus)
+ AddEnvVarPaths("CPLUS_INCLUDE_PATH");
+ else if (Lang.ObjC1)
+ AddEnvVarPaths("OBJC_INCLUDE_PATH");
+ else
+ AddEnvVarPaths("C_INCLUDE_PATH");
+}
+
+
+/// 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) {
+ fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
+ CurEntry.getName());
+ if (DirToRemove != i)
+ fprintf(stderr, " 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) {
+ fprintf(stderr, "#include \"...\" search starts here:\n");
+ unsigned QuotedIdx = IncludeGroup[Quoted].size();
+ for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
+ if (i == QuotedIdx)
+ fprintf(stderr, "#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)";
+ }
+ fprintf(stderr, " %s%s\n", Name, Suffix);
+ }
+ fprintf(stderr, "End of search list.\n");
+ }
+}
+
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
new file mode 100644
index 0000000..0945037
--- /dev/null
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -0,0 +1,495 @@
+//===--- 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/Frontend/InitPreprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/System/Path.h"
+
+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(std::vector<char> &Buf, const char *Macro,
+ const char *Command = "#define ") {
+ Buf.insert(Buf.end(), Command, Command+strlen(Command));
+ if (const char *Equal = strchr(Macro, '=')) {
+ // Turn the = into ' '.
+ Buf.insert(Buf.end(), Macro, Equal);
+ Buf.push_back(' ');
+
+ // Per GCC -D semantics, the macro ends at \n if it exists.
+ const char *End = strpbrk(Equal, "\n\r");
+ if (End) {
+ fprintf(stderr, "warning: macro '%s' contains embedded newline, text "
+ "after the newline is ignored.\n",
+ std::string(Macro, Equal).c_str());
+ } else {
+ End = Equal+strlen(Equal);
+ }
+
+ Buf.insert(Buf.end(), Equal+1, End);
+ } else {
+ // Push "macroname 1".
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back(' ');
+ Buf.push_back('1');
+ }
+ Buf.push_back('\n');
+}
+
+// Append a #undef line to Buf for Macro. Macro should be of the form XXX
+// and we emit "#undef XXX".
+static void UndefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) {
+ // Push "macroname".
+ const char *Command = "#undef ";
+ Buf.insert(Buf.end(), Command, Command+strlen(Command));
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back('\n');
+}
+
+/// Add the quoted name of an implicit include file.
+static void AddQuotedIncludePath(std::vector<char> &Buf,
+ const std::string &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;
+
+ // Escape double quotes etc.
+ Buf.push_back('"');
+ std::string EscapedFile = Lexer::Stringify(Path.toString());
+ Buf.insert(Buf.end(), EscapedFile.begin(), EscapedFile.end());
+ Buf.push_back('"');
+}
+
+/// AddImplicitInclude - Add an implicit #include of the specified file to the
+/// predefines buffer.
+static void AddImplicitInclude(std::vector<char> &Buf,
+ const std::string &File) {
+ const char *Inc = "#include ";
+ Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
+ AddQuotedIncludePath(Buf, File);
+ Buf.push_back('\n');
+}
+
+static void AddImplicitIncludeMacros(std::vector<char> &Buf,
+ const std::string &File) {
+ const char *Inc = "#__include_macros ";
+ Buf.insert(Buf.end(), Inc, Inc+strlen(Inc));
+ AddQuotedIncludePath(Buf, File);
+ Buf.push_back('\n');
+ // Marker token to stop the __include_macros fetch loop.
+ const char *Marker = "##\n"; // ##?
+ Buf.insert(Buf.end(), Marker, Marker+strlen(Marker));
+}
+
+/// AddImplicitIncludePTH - Add an implicit #include using the original file
+/// used to generate a PTH cache.
+static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor &PP,
+ const std::string& ImplicitIncludePTH) {
+ PTHManager *P = PP.getPTHManager();
+ assert(P && "No PTHManager.");
+ const char *OriginalFile = P->getOriginalSourceFile();
+
+ if (!OriginalFile) {
+ assert(!ImplicitIncludePTH.empty());
+ fprintf(stderr, "error: PTH file '%s' does not designate an original "
+ "source header file for -include-pth\n",
+ ImplicitIncludePTH.c_str());
+ exit (1);
+ }
+
+ AddImplicitInclude(Buf, 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 == &llvm::APFloat::IEEEsingle)
+ return IEEESingleVal;
+ if (Sem == &llvm::APFloat::IEEEdouble)
+ return IEEEDoubleVal;
+ if (Sem == &llvm::APFloat::x87DoubleExtended)
+ return X87DoubleExtendedVal;
+ if (Sem == &llvm::APFloat::PPCDoubleDouble)
+ return PPCDoubleDoubleVal;
+ assert(Sem == &llvm::APFloat::IEEEquad);
+ return IEEEQuadVal;
+}
+
+static void DefineFloatMacros(std::vector<char> &Buf, const char *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 HasInifinity = 1, HasQuietNaN = 1;
+ 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");
+
+ char MacroBuf[100];
+ sprintf(MacroBuf, "__%s_DENORM_MIN__=%s", Prefix, DenormMin);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_DIG__=%d", Prefix, Digits);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_EPSILON__=%s", Prefix, Epsilon);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_INFINITY__=%d", Prefix, HasInifinity);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_QUIET_NAN__=%d", Prefix, HasQuietNaN);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MANT_DIG__=%d", Prefix, MantissaDigits);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX_10_EXP__=%d", Prefix, Max10Exp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX_EXP__=%d", Prefix, MaxExp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MAX__=%s", Prefix, Max);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN_10_EXP__=(%d)", Prefix, Min10Exp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN_EXP__=(%d)", Prefix, MinExp);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_MIN__=%s", Prefix, Min);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ sprintf(MacroBuf, "__%s_HAS_DENORM__=1", Prefix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+
+/// 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(const char *MacroName, unsigned TypeWidth,
+ const char *ValSuffix, bool isSigned,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ long long MaxVal;
+ if (isSigned)
+ MaxVal = (1LL << (TypeWidth - 1)) - 1;
+ else
+ MaxVal = ~0LL >> (64-TypeWidth);
+
+ sprintf(MacroBuf, "%s=%llu%s", MacroName, MaxVal, ValSuffix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+static void DefineType(const char *MacroName, TargetInfo::IntType Ty,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ sprintf(MacroBuf, "%s=%s", MacroName, TargetInfo::getTypeName(Ty));
+ DefineBuiltinMacro(Buf, MacroBuf);
+}
+
+
+static void InitializePredefinedMacros(const TargetInfo &TI,
+ const LangOptions &LangOpts,
+ std::vector<char> &Buf) {
+ char MacroBuf[60];
+ // Compiler version introspection macros.
+ DefineBuiltinMacro(Buf, "__llvm__=1"); // LLVM Backend
+ DefineBuiltinMacro(Buf, "__clang__=1"); // Clang Frontend
+
+ // Currently claim to be compatible with GCC 4.2.1-5621.
+ DefineBuiltinMacro(Buf, "__APPLE_CC__=5621");
+ DefineBuiltinMacro(Buf, "__GNUC_MINOR__=2");
+ DefineBuiltinMacro(Buf, "__GNUC_PATCHLEVEL__=1");
+ DefineBuiltinMacro(Buf, "__GNUC__=4");
+ DefineBuiltinMacro(Buf, "__GXX_ABI_VERSION=1002");
+ DefineBuiltinMacro(Buf, "__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)
+ DefineBuiltinMacro(Buf, "__STDC__=1");
+ if (LangOpts.AsmPreprocessor)
+ DefineBuiltinMacro(Buf, "__ASSEMBLER__=1");
+ if (LangOpts.C99 && !LangOpts.CPlusPlus)
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199901L");
+ else if (0) // STDC94 ?
+ DefineBuiltinMacro(Buf, "__STDC_VERSION__=199409L");
+
+ // Standard conforming mode?
+ if (!LangOpts.GNUMode)
+ DefineBuiltinMacro(Buf, "__STRICT_ANSI__=1");
+
+ if (LangOpts.CPlusPlus0x)
+ DefineBuiltinMacro(Buf, "__GXX_EXPERIMENTAL_CXX0X__");
+
+ if (LangOpts.Freestanding)
+ DefineBuiltinMacro(Buf, "__STDC_HOSTED__=0");
+ else
+ DefineBuiltinMacro(Buf, "__STDC_HOSTED__=1");
+
+ if (LangOpts.ObjC1) {
+ DefineBuiltinMacro(Buf, "__OBJC__=1");
+ if (LangOpts.ObjCNonFragileABI) {
+ DefineBuiltinMacro(Buf, "__OBJC2__=1");
+ DefineBuiltinMacro(Buf, "OBJC_ZEROCOST_EXCEPTIONS=1");
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ }
+
+ if (LangOpts.getGCMode() != LangOptions::NonGC)
+ DefineBuiltinMacro(Buf, "__OBJC_GC__=1");
+
+ if (LangOpts.NeXTRuntime)
+ DefineBuiltinMacro(Buf, "__NEXT_RUNTIME__=1");
+ }
+
+ // darwin_constant_cfstrings controls this. This is also dependent
+ // on other things like the runtime I believe. This is set even for C code.
+ DefineBuiltinMacro(Buf, "__CONSTANT_CFSTRINGS__=1");
+
+ if (LangOpts.ObjC2)
+ DefineBuiltinMacro(Buf, "OBJC_NEW_PROPERTIES");
+
+ if (LangOpts.ObjCSenderDispatch)
+ DefineBuiltinMacro(Buf, "__OBJC_SENDER_AWARE_DISPATCH__");
+
+ if (LangOpts.PascalStrings)
+ DefineBuiltinMacro(Buf, "__PASCAL_STRINGS__");
+
+ if (LangOpts.Blocks) {
+ DefineBuiltinMacro(Buf, "__block=__attribute__((__blocks__(byref)))");
+ DefineBuiltinMacro(Buf, "__BLOCKS__=1");
+ }
+
+ if (LangOpts.CPlusPlus) {
+ DefineBuiltinMacro(Buf, "__DEPRECATED=1");
+ DefineBuiltinMacro(Buf, "__EXCEPTIONS=1");
+ DefineBuiltinMacro(Buf, "__GNUG__=4");
+ DefineBuiltinMacro(Buf, "__GXX_WEAK__=1");
+ DefineBuiltinMacro(Buf, "__cplusplus=1");
+ DefineBuiltinMacro(Buf, "__private_extern__=extern");
+ }
+
+ // Filter out some microsoft extensions when trying to parse in ms-compat
+ // mode.
+ if (LangOpts.Microsoft) {
+ DefineBuiltinMacro(Buf, "_cdecl=__cdecl");
+ DefineBuiltinMacro(Buf, "__int8=__INT8_TYPE__");
+ DefineBuiltinMacro(Buf, "__int16=__INT16_TYPE__");
+ DefineBuiltinMacro(Buf, "__int32=__INT32_TYPE__");
+ DefineBuiltinMacro(Buf, "__int64=__INT64_TYPE__");
+ }
+
+ if (LangOpts.Optimize)
+ DefineBuiltinMacro(Buf, "__OPTIMIZE__=1");
+ if (LangOpts.OptimizeSize)
+ DefineBuiltinMacro(Buf, "__OPTIMIZE_SIZE__=1");
+
+ // 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");
+ DefineBuiltinMacro(Buf, "__CHAR_BIT__=8");
+
+ unsigned IntMaxWidth;
+ const char *IntMaxSuffix;
+ if (TI.getIntMaxType() == TargetInfo::SignedLongLong) {
+ IntMaxWidth = TI.getLongLongWidth();
+ IntMaxSuffix = "LL";
+ } else if (TI.getIntMaxType() == TargetInfo::SignedLong) {
+ IntMaxWidth = TI.getLongWidth();
+ IntMaxSuffix = "L";
+ } else {
+ assert(TI.getIntMaxType() == TargetInfo::SignedInt);
+ IntMaxWidth = TI.getIntWidth();
+ IntMaxSuffix = "";
+ }
+
+ DefineTypeSize("__SCHAR_MAX__", TI.getCharWidth(), "", true, Buf);
+ DefineTypeSize("__SHRT_MAX__", TI.getShortWidth(), "", true, Buf);
+ DefineTypeSize("__INT_MAX__", TI.getIntWidth(), "", true, Buf);
+ DefineTypeSize("__LONG_MAX__", TI.getLongWidth(), "L", true, Buf);
+ DefineTypeSize("__LONG_LONG_MAX__", TI.getLongLongWidth(), "LL", true, Buf);
+ DefineTypeSize("__WCHAR_MAX__", TI.getWCharWidth(), "", true, Buf);
+ DefineTypeSize("__INTMAX_MAX__", IntMaxWidth, IntMaxSuffix, true, Buf);
+
+ DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Buf);
+ DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Buf);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Buf);
+ DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Buf);
+ DefineType("__SIZE_TYPE__", TI.getSizeType(), Buf);
+ DefineType("__WCHAR_TYPE__", TI.getWCharType(), Buf);
+ // FIXME: TargetInfo hookize __WINT_TYPE__.
+ DefineBuiltinMacro(Buf, "__WINT_TYPE__=int");
+
+ DefineFloatMacros(Buf, "FLT", &TI.getFloatFormat());
+ DefineFloatMacros(Buf, "DBL", &TI.getDoubleFormat());
+ DefineFloatMacros(Buf, "LDBL", &TI.getLongDoubleFormat());
+
+ // Define a __POINTER_WIDTH__ macro for stdint.h.
+ sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0));
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ if (!TI.isCharSigned())
+ DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__");
+
+ // Define fixed-sized integer types for stdint.h
+ assert(TI.getCharWidth() == 8 && "unsupported target types");
+ assert(TI.getShortWidth() == 16 && "unsupported target types");
+ DefineBuiltinMacro(Buf, "__INT8_TYPE__=char");
+ DefineBuiltinMacro(Buf, "__INT16_TYPE__=short");
+
+ if (TI.getIntWidth() == 32)
+ DefineBuiltinMacro(Buf, "__INT32_TYPE__=int");
+ else {
+ assert(TI.getLongLongWidth() == 32 && "unsupported target types");
+ DefineBuiltinMacro(Buf, "__INT32_TYPE__=long long");
+ }
+
+ // 16-bit targets doesn't necessarily have a 64-bit type.
+ if (TI.getLongLongWidth() == 64)
+ DefineBuiltinMacro(Buf, "__INT64_TYPE__=long long");
+
+ // Add __builtin_va_list typedef.
+ {
+ const char *VAList = TI.getVAListDeclaration();
+ Buf.insert(Buf.end(), VAList, VAList+strlen(VAList));
+ Buf.push_back('\n');
+ }
+
+ if (const char *Prefix = TI.getUserLabelPrefix()) {
+ sprintf(MacroBuf, "__USER_LABEL_PREFIX__=%s", Prefix);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ }
+
+ // Build configuration options. FIXME: these should be controlled by
+ // command line options or something.
+ DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0");
+
+ if (LangOpts.Static)
+ DefineBuiltinMacro(Buf, "__STATIC__=1");
+ else
+ DefineBuiltinMacro(Buf, "__DYNAMIC__=1");
+
+ if (LangOpts.GNUInline)
+ DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1");
+ else
+ DefineBuiltinMacro(Buf, "__GNUC_STDC_INLINE__=1");
+
+ if (LangOpts.NoInline)
+ DefineBuiltinMacro(Buf, "__NO_INLINE__=1");
+
+ if (unsigned PICLevel = LangOpts.PICLevel) {
+ sprintf(MacroBuf, "__PIC__=%d", PICLevel);
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ sprintf(MacroBuf, "__pic__=%d", PICLevel);
+ DefineBuiltinMacro(Buf, MacroBuf);
+ }
+
+ // Macros to control C99 numerics and <float.h>
+ DefineBuiltinMacro(Buf, "__FLT_EVAL_METHOD__=0");
+ DefineBuiltinMacro(Buf, "__FLT_RADIX__=2");
+ sprintf(MacroBuf, "__DECIMAL_DIG__=%d",
+ PickFP(&TI.getLongDoubleFormat(), -1/*FIXME*/, 17, 21, 33, 36));
+ DefineBuiltinMacro(Buf, MacroBuf);
+
+ // Get other target #defines.
+ TI.getTargetDefines(LangOpts, Buf);
+}
+
+/// InitializePreprocessor - Initialize the preprocessor getting it and the
+/// environment ready to process a single file. This returns true on error.
+///
+bool InitializePreprocessor(Preprocessor &PP,
+ const PreprocessorInitOptions& InitOpts) {
+ std::vector<char> PredefineBuffer;
+
+ const char *LineDirective = "# 1 \"<built-in>\" 3\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Install things like __POWERPC__, __GNUC__, etc into the macro table.
+ InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(),
+ PredefineBuffer);
+
+ // Add on the predefines from the driver. Wrap in a #line directive to report
+ // that they come from the command line.
+ LineDirective = "# 1 \"<command line>\" 1\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Process #define's and #undef's in the order they are given.
+ for (PreprocessorInitOptions::macro_iterator I = InitOpts.macro_begin(),
+ E = InitOpts.macro_end(); I != E; ++I) {
+ if (I->second) // isUndef
+ UndefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ else
+ DefineBuiltinMacro(PredefineBuffer, I->first.c_str());
+ }
+
+ // If -imacros are specified, include them now. These are processed before
+ // any -include directives.
+ for (PreprocessorInitOptions::imacro_iterator I = InitOpts.imacro_begin(),
+ E = InitOpts.imacro_end(); I != E; ++I)
+ AddImplicitIncludeMacros(PredefineBuffer, *I);
+
+ // Process -include directives.
+ for (PreprocessorInitOptions::include_iterator I = InitOpts.include_begin(),
+ E = InitOpts.include_end(); I != E; ++I) {
+ if (I->second) // isPTH
+ AddImplicitIncludePTH(PredefineBuffer, PP, I->first);
+ else
+ AddImplicitInclude(PredefineBuffer, I->first);
+ }
+
+ LineDirective = "# 2 \"<built-in>\" 2 3\n";
+ PredefineBuffer.insert(PredefineBuffer.end(),
+ LineDirective, LineDirective+strlen(LineDirective));
+
+ // Null terminate PredefinedBuffer and add it.
+ PredefineBuffer.push_back(0);
+ PP.setPredefines(&PredefineBuffer[0]);
+
+ // Once we've read this, we're done.
+ return false;
+}
+
+} // namespace clang
diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile
new file mode 100644
index 0000000..8d70847
--- /dev/null
+++ b/lib/Frontend/Makefile
@@ -0,0 +1,18 @@
+##===- 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
+CXXFLAGS = -fno-rtti
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Frontend/ManagerRegistry.cpp
new file mode 100644
index 0000000..79f1e81
--- /dev/null
+++ b/lib/Frontend/ManagerRegistry.cpp
@@ -0,0 +1,20 @@
+//===- ManagerRegistry.cpp - Pluggble Analyzer module creators --*- 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 pluggable analyzer module creators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ManagerRegistry.h"
+
+using namespace clang;
+
+StoreManagerCreator ManagerRegistry::StoreMgrCreator = 0;
+
+ConstraintManagerCreator ManagerRegistry::ConstraintMgrCreator = 0;
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
new file mode 100644
index 0000000..63e4337
--- /dev/null
+++ b/lib/Frontend/PCHReader.cpp
@@ -0,0 +1,2260 @@
+//===--- 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 "../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/Lex/MacroInfo.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 "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <iterator>
+#include <cstdio>
+#include <sys/stat.h>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// PCH reader implementation
+//===----------------------------------------------------------------------===//
+
+PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context)
+ : SemaObj(0), PP(PP), Context(Context), Consumer(0),
+ IdentifierTableData(0), IdentifierLookupTable(0),
+ IdentifierOffsets(0),
+ MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
+ TotalSelectorsInMethodPool(0), SelectorOffsets(0),
+ TotalNumSelectors(0), NumStatHits(0), NumStatMisses(0),
+ NumSLocEntriesRead(0), NumStatementsRead(0),
+ NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0),
+ NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0) { }
+
+PCHReader::~PCHReader() {}
+
+Expr *PCHReader::ReadDeclExpr() {
+ return dyn_cast_or_null<Expr>(ReadStmt(DeclsCursor));
+}
+
+Expr *PCHReader::ReadTypeExpr() {
+ return dyn_cast_or_null<Expr>(ReadStmt(Stream));
+}
+
+
+namespace {
+class VISIBILITY_HIDDEN 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 = clang::BernsteinHashPartial(II->getName(), II->getLength(), 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;
+ }
+
+ Prev->Next = new 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;
+ }
+
+ Prev->Next = new 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 VISIBILITY_HIDDEN 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 BernsteinHash(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.
+ Sema *SemaObj = Reader.getSema();
+ if (Reader.getContext() == 0) return II;
+
+ while (DataLen > 0) {
+ NamedDecl *D = cast<NamedDecl>(Reader.GetDecl(ReadUnalignedLE32(d)));
+ 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.
+ Reader.PreloadedDecls.push_back(D);
+ }
+
+ DataLen -= 4;
+ }
+ 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;
+
+// FIXME: use the diagnostics machinery
+bool PCHReader::Error(const char *Msg) {
+ Diagnostic &Diags = PP.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg);
+ Diag(DiagID);
+ return true;
+}
+
+/// \brief Split the given string into a vector of lines, eliminating
+/// any empty lines in the process.
+///
+/// \param Str the string to split.
+/// \param Len the length of Str.
+/// \param KeepEmptyLines true if empty lines should be included
+/// \returns a vector of lines, with the line endings removed
+std::vector<std::string> splitLines(const char *Str, unsigned Len,
+ bool KeepEmptyLines = false) {
+ std::vector<std::string> Lines;
+ for (unsigned LineStart = 0; LineStart < Len; ++LineStart) {
+ unsigned LineEnd = LineStart;
+ while (LineEnd < Len && Str[LineEnd] != '\n')
+ ++LineEnd;
+ if (LineStart != LineEnd || KeepEmptyLines)
+ Lines.push_back(std::string(&Str[LineStart], &Str[LineEnd]));
+ LineStart = LineEnd;
+ }
+ return Lines;
+}
+
+/// \brief Determine whether the string Haystack starts with the
+/// substring Needle.
+static bool startsWith(const std::string &Haystack, const char *Needle) {
+ for (unsigned I = 0, N = Haystack.size(); Needle[I] != 0; ++I) {
+ if (I == N)
+ return false;
+ if (Haystack[I] != Needle[I])
+ return false;
+ }
+
+ return true;
+}
+
+/// \brief Determine whether the string Haystack starts with the
+/// substring Needle.
+static inline bool startsWith(const std::string &Haystack,
+ const std::string &Needle) {
+ return startsWith(Haystack, Needle.c_str());
+}
+
+/// \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(const char *PCHPredef,
+ unsigned PCHPredefLen,
+ FileID PCHBufferID) {
+ const char *Predef = PP.getPredefines().c_str();
+ unsigned PredefLen = PP.getPredefines().size();
+
+ // If the two predefines buffers compare equal, we're done!
+ if (PredefLen == PCHPredefLen &&
+ strncmp(Predef, PCHPredef, PCHPredefLen) == 0)
+ 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.
+ std::vector<std::string> CmdLineLines = splitLines(Predef, PredefLen);
+ std::vector<std::string> PCHLines = splitLines(PCHPredef, PCHPredefLen);
+
+ // Sort both sets of predefined buffer lines, since
+ std::sort(CmdLineLines.begin(), CmdLineLines.end());
+ std::sort(PCHLines.begin(), PCHLines.end());
+
+ // Determine which predefines that where used to build the PCH file
+ // are missing from the command line.
+ std::vector<std::string> 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) {
+ const std::string &Missing = MissingPredefines[I];
+ if (!startsWith(Missing, "#define ") != 0) {
+ 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");
+ std::string MacroName = Missing.substr(StartOfMacroName,
+ EndOfMacroName - StartOfMacroName);
+
+ // Determine whether this macro was given a different definition
+ // on the command line.
+ std::string MacroDefStart = "#define " + MacroName;
+ std::string::size_type MacroDefLen = MacroDefStart.size();
+ std::vector<std::string>::iterator ConflictPos
+ = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(),
+ MacroDefStart);
+ for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) {
+ if (!startsWith(*ConflictPos, 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()) {
+ Diag(diag::warn_cmdline_conflicting_macro_def)
+ << MacroName;
+
+ // Show the definition of this macro within the PCH file.
+ const char *MissingDef = strstr(PCHPredef, Missing.c_str());
+ unsigned Offset = MissingDef - PCHPredef;
+ SourceLocation PCHMissingLoc
+ = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ .getFileLocWithOffset(Offset);
+ 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) {
+ Diag(diag::warn_cmdline_missing_macro_defs);
+ MissingDefines = true;
+ }
+
+ // Show the definition of this macro within the PCH file.
+ const char *MissingDef = strstr(PCHPredef, Missing.c_str());
+ unsigned Offset = MissingDef - PCHPredef;
+ SourceLocation PCHMissingLoc
+ = SourceMgr.getLocForStartOfFile(PCHBufferID)
+ .getFileLocWithOffset(Offset);
+ 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<std::string> 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) {
+ const std::string &Extra = ExtraPredefines[I];
+ if (!startsWith(Extra, "#define ") != 0) {
+ 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");
+ std::string MacroName = Extra.substr(StartOfMacroName,
+ EndOfMacroName - StartOfMacroName);
+
+ // 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 = get(MacroName.c_str(),
+ MacroName.c_str() + MacroName.size())) {
+ 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;
+}
+
+//===----------------------------------------------------------------------===//
+// Source Manager Deserialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Read the line table in the source manager block.
+/// \returns true if ther was an error.
+static bool ParseLineTable(SourceManager &SourceMgr,
+ 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;
+ 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 VISIBILITY_HIDDEN 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 VISIBILITY_HIDDEN 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 BernsteinHash(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 VISIBILITY_HIDDEN 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 ::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;
+ }
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+ RecordData Record;
+ unsigned NumHeaderInfos = 0;
+ 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(SourceMgr, Record))
+ return Failure;
+ break;
+
+ case pch::SM_HEADER_FILE_INFO: {
+ HeaderFileInfo HFI;
+ HFI.isImport = Record[0];
+ HFI.DirInfo = Record[1];
+ HFI.NumIncludes = Record[2];
+ HFI.ControllingMacroID = Record[3];
+ PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
+ 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;
+ }
+
+ SourceManager &SourceMgr = PP.getSourceManager();
+ 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: {
+ const FileEntry *File
+ = PP.getFileManager().getFile(BlobStart, BlobStart + BlobLen);
+ // FIXME: Error recovery if file cannot be found.
+ 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();
+
+ 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);
+ assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file");
+ (void)RecCode;
+ llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBuffer(BlobStart,
+ 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) {
+ // 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);
+
+ 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];
+ 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;
+ ++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;
+ }
+ }
+ }
+}
+
+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::TYPES_BLOCK_ID: // Skip types block (lazily loaded)
+ default: // Skip unknown content.
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::DECLS_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::DECLS_BLOCK_ID)) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+
+ case pch::PREPROCESSOR_BLOCK_ID:
+ 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;
+ }
+
+ std::string TargetTriple(BlobStart, BlobLen);
+ if (TargetTriple != PP.getTargetInfo().getTargetTriple()) {
+ Diag(diag::warn_pch_target_triple)
+ << TargetTriple << PP.getTargetInfo().getTargetTriple();
+ 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));
+ 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]);
+ 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::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())
+ PP.setCounterValue(Record[0]);
+ break;
+
+ case pch::SOURCE_LOCATION_OFFSETS:
+ SLocOffsets = (const uint32_t *)BlobStart;
+ TotalNumSLocEntries = Record[0];
+ PP.getSourceManager().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:
+ PP.getFileManager().setStatCache(
+ new PCHStatCache((const unsigned char *)BlobStart + Record[0],
+ (const unsigned char *)BlobStart,
+ NumStatHits, NumStatMisses));
+ 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::OBJC_CATEGORY_IMPLEMENTATIONS:
+ if (!ObjCCategoryImpls.empty()) {
+ Error("duplicate OBJC_CATEGORY_IMPLEMENTATIONS record in PCH file");
+ return Failure;
+ }
+ ObjCCategoryImpls.swap(Record);
+ break;
+
+ case pch::ORIGINAL_FILE_NAME:
+ OriginalFileName.assign(BlobStart, BlobLen);
+ 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.
+ std::string ErrStr;
+ Buffer.reset(llvm::MemoryBuffer::getFile(FileName.c_str(), &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.
+ PP.getSourceManager().ClearPreallocatedSLocEntries();
+
+ // Remove the stat cache.
+ PP.getFileManager().setStatCache(0);
+
+ return IgnorePCH;
+ }
+ break;
+ default:
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in PCH file");
+ return Failure;
+ }
+ break;
+ }
+ }
+
+ // Load the translation unit declaration
+ if (Context)
+ ReadDeclRecord(DeclOffsets[0], 0);
+
+ // Check the predefines buffer.
+ if (CheckPredefinesBuffer(PCHPredefines, PCHPredefinesLen,
+ PCHPredefinesBufferID))
+ return IgnorePCH;
+
+ // Initialization of builtins and library builtins 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->getName(), 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;
+ }
+
+ // Load the special types.
+ if (Context) {
+ 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));
+ }
+
+ return Success;
+}
+
+/// \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) {
+ // Open the PCH file.
+ std::string ErrStr;
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr));
+ if (!Buffer) {
+ fprintf(stderr, "error: %s\n", ErrStr.c_str());
+ 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') {
+ fprintf(stderr,
+ "error: '%s' does not appear to be a precompiled header file\n",
+ PCHFileName.c_str());
+ 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)) {
+ fprintf(stderr, "error: malformed block record in PCH file\n");
+ return std::string();
+ }
+ break;
+
+ default:
+ if (Stream.SkipBlock()) {
+ fprintf(stderr, "error: malformed block record in PCH file\n");
+ return std::string();
+ }
+ break;
+ }
+ continue;
+ }
+
+ if (Code == llvm::bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd()) {
+ fprintf(stderr, "error: error at end of module block in PCH file\n");
+ 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) {
+ const LangOptions &LangOpts = PP.getLangOptions();
+#define PARSE_LANGOPT_BENIGN(Option) ++Idx
+#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \
+ if (Record[Idx] != LangOpts.Option) { \
+ Diag(DiagID) << (unsigned)Record[Idx] << LangOpts.Option; \
+ return true; \
+ } \
+ ++Idx
+
+ unsigned Idx = 0;
+ 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_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_BENIGN(PascalStrings);
+ PARSE_LANGOPT_BENIGN(WritableStrings);
+ PARSE_LANGOPT_IMPORTANT(LaxVectorConversions,
+ diag::warn_pch_lax_vector_conversions);
+ PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_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(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);
+ if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) {
+ Diag(diag::warn_pch_gc_mode)
+ << (unsigned)Record[Idx] << LangOpts.getGCMode();
+ return true;
+ }
+ ++Idx;
+ PARSE_LANGOPT_BENIGN(getVisibilityMode());
+ PARSE_LANGOPT_BENIGN(InstantiationDepth);
+#undef PARSE_LANGOPT_IRRELEVANT
+#undef PARSE_LANGOPT_BENIGN
+
+ return false;
+}
+
+/// \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(Stream);
+
+ Stream.JumpToBit(Offset);
+ RecordData Record;
+ unsigned Code = Stream.ReadCode();
+ switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
+ case pch::TYPE_EXT_QUAL: {
+ assert(Record.size() == 3 &&
+ "Incorrect encoding of extended qualifier type");
+ QualType Base = GetType(Record[0]);
+ QualType::GCAttrTypes GCAttr = (QualType::GCAttrTypes)Record[1];
+ unsigned AddressSpace = Record[2];
+
+ QualType T = Base;
+ if (GCAttr != QualType::GCNone)
+ T = Context->getObjCGCQualType(T, GCAttr);
+ if (AddressSpace)
+ T = Context->getAddrSpaceQualType(T, AddressSpace);
+ return T;
+ }
+
+ case pch::TYPE_FIXED_WIDTH_INT: {
+ assert(Record.size() == 2 && "Incorrect encoding of fixed-width int type");
+ return Context->getFixedWidthIntType(Record[0], Record[1]);
+ }
+
+ case pch::TYPE_COMPLEX: {
+ assert(Record.size() == 1 && "Incorrect encoding of complex type");
+ QualType ElemType = GetType(Record[0]);
+ return Context->getComplexType(ElemType);
+ }
+
+ case pch::TYPE_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of pointer type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getPointerType(PointeeType);
+ }
+
+ case pch::TYPE_BLOCK_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of block pointer type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getBlockPointerType(PointeeType);
+ }
+
+ case pch::TYPE_LVALUE_REFERENCE: {
+ assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getLValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_RVALUE_REFERENCE: {
+ assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type");
+ QualType PointeeType = GetType(Record[0]);
+ return Context->getRValueReferenceType(PointeeType);
+ }
+
+ case pch::TYPE_MEMBER_POINTER: {
+ assert(Record.size() == 1 && "Incorrect encoding of member pointer type");
+ 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];
+ return Context->getVariableArrayType(ElementType, ReadTypeExpr(),
+ ASM, IndexTypeQuals);
+ }
+
+ case pch::TYPE_VECTOR: {
+ if (Record.size() != 2) {
+ Error("incorrect encoding of vector type in PCH file");
+ return QualType();
+ }
+
+ QualType ElementType = GetType(Record[0]);
+ unsigned NumElements = Record[1];
+ return Context->getVectorType(ElementType, NumElements);
+ }
+
+ case pch::TYPE_EXT_VECTOR: {
+ if (Record.size() != 2) {
+ 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() != 1) {
+ Error("incorrect encoding of no-proto function type");
+ return QualType();
+ }
+ QualType ResultType = GetType(Record[0]);
+ return Context->getFunctionNoProtoType(ResultType);
+ }
+
+ case pch::TYPE_FUNCTION_PROTO: {
+ QualType ResultType = GetType(Record[0]);
+ unsigned Idx = 1;
+ 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());
+ }
+
+ case pch::TYPE_TYPEDEF:
+ assert(Record.size() == 1 && "incorrect encoding of typedef type");
+ 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_RECORD:
+ assert(Record.size() == 1 && "incorrect encoding of record type");
+ return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_ENUM:
+ assert(Record.size() == 1 && "incorrect encoding of enum type");
+ return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_OBJC_INTERFACE:
+ assert(Record.size() == 1 && "incorrect encoding of objc interface type");
+ return Context->getObjCInterfaceType(
+ cast<ObjCInterfaceDecl>(GetDecl(Record[0])));
+
+ case pch::TYPE_OBJC_QUALIFIED_INTERFACE: {
+ unsigned Idx = 0;
+ ObjCInterfaceDecl *ItfD = cast<ObjCInterfaceDecl>(GetDecl(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->getObjCQualifiedInterfaceType(ItfD, Protos.data(), NumProtos);
+ }
+
+ case pch::TYPE_OBJC_QUALIFIED_ID: {
+ unsigned Idx = 0;
+ 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->getObjCQualifiedIdType(Protos.data(), NumProtos);
+ }
+ }
+ // Suppress a GCC warning
+ return QualType();
+}
+
+
+QualType PCHReader::GetType(pch::TypeID ID) {
+ unsigned Quals = ID & 0x07;
+ unsigned Index = ID >> 3;
+
+ 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;
+ }
+
+ assert(!T.isNull() && "Unknown predefined type");
+ return T.getQualifiedType(Quals);
+ }
+
+ Index -= pch::NUM_PREDEF_TYPE_IDS;
+ assert(Index < TypesLoaded.size() && "Type index out-of-range");
+ if (!TypesLoaded[Index])
+ TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]).getTypePtr();
+
+ return QualType(TypesLoaded[Index], Quals);
+}
+
+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;
+ assert(Offset && "DeclContext has no lexical decls in storage");
+
+ // 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);
+ (void)RecCode;
+ assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block");
+
+ // 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;
+ assert(Offset && "DeclContext has no visible decls in storage");
+
+ // 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);
+ (void)RecCode;
+ assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block");
+ 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) {
+ Decl *D = GetDecl(ExternalDefinitions[I]);
+ DeclGroupRef DG(D);
+ Consumer->HandleTopLevelDecl(DG);
+ }
+
+ 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(),
+ (Type *)0);
+ 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 table of tentative definitions.
+ for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
+ VarDecl *Var = cast<VarDecl>(GetDecl(TentativeDefinitions[I]));
+ SemaObj->TentativeDefinitions[Var->getDeclName()] = Var;
+ }
+
+ // 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])));
+
+ // If there were any Objective-C category implementations,
+ // deserialize them and add them to Sema's vector of such
+ // definitions.
+ for (unsigned I = 0, N = ObjCCategoryImpls.size(); I != N; ++I)
+ SemaObj->ObjCCategoryImpls.push_back(
+ cast<ObjCCategoryImplDecl>(GetDecl(ObjCCategoryImpls[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;
+}
+
+IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
+ if (ID == 0)
+ return 0;
+
+ if (!IdentifierTableData || IdentifiersLoaded.empty()) {
+ Error("no identifier table in PCH file");
+ return 0;
+ }
+
+ 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().
+ const char *StrLenPtr = Str - 2;
+ unsigned StrLen = (((unsigned) StrLenPtr[0])
+ | (((unsigned) StrLenPtr[1]) << 8)) - 1;
+ IdentifiersLoaded[ID - 1]
+ = &PP.getIdentifierTable().get(Str, 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];
+}
+
+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(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXDestructorName:
+ return Context->DeclarationNames.getCXXDestructorName(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXConversionFunctionName:
+ return Context->DeclarationNames.getCXXConversionFunctionName(
+ GetType(Record[Idx++]));
+
+ case DeclarationName::CXXOperatorName:
+ return Context->DeclarationNames.getCXXOperatorName(
+ (OverloadedOperatorKind)Record[Idx++]);
+
+ case DeclarationName::CXXUsingDirective:
+ return DeclarationName::getUsingDirectiveName();
+ }
+
+ // Required to silence GCC warning
+ return DeclarationName();
+}
+
+/// \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;
+}
+
+DiagnosticBuilder PCHReader::Diag(unsigned DiagID) {
+ return Diag(SourceLocation(), DiagID);
+}
+
+DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) {
+ return PP.getDiagnostics().Report(FullSourceLoc(Loc,
+ PP.getSourceManager()),
+ DiagID);
+}
+
+/// \brief Retrieve the identifier table associated with the
+/// preprocessor.
+IdentifierTable &PCHReader::getIdentifierTable() {
+ 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));
+ }
+}
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
new file mode 100644
index 0000000..6856623
--- /dev/null
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -0,0 +1,712 @@
+//===--- 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/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 VisitTypeDecl(TypeDecl *TD);
+ void VisitTypedefDecl(TypedefDecl *TD);
+ void VisitTagDecl(TagDecl *TD);
+ void VisitEnumDecl(EnumDecl *ED);
+ void VisitRecordDecl(RecordDecl *RD);
+ void VisitValueDecl(ValueDecl *VD);
+ void VisitEnumConstantDecl(EnumConstantDecl *ECD);
+ void VisitFunctionDecl(FunctionDecl *FD);
+ void VisitFieldDecl(FieldDecl *FD);
+ void VisitVarDecl(VarDecl *VD);
+ void VisitImplicitParamDecl(ImplicitParamDecl *PD);
+ void VisitParmVarDecl(ParmVarDecl *PD);
+ void VisitOriginalParmVarDecl(OriginalParmVarDecl *PD);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitBlockDecl(BlockDecl *BD);
+ std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
+ 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->setAccess((AccessSpecifier)Record[Idx++]);
+}
+
+void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
+ VisitDecl(TU);
+}
+
+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);
+ TD->setUnderlyingType(Reader.GetType(Record[Idx + 1]));
+ TD->setTypeForDecl(Reader.GetType(Record[Idx]).getTypePtr());
+ Idx += 2;
+}
+
+void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
+ VisitTypeDecl(TD);
+ TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
+ TD->setDefinition(Record[Idx++]);
+ TD->setTypedefForAnonDecl(
+ cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++])));
+}
+
+void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) {
+ VisitTagDecl(ED);
+ ED->setIntegerType(Reader.GetType(Record[Idx++]));
+ // FIXME: C++ InstantiatedFrom
+}
+
+void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) {
+ VisitTagDecl(RD);
+ RD->setHasFlexibleArrayMember(Record[Idx++]);
+ RD->setAnonymousStructOrUnion(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::VisitFunctionDecl(FunctionDecl *FD) {
+ VisitValueDecl(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->setInline(Record[Idx++]);
+ FD->setC99InlineDefinition(Record[Idx++]);
+ FD->setVirtualAsWritten(Record[Idx++]);
+ FD->setPure(Record[Idx++]);
+ FD->setHasInheritedPrototype(Record[Idx++]);
+ FD->setHasWrittenPrototype(Record[Idx++]);
+ FD->setDeleted(Record[Idx++]);
+ FD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ // FIXME: C++ TemplateOrInstantiation
+ 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(*Reader.getContext(), Params.data(), NumParams);
+}
+
+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->setResultType(Reader.GetType(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);
+}
+
+void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
+ VisitNamedDecl(CD);
+ CD->setAtEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+}
+
+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++])));
+ ID->setProtocolList(Protocols.data(), NumProtocols, *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->setIVarList(IVars.data(), NumIvars, *Reader.getContext());
+ 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->setAtEndLoc(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++])));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *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++])));
+ CD->setClassList(*Reader.getContext(), ClassRefs.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++])));
+ FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *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++])));
+ CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+ CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
+ CD->setLocEnd(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->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) {
+ VisitNamedDecl(D);
+ D->setClassInterface(
+ cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])));
+ D->setLocEnd(SourceLocation::getFromRawEncoding(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++])));
+}
+
+
+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++])));
+}
+
+void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) {
+ VisitValueDecl(FD);
+ FD->setMutable(Record[Idx++]);
+ if (Record[Idx++])
+ FD->setBitWidth(Reader.ReadDeclExpr());
+}
+
+void PCHDeclReader::VisitVarDecl(VarDecl *VD) {
+ VisitValueDecl(VD);
+ VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]);
+ VD->setThreadSpecified(Record[Idx++]);
+ VD->setCXXDirectInitializer(Record[Idx++]);
+ VD->setDeclaredInCondition(Record[Idx++]);
+ VD->setPreviousDeclaration(
+ cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
+ VD->setTypeSpecStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (Record[Idx++])
+ VD->setInit(*Reader.getContext(), Reader.ReadDeclExpr());
+}
+
+void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
+ VisitVarDecl(PD);
+}
+
+void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
+ VisitVarDecl(PD);
+ PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+ // FIXME: default argument (C++ only)
+}
+
+void PCHDeclReader::VisitOriginalParmVarDecl(OriginalParmVarDecl *PD) {
+ VisitParmVarDecl(PD);
+ PD->setOriginalType(Reader.GetType(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(*Reader.getContext(), Params.data(), NumParams);
+}
+
+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(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) {
+ STRING_ATTR(Alias);
+ UNSIGNED_ATTR(Aligned);
+ SIMPLE_ATTR(AlwaysInline);
+ SIMPLE_ATTR(AnalyzerNoReturn);
+ STRING_ATTR(Annotate);
+ STRING_ATTR(AsmLabel);
+
+ case Attr::Blocks:
+ New = ::new (*Context) BlocksAttr(
+ (BlocksAttr::BlocksAttrTypes)Record[Idx++]);
+ break;
+
+ 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);
+
+ case Attr::Format: {
+ std::string Type = ReadString(Record, Idx);
+ unsigned FormatIdx = Record[Idx++];
+ unsigned FirstArg = Record[Idx++];
+ New = ::new (*Context) FormatAttr(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);
+
+ case Attr::IBOutletKind:
+ New = ::new (*Context) IBOutletAttr();
+ break;
+
+ SIMPLE_ATTR(NoReturn);
+ SIMPLE_ATTR(NoThrow);
+ SIMPLE_ATTR(Nodebug);
+ SIMPLE_ATTR(Noinline);
+
+ 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(ArgNums.data(), Size);
+ break;
+ }
+
+ SIMPLE_ATTR(ObjCException);
+ SIMPLE_ATTR(ObjCNSObject);
+ SIMPLE_ATTR(CFReturnsRetained);
+ SIMPLE_ATTR(NSReturnsRetained);
+ SIMPLE_ATTR(Overloadable);
+ UNSIGNED_ATTR(Packed);
+ SIMPLE_ATTR(Pure);
+ UNSIGNED_ATTR(Regparm);
+ STRING_ATTR(Section);
+ SIMPLE_ATTR(StdCall);
+ 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(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 (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);
+
+ 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, QualType());
+ break;
+ case pch::DECL_ENUM:
+ D = EnumDecl::Create(*Context, 0, SourceLocation(), 0, 0);
+ break;
+ case pch::DECL_RECORD:
+ D = RecordDecl::Create(*Context, TagDecl::TK_struct, 0, SourceLocation(),
+ 0, 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());
+ break;
+ case pch::DECL_OBJC_METHOD:
+ D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(),
+ Selector(), QualType(), 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(),
+ 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(), 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, 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,
+ false);
+ break;
+ case pch::DECL_VAR:
+ D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(),
+ VarDecl::None, SourceLocation());
+ 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(),
+ VarDecl::None, 0);
+ break;
+ case pch::DECL_ORIGINAL_PARM_VAR:
+ D = OriginalParmVarDecl::Create(*Context, 0, SourceLocation(), 0,
+ QualType(), QualType(), 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/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
new file mode 100644
index 0000000..10059f6
--- /dev/null
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -0,0 +1,1136 @@
+//===--- 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/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 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 VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
+ unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
+
+ unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ unsigned VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ unsigned VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ unsigned VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ unsigned VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+ };
+}
+
+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->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->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);
+ PrevSC = SC;
+ }
+ return 2;
+}
+
+unsigned PCHStmtReader::VisitWhileStmt(WhileStmt *S) {
+ VisitStmt(S);
+ 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++]));
+ 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->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++]));
+ 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++]);
+
+ unsigned StackIdx
+ = StmtStack.size() - (NumOutputs*2 + NumInputs*2 + NumClobbers + 1);
+ S->setAsmString(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+
+ // Outputs and inputs
+ llvm::SmallVector<std::string, 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.ReadString(Record, Idx));
+ Constraints.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+ Exprs.push_back(StmtStack[StackIdx++]);
+ }
+ S->setOutputsAndInputs(NumOutputs, NumInputs,
+ Names.data(), Constraints.data(), Exprs.data());
+
+ // Constraints
+ llvm::SmallVector<StringLiteral*, 16> Clobbers;
+ for (unsigned I = 0; I != NumClobbers; ++I)
+ Clobbers.push_back(cast_or_null<StringLiteral>(StmtStack[StackIdx++]));
+ S->setClobbers(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<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ 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::SmallVector<char, 16> Str(&Record[Idx], &Record[Idx] + Len);
+ E->setStrData(*Reader.getContext(), Str.data(), Len);
+ 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::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ E->setSizeof(Record[Idx++]);
+ if (Record[Idx] == 0) {
+ E->setArgument(cast<Expr>(StmtStack.back()));
+ ++Idx;
+ } else {
+ E->setArgument(Reader.GetType(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<NamedDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setArrow(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ E->setSubExpr(cast<Expr>(StmtStack.back()));
+ 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]));
+ return 3;
+}
+
+unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setLvalueCast(Record[Idx++]);
+ return 1;
+}
+
+unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+ VisitCastExpr(E);
+ E->setTypeAsWritten(Reader.GetType(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->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(NumInits);
+ for (unsigned I = 0; I != NumInits; ++I)
+ E->updateInit(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(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((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++]);
+ 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->setEncodedType(Reader.GetType(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::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ VisitExpr(E);
+ E->setGetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setSetterMethod(
+ cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+ E->setClassProp(
+ 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);
+ E->setNumArgs(Record[Idx++]);
+ E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setSelector(Reader.GetSelector(Record, Idx));
+ E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++])));
+
+ E->setReceiver(
+ cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1]));
+ if (!E->getReceiver()) {
+ ObjCMessageExpr::ClassInfo CI;
+ CI.first = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]));
+ CI.second = Reader.GetIdentifierInfo(Record, Idx);
+ E->setClassInfo(CI);
+ }
+
+ 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::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[StmtStack.size() - 2]));
+ S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++])));
+ S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 2;
+}
+
+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);
+ S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3]));
+ S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2]));
+ S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1]));
+ S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return 3;
+}
+
+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;
+}
+
+
+// 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_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, 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(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) ObjCKVCRefExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_MESSAGE_EXPR:
+ S = new (Context) ObjCMessageExpr(Empty);
+ break;
+ case pch::EXPR_OBJC_SUPER_EXPR:
+ S = new (Context) ObjCSuperExpr(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 = new (Context) ObjCAtTryStmt(Empty);
+ 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;
+ }
+
+ // 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!");
+ SwitchCaseStmts.clear();
+ return StmtStack.back();
+}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
new file mode 100644
index 0000000..9f9b3b4
--- /dev/null
+++ b/lib/Frontend/PCHWriter.cpp
@@ -0,0 +1,1966 @@
+//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- 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 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/Lex/MacroInfo.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/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/System/Path.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Type serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN 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 PCHTypeWriter::VisitExtQualType(const ExtQualType *T) {
+ Writer.AddTypeRef(QualType(T->getBaseType(), 0), Record);
+ Record.push_back(T->getObjCGCAttr()); // FIXME: use stable values
+ Record.push_back(T->getAddressSpace());
+ Code = pch::TYPE_EXT_QUAL;
+}
+
+void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) {
+ assert(false && "Built-in types are never serialized");
+}
+
+void PCHTypeWriter::VisitFixedWidthIntType(const FixedWidthIntType *T) {
+ Record.push_back(T->getWidth());
+ Record.push_back(T->isSigned());
+ Code = pch::TYPE_FIXED_WIDTH_INT;
+}
+
+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->getIndexTypeQualifier()); // 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.AddStmt(T->getSizeExpr());
+ Code = pch::TYPE_VARIABLE_ARRAY;
+}
+
+void PCHTypeWriter::VisitVectorType(const VectorType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Record.push_back(T->getNumElements());
+ 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);
+}
+
+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;
+}
+
+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::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::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ // FIXME: Serialize this type (C++ only)
+ assert(false && "Cannot serialize template specialization types");
+}
+
+void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) {
+ // FIXME: Serialize this type (C++ only)
+ assert(false && "Cannot serialize qualified name types");
+}
+
+void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
+ Writer.AddDeclRef(T->getDecl(), Record);
+ Code = pch::TYPE_OBJC_INTERFACE;
+}
+
+void
+PCHTypeWriter::VisitObjCQualifiedInterfaceType(
+ const ObjCQualifiedInterfaceType *T) {
+ VisitObjCInterfaceType(T);
+ Record.push_back(T->getNumProtocols());
+ for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_QUALIFIED_INTERFACE;
+}
+
+void PCHTypeWriter::VisitObjCQualifiedIdType(const ObjCQualifiedIdType *T) {
+ Record.push_back(T->getNumProtocols());
+ for (ObjCQualifiedIdType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end(); I != E; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Code = pch::TYPE_OBJC_QUALIFIED_ID;
+}
+
+//===----------------------------------------------------------------------===//
+// 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);
+#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(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(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(OBJC_CATEGORY_IMPLEMENTATIONS);
+
+ // 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);
+ RECORD(SM_HEADER_FILE_INFO);
+
+ // Preprocessor Block.
+ BLOCK(PREPROCESSOR_BLOCK);
+ RECORD(PP_MACRO_OBJECT_LIKE);
+ RECORD(PP_MACRO_FUNCTION_LIKE);
+ RECORD(PP_TOKEN);
+
+ // Types block.
+ BLOCK(TYPES_BLOCK);
+ RECORD(TYPE_EXT_QUAL);
+ RECORD(TYPE_FIXED_WIDTH_INT);
+ 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_QUALIFIED_INTERFACE);
+ RECORD(TYPE_OBJC_QUALIFIED_ID);
+ // Statements and Exprs can occur in the Types block.
+ AddStmtsExprs(Stream, Record);
+
+ // Decls block.
+ BLOCK(DECLS_BLOCK);
+ 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_ORIGINAL_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 block.
+ AddStmtsExprs(Stream, Record);
+#undef RECORD
+#undef BLOCK
+ Stream.ExitBlock();
+}
+
+
+/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
+void PCHWriter::WriteMetadata(ASTContext &Context) {
+ using namespace llvm;
+
+ // 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());
+ std::string MainFileName;
+
+ if (!MainFilePath.isAbsolute()) {
+ llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
+ P.appendComponent(MainFilePath.toString());
+ MainFileName = P.toString();
+ } else {
+ MainFileName = MainFilePath.toString();
+ }
+
+ RecordData Record;
+ Record.push_back(pch::ORIGINAL_FILE_NAME);
+ Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileName.c_str(),
+ MainFileName.size());
+ }
+
+ // 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::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);
+ const char *Triple = Target.getTargetTriple();
+ Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple, strlen(Triple));
+}
+
+/// \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.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.PascalStrings); // Allow Pascal strings
+ Record.push_back(LangOpts.WritableStrings); // Allow writable strings
+ Record.push_back(LangOpts.LaxVectorConversions);
+ Record.push_back(LangOpts.Exceptions); // Support exception handling.
+
+ 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.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.getGCMode());
+ Record.push_back(LangOpts.getVisibilityMode());
+ Record.push_back(LangOpts.InstantiationDepth);
+ Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record);
+}
+
+//===----------------------------------------------------------------------===//
+// stat cache Serialization
+//===----------------------------------------------------------------------===//
+
+namespace {
+// Trait used for the on-disk hash table of stat cache results.
+class VISIBILITY_HIDDEN 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 BernsteinHash(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) {
+ // 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)
+ Generator.insert(Stat->first(), Stat->second);
+
+ // Create the on-disk hash table in a buffer.
+ llvm::SmallVector<char, 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.front(),
+ StatCacheData.size());
+}
+
+//===----------------------------------------------------------------------===//
+// 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
+ 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) {
+ 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);
+ 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 entries for all of the header files we know about.
+ HeaderSearch &HS = PP.getHeaderSearchInfo();
+ Record.clear();
+ for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
+ E = HS.header_file_end();
+ I != E; ++I) {
+ Record.push_back(I->isImport);
+ Record.push_back(I->DirInfo);
+ Record.push_back(I->NumIncludes);
+ AddIdentifierRef(I->ControllingMacro, Record);
+ Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record);
+ Record.clear();
+ }
+
+ // 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 (SourceManager::sloc_entry_iterator
+ SLoc = SourceMgr.sloc_entry_begin() + 1,
+ SLocEnd = SourceMgr.sloc_entry_end();
+ SLoc != SLocEnd; ++SLoc) {
+ // 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.
+ Stream.EmitRecordWithBlob(SLocFileAbbrv, Record,
+ Content->Entry->getName(),
+ strlen(Content->Entry->getName()));
+
+ // 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();
+ const char *Name = Buffer->getBufferIdentifier();
+ Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, Name, strlen(Name) + 1);
+ Record.clear();
+ Record.push_back(pch::SM_SLOC_BUFFER_BLOB);
+ Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record,
+ 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();
+ SourceManager::sloc_entry_iterator NextSLoc = SLoc;
+ if (++NextSLoc != SLocEnd)
+ NextOffset = NextSLoc->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.
+ 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;
+
+ // FIXME: Remove this identifier reference?
+ 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);
+ }
+ 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;
+ }
+ Stream.ExitBlock();
+}
+
+//===----------------------------------------------------------------------===//
+// Type Serialization
+//===----------------------------------------------------------------------===//
+
+/// \brief Write the representation of a type to the PCH stream.
+void PCHWriter::WriteType(const Type *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);
+ 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();
+}
+
+/// \brief Write a block containing all of the types.
+void PCHWriter::WriteTypesBlock(ASTContext &Context) {
+ // Enter the types block.
+ Stream.EnterSubblock(pch::TYPES_BLOCK_ID, 2);
+
+ // Emit all of the types that need to be emitted (so far).
+ while (!TypesToEmit.empty()) {
+ const Type *T = TypesToEmit.front();
+ TypesToEmit.pop();
+ assert(!isa<BuiltinType>(T) && "Built-in types are not serialized");
+ WriteType(T);
+ }
+
+ // Exit the types block
+ Stream.ExitBlock();
+}
+
+//===----------------------------------------------------------------------===//
+// 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(Context))
+ return 0;
+
+ uint64_t Offset = Stream.GetCurrentBitNo();
+ RecordData Record;
+ for (DeclContext::decl_iterator D = DC->decls_begin(Context),
+ DEnd = DC->decls_end(Context);
+ 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(Context, 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 VISIBILITY_HIDDEN 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 = clang::BernsteinHashPartial(II->getName(), II->getLength(), 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::SmallVector<char, 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.front(),
+ MethodPool.size());
+
+ // 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 VISIBILITY_HIDDEN 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 clang::BernsteinHash(II->getName());
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II,
+ pch::IdentID ID) {
+ unsigned KeyLen = strlen(II->getName()) + 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->getName(), 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) | hasMacroDefinition;
+ Bits = (Bits << 1) | II->isExtensionToken();
+ Bits = (Bits << 1) | II->isPoisoned();
+ Bits = (Bits << 1) | 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::SmallVector<char, 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.front(),
+ IdentifierTable.size());
+ }
+
+ // 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
+ Record.push_back(Attr->isInherited());
+ switch (Attr->getKind()) {
+ case Attr::Alias:
+ AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
+ 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::Blocks:
+ Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
+ 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:
+ 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::IBOutletKind:
+ case Attr::NoReturn:
+ case Attr::NoThrow:
+ case Attr::Nodebug:
+ case Attr::Noinline:
+ 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::ObjCException:
+ case Attr::ObjCNSObject:
+ case Attr::CFReturnsRetained:
+ case Attr::NSReturnsRetained:
+ case Attr::Overloadable:
+ break;
+
+ case Attr::Packed:
+ Record.push_back(cast<PackedAttr>(Attr)->getAlignment());
+ break;
+
+ case Attr::Pure:
+ break;
+
+ case Attr::Regparm:
+ Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
+ 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::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) {
+ 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;
+ DeclsToEmit.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 header file. Generally, this record will be empty.
+ RecordData TentativeDefinitions;
+ for (llvm::DenseMap<DeclarationName, VarDecl *>::iterator
+ TD = SemaRef.TentativeDefinitions.begin(),
+ TDEnd = SemaRef.TentativeDefinitions.end();
+ TD != TDEnd; ++TD)
+ AddDeclRef(TD->second, TentativeDefinitions);
+
+ // Build a record containing all of the locally-scoped external
+ // declarations in this header file. Generally, this record will be
+ // empty.
+ RecordData LocallyScopedExternalDecls;
+ 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);
+
+ // Build a record containing all of the Objective-C category
+ // implementations.
+ RecordData ObjCCategoryImpls;
+ for (unsigned I = 0, N = SemaRef.ObjCCategoryImpls.size(); I != N; ++I)
+ AddDeclRef(SemaRef.ObjCCategoryImpls[I], ObjCCategoryImpls);
+
+ // Write the remaining PCH contents.
+ RecordData Record;
+ Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4);
+ WriteMetadata(Context);
+ WriteLanguageOptions(Context.getLangOptions());
+ if (StatCalls)
+ WriteStatCache(*StatCalls);
+ WriteSourceManagerBlock(Context.getSourceManager(), PP);
+ WritePreprocessor(PP);
+
+ // Keep writing types and declarations until all types and
+ // declarations have been written.
+ do {
+ if (!DeclsToEmit.empty())
+ WriteDeclsBlock(Context);
+ if (!TypesToEmit.empty())
+ WriteTypesBlock(Context);
+ } while (!(DeclsToEmit.empty() && TypesToEmit.empty()));
+
+ 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 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);
+ Stream.EmitRecord(pch::SPECIAL_TYPES, Record);
+
+ // 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 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);
+
+ // Write the record containing Objective-C category implementations.
+ if (!ObjCCategoryImpls.empty())
+ Stream.EmitRecord(pch::OBJC_CATEGORY_IMPLEMENTATIONS, ObjCCategoryImpls);
+
+ // 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::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;
+}
+
+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::AddTypeRef(QualType T, RecordData &Record) {
+ if (T.isNull()) {
+ Record.push_back(pch::PREDEF_TYPE_NULL_ID);
+ return;
+ }
+
+ 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::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break;
+ case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break;
+ }
+
+ Record.push_back((ID << 3) | T.getCVRQualifiers());
+ return;
+ }
+
+ pch::TypeID &ID = TypeIDs[T.getTypePtr()];
+ if (ID == 0) {
+ // We haven't seen this type before. Assign it a new ID and put it
+ // into the queu of types to emit.
+ ID = NextTypeID++;
+ TypesToEmit.push(T.getTypePtr());
+ }
+
+ // Encode the type qualifiers in the type reference.
+ Record.push_back((ID << 3) | T.getCVRQualifiers());
+}
+
+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();
+ DeclsToEmit.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::CXXUsingDirective:
+ // No extra data to emit
+ break;
+ }
+}
+
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
new file mode 100644
index 0000000..6734661
--- /dev/null
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -0,0 +1,532 @@
+//===--- 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/Expr.h"
+#include "llvm/Bitcode/BitstreamWriter.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 VisitTypeDecl(TypeDecl *D);
+ void VisitTypedefDecl(TypedefDecl *D);
+ void VisitTagDecl(TagDecl *D);
+ void VisitEnumDecl(EnumDecl *D);
+ void VisitRecordDecl(RecordDecl *D);
+ void VisitValueDecl(ValueDecl *D);
+ void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFieldDecl(FieldDecl *D);
+ void VisitVarDecl(VarDecl *D);
+ void VisitImplicitParamDecl(ImplicitParamDecl *D);
+ void VisitParmVarDecl(ParmVarDecl *D);
+ void VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitBlockDecl(BlockDecl *D);
+ void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
+ uint64_t VisibleOffset);
+ 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->getAccess());
+}
+
+void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDecl(D);
+ 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.AddTypeRef(D->getUnderlyingType(), Record);
+ Code = pch::DECL_TYPEDEF;
+}
+
+void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
+ VisitTypeDecl(D);
+ Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
+ Record.push_back(D->isDefinition());
+ Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record);
+}
+
+void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) {
+ VisitTagDecl(D);
+ Writer.AddTypeRef(D->getIntegerType(), Record);
+ // FIXME: C++ InstantiatedFrom
+ Code = pch::DECL_ENUM;
+}
+
+void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) {
+ VisitTagDecl(D);
+ Record.push_back(D->hasFlexibleArrayMember());
+ Record.push_back(D->isAnonymousStructOrUnion());
+ 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::VisitFunctionDecl(FunctionDecl *D) {
+ VisitValueDecl(D);
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
+ Writer.AddStmt(D->getBody(Context));
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->isInline());
+ Record.push_back(D->isC99InlineDefinition());
+ 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());
+ Writer.AddSourceLocation(D->getTypeSpecStartLoc(), Record);
+ // FIXME: C++ TemplateOrInstantiation
+ 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(Context));
+ 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());
+ Writer.AddTypeRef(D->getResultType(), 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.AddSourceLocation(D->getAtEndLoc(), 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);
+ 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);
+ 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, Record);
+ Code = pch::DECL_OBJC_CLASS;
+}
+
+void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
+ VisitDecl(D);
+ 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);
+ 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 (ObjCProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
+ Writer.AddDeclRef(*I, Record);
+ Writer.AddDeclRef(D->getNextClassCategory(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), 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.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) {
+ VisitNamedDecl(D);
+ Writer.AddDeclRef(D->getClassInterface(), Record);
+ Writer.AddSourceLocation(D->getLocEnd(), 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);
+ 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);
+ Code = pch::DECL_OBJC_PROPERTY_IMPL;
+}
+
+void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) {
+ VisitValueDecl(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) {
+ VisitValueDecl(D);
+ Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+ Record.push_back(D->isThreadSpecified());
+ Record.push_back(D->hasCXXDirectInitializer());
+ Record.push_back(D->isDeclaredInCondition());
+ Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
+ Writer.AddSourceLocation(D->getTypeSpecStartLoc(), 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
+ // FIXME: emit default argument (C++)
+ // FIXME: why isn't the "default argument" just stored as the initializer
+ // in VarDecl?
+ 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->hasAttrs() &&
+ !D->isImplicit() &&
+ D->getAccess() == AS_none &&
+ D->getStorageClass() == 0 &&
+ !D->hasCXXDirectInitializer() && // Can params have this ever?
+ D->getObjCDeclQualifier() == 0)
+ 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->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl");
+ assert(D->getInit() == 0 && "PARM_VAR_DECL never has init");
+}
+
+void PCHDeclWriter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+ VisitParmVarDecl(D);
+ Writer.AddTypeRef(D->getOriginalType(), Record);
+ Code = pch::DECL_ORIGINAL_PARM_VAR;
+ AbbrevToUse = 0;
+}
+
+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;
+}
+
+/// \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(AS_none)); // C++ AccessSpecifier
+
+ // NamedDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
+ // ValueDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
+ // VarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
+ Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
+ Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition
+ Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TypeSpecStartLoc
+ Abv->Add(BitCodeAbbrevOp(0)); // HasInit
+ // ParmVarDecl
+ Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier
+
+ ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv);
+}
+
+/// \brief Write a block containing all of the declarations.
+void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
+ // Enter the declarations block.
+ Stream.EnterSubblock(pch::DECLS_BLOCK_ID, 3);
+
+ // Output the abbreviations that we will use in this block.
+ WriteDeclsBlockAbbrevs();
+
+ // Emit all of the declarations.
+ RecordData Record;
+ PCHDeclWriter W(*this, Context, Record);
+ while (!DeclsToEmit.empty()) {
+ // Pull the next declaration off the queue
+ Decl *D = DeclsToEmit.front();
+ DeclsToEmit.pop();
+
+ // 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) {
+ fprintf(stderr, "Cannot serialize declaration of kind %s\n",
+ D->getDeclKindName());
+ assert(false && "Unhandled declaration kind while generating PCH");
+ exit(-1);
+ }
+ 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.
+ if (isa<FileScopeAsmDecl>(D))
+ ExternalDefinitions.push_back(ID);
+ }
+
+ // Exit the declarations block
+ Stream.ExitBlock();
+}
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
new file mode 100644
index 0000000..b7caee5
--- /dev/null
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -0,0 +1,829 @@
+//===--- 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/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 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 VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+ void VisitObjCSuperExpr(ObjCSuperExpr *E);
+
+ // Objective-C Statements
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
+ void VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
+ void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *);
+ void VisitObjCAtTryStmt(ObjCAtTryStmt *);
+ void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *);
+ void VisitObjCAtThrowStmt(ObjCAtThrowStmt *);
+ };
+}
+
+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.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.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.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);
+ Code = pch::STMT_DO;
+}
+
+void PCHStmtWriter::VisitForStmt(ForStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getInit());
+ Writer.WriteSubStmt(S->getCond());
+ 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);
+ 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());
+ Writer.WriteSubStmt(S->getAsmString());
+
+ // Outputs
+ for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) {
+ Writer.AddString(S->getOutputName(I), Record);
+ Writer.WriteSubStmt(S->getOutputConstraintLiteral(I));
+ Writer.WriteSubStmt(S->getOutputExpr(I));
+ }
+
+ // Inputs
+ for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) {
+ Writer.AddString(S->getInputName(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);
+ 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->getLoc(), 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::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->isSizeOf());
+ if (E->isArgumentType())
+ Writer.AddTypeRef(E->getArgumentType(), 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());
+ Code = pch::EXPR_MEMBER;
+}
+
+void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
+ VisitExpr(E);
+ Writer.WriteSubStmt(E->getSubExpr());
+}
+
+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());
+ 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.AddTypeRef(E->getTypeAsWritten(), 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.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());
+ 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.AddTypeRef(E->getEncodedType(), 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::VisitObjCKVCRefExpr(ObjCKVCRefExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getGetterMethod(), Record);
+ Writer.AddDeclRef(E->getSetterMethod(), Record);
+
+ // NOTE: ClassProp and Base are mutually exclusive.
+ Writer.AddDeclRef(E->getClassProp(), 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());
+ Writer.AddSourceLocation(E->getLeftLoc(), Record);
+ Writer.AddSourceLocation(E->getRightLoc(), Record);
+ Writer.AddSelectorRef(E->getSelector(), Record);
+ Writer.AddDeclRef(E->getMethodDecl(), Record); // optional
+ Writer.WriteSubStmt(E->getReceiver());
+
+ if (!E->getReceiver()) {
+ ObjCMessageExpr::ClassInfo CI = E->getClassInfo();
+ Writer.AddDeclRef(CI.first, Record);
+ Writer.AddIdentifierRef(CI.second, 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.WriteSubStmt(S->getNextCatchStmt());
+ 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) {
+ Writer.WriteSubStmt(S->getTryBody());
+ Writer.WriteSubStmt(S->getCatchStmts());
+ 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;
+}
+
+//===----------------------------------------------------------------------===//
+// 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);
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
+ "Unhandled expression writing PCH file");
+ 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);
+ assert(Writer.Code != pch::STMT_NULL_PTR &&
+ "Unhandled expression writing PCH file");
+ 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();
+ SwitchCaseIDs.clear();
+}
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
new file mode 100644
index 0000000..387ed45
--- /dev/null
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -0,0 +1,389 @@
+//===--- 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/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/System/Path.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;
+ class PreprocessorFactory;
+}
+
+namespace {
+ class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient {
+ std::vector<const PathDiagnostic*> BatchedDiags;
+ const std::string OutputFile;
+ const LangOptions &LangOpts;
+ public:
+ PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts);
+ ~PlistDiagnostics();
+ void HandlePathDiagnostic(const PathDiagnostic* D);
+
+ PathGenerationScheme getGenerationScheme() const { return Extensive; }
+ 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)
+ : OutputFile(output), LangOpts(LO) {}
+
+PathDiagnosticClient*
+clang::CreatePlistDiagnosticClient(const std::string& s,
+ Preprocessor *PP, PreprocessorFactory*) {
+ return new PlistDiagnostics(s, PP->getLangOptions());
+}
+
+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 << "&amp;"; break;
+ case '<': o << "&lt;"; break;
+ case '>': o << "&gt;"; break;
+ case '\'': o << "&apos;"; break;
+ case '\"': o << "&quot;"; 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);
+}
+
+PlistDiagnostics::~PlistDiagnostics() {
+
+ // 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(), false, 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);
+
+ // Close up the entry.
+ o << " </dict>\n";
+ }
+
+ o << " </array>\n";
+
+ // Finish.
+ o << "</dict>\n</plist>";
+}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
new file mode 100644
index 0000000..f02d5d4
--- /dev/null
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -0,0 +1,831 @@
+//===--- 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,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
+ ClassName, ClassLoc,
+ SuperName, SuperLoc,
+ ProtoRefs, NumProtocols,
+ EndProtoLoc, AttrList);
+ }
+
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
+ Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ Out << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList,
+ 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, FullExprArg 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, 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 TagType, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr, AccessSpecifier AS,
+ bool &Owned) {
+ // 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,
+ 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) {
+ 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, StmtArg ThenVal,
+ SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ 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, StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond){
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg 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,
+ FullExprArg RetValExp) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc,
+ bool IsSimple,
+ bool IsVolatile,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ std::string *Names,
+ MultiExprArg Constraints,
+ MultiExprArg Exprs,
+ ExprArg AsmString,
+ MultiExprArg Clobbers,
+ SourceLocation RParenLoc) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclPtrTy Parm, StmtArg Body,
+ StmtArg CatchList) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ Out << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch,
+ 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) {
+ 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(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) {
+ 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) {
+ 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/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
new file mode 100644
index 0000000..89d099c
--- /dev/null
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -0,0 +1,470 @@
+//===--- 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/Lex/MacroInfo.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.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())
+ ;
+ else if (MI.getNumArgs() == 1)
+ OS << (*MI.arg_begin())->getName();
+ else {
+ MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+ OS << (*AI++)->getName();
+ while (AI != E)
+ OS << ',' << (*AI++)->getName();
+ }
+
+ if (MI.isVariadic()) {
+ if (!MI.arg_empty())
+ OS << ',';
+ OS << "...";
+ }
+ 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::SmallVector<char, 128> SpellingBuffer;
+ for (MacroInfo::tokens_iterator I = MI.tokens_begin(), E = MI.tokens_end();
+ I != E; ++I) {
+ if (I->hasLeadingSpace())
+ OS << ' ';
+
+ // Make sure we have enough space in the spelling buffer.
+ if (I->getLength() < SpellingBuffer.size())
+ SpellingBuffer.resize(I->getLength());
+ const char *Buffer = SpellingBuffer.data();
+ unsigned SpellingLen = PP.getSpelling(*I, Buffer);
+ OS.write(Buffer, SpellingLen);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessed token printer
+//===----------------------------------------------------------------------===//
+
+namespace {
+class PrintPPOutputPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ 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;
+public:
+ PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os,
+ bool lineMarkers, bool defines)
+ : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers),
+ DumpDefines(defines) {
+ CurLine = 0;
+ CurFilename += "<uninit>";
+ EmittedTokensOnThisLine = false;
+ EmittedMacroOnThisLine = false;
+ FileType = SrcMgr::C_User;
+ Initialized = false;
+ }
+
+ 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);
+ bool AvoidConcat(const Token &PrevTok, const Token &Tok) {
+ return ConcatInfo.AvoidConcat(PrevTok, Tok);
+ }
+ void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0);
+
+ /// 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;
+ }
+
+ 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(SourceLocation Loc) {
+ unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc);
+
+ 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 = PP.getSourceManager();
+ if (Reason == PPCallbacks::EnterFile) {
+ SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc();
+ if (IncludeLoc.isValid())
+ MoveToLine(IncludeLoc);
+ } else if (Reason == PPCallbacks::SystemHeaderPragma) {
+ MoveToLine(Loc);
+
+ // 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.
+ }
+
+ Loc = SourceMgr.getInstantiationLoc(Loc);
+ // FIXME: Should use presumed line #!
+ CurLine = SourceMgr.getInstantiationLineNumber(Loc);
+
+ if (DisableLineMarkers) return;
+
+ CurFilename.clear();
+ CurFilename += SourceMgr.getPresumedLoc(Loc).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.
+ const SourceManager &SourceMgr = PP.getSourceManager();
+ unsigned ColNo = SourceMgr.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;
+}
+
+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 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(PrevTok, Tok))) {
+ OS << ' ';
+ }
+
+ if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ OS.write(II->getName(), II->getLength());
+ } 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);
+ } else {
+ std::string S = PP.getSpelling(Tok);
+ OS.write(&S[0], S.size());
+ }
+ Callbacks->SetEmittedTokensOnThisLine();
+
+ if (Tok.is(tok::eof)) break;
+
+ PrevTok = Tok;
+ PP.Lex(Tok);
+ }
+}
+
+namespace {
+ struct SortMacrosByID {
+ typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+ bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const {
+ return strcmp(LHS.first->getName(), RHS.first->getName()) < 0;
+ }
+ };
+}
+
+void clang::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));
+
+ std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID;
+ for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
+ I != E; ++I)
+ MacrosByID.push_back(*I);
+ std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID());
+
+ 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,
+ bool EnableCommentOutput,
+ bool EnableMacroCommentOutput,
+ bool DisableLineMarkers,
+ bool DumpDefines) {
+ // Inform the preprocessor whether we want it to retain comments or not, due
+ // to -C or -CC.
+ PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
+
+ OS->SetBufferSize(64*1024);
+
+ PrintPPOutputPPCallbacks *Callbacks =
+ new PrintPPOutputPPCallbacks(PP, *OS, DisableLineMarkers, DumpDefines);
+ PP.AddPragmaHandler(0, new UnknownPragmaHandler("#pragma", Callbacks));
+ PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC",
+ Callbacks));
+
+ PP.setPPCallbacks(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/lib/Frontend/RewriteBlocks.cpp b/lib/Frontend/RewriteBlocks.cpp
new file mode 100644
index 0000000..9d73d90
--- /dev/null
+++ b/lib/Frontend/RewriteBlocks.cpp
@@ -0,0 +1,1162 @@
+//===--- RewriteBlocks.cpp ----------------------------------------------===//
+//
+// 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 closure rewriter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <sstream>
+
+using namespace clang;
+using llvm::utostr;
+
+namespace {
+
+class RewriteBlocks : public ASTConsumer {
+ Rewriter Rewrite;
+ Diagnostic &Diags;
+ const LangOptions &LangOpts;
+ unsigned RewriteFailedDiag;
+
+ ASTContext *Context;
+ SourceManager *SM;
+ FileID MainFileID;
+ const char *MainFileStart, *MainFileEnd;
+
+ // Block expressions.
+ llvm::SmallVector<BlockExpr *, 32> Blocks;
+ llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
+
+ // Block related declarations.
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+
+ llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs;
+
+ // The function/method we are rewriting.
+ FunctionDecl *CurFunctionDef;
+ ObjCMethodDecl *CurMethodDef;
+
+ bool IsHeader;
+
+ std::string Preamble;
+public:
+ RewriteBlocks(std::string inFile, Diagnostic &D,
+ const LangOptions &LOpts);
+ ~RewriteBlocks() {
+ // Get the buffer corresponding to MainFileID.
+ // If we haven't changed it, then we are done.
+ if (const RewriteBuffer *RewriteBuf =
+ Rewrite.getRewriteBufferFor(MainFileID)) {
+ std::string S(RewriteBuf->begin(), RewriteBuf->end());
+ printf("%s\n", S.c_str());
+ } else {
+ printf("No changes\n");
+ }
+ }
+
+ void Initialize(ASTContext &context);
+
+ void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen);
+ void ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength);
+
+ // 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);
+
+ // Top level
+ Stmt *RewriteFunctionBody(Stmt *S);
+ void InsertBlockLiteralsWithinFunction(FunctionDecl *FD);
+ void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD);
+
+ // Block specific rewrite rules.
+ std::string SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
+
+ void RewriteBlockCall(CallExpr *Exp);
+ void RewriteBlockPointerDecl(NamedDecl *VD);
+ void RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ 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,
+ bool hasCopyDisposeHelpers);
+ std::string SynthesizeBlockCall(CallExpr *Exp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName);
+
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockCallExprs(Stmt *S);
+ void GetBlockDeclRefExprs(Stmt *S);
+
+ // 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 isBlockPointerType(QualType T) { return isa<BlockPointerType>(T); }
+
+ // 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->getAsPointerType()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ isa<ObjCQualifiedIdType>(PT->getPointeeType()))
+ return true;
+ }
+ return false;
+ }
+ // ObjC rewrite methods.
+ void RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl);
+ void RewriteCategoryDecl(ObjCCategoryDecl *CatDecl);
+ void RewriteProtocolDecl(ObjCProtocolDecl *PDecl);
+ void RewriteMethodDecl(ObjCMethodDecl *MDecl);
+
+ void RewriteFunctionProtoType(QualType funcType, NamedDecl *D);
+ void CheckFunctionPointerDecl(QualType dType, NamedDecl *ND);
+ void RewriteCastExpr(CastExpr *CE);
+
+ bool PointerTypeTakesAnyBlockArguments(QualType QT);
+ void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
+};
+
+}
+
+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";
+}
+
+RewriteBlocks::RewriteBlocks(std::string inFile,
+ Diagnostic &D, const LangOptions &LOpts) :
+ Diags(D), LangOpts(LOpts) {
+ IsHeader = IsHeaderFile(inFile);
+ CurFunctionDef = 0;
+ CurMethodDef = 0;
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ "rewriting failed");
+}
+
+ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts) {
+ return new RewriteBlocks(InFile, Diags, LangOpts);
+}
+
+void RewriteBlocks::Initialize(ASTContext &context) {
+ Context = &context;
+ SM = &Context->getSourceManager();
+
+ // 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(), LangOpts);
+
+ if (IsHeader)
+ Preamble = "#pragma once\n";
+ 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 Size;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "enum {\n";
+ Preamble += " BLOCK_HAS_COPY_DISPOSE = (1<<25),\n";
+ Preamble += " BLOCK_IS_GLOBAL = (1<<28)\n";
+ Preamble += "};\n";
+ if (LangOpts.Microsoft)
+ Preamble += "#define __OBJC_RW_EXTERN extern \"C\" __declspec(dllimport)\n";
+ else
+ Preamble += "#define __OBJC_RW_EXTERN extern\n";
+ Preamble += "// Runtime copy/destroy helper functions\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_copy_assign(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_assign_copy(void *, void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_destroy(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void _Block_byref_release(void *);\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteGlobalBlock;\n";
+ Preamble += "__OBJC_RW_EXTERN void *_NSConcreteStackBlock;\n";
+ Preamble += "#endif\n";
+
+ InsertText(SM->getLocForStartOfFile(MainFileID),
+ Preamble.c_str(), Preamble.size());
+}
+
+void RewriteBlocks::InsertText(SourceLocation Loc, const char *StrData,
+ unsigned StrLen)
+{
+ if (!Rewrite.InsertText(Loc, StrData, StrLen))
+ return;
+ Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag);
+}
+
+void RewriteBlocks::ReplaceText(SourceLocation Start, unsigned OrigLength,
+ const char *NewStr, unsigned NewLength) {
+ if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength))
+ return;
+ Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
+}
+
+void RewriteBlocks::RewriteMethodDecl(ObjCMethodDecl *Method) {
+ bool haveBlockPtrs = false;
+ for (ObjCMethodDecl::param_iterator I = Method->param_begin(),
+ E = Method->param_end(); I != E; ++I)
+ if (isBlockPointerType((*I)->getType()))
+ haveBlockPtrs = true;
+
+ if (!haveBlockPtrs)
+ return;
+
+ // Do a fuzzy rewrite.
+ // We have 1 or more arguments that have closure pointers.
+ SourceLocation Loc = Method->getLocStart();
+ SourceLocation LocEnd = Method->getLocEnd();
+ const char *startBuf = SM->getCharacterData(Loc);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ const char *methodPtr = startBuf;
+ std::string Tag = "struct __block_impl *";
+
+ while (*methodPtr++ && (methodPtr != endBuf)) {
+ switch (*methodPtr) {
+ case ':':
+ methodPtr++;
+ if (*methodPtr == '(') {
+ const char *scanType = ++methodPtr;
+ bool foundBlockPointer = false;
+ unsigned parenCount = 1;
+
+ while (parenCount) {
+ switch (*scanType) {
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ case '^':
+ foundBlockPointer = true;
+ break;
+ }
+ scanType++;
+ }
+ if (foundBlockPointer) {
+ // advance the location to startArgList.
+ Loc = Loc.getFileLocWithOffset(methodPtr-startBuf);
+ assert((Loc.isValid()) && "Invalid Loc");
+ ReplaceText(Loc, scanType-methodPtr-1, Tag.c_str(), Tag.size());
+
+ // Advance startBuf. Since the underlying buffer has changed,
+ // it's very important to advance startBuf (so we can correctly
+ // compute a relative Loc the next time around).
+ startBuf = methodPtr;
+ }
+ // Advance the method ptr to the end of the type.
+ methodPtr = scanType;
+ }
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(*Context),
+ E = ClassDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(*Context),
+ E = ClassDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(*Context),
+ E = CatDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCCategoryDecl::classmeth_iterator
+ I = CatDecl->classmeth_begin(*Context),
+ E = CatDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteBlocks::HandleTopLevelSingleDecl(Decl *D) {
+ // 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;
+
+ 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);
+
+ // If we have a decl in the main file, see if we should rewrite it.
+ if (SM->isFromMainFile(Loc))
+ HandleDeclInMainFile(D);
+ return;
+}
+
+std::string RewriteBlocks::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)) {
+ S += "()";
+ } 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();
+ (*AI)->getType().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::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
+ Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ // 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 (isBlockPointerType((*I)->getType()))
+ S += "struct __block_impl *";
+ else
+ (*I)->getType().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 RewriteBlocks::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_copy_assign(&dst->";
+ S += (*I)->getNameAsString();
+ S += ", src->";
+ S += (*I)->getNameAsString();
+ S += ");}";
+ }
+ 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_destroy(src->";
+ S += (*I)->getNameAsString();
+ S += ");";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteBlocks::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers) {
+ std::string S = "struct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+
+ if (hasCopyDisposeHelpers)
+ S += " void *copy;\n void *dispose;\n";
+
+ Constructor += "(void *fp";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += ", void *copyHelp, void *disposeHelp";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<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 (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
+ (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<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 (isBlockPointerType((*I)->getType())) {
+ S += "struct __block_impl *";
+ Constructor += ", void *" + ArgName;
+ } else {
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
+ Context->PrintingPolicy);
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
+ Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + "; // by ref\n";
+ }
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+
+ // Initialize all "by copy" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ // Initialize all "by ref" arguments.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ std::string Name = (*I)->getNameAsString();
+ Constructor += " ";
+ if (isBlockPointerType((*I)->getType()))
+ Constructor += Name + " = (struct __block_impl *)_";
+ else
+ Constructor += Name + " = _";
+ Constructor += Name + ";\n";
+ }
+ } else {
+ // Finish writing the constructor.
+ // FIXME: handle NSConcreteGlobalBlock.
+ Constructor += ", int flags=0) {\n";
+ Constructor += " impl.isa = 0/*&_NSConcreteStackBlock*/;\n impl.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+
+void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName) {
+ // Insert closures that were part of the function.
+ for (unsigned i = 0; i < Blocks.size(); i++) {
+
+ CollectBlockDeclRefInfo(Blocks[i]);
+
+ std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+ ImportedBlockDecls.size() > 0);
+
+ InsertText(FunLocStart, CI.c_str(), CI.size());
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+
+ InsertText(FunLocStart, CF.c_str(), CF.size());
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ BlockCallExprs.clear();
+ ImportedBlockDecls.clear();
+ }
+ Blocks.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteBlocks::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const char *FuncName = FD->getNameAsCString();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteBlocks::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ SourceLocation FunLocStart = MD->getLocStart();
+ std::string FuncName = MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName.c_str());
+}
+
+void RewriteBlocks::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);
+ return;
+}
+
+void RewriteBlocks::GetBlockCallExprs(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))
+ GetBlockCallExprs(CBE->getBody());
+ else
+ GetBlockCallExprs(*CI);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
+ }
+ }
+ return;
+}
+
+std::string RewriteBlocks::SynthesizeBlockCall(CallExpr *Exp) {
+ // Navigate to relevant type information.
+ const char *closureName = 0;
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
+ closureName = DRE->getDecl()->getNameAsCString();
+ CPT = DRE->getType()->getAsBlockPointerType();
+ } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
+ closureName = CDRE->getDecl()->getNameAsCString();
+ CPT = CDRE->getType()->getAsBlockPointerType();
+ } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
+ closureName = MExpr->getMemberDecl()->getNameAsCString();
+ CPT = MExpr->getType()->getAsBlockPointerType();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ assert(FT && "RewriteBlockClass: Bad type");
+ const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT);
+ // FTP will be null for closures that don't take arguments.
+
+ // Build a closure call - start with a paren expr to enforce precedence.
+ std::string BlockCall = "(";
+
+ // Synthesize the cast.
+ BlockCall += "(" + Exp->getType().getAsString() + "(*)";
+ BlockCall += "(struct __block_impl *";
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I && (I != E); ++I)
+ BlockCall += ", " + (*I).getAsString();
+ }
+ BlockCall += "))"; // close the argument list and paren expression.
+
+ // Invoke the closure. We need to cast it since the declaration type is
+ // bogus (it's a function pointer type)
+ BlockCall += "((struct __block_impl *)";
+ std::string closureExprBufStr;
+ llvm::raw_string_ostream closureExprBuf(closureExprBufStr);
+ Exp->getCallee()->printPretty(closureExprBuf, *Context);
+ BlockCall += closureExprBuf.str();
+ BlockCall += ")->FuncPtr)";
+
+ // Add the arguments.
+ BlockCall += "((struct __block_impl *)";
+ BlockCall += closureExprBuf.str();
+ for (CallExpr::arg_iterator I = Exp->arg_begin(),
+ E = Exp->arg_end(); I != E; ++I) {
+ std::string syncExprBufS;
+ llvm::raw_string_ostream Buf(syncExprBufS);
+ (*I)->printPretty(Buf, *Context);
+ BlockCall += ", " + Buf.str();
+ }
+ return BlockCall;
+}
+
+void RewriteBlocks::RewriteBlockCall(CallExpr *Exp) {
+ std::string BlockCall = SynthesizeBlockCall(Exp);
+
+ const char *startBuf = SM->getCharacterData(Exp->getLocStart());
+ const char *endBuf = SM->getCharacterData(Exp->getLocEnd());
+
+ ReplaceText(Exp->getLocStart(), endBuf-startBuf,
+ BlockCall.c_str(), BlockCall.size());
+}
+
+void RewriteBlocks::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
+ // FIXME: Add more elaborate code generation required by the ABI.
+ InsertText(BDRE->getLocStart(), "*", 1);
+}
+
+void RewriteBlocks::RewriteCastExpr(CastExpr *CE) {
+ SourceLocation LocStart = CE->getLocStart();
+ SourceLocation LocEnd = CE->getLocEnd();
+
+ if (!Rewriter::isRewritable(LocStart) || !Rewriter::isRewritable(LocEnd))
+ return;
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+
+ // 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, "*", 1);
+ break;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::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, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteBlocks::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAsPointerType();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ } else {
+ const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ }
+ if (FTP) {
+ for (FunctionProtoType::arg_type_iterator I = FTP->arg_type_begin(),
+ E = FTP->arg_type_end(); I != E; ++I)
+ if (isBlockPointerType(*I))
+ return true;
+ }
+ return false;
+}
+
+void RewriteBlocks::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 RewriteBlocks::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, "*", 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, "*", 1);
+ }
+ argListBegin++;
+ }
+ }
+ return;
+}
+
+void RewriteBlocks::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())
+ BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (isBlockPointerType(BlockDeclRefs[i]->getType())) {
+ GetBlockCallExprs(Blocks[i]);
+ ImportedBlockDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ }
+}
+
+std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = std::string(CurFunctionDef->getNameAsString());
+ else if (CurMethodDef) {
+ FuncName = CurMethodDef->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+ } else if (VD)
+ FuncName = std::string(VD->getNameAsString());
+
+ std::string BlockNumber = utostr(Blocks.size()-1);
+
+ std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
+ std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
+
+ std::string FunkTypeStr;
+
+ // Get a pointer to the function type so we can cast appropriately.
+ Context->getPointerType(QualType(Exp->getFunctionType(),0))
+ .getAsStringInternal(FunkTypeStr, Context->PrintingPolicy);
+
+ // Rewrite the closure block with a compound literal. The first cast is
+ // to prevent warnings from the C compiler.
+ std::string Init = "(" + FunkTypeStr;
+
+ Init += ")&" + Tag;
+
+ // Initialize the block function.
+ Init += "((void*)" + Func;
+
+ if (ImportedBlockDecls.size()) {
+ std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
+ Init += ",(void*)" + Buf;
+ }
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ Init += ",";
+ if (isObjCType((*I)->getType())) {
+ Init += "[[";
+ Init += (*I)->getNameAsString();
+ Init += " retain] autorelease]";
+ } else if (isBlockPointerType((*I)->getType())) {
+ Init += "(void *)";
+ Init += (*I)->getNameAsString();
+ } else {
+ Init += (*I)->getNameAsString();
+ }
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ Init += ",&";
+ Init += (*I)->getNameAsString();
+ }
+ }
+ Init += ")";
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ ImportedBlockDecls.clear();
+
+ return Init;
+}
+
+//===----------------------------------------------------------------------===//
+// Function Body / Expression rewriting
+//===----------------------------------------------------------------------===//
+
+Stmt *RewriteBlocks::RewriteFunctionBody(Stmt *S) {
+ // Start by rewriting all children.
+ for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
+ CI != E; ++CI)
+ if (*CI) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
+ Stmt *newStmt = RewriteFunctionBody(CBE->getBody());
+ if (newStmt)
+ *CI = newStmt;
+
+ // We've just rewritten the block body in place.
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
+ RewrittenBlockExprs[CBE] = S;
+ std::string Init = SynthesizeBlockInitExpr(CBE);
+ // Do the rewrite, using S.size() which contains the rewritten size.
+ ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
+ } else {
+ Stmt *newStmt = RewriteFunctionBody(*CI);
+ if (newStmt)
+ *CI = newStmt;
+ }
+ }
+ // Handle specific things.
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType())
+ RewriteBlockCall(CE);
+ }
+ if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
+ RewriteCastExpr(CE);
+ }
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ 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 (isBlockPointerType(ND->getType()))
+ RewriteBlockPointerDecl(ND);
+ else if (ND->getType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(ND->getType(), ND);
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ }
+ }
+ }
+ // Handle specific things.
+ if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
+ if (BDRE->isByRef())
+ RewriteBlockDeclRefExpr(BDRE);
+ }
+ // Return this stmt unmodified.
+ return S;
+}
+
+void RewriteBlocks::RewriteFunctionProtoType(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 (isBlockPointerType(*I)) {
+ // All the args are checked/rewritten. Don't call twice!
+ RewriteBlockPointerDecl(D);
+ break;
+ }
+ }
+}
+
+void RewriteBlocks::CheckFunctionPointerDecl(QualType funcType, NamedDecl *ND) {
+ const PointerType *PT = funcType->getAsPointerType();
+ if (PT && PointerTypeTakesAnyBlockArguments(funcType))
+ RewriteFunctionProtoType(PT->getPointeeType(), ND);
+}
+
+/// HandleDeclInMainFile - This is called for each top-level decl defined in the
+/// main file of the input.
+void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // 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.
+ RewriteFunctionProtoType(FD->getType(), FD);
+
+ // FIXME: Handle CXXTryStmt
+ if (CompoundStmt *Body = FD->getCompoundBody(*Context)) {
+ CurFunctionDef = FD;
+ FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
+ // This synthesizes and inserts the block "impl" struct, invoke function,
+ // and any copy/dispose helper functions.
+ InsertBlockLiteralsWithinFunction(FD);
+ CurFunctionDef = 0;
+ }
+ return;
+ }
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ RewriteMethodDecl(MD);
+ if (Stmt *Body = MD->getBody(*Context)) {
+ CurMethodDef = MD;
+ RewriteFunctionBody(Body);
+ InsertBlockLiteralsWithinMethod(MD);
+ CurMethodDef = 0;
+ }
+ }
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (isBlockPointerType(VD->getType())) {
+ RewriteBlockPointerDecl(VD);
+ if (VD->getInit()) {
+ if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
+ RewriteFunctionBody(CBE->getBody(*Context));
+
+ // We've just rewritten the block body in place.
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
+ RewrittenBlockExprs[CBE] = S;
+ std::string Init = SynthesizeBlockInitExpr(CBE, VD);
+ // Do the rewrite, using S.size() which contains the rewritten size.
+ ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
+ SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(),
+ VD->getNameAsCString());
+ } else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ } else if (VD->getType()->isFunctionPointerType()) {
+ CheckFunctionPointerDecl(VD->getType(), VD);
+ if (VD->getInit()) {
+ if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
+ RewriteCastExpr(CE);
+ }
+ }
+ }
+ return;
+ }
+ if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ if (isBlockPointerType(TD->getUnderlyingType()))
+ RewriteBlockPointerDecl(TD);
+ else if (TD->getUnderlyingType()->isFunctionPointerType())
+ CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ return;
+ }
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ if (RD->isDefinition()) {
+ for (RecordDecl::field_iterator i = RD->field_begin(*Context),
+ e = RD->field_end(*Context); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+}
diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp
new file mode 100644
index 0000000..5ef4892
--- /dev/null
+++ b/lib/Frontend/RewriteMacros.cpp
@@ -0,0 +1,215 @@
+//===--- 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/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/OwningPtr.h"
+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.
+ Lexer RawLex(SM.getMainFileID(), 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())
+ RawTok.setIdentifierInfo(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 (!strcmp(II->getName(), "warning")) {
+ // Comment out #warning.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ } else if (!strcmp(II->getName(), "pragma") &&
+ RawTokens[CurRawTok+1].is(tok::identifier) &&
+ !strcmp(RawTokens[CurRawTok+1].getIdentifierInfo()->getName(),
+ "mark")){
+ // Comment out #pragma mark.
+ RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//", 2);
+ }
+ }
+
+ // 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, 2+!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, "*/", 2);
+ 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[0], Expansion.size());
+ }
+
+ // 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/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
new file mode 100644
index 0000000..f382704
--- /dev/null
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -0,0 +1,4693 @@
+//===--- 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/ADT/StringExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using llvm::utostr;
+
+namespace {
+ class RewriteObjC : public ASTConsumer {
+ 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;
+
+ unsigned NumObjCStringLiterals;
+
+ FunctionDecl *MsgSendFunctionDecl;
+ FunctionDecl *MsgSendSuperFunctionDecl;
+ FunctionDecl *MsgSendStretFunctionDecl;
+ FunctionDecl *MsgSendSuperStretFunctionDecl;
+ FunctionDecl *MsgSendFpretFunctionDecl;
+ FunctionDecl *GetClassFunctionDecl;
+ FunctionDecl *GetMetaClassFunctionDecl;
+ 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;
+
+ std::string Preamble;
+
+ // Block expressions.
+ llvm::SmallVector<BlockExpr *, 32> Blocks;
+ llvm::SmallVector<BlockDeclRefExpr *, 32> BlockDeclRefs;
+ llvm::DenseMap<BlockDeclRefExpr *, CallExpr *> BlockCallExprs;
+
+ // Block related declarations.
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> BlockByRefDecls;
+ llvm::SmallPtrSet<ValueDecl *, 8> ImportedBlockDecls;
+
+ 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;
+ 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);
+ const std::string &Str = S.str();
+
+ // If replacement succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(SrcRange.getBegin(), Size, &Str[0], Str.size())) {
+ ReplacedNodes[Old] = New;
+ return;
+ }
+ if (SilenceRewriteMacroWarning)
+ return;
+ Diags.Report(Context->getFullLoc(Old->getLocStart()), RewriteFailedDiag)
+ << Old->getSourceRange();
+ }
+
+ void InsertText(SourceLocation Loc, const char *StrData, unsigned StrLen,
+ bool InsertAfter = true) {
+ // If insertion succeeded or warning disabled return with no warning.
+ if (!Rewrite.InsertText(Loc, StrData, StrLen, 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,
+ const char *NewStr, unsigned NewLength) {
+ // If removal succeeded or warning disabled return with no warning.
+ if (!Rewrite.ReplaceText(Start, OrigLength, NewStr, NewLength) ||
+ 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 RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
+ void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
+ void RewriteForwardProtocolDecl(ObjCForwardProtocolDecl *Dcl);
+ void RewriteMethodDeclaration(ObjCMethodDecl *Method);
+ void RewriteProperty(ObjCPropertyDecl *prop);
+ void RewriteFunctionDecl(FunctionDecl *FD);
+ void RewriteObjCQualifiedInterfaceTypes(Decl *Dcl);
+ void RewriteObjCQualifiedInterfaceTypes(Expr *E);
+ bool needToScanForQualifiers(QualType T);
+ ObjCInterfaceDecl *isSuperReceiver(Expr *recExpr);
+ QualType getSuperStructType();
+ QualType getConstantStringStructType();
+ 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);
+ 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 WarnAboutReturnGotoContinueOrBreakStmts(Stmt *S);
+ 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);
+ Stmt *SynthMessageExpr(ObjCMessageExpr *Exp);
+ 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 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(ObjCImplementationDecl *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);
+ Stmt *RewriteBlockDeclRefExpr(BlockDeclRefExpr *VD);
+ 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,
+ bool hasCopyDisposeHelpers);
+ Stmt *SynthesizeBlockCall(CallExpr *Exp);
+ void SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName);
+
+ void CollectBlockDeclRefInfo(BlockExpr *Exp);
+ void GetBlockCallExprs(Stmt *S);
+ void GetBlockDeclRefExprs(Stmt *S);
+
+ // 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);
+ }
+
+ // 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->getAsPointerType()) {
+ if (isa<ObjCInterfaceType>(PT->getPointeeType()) ||
+ isa<ObjCQualifiedIdType>(PT->getPointeeType()))
+ 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);
+
+ void QuoteDoublequotes(std::string &From, std::string &To) {
+ for(unsigned i = 0; i < From.length(); i++) {
+ if (From[i] == '"')
+ To += "\\\"";
+ else
+ To += From[i];
+ }
+ }
+ };
+}
+
+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->getAsPointerType();
+ 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;
+ SelGetUidFunctionDecl = 0;
+ CFStringFunctionDecl = 0;
+ ConstantStringClassReference = 0;
+ NSStringRecord = 0;
+ CurMethodDef = 0;
+ CurFunctionDef = 0;
+ GlobalVarDecl = 0;
+ SuperStructDecl = 0;
+ ProtocolTypeDecl = 0;
+ ConstantStringDecl = 0;
+ BcLabelCount = 0;
+ SuperContructorFunctionDecl = 0;
+ NumObjCStringLiterals = 0;
+ PropParentMap = 0;
+ CurrentBody = 0;
+ DisableReplaceStmt = 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_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 Size;\n";
+ Preamble += " void *FuncPtr;\n";
+ Preamble += "};\n";
+ Preamble += "// Runtime copy/destroy helper functions (from Block_private.h)\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_assign(void *, const void *, const int);\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void _Block_object_dispose(const void *, const int);\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteGlobalBlock[32];\n";
+ Preamble += "__OBJC_RW_STATICIMPORT void *_NSConcreteStackBlock[32];\n";
+ Preamble += "#endif\n";
+ if (LangOpts.Microsoft) {
+ Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
+ Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
+ Preamble += "#define __attribute__(X)\n";
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
+ // 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(*Context),
+ DIEnd = LSD->decls_end(*Context);
+ 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);
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.first;
+ const char *MainBufEnd = MainBuf.second;
+ size_t ImportLen = strlen("import");
+ size_t IncludeLen = strlen("include");
+
+ // 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", IncludeLen);
+ BufPtr += ImportLen;
+ }
+ }
+ }
+}
+
+void RewriteObjC::RewriteTabs() {
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ const char *MainBufStart = MainBuf.first;
+ const char *MainBufEnd = MainBuf.second;
+
+ // 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, " ", Spaces);
+ }
+}
+
+static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl,
+ ObjCIvarDecl *OID) {
+ std::string S;
+ S = "((struct ";
+ S += ClassDecl->getIdentifier()->getName();
+ S += "_IMPL *)self)->";
+ S += OID->getNameAsCString();
+ return S;
+}
+
+void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
+ ObjCImplementationDecl *IMD,
+ ObjCCategoryImplDecl *CID) {
+ SourceLocation startLoc = PID->getLocStart();
+ InsertText(startLoc, "// ", 3);
+ 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;
+
+ std::string Getr;
+ RewriteObjCMethodDecl(PD->getGetterMethodDecl(), Getr);
+ Getr += "{ ";
+ // Synthesize an explicit cast to gain access to the ivar.
+ // FIXME: deal with code generation implications for various property
+ // attributes (copy, retain, nonatomic).
+ // See objc-act.c:objc_synthesize_new_getter() for details.
+ Getr += "return " + getIvarAccessString(ClassDecl, OID);
+ Getr += "; }";
+ InsertText(onePastSemiLoc, Getr.c_str(), Getr.size());
+ if (PD->isReadOnly())
+ return;
+
+ // Generate the 'setter' function.
+ std::string Setr;
+ RewriteObjCMethodDecl(PD->getSetterMethodDecl(), Setr);
+ Setr += "{ ";
+ // Synthesize an explicit cast to initialize the ivar.
+ // FIXME: deal with code generation implications for various property
+ // attributes (copy, retain, nonatomic).
+ // See objc-act.c:objc_synthesize_new_setter() for details.
+ Setr += getIvarAccessString(ClassDecl, OID) + " = ";
+ Setr += PD->getNameAsCString();
+ Setr += "; }";
+ InsertText(onePastSemiLoc, Setr.c_str(), Setr.size());
+}
+
+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 += "// ";
+ typedefString.append(startBuf, semiPtr-startBuf+1);
+ typedefString += "\n";
+ for (ObjCClassDecl::iterator I = ClassDecl->begin(), E = ClassDecl->end();
+ I != E; ++I) {
+ ObjCInterfaceDecl *ForwardDecl = *I;
+ 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.c_str(), typedefString.size());
+}
+
+void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
+ SourceLocation LocStart = Method->getLocStart();
+ SourceLocation LocEnd = Method->getLocEnd();
+
+ if (SM->getInstantiationLineNumber(LocEnd) >
+ SM->getInstantiationLineNumber(LocStart)) {
+ InsertText(LocStart, "#if 0\n", 6);
+ ReplaceText(LocEnd, 1, ";\n#endif\n", 9);
+ } else {
+ InsertText(LocStart, "// ", 3);
+ }
+}
+
+void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop)
+{
+ SourceLocation Loc = prop->getLocation();
+
+ ReplaceText(Loc, 0, "// ", 3);
+
+ // 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, "// ", 3);
+
+ for (ObjCCategoryDecl::instmeth_iterator
+ I = CatDecl->instmeth_begin(*Context),
+ E = CatDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCCategoryDecl::classmeth_iterator
+ I = CatDecl->classmeth_begin(*Context),
+ E = CatDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(CatDecl->getAtEndLoc(), 0, "// ", 3);
+}
+
+void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+
+ SourceLocation LocStart = PDecl->getLocStart();
+
+ // FIXME: handle protocol headers that are declared across multiple lines.
+ ReplaceText(LocStart, 0, "// ", 3);
+
+ for (ObjCProtocolDecl::instmeth_iterator
+ I = PDecl->instmeth_begin(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCProtocolDecl::classmeth_iterator
+ I = PDecl->classmeth_begin(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ SourceLocation LocEnd = PDecl->getAtEndLoc();
+ ReplaceText(LocEnd, 0, "// ", 3);
+
+ // 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"))) {
+ std::string CommentedOptional = "/* @optional */";
+ SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@optional"),
+ CommentedOptional.c_str(), CommentedOptional.size());
+
+ }
+ else if (*p == '@' && !strncmp(p+1, "required", strlen("required"))) {
+ std::string CommentedRequired = "/* @required */";
+ SourceLocation OptionalLoc = LocStart.getFileLocWithOffset(p-startBuf);
+ ReplaceText(OptionalLoc, strlen("@required"),
+ CommentedRequired.c_str(), CommentedRequired.size());
+
+ }
+ }
+}
+
+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, "// ", 3);
+}
+
+void RewriteObjC::RewriteObjCMethodDecl(ObjCMethodDecl *OMD,
+ std::string &ResultStr) {
+ //fprintf(stderr,"In RewriteObjCMethodDecl\n");
+ const FunctionType *FPRetType = 0;
+ ResultStr += "\nstatic ";
+ if (OMD->getResultType()->isObjCQualifiedIdType())
+ ResultStr += "id";
+ else if (OMD->getResultType()->isFunctionPointerType() ||
+ OMD->getResultType()->isBlockPointerType()) {
+ // needs special handling, since pointer-to-functions have special
+ // syntax (where a decaration models use).
+ QualType retType = OMD->getResultType();
+ QualType PointeeTy;
+ if (const PointerType* PT = retType->getAsPointerType())
+ PointeeTy = PT->getPointeeType();
+ else if (const BlockPointerType *BPT = retType->getAsBlockPointerType())
+ PointeeTy = BPT->getPointeeType();
+ if ((FPRetType = PointeeTy->getAsFunctionType())) {
+ ResultStr += FPRetType->getResultType().getAsString();
+ ResultStr += "(*";
+ }
+ } else
+ ResultStr += OMD->getResultType().getAsString();
+ 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();
+ if (isTopLevelBlockPointerType(PDecl->getType())) {
+ // Make sure we convert "t (^)(...)" to "t (*)(...)".
+ const BlockPointerType *BPT = PDecl->getType()->getAsBlockPointerType();
+ Context->getPointerType(BPT->getPointeeType()).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);
+
+ if (IMD)
+ InsertText(IMD->getLocStart(), "// ", 3);
+ else
+ InsertText(CID->getLocStart(), "// ", 3);
+
+ for (ObjCCategoryImplDecl::instmeth_iterator
+ I = IMD ? IMD->instmeth_begin(*Context) : CID->instmeth_begin(*Context),
+ E = IMD ? IMD->instmeth_end(*Context) : CID->instmeth_end(*Context);
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf,
+ ResultStr.c_str(), ResultStr.size());
+ }
+
+ for (ObjCCategoryImplDecl::classmeth_iterator
+ I = IMD ? IMD->classmeth_begin(*Context) : CID->classmeth_begin(*Context),
+ E = IMD ? IMD->classmeth_end(*Context) : CID->classmeth_end(*Context);
+ I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
+
+ const char *startBuf = SM->getCharacterData(LocStart);
+ const char *endBuf = SM->getCharacterData(LocEnd);
+ ReplaceText(LocStart, endBuf-startBuf,
+ ResultStr.c_str(), ResultStr.size());
+ }
+ for (ObjCCategoryImplDecl::propimpl_iterator
+ I = IMD ? IMD->propimpl_begin(*Context) : CID->propimpl_begin(*Context),
+ E = IMD ? IMD->propimpl_end(*Context) : CID->propimpl_end(*Context);
+ I != E; ++I) {
+ RewritePropertyImplDecl(*I, IMD, CID);
+ }
+
+ if (IMD)
+ InsertText(IMD->getLocEnd(), "// ", 3);
+ else
+ InsertText(CID->getLocEnd(), "// ", 3);
+}
+
+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(*Context),
+ E = ClassDecl->prop_end(*Context); I != E; ++I)
+ RewriteProperty(*I);
+ for (ObjCInterfaceDecl::instmeth_iterator
+ I = ClassDecl->instmeth_begin(*Context),
+ E = ClassDecl->instmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator
+ I = ClassDecl->classmeth_begin(*Context),
+ E = ClassDecl->classmeth_end(*Context);
+ I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(ClassDecl->getAtEndLoc(), 0, "// ", 3);
+}
+
+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];
+ }
+ MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ PDecl->getSetterName(), PDecl->getType(),
+ PDecl->getSetterMethodDecl(),
+ SourceLocation(), SourceLocation(),
+ &ExprVec[0], 1);
+ 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];
+ }
+ MsgExpr = new (Context) ObjCMessageExpr(dyn_cast<Expr>(Receiver),
+ PDecl->getGetterName(), PDecl->getType(),
+ PDecl->getGetterMethodDecl(),
+ SourceLocation(), SourceLocation(),
+ 0, 0);
+
+ 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) {
+ ObjCIvarDecl *D = IV->getDecl();
+ if (CurMethodDef) {
+ if (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
+ ObjCInterfaceType *iFaceDecl =
+ dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(*Context,
+ 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.c_str());
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT, IV->getBase(),
+ castT,SourceLocation(),
+ SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(),
+ castExpr);
+ if (IV->isFreeIvar() &&
+ CurMethodDef->getClassInterface() == iFaceDecl->getDecl()) {
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, D,
+ IV->getLocation(),
+ D->getType());
+ ReplaceStmt(IV, ME);
+ // delete IV; leak for now, see RewritePropertySetter() usage for more info.
+ return ME;
+ }
+
+ ReplaceStmt(IV->getBase(), PE);
+ // 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 (const PointerType *pType = IV->getBase()->getType()->getAsPointerType()) {
+ ObjCInterfaceType *iFaceDecl = dyn_cast<ObjCInterfaceType>(pType->getPointeeType());
+ // lookup which class implements the instance variable.
+ ObjCInterfaceDecl *clsDeclared = 0;
+ iFaceDecl->getDecl()->lookupInstanceVariable(*Context,
+ 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.c_str());
+ RecordDecl *RD = RecordDecl::Create(*Context, TagDecl::TK_struct, TUDecl,
+ SourceLocation(), II);
+ assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
+ QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
+ CastExpr *castExpr = new (Context) CStyleCastExpr(castT, IV->getBase(),
+ castT, SourceLocation(),
+ SourceLocation());
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
+ IV->getBase()->getLocEnd(), castExpr);
+ ReplaceStmt(IV->getBase(), PE);
+ // 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;
+}
+
+/// 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.c_str(), buf.size());
+
+ 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.c_str(), buf.size());
+
+ 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();
+ 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();
+ elementTypeAsString
+ = cast<ValueDecl>(DR->getDecl())->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.c_str(), buf.size());
+ // 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.c_str(), buf.size());
+
+ /// __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 += " = ((id)0);\n\t";
+ buf += "__break_label_";
+ buf += utostr(ObjCBcLabelNo.back());
+ buf += ": ;\n\t";
+ buf += "}\n\t";
+ buf += "else\n\t\t";
+ buf += elementName;
+ buf += " = ((id)0);\n";
+ 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.c_str(), buf.size());
+ } 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.c_str(), buf.size());
+ }
+ 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.c_str(), buf.size());
+ // 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.c_str(), buf.size());
+ 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";
+ buf += " objc_sync_exit(";
+ Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ S->getSynchExpr(),
+ Context->getObjCIdType(),
+ SourceLocation(),
+ SourceLocation());
+ std::string syncExprBufS;
+ llvm::raw_string_ostream syncExprBuf(syncExprBufS);
+ syncExpr->printPretty(syncExprBuf, *Context);
+ buf += syncExprBuf.str();
+ buf += ");\n";
+ buf += " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ buf += "}\n";
+ buf += "}";
+
+ ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ return 0;
+}
+
+void RewriteObjC::WarnAboutReturnGotoContinueOrBreakStmts(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)
+ WarnAboutReturnGotoContinueOrBreakStmts(*CI);
+
+ if (isa<ReturnStmt>(S) || isa<ContinueStmt>(S) ||
+ isa<BreakStmt>(S) || isa<GotoStmt>(S)) {
+ Diags.Report(Context->getFullLoc(S->getLocStart()),
+ TryFinallyContainsReturnDiag);
+ }
+ 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.c_str(), buf.size());
+
+ startLoc = S->getTryBody()->getLocEnd();
+ startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '}') && "bogus @try block");
+
+ SourceLocation lastCurlyLoc = startLoc;
+ ObjCAtCatchStmt *catchList = S->getCatchStmts();
+ if (catchList) {
+ 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.c_str(), buf.size());
+ } else { /* no catch list */
+ buf = "}\nelse {\n";
+ buf += " _rethrow = objc_exception_extract(&_stack);\n";
+ buf += "}";
+ ReplaceText(lastCurlyLoc, 1, buf.c_str(), buf.size());
+ }
+ bool sawIdTypedCatch = false;
+ Stmt *lastCatchBody = 0;
+ while (catchList) {
+ ParmVarDecl *catchDecl = catchList->getCatchParamDecl();
+
+ if (catchList == S->getCatchStmts())
+ buf = "if ("; // we are generating code for the first catch clause
+ else
+ buf = "else if (";
+ startLoc = catchList->getLocStart();
+ startBuf = SM->getCharacterData(startLoc);
+
+ assert((*startBuf == '@') && "bogus @catch location");
+
+ const char *lParenLoc = strchr(startBuf, '(');
+
+ if (catchList->hasEllipsis()) {
+ // Now rewrite the body...
+ lastCatchBody = catchList->getCatchBody();
+ SourceLocation bodyLoc = lastCatchBody->getLocStart();
+ const char *bodyBuf = SM->getCharacterData(bodyLoc);
+ assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' &&
+ "bogus @catch paren location");
+ assert((*bodyBuf == '{') && "bogus @catch body location");
+
+ buf += "1) { id _tmp = _caught;";
+ Rewrite.ReplaceText(startLoc, bodyBuf-startBuf+1,
+ buf.c_str(), buf.size());
+ } else if (catchDecl) {
+ QualType t = catchDecl->getType();
+ if (t == Context->getObjCIdType()) {
+ buf += "1) { ";
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ sawIdTypedCatch = true;
+ } else if (const PointerType *pType = t->getAsPointerType()) {
+ ObjCInterfaceType *cls; // Should be a pointer to a class.
+
+ cls = dyn_cast<ObjCInterfaceType>(pType->getPointeeType().getTypePtr());
+ if (cls) {
+ buf += "objc_exception_match((struct objc_class *)objc_getClass(\"";
+ buf += cls->getDecl()->getNameAsString();
+ buf += "\"), (struct objc_object *)_caught)) { ";
+ ReplaceText(startLoc, lParenLoc-startBuf+1, buf.c_str(), buf.size());
+ }
+ }
+ // Now rewrite the body...
+ lastCatchBody = catchList->getCatchBody();
+ SourceLocation rParenLoc = catchList->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");
+
+ buf = " = _caught;";
+ // Here we replace ") {" with "= _caught;" (which initializes and
+ // declares the @catch parameter).
+ ReplaceText(rParenLoc, bodyBuf-rParenBuf+1, buf.c_str(), buf.size());
+ } else {
+ assert(false && "@catch rewrite bug");
+ }
+ // make sure all the catch bodies get rewritten!
+ catchList = catchList->getNextCatchStmt();
+ }
+ // 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.c_str(), buf.size());
+
+ // Set lastCurlyLoc
+ lastCurlyLoc = lastCatchBody->getLocEnd();
+ }
+ if (ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt()) {
+ startLoc = finalStmt->getLocStart();
+ startBuf = SM->getCharacterData(startLoc);
+ assert((*startBuf == '@') && "bogus @finally start");
+
+ buf = "/* @finally */";
+ ReplaceText(startLoc, 8, buf.c_str(), buf.size());
+
+ 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);
+ buf = " if (!_rethrow) objc_exception_try_exit(&_stack);\n";
+ InsertText(startLoc, buf.c_str(), buf.size());
+ endLoc = endLoc.getFileLocWithOffset(-1);
+ buf = " if (_rethrow) objc_exception_throw(_rethrow);\n";
+ InsertText(endLoc, buf.c_str(), buf.size());
+
+ // Set lastCurlyLoc
+ lastCurlyLoc = body->getLocEnd();
+
+ // Now check for any return/continue/go statements within the @try.
+ WarnAboutReturnGotoContinueOrBreakStmts(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.c_str(), buf.size());
+ }
+ // Now emit the final closing curly brace...
+ lastCurlyLoc = lastCurlyLoc.getFileLocWithOffset(1);
+ buf = " } /* @try scope end */\n";
+ InsertText(lastCurlyLoc, buf.c_str(), buf.size());
+ 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.c_str(), buf.size());
+
+ const char *semiBuf = strchr(startBuf, ';');
+ assert((*semiBuf == ';') && "@throw: can't find ';'");
+ SourceLocation semiLoc = startLoc.getFileLocWithOffset(semiBuf-startBuf);
+ buf = ");";
+ ReplaceText(semiLoc, 1, buf.c_str(), buf.size());
+ 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) {
+ // 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, DRE,
+ /*isLvalue=*/false);
+
+ const FunctionType *FT = msgSendType->getAsFunctionType();
+
+ return new (Context) CallExpr(*Context, ICE, args, nargs, FT->getResultType(),
+ SourceLocation());
+}
+
+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 *pType = T->getAsPointerType()) {
+ Type *pointeeType = pType->getPointeeType().getTypePtr();
+ if (isa<ObjCQualifiedInterfaceType>(pointeeType))
+ return true; // we have "Class <Protocol> *".
+ }
+ 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, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ }
+}
+
+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()->getAsFunctionType();
+ assert(funcType && "missing function type");
+ proto = dyn_cast<FunctionProtoType>(funcType);
+ if (!proto)
+ return;
+ Type = proto->getResultType();
+ }
+ 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, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ }
+ 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, "/*", 2);
+ InsertText(GreaterLoc, "*/", 2);
+ }
+ 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++;
+ }
+ }
+}
+
+// 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.getQualifiedType(QualType::Const)));
+ QualType getFuncType = Context->getFunctionType(Context->getObjCSelType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SelGetUidIdent, getFuncType,
+ FunctionDecl::Extern, 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);
+}
+
+// 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);
+ SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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);
+ MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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, TagDecl::TK_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);
+ MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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);
+ MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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, TagDecl::TK_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);
+ MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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);
+ MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ FunctionDecl::Extern, 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.getQualifiedType(QualType::Const)));
+ QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ getClassIdent, getClassType,
+ FunctionDecl::Extern, 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.getQualifiedType(QualType::Const)));
+ QualType getClassType = Context->getFunctionType(Context->getObjCIdType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ getClassIdent, getClassType,
+ FunctionDecl::Extern, 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);
+ Preamble += prettyBuf.str();
+ Preamble += ",";
+ // The minus 2 removes the begin/end double quotes.
+ Preamble += utostr(prettyBuf.str().size()-2) + "};\n";
+
+ VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
+ &Context->Idents.get(S.c_str()), strType,
+ VarDecl::Static);
+ 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 = new (Context) CStyleCastExpr(Exp->getType(), Unop,
+ Exp->getType(), SourceLocation(), SourceLocation());
+ ReplaceStmt(Exp, cast);
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return cast;
+}
+
+ObjCInterfaceDecl *RewriteObjC::isSuperReceiver(Expr *recExpr) {
+ // check if we are sending a message to 'super'
+ if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return 0;
+
+ if (ObjCSuperExpr *Super = dyn_cast<ObjCSuperExpr>(recExpr)) {
+ const PointerType *PT = Super->getType()->getAsPointerType();
+ assert(PT);
+ ObjCInterfaceType *IT = cast<ObjCInterfaceType>(PT->getPointeeType());
+ return IT->getDecl();
+ }
+ return 0;
+}
+
+// struct objc_super { struct objc_object *receiver; struct objc_class *super; };
+QualType RewriteObjC::getSuperStructType() {
+ if (!SuperStructDecl) {
+ SuperStructDecl = RecordDecl::Create(*Context, TagDecl::TK_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(*Context,
+ FieldDecl::Create(*Context, SuperStructDecl,
+ SourceLocation(), 0,
+ FieldTypes[i], /*BitWidth=*/0,
+ /*Mutable=*/false));
+ }
+
+ SuperStructDecl->completeDefinition(*Context);
+ }
+ return Context->getTagDeclType(SuperStructDecl);
+}
+
+QualType RewriteObjC::getConstantStringStructType() {
+ if (!ConstantStringDecl) {
+ ConstantStringDecl = RecordDecl::Create(*Context, TagDecl::TK_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(*Context,
+ FieldDecl::Create(*Context,
+ ConstantStringDecl,
+ SourceLocation(), 0,
+ FieldTypes[i],
+ /*BitWidth=*/0,
+ /*Mutable=*/true));
+ }
+
+ ConstantStringDecl->completeDefinition(*Context);
+ }
+ return Context->getTagDeclType(ConstantStringDecl);
+}
+
+Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
+ if (!SelGetUidFunctionDecl)
+ SynthSelGetUidFunctionDecl();
+ if (!MsgSendFunctionDecl)
+ SynthMsgSendFunctionDecl();
+ if (!MsgSendSuperFunctionDecl)
+ SynthMsgSendSuperFunctionDecl();
+ if (!MsgSendStretFunctionDecl)
+ SynthMsgSendStretFunctionDecl();
+ if (!MsgSendSuperStretFunctionDecl)
+ SynthMsgSendSuperStretFunctionDecl();
+ if (!MsgSendFpretFunctionDecl)
+ SynthMsgSendFpretFunctionDecl();
+ if (!GetClassFunctionDecl)
+ SynthGetClassFunctionDecl();
+ 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->isStructureType() || resultType->isUnionType())
+ MsgSendStretFlavor = MsgSendStretFunctionDecl;
+ else if (resultType->isRealFloatingType())
+ MsgSendFlavor = MsgSendFpretFunctionDecl;
+ }
+
+ // Synthesize a call to objc_msgSend().
+ llvm::SmallVector<Expr*, 8> MsgExprs;
+ IdentifierInfo *clsName = Exp->getClassName();
+
+ // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend().
+ if (clsName) { // class message.
+ // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle
+ // the 'super' idiom within a class method.
+ if (!strcmp(clsName->getName(), "super")) {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ ObjCInterfaceDecl *SuperDecl =
+ CurMethodDef->getClassInterface()->getSuperClass();
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ // set the receiver to self, the first argument to all methods.
+ InitExprs.push_back(
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()),
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation())); // set the 'receiver'.
+
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ SuperDecl->getIdentifier()->getName(),
+ SuperDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back( // set 'super class', using objc_getClass().
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ Cls, Context->getObjCIdType(),
+ SourceLocation(), SourceLocation()));
+ // 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 = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ SuperRep, Context->getPointerType(superType),
+ SourceLocation(), SourceLocation());
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE,
+ false);
+ // struct objc_super *
+ SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
+ Context->getPointerType(SuperRep->getType()),
+ SourceLocation());
+ }
+ MsgExprs.push_back(SuperRep);
+ } else {
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ clsName->getName(),
+ clsName->getLength(),
+ false, argType,
+ SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ MsgExprs.push_back(Cls);
+ }
+ } else { // instance message.
+ Expr *recExpr = Exp->getReceiver();
+
+ if (ObjCInterfaceDecl *SuperDecl = isSuperReceiver(recExpr)) {
+ MsgSendFlavor = MsgSendSuperFunctionDecl;
+ if (MsgSendStretFlavor)
+ MsgSendStretFlavor = MsgSendSuperStretFunctionDecl;
+ assert(MsgSendFlavor && "MsgSendFlavor is NULL!");
+
+ llvm::SmallVector<Expr*, 4> InitExprs;
+
+ InitExprs.push_back(
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()),
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation())); // set the 'receiver'.
+
+ llvm::SmallVector<Expr*, 8> ClsExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ClsExprs.push_back(StringLiteral::Create(*Context,
+ SuperDecl->getIdentifier()->getName(),
+ SuperDecl->getIdentifier()->getLength(),
+ false, argType, SourceLocation()));
+ CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl,
+ &ClsExprs[0],
+ ClsExprs.size());
+ // To turn off a warning, type-cast to 'id'
+ InitExprs.push_back(
+ // set 'super class', using objc_getClass().
+ new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation()));
+ // 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 = new (Context) CStyleCastExpr(Context->getPointerType(superType),
+ SuperRep, Context->getPointerType(superType),
+ SourceLocation(), SourceLocation());
+ } else {
+ // (struct objc_super) { <exprs from above> }
+ InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
+ &InitExprs[0], InitExprs.size(),
+ SourceLocation());
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
+ }
+ MsgExprs.push_back(SuperRep);
+ } else {
+ // Remove all type-casts because it may contain objc-style types; e.g.
+ // Foo<Proto> *.
+ while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
+ recExpr = CE->getSubExpr();
+ recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), recExpr,
+ Context->getObjCIdType(),
+ SourceLocation(), SourceLocation());
+ MsgExprs.push_back(recExpr);
+ }
+ }
+ // 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());
+ 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();
+ userExpr = new (Context) CStyleCastExpr(type, userExpr, type, SourceLocation(), SourceLocation());
+ }
+ // 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 = new (Context) CStyleCastExpr(Context->getObjCIdType(),
+ userExpr, Context->getObjCIdType(),
+ SourceLocation(), SourceLocation());
+ }
+ }
+ 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 (*)(...)".
+ if (isTopLevelBlockPointerType(t)) {
+ const BlockPointerType *BPT = t->getAsBlockPointerType();
+ t = Context->getPointerType(BPT->getPointeeType());
+ }
+ ArgTypes.push_back(t);
+ }
+ returnType = OMD->getResultType()->isObjCQualifiedIdType()
+ ? Context->getObjCIdType() : OMD->getResultType();
+ } 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 = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), DRE,
+ Context->getPointerType(Context->VoidTy),
+ SourceLocation(), SourceLocation());
+
+ // 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);
+ castType = Context->getPointerType(castType);
+ cast = new (Context) CStyleCastExpr(castType, cast, castType, SourceLocation(), SourceLocation());
+
+ // Don't forget the parens to enforce the proper binding.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
+
+ const FunctionType *FT = msgSendType->getAsFunctionType();
+ CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), SourceLocation());
+ 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 = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), STDRE,
+ Context->getPointerType(Context->VoidTy),
+ SourceLocation(), SourceLocation());
+ // Now do the "normal" pointer to function cast.
+ castType = Context->getFunctionType(returnType,
+ &ArgTypes[0], ArgTypes.size(),
+ Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0);
+ castType = Context->getPointerType(castType);
+ cast = new (Context) CStyleCastExpr(castType, cast, castType, SourceLocation(), SourceLocation());
+
+ // Don't forget the parens to enforce the proper binding.
+ PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
+
+ FT = msgSendType->getAsFunctionType();
+ CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0],
+ MsgExprs.size(),
+ FT->getResultType(), SourceLocation());
+
+ // Build sizeof(returnType)
+ SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true,
+ 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, CE, 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);
+
+ // 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) {
+ ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ &Context->Idents.get("Protocol"),
+ Context->getObjCIdType());
+ }
+ 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, QualType()/*UNUSED*/, VarDecl::Extern);
+ DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation());
+ Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
+ Context->getPointerType(DRE->getType()),
+ SourceLocation());
+ CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(), DerefExpr,
+ DerefExpr->getType(),
+ SourceLocation(), SourceLocation());
+ 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.c_str(), Result.size());
+ 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.c_str(), Result.size());
+ } else {
+ // rewrite the original header *without* disturbing the '{'
+ ReplaceText(LocStart, cursor-startBuf-1, Result.c_str(), Result.size());
+ }
+ 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.c_str(), Result.size());
+ }
+ 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, "// ", 3);
+ }
+ // 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, "/* ", 3);
+ cursor = strchr(cursor, '>');
+ cursor++;
+ atLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ InsertText(atLoc, " */", 3);
+ } else if (*cursor == '^') { // rewrite block specifier.
+ SourceLocation caretLoc = LocStart.getFileLocWithOffset(cursor-startBuf);
+ ReplaceText(caretLoc, 1, "*", 1);
+ }
+ cursor++;
+ }
+ // Don't forget to add a ';'!!
+ InsertText(LocEnd.getFileLocWithOffset(1), ";", 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.c_str(), Result.size());
+ }
+ // 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;
+
+ static bool objc_impl_method = false;
+ 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(*Context) != PDecl->instmeth_end(*Context)) {
+ unsigned NumMethods = std::distance(PDecl->instmeth_begin(*Context),
+ PDecl->instmeth_end(*Context));
+ /* 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(*Context),
+ E = PDecl->instmeth_end(*Context);
+ I != E; ++I) {
+ if (I == PDecl->instmeth_begin(*Context))
+ 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(*Context),
+ PDecl->classmeth_end(*Context));
+ 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(*Context),
+ E = PDecl->classmeth_end(*Context);
+ I != E; ++I) {
+ if (I == PDecl->classmeth_begin(*Context))
+ 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(*Context) != PDecl->instmeth_end(*Context)) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += ", ";
+ }
+ else
+ Result += "0, ";
+ if (PDecl->classmeth_begin(*Context) != PDecl->classmeth_end(*Context)) {
+ 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(*Context),
+ IDecl->instmeth_end(*Context));
+
+ // 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(*Context),
+ PropEnd = IDecl->propimpl_end(*Context);
+ 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(*Context),
+ IDecl->classmeth_end(*Context),
+ 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(*Context) != IDecl->instmeth_end(*Context)) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_INSTANCE_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ if (IDecl->classmeth_begin(*Context) != IDecl->classmeth_end(*Context)) {
+ 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(ObjCImplementationDecl *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(*Context)
+ ? IDecl->ivar_size(*Context)
+ : (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(*Context)) {
+ for (ObjCImplementationDecl::ivar_iterator
+ IV = IDecl->ivar_begin(*Context),
+ IVEnd = IDecl->ivar_end(*Context);
+ IV != IVEnd; ++IV)
+ IVars.push_back(*IV);
+ IVI = IVars.begin();
+ IVE = IVars.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(*Context),
+ IDecl->instmeth_end(*Context));
+
+ // 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(*Context),
+ PropEnd = IDecl->propimpl_end(*Context);
+ 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(*Context),
+ IDecl->classmeth_end(*Context),
+ 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(*Context) != IDecl->classmeth_end(*Context)) {
+ 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(*Context) != IDecl->instmeth_end(*Context)) {
+ 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();
+
+ // This is needed for determining instance variable offsets.
+ Result += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((int) &((TYPE *)0)->MEMBER)\n";
+ // 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";
+ }
+}
+
+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();
+ (*AI)->getType().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::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ Context->getPointerType((*I)->getType()).getAsStringInternal(Name,
+ Context->PrintingPolicy);
+ S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n";
+ }
+ // Next, emit a declaration for all "by copy" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
+ E = BlockByCopyDecls.end(); I != E; ++I) {
+ S += " ";
+ std::string Name = (*I)->getNameAsString();
+ // 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()))
+ S += "struct __block_impl *";
+ else
+ (*I)->getType().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();
+ S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);}";
+ }
+ 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();
+ S += ", 3/*BLOCK_FIELD_IS_OBJECT*/);";
+ }
+ S += "}\n";
+ return S;
+}
+
+std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag,
+ bool hasCopyDisposeHelpers) {
+ std::string S = "\nstruct " + Tag;
+ std::string Constructor = " " + Tag;
+
+ S += " {\n struct __block_impl impl;\n";
+
+ if (hasCopyDisposeHelpers)
+ S += " void *copy;\n void *dispose;\n";
+
+ Constructor += "(void *fp";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += ", void *copyHelp, void *disposeHelp";
+
+ if (BlockDeclRefs.size()) {
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<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 {
+ (*I)->getType().getAsStringInternal(FieldName, Context->PrintingPolicy);
+ (*I)->getType().getAsStringInternal(ArgName, Context->PrintingPolicy);
+ Constructor += ", " + ArgName;
+ }
+ S += FieldName + ";\n";
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<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 {
+ Context->getPointerType((*I)->getType()).getAsStringInternal(FieldName,
+ Context->PrintingPolicy);
+ Context->getPointerType((*I)->getType()).getAsStringInternal(ArgName,
+ Context->PrintingPolicy);
+ 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.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+
+ // Initialize all "by copy" arguments.
+ for (llvm::SmallPtrSet<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::SmallPtrSet<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 + ";\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.Size = sizeof(";
+ Constructor += Tag + ");\n impl.Flags = flags;\n impl.FuncPtr = fp;\n";
+ if (hasCopyDisposeHelpers)
+ Constructor += " copy = copyHelp;\n dispose = disposeHelp;\n";
+ }
+ Constructor += " ";
+ Constructor += "}\n";
+ S += Constructor;
+ S += "};\n";
+ return S;
+}
+
+void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
+ const char *FunName) {
+ // Insert closures that were part of the function.
+ for (unsigned i = 0; i < Blocks.size(); i++) {
+
+ CollectBlockDeclRefInfo(Blocks[i]);
+
+ std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i);
+
+ std::string CI = SynthesizeBlockImpl(Blocks[i], Tag,
+ ImportedBlockDecls.size() > 0);
+
+ InsertText(FunLocStart, CI.c_str(), CI.size());
+
+ std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag);
+
+ InsertText(FunLocStart, CF.c_str(), CF.size());
+
+ if (ImportedBlockDecls.size()) {
+ std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag);
+ InsertText(FunLocStart, HF.c_str(), HF.size());
+ }
+
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.clear();
+ BlockCallExprs.clear();
+ ImportedBlockDecls.clear();
+ }
+ Blocks.clear();
+ RewrittenBlockExprs.clear();
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) {
+ SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
+ const char *FuncName = FD->getNameAsCString();
+
+ SynthesizeBlockLiterals(FunLocStart, FuncName);
+}
+
+void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) {
+ //fprintf(stderr,"In InsertBlockLiteralsWitinMethod\n");
+ //SourceLocation FunLocStart = MD->getLocStart();
+ // FIXME: This hack works around a bug in Rewrite.InsertText().
+ SourceLocation FunLocStart = MD->getLocStart().getFileLocWithOffset(-1);
+ std::string FuncName = MD->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+
+ 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);
+ return;
+}
+
+void RewriteObjC::GetBlockCallExprs(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))
+ GetBlockCallExprs(CBE->getBody());
+ else
+ GetBlockCallExprs(*CI);
+ }
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ BlockCallExprs[dyn_cast<BlockDeclRefExpr>(CE->getCallee())] = CE;
+ }
+ }
+ return;
+}
+
+Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) {
+ // Navigate to relevant type information.
+ const char *closureName = 0;
+ const BlockPointerType *CPT = 0;
+
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp->getCallee())) {
+ closureName = DRE->getDecl()->getNameAsCString();
+ CPT = DRE->getType()->getAsBlockPointerType();
+ } else if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(Exp->getCallee())) {
+ closureName = CDRE->getDecl()->getNameAsCString();
+ CPT = CDRE->getType()->getAsBlockPointerType();
+ } else if (MemberExpr *MExpr = dyn_cast<MemberExpr>(Exp->getCallee())) {
+ closureName = MExpr->getMemberDecl()->getNameAsCString();
+ CPT = MExpr->getType()->getAsBlockPointerType();
+ } else {
+ assert(1 && "RewriteBlockClass: Bad type");
+ }
+ assert(CPT && "RewriteBlockClass: Bad type");
+ const FunctionType *FT = CPT->getPointeeType()->getAsFunctionType();
+ 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, TagDecl::TK_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 (*)(...)".
+ if (isTopLevelBlockPointerType(t)) {
+ const BlockPointerType *BPT = t->getAsBlockPointerType();
+ t = Context->getPointerType(BPT->getPointeeType());
+ }
+ 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);
+
+ PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
+
+ CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, Exp->getCallee(),
+ PtrBlock, SourceLocation(),
+ SourceLocation());
+ // 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,
+ /*BitWidth=*/0, /*Mutable=*/true);
+ MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
+ FD->getType());
+
+ CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType, ME,
+ PtrToFuncCastType,
+ SourceLocation(),
+ SourceLocation());
+ 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);
+ 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(BlockDeclRefExpr *BDRE) {
+ // FIXME: Add more elaborate code generation required by the ABI.
+ Expr *DerefExpr = new (Context) UnaryOperator(BDRE, UnaryOperator::Deref,
+ Context->getPointerType(BDRE->getType()),
+ SourceLocation());
+ // Need parens to enforce precedence.
+ ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), DerefExpr);
+ ReplaceStmt(BDRE, 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);
+
+ // 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, "*", 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, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
+ }
+ }
+ return;
+}
+
+bool RewriteObjC::PointerTypeTakesAnyBlockArguments(QualType QT) {
+ const FunctionProtoType *FTP;
+ const PointerType *PT = QT->getAsPointerType();
+ if (PT) {
+ FTP = PT->getPointeeType()->getAsFunctionProtoType();
+ } else {
+ const BlockPointerType *BPT = QT->getAsBlockPointerType();
+ assert(BPT && "BlockPointerTypeTakeAnyBlockArguments(): not a block pointer type");
+ FTP = BPT->getPointeeType()->getAsFunctionProtoType();
+ }
+ 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, "*", 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, "*", 1);
+ }
+ argListBegin++;
+ }
+ }
+ 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())
+ BlockByCopyDecls.insert(BlockDeclRefs[i]->getDecl());
+ // Unique all "by ref" declarations.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->isByRef()) {
+ BlockByRefDecls.insert(BlockDeclRefs[i]->getDecl());
+ }
+ // Find any imported blocks...they will need special attention.
+ for (unsigned i = 0; i < BlockDeclRefs.size(); i++)
+ if (BlockDeclRefs[i]->getType()->isBlockPointerType()) {
+ GetBlockCallExprs(BlockDeclRefs[i]);
+ 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, FunctionDecl::Extern, false,
+ false);
+}
+
+Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
+ Blocks.push_back(Exp);
+
+ CollectBlockDeclRefInfo(Exp);
+ std::string FuncName;
+
+ if (CurFunctionDef)
+ FuncName = CurFunctionDef->getNameAsString();
+ else if (CurMethodDef) {
+ FuncName = CurMethodDef->getSelector().getAsString();
+ // Convert colons to underscores.
+ std::string::size_type loc = 0;
+ while ((loc = FuncName.find(":", loc)) != std::string::npos)
+ FuncName.replace(loc, 1, "_");
+ } 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 FType = Context->getPointerType(QualType(Exp->getFunctionType(),0));
+
+ 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 = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+
+ if (ImportedBlockDecls.size()) {
+ std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
+ FD = SynthBlockInitFunctionDecl(Buf.c_str());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+
+ Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
+ FD = SynthBlockInitFunctionDecl(Buf.c_str());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ InitExprs.push_back(castExpr);
+ }
+ // Add initializers for any closure decl refs.
+ if (BlockDeclRefs.size()) {
+ Expr *Exp;
+ // Output all "by copy" declarations.
+ for (llvm::SmallPtrSet<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());
+ } else if (isTopLevelBlockPointerType((*I)->getType())) {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy, Arg,
+ Context->VoidPtrTy, SourceLocation(),
+ SourceLocation());
+ } else {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ }
+ InitExprs.push_back(Exp);
+ }
+ // Output all "by ref" declarations.
+ for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
+ E = BlockByRefDecls.end(); I != E; ++I) {
+ FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
+ Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
+ Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf,
+ Context->getPointerType(Exp->getType()),
+ SourceLocation());
+ InitExprs.push_back(Exp);
+ }
+ }
+ 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 = new (Context) CStyleCastExpr(FType, NewRep, FType, SourceLocation(),
+ SourceLocation());
+ BlockDeclRefs.clear();
+ BlockByRefDecls.clear();
+ BlockByCopyDecls.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 = RewriteFunctionBodyOrGlobalInitializer(*CI);
+ if (newStmt)
+ *CI = newStmt;
+ }
+
+ if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
+ // Rewrite the block body in place.
+ RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
+
+ // Now we snarf the rewritten text and stash it away for later use.
+ std::string Str = Rewrite.getRewritenText(BE->getSourceRange());
+ RewrittenBlockExprs[BE] = Str;
+
+ Stmt *blockTranscribed = SynthBlockInitExpr(BE);
+ //blockTranscribed->dump();
+ ReplaceStmt(S, blockTranscribed);
+ return blockTranscribed;
+ }
+ // Handle specific things.
+ if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
+ return RewriteAtEncode(AtEncode);
+
+ if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
+ return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
+
+ 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.
+ 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 (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 (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ if (CE->getCallee()->getType()->isBlockPointerType()) {
+ Stmt *BlockCall = SynthesizeBlockCall(CE);
+ 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;
+}
+
+/// 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(*Context)) {
+ CurFunctionDef = 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;
+ }
+ return;
+ }
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (CompoundStmt *Body = MD->getBody()) {
+ 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);
+ }
+ }
+ }
+ 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()) {
+ for (RecordDecl::field_iterator i = RD->field_begin(*Context),
+ e = RD->field_end(*Context); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+ // Nothing yet.
+}
+
+void RewriteObjC::HandleTranslationUnit(ASTContext &C) {
+ // Get the top-level buffer that this corresponds to.
+
+ // Rewrite tabs if we care.
+ //RewriteTabs();
+
+ 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.c_str(), Preamble.size(), 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 {
+ fprintf(stderr, "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/lib/Frontend/RewriteTest.cpp b/lib/Frontend/RewriteTest.cpp
new file mode 100644
index 0000000..f9eb58f
--- /dev/null
+++ b/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/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
new file mode 100644
index 0000000..c861881
--- /dev/null
+++ b/lib/Frontend/StmtXML.cpp
@@ -0,0 +1,409 @@
+//===--- 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"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// StmtXML Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class VISIBILITY_HIDDEN StmtXML : public StmtVisitor<StmtXML> {
+ DocumentXML& Doc;
+
+ static const char *getOpcodeStr(UnaryOperator::Opcode Op);
+ static const char *getOpcodeStr(BinaryOperator::Opcode Op);
+
+ public:
+ StmtXML(DocumentXML& doc)
+ : Doc(doc) {
+ }
+
+ void DumpSubTree(Stmt *S) {
+ if (S)
+ {
+ Doc.addSubNode(S->getStmtClassName());
+ Doc.addLocationRange(S->getSourceRange());
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ } else {
+ Visit(S);
+ for (Stmt::child_iterator i = S->child_begin(), e = S->child_end(); i != e; ++i)
+ {
+ DumpSubTree(*i);
+ }
+ }
+ Doc.toParent();
+ } else {
+ Doc.addSubNode("NULL").toParent();
+ }
+ }
+
+ void DumpTypeExpr(const QualType& T)
+ {
+ Doc.addSubNode("TypeExpr");
+ Doc.addTypeAttribute(T);
+ Doc.toParent();
+ }
+
+ void DumpExpr(const Expr *Node) {
+ Doc.addTypeAttribute(Node->getType());
+ }
+
+ // 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 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 VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node);
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
+ void VisitObjCSuperExpr(ObjCSuperExpr *Node);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt printing methods.
+//===----------------------------------------------------------------------===//
+
+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::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::VisitObjCKVCRefExpr(ObjCKVCRefExpr *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");
+}
+
+//===----------------------------------------------------------------------===//
+// 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/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
new file mode 100644
index 0000000..a4518ee
--- /dev/null
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -0,0 +1,39 @@
+//===--- 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> StrC;
+ Info.FormatDiagnostic(StrC);
+ std::string Str(StrC.begin(), StrC.end());
+ switch (Level) {
+ default: assert(0 && "Diagnostic not handled during diagnostic buffering!");
+ case Diagnostic::Note:
+ Notes.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ case Diagnostic::Warning:
+ Warnings.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ case Diagnostic::Error:
+ case Diagnostic::Fatal:
+ Errors.push_back(std::make_pair(Info.getLocation(), Str));
+ break;
+ }
+}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
new file mode 100644
index 0000000..b1c0533
--- /dev/null
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -0,0 +1,710 @@
+//===--- 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/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/SmallString.h"
+#include <algorithm>
+using namespace clang;
+
+/// \brief Number of spaces to indent when word-wrapping.
+const unsigned WordWrapIndentation = 6;
+
+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 (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 #.
+ }
+
+ // Pick the first non-whitespace column.
+ while (StartColNo < SourceLine.size() &&
+ (SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
+ ++StartColNo;
+
+ // 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();
+ }
+ }
+
+ // Pick the last non-whitespace column.
+ if (EndColNo <= SourceLine.size())
+ while (EndColNo-1 &&
+ (SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
+ --EndColNo;
+ else
+ EndColNo = SourceLine.size();
+
+ // Fill the range with ~'s.
+ assert(StartColNo <= EndColNo && "Invalid range!");
+ 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) {
+ if (CaretLine.size() > SourceLine.size())
+ SourceLine.resize(CaretLine.size(), ' ');
+
+ // 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) {
+ 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,
+ SourceManager &SM,
+ const CodeModificationHint *Hints,
+ unsigned NumHints,
+ unsigned Columns) {
+ 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()) {
+ SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first;
+ // FIXME: Map ranges?
+ EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns);
+
+ 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 (ShowLocation) {
+ std::pair<FileID, unsigned> IInfo = SM.getDecomposedInstantiationLoc(Loc);
+
+ // Emit the file/line/column that this expansion came from.
+ OS << SM.getBuffer(IInfo.first)->getBufferIdentifier() << ':'
+ << SM.getLineNumber(IInfo.first, IInfo.second) << ':';
+ if (ShowColumn)
+ OS << SM.getColumnNumber(IInfo.first, IInfo.second) << ':';
+ OS << ' ';
+ }
+ OS << "note: instantiated from:\n";
+
+ EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns);
+ 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.
+ std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID);
+ const char *BufStart = BufferInfo.first;
+
+ 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;
+
+ // 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 8 characters 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 NumSpaces = ((i+8)&~7) - (i+1);
+ assert(NumSpaces < 8 && "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 (PrintRangeInfo) {
+ SourceLine = ' ' + SourceLine;
+ CaretLine = ' ' + CaretLine;
+ }
+
+ std::string FixItInsertionLine;
+ if (NumHints && PrintFixItInfo) {
+ for (const CodeModificationHint *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;
+ }
+ }
+ }
+ }
+
+ // 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';
+ OS << CaretLine << '\n';
+
+ if (!FixItInsertionLine.empty()) {
+ if (PrintRangeInfo)
+ OS << ' ';
+ OS << FixItInsertionLine << '\n';
+ }
+}
+
+/// \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.
+unsigned findEndOfWord(unsigned Start,
+ const llvm::SmallVectorImpl<char> &Str,
+ unsigned Length, unsigned Column,
+ unsigned Columns) {
+ unsigned End = Start + 1;
+
+ // 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::SmallVector<char, 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 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 (ShowLocation) {
+ OS << PLoc.getFilename() << ':' << LineNo << ':';
+ if (ShowColumn)
+ if (unsigned ColNo = PLoc.getColumn())
+ OS << ColNo << ':';
+
+ if (PrintRangeInfo && 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();
+ std::pair<FileID, unsigned> BInfo=SM.getDecomposedInstantiationLoc(B);
+
+ E = SM.getInstantiationLoc(E);
+ 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 << ' ';
+ }
+ }
+
+ 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;
+ }
+
+ llvm::SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+
+ if (PrintDiagnosticOption)
+ if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) {
+ OutStr += " [-W";
+ OutStr += Opt;
+ OutStr += ']';
+ }
+
+ if (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, MessageLength, Column);
+ } else {
+ OS.write(OutStr.begin(), OutStr.size());
+ }
+ OS << '\n';
+
+ // 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 (CaretDiagnostics && Info.getLocation().isValid() &&
+ ((LastLoc != Info.getLocation()) || Info.getNumRanges() ||
+ (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) ||
+ Info.getNumCodeModificationHints())) {
+ // 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.getNumCodeModificationHints();
+ for (unsigned idx = 0; idx < NumHints; ++idx) {
+ const CodeModificationHint &Hint = Info.getCodeModificationHint(idx);
+ if (Hint.RemoveRange.isValid()) {
+ assert(NumRanges < 20 && "Out of space");
+ Ranges[NumRanges++] = Hint.RemoveRange;
+ }
+ }
+
+ EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(),
+ Info.getCodeModificationHints(),
+ Info.getNumCodeModificationHints(),
+ MessageLength);
+ }
+
+ OS.flush();
+}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
new file mode 100644
index 0000000..81f75bd
--- /dev/null
+++ b/lib/Frontend/Warnings.cpp
@@ -0,0 +1,106 @@
+//===--- 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 and
+// -Werror.
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+// -Wfoo, -Wno-foo, -Werror=foo
+//
+#include "clang/Frontend/Utils.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include <cstdio>
+#include <cstring>
+#include <utility>
+#include <algorithm>
+using namespace clang;
+
+bool clang::ProcessWarningOptions(Diagnostic &Diags,
+ std::vector<std::string> &Warnings,
+ bool Pedantic, bool PedanticErrors,
+ bool NoWarnings) {
+ Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
+ Diags.setIgnoreAllWarnings(NoWarnings);
+
+ // 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 (PedanticErrors)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Error);
+ else if (Pedantic)
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Warn);
+ else
+ Diags.setExtensionHandlingBehavior(Diagnostic::Ext_Ignore);
+
+ // FIXME: -Wfatal-errors / -Wfatal-errors=foo
+
+ for (unsigned i = 0, e = Warnings.size(); i != e; ++i) {
+ const std::string &Opt = 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) {
+ fprintf(stderr, "warning: unknown -Werror warning specifier: -W%s\n",
+ Opt.c_str());
+ continue;
+ }
+ Specifier = OptStart+6;
+ }
+
+ if (Specifier == 0) {
+ Diags.setWarningsAsErrors(true);
+ 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;
+ }
+
+ if (Diags.setDiagnosticGroupMapping(OptStart, Mapping))
+ fprintf(stderr, "warning: unknown warning option: -W%s\n", Opt.c_str());
+ }
+
+ return false;
+}
OpenPOWER on IntegriCloud