summaryrefslogtreecommitdiffstats
path: root/clang/tools/clang-cc
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-03-24 03:00:12 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-03-24 03:00:12 +0000
commite5a7ecc23afc0b7c0548c1e1d1f3a73e5811891e (patch)
tree6f57deeeb880aa041fb9dc03dc73af18b3423bad /clang/tools/clang-cc
parent3db73ab7f6d08b17e5a59088d9df39983b048946 (diff)
downloadbcm5719-llvm-e5a7ecc23afc0b7c0548c1e1d1f3a73e5811891e.tar.gz
bcm5719-llvm-e5a7ecc23afc0b7c0548c1e1d1f3a73e5811891e.zip
Move <root>/Driver into <root>/tools/clang-cc.
Again, I tried to update cmake but it is untested. llvm-svn: 67605
Diffstat (limited to 'clang/tools/clang-cc')
-rw-r--r--clang/tools/clang-cc/ASTConsumers.cpp1074
-rw-r--r--clang/tools/clang-cc/ASTConsumers.h85
-rw-r--r--clang/tools/clang-cc/Analyses.def77
-rw-r--r--clang/tools/clang-cc/AnalysisConsumer.cpp770
-rw-r--r--clang/tools/clang-cc/Backend.cpp436
-rw-r--r--clang/tools/clang-cc/CMakeLists.txt41
-rw-r--r--clang/tools/clang-cc/CacheTokens.cpp824
-rw-r--r--clang/tools/clang-cc/DependencyFile.cpp272
-rw-r--r--clang/tools/clang-cc/DiagChecker.cpp302
-rw-r--r--clang/tools/clang-cc/HTMLPrint.cpp97
-rw-r--r--clang/tools/clang-cc/Makefile28
-rw-r--r--clang/tools/clang-cc/PrintParserCallbacks.cpp819
-rw-r--r--clang/tools/clang-cc/PrintPreprocessedOutput.cpp469
-rw-r--r--clang/tools/clang-cc/RewriteBlocks.cpp1146
-rw-r--r--clang/tools/clang-cc/RewriteMacros.cpp236
-rw-r--r--clang/tools/clang-cc/RewriteObjC.cpp4588
-rw-r--r--clang/tools/clang-cc/RewriteTest.cpp40
-rw-r--r--clang/tools/clang-cc/SerializationTest.cpp193
-rw-r--r--clang/tools/clang-cc/Warnings.cpp222
-rw-r--r--clang/tools/clang-cc/clang.cpp1703
-rw-r--r--clang/tools/clang-cc/clang.h63
21 files changed, 13485 insertions, 0 deletions
diff --git a/clang/tools/clang-cc/ASTConsumers.cpp b/clang/tools/clang-cc/ASTConsumers.cpp
new file mode 100644
index 00000000000..9eba137918e
--- /dev/null
+++ b/clang/tools/clang-cc/ASTConsumers.cpp
@@ -0,0 +1,1074 @@
+//===--- 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 "ASTConsumers.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/AST/TranslationUnit.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/CodeGen/ModuleBuilder.h"
+#include "llvm/Module.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+/// DeclPrinter - Utility class for printing top-level decls.
+
+namespace {
+ class DeclPrinter {
+ public:
+ llvm::raw_ostream& Out;
+ unsigned Indentation;
+
+ DeclPrinter(llvm::raw_ostream* out) : Out(out ? *out : llvm::errs()),
+ Indentation(0) {}
+ DeclPrinter() : Out(llvm::errs()), Indentation(0) {}
+ virtual ~DeclPrinter();
+
+ void ChangeIndent(int I) {
+ Indentation += I;
+ }
+
+ llvm::raw_ostream& Indent() {
+ for (unsigned i = 0; i < Indentation; ++i)
+ Out << " ";
+ return Out;
+ }
+
+ void PrintDecl(Decl *D);
+ void Print(NamedDecl *ND);
+ void Print(NamespaceDecl *NS);
+ void PrintFunctionDeclStart(FunctionDecl *FD);
+ void PrintTypeDefDecl(TypedefDecl *TD);
+ void PrintLinkageSpec(LinkageSpecDecl *LS);
+ void PrintObjCMethodDecl(ObjCMethodDecl *OMD);
+ void PrintObjCImplementationDecl(ObjCImplementationDecl *OID);
+ void PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID);
+ void PrintObjCProtocolDecl(ObjCProtocolDecl *PID);
+ void PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID);
+ void PrintObjCCategoryDecl(ObjCCategoryDecl *PID);
+ void PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID);
+ void PrintObjCPropertyDecl(ObjCPropertyDecl *PD);
+ void PrintObjCPropertyImplDecl(ObjCPropertyImplDecl *PID);
+
+ void PrintTemplateDecl(TemplateDecl *TD);
+ };
+} // end anonymous namespace
+
+DeclPrinter::~DeclPrinter() {
+ Out.flush();
+}
+
+void DeclPrinter:: PrintDecl(Decl *D) {
+ Indent();
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ PrintFunctionDeclStart(FD);
+
+ if (FD->getBody()) {
+ Out << ' ';
+ FD->getBody()->printPretty(Out, 0, Indentation, true);
+ Out << '\n';
+ }
+ } else if (isa<ObjCMethodDecl>(D)) {
+ // Do nothing, methods definitions are printed in
+ // PrintObjCImplementationDecl.
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ PrintTypeDefDecl(TD);
+ } else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ PrintObjCInterfaceDecl(OID);
+ } else if (ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(D)) {
+ PrintObjCProtocolDecl(PID);
+ } else if (ObjCForwardProtocolDecl *OFPD =
+ dyn_cast<ObjCForwardProtocolDecl>(D)) {
+ Out << "@protocol ";
+ for (ObjCForwardProtocolDecl::iterator I = OFPD->begin(), E = OFPD->end();
+ I != E; ++I) {
+ if (I != OFPD->begin()) Out << ", ";
+ Out << (*I)->getNameAsString();
+ }
+ Out << ";\n";
+ } else if (ObjCImplementationDecl *OID =
+ dyn_cast<ObjCImplementationDecl>(D)) {
+ PrintObjCImplementationDecl(OID);
+ } else if (ObjCCategoryImplDecl *OID =
+ dyn_cast<ObjCCategoryImplDecl>(D)) {
+ PrintObjCCategoryImplDecl(OID);
+ } else if (ObjCCategoryDecl *OID =
+ dyn_cast<ObjCCategoryDecl>(D)) {
+ PrintObjCCategoryDecl(OID);
+ } else if (ObjCCompatibleAliasDecl *OID =
+ dyn_cast<ObjCCompatibleAliasDecl>(D)) {
+ PrintObjCCompatibleAliasDecl(OID);
+ } else if (ObjCClassDecl *OFCD = dyn_cast<ObjCClassDecl>(D)) {
+ Out << "@class ";
+ for (ObjCClassDecl::iterator I = OFCD->begin(), E = OFCD->end();
+ I != E; ++I) {
+ if (I != OFCD->begin()) Out << ", ";
+ Out << (*I)->getNameAsString();
+ }
+ Out << ";\n";
+ } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ Out << "enum " << ED->getNameAsString() << " {\n";
+ for (EnumDecl::enumerator_iterator E = ED->enumerator_begin(),
+ EEnd = ED->enumerator_end();
+ E != EEnd; ++E)
+ Out << " " << (*E)->getNameAsString() << ",\n";
+ Out << "};\n";
+ } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ // print a free standing tag decl (e.g. "struct x;").
+ Out << TD->getKindName();
+ Out << " ";
+ if (const IdentifierInfo *II = TD->getIdentifier())
+ Out << II->getName();
+
+ Out << " {\n";
+ ChangeIndent(1);
+ for (DeclContext::decl_iterator i = TD->decls_begin();
+ i != TD->decls_end();
+ ++i)
+ PrintDecl(*i);
+ ChangeIndent(-1);
+ Indent();
+ Out << "}";
+
+ Out << "\n";
+ } else if (TemplateDecl *TempD = dyn_cast<TemplateDecl>(D)) {
+ PrintTemplateDecl(TempD);
+ } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ PrintLinkageSpec(LSD);
+ } else if (FileScopeAsmDecl *AD = dyn_cast<FileScopeAsmDecl>(D)) {
+ Out << "asm(";
+ AD->getAsmString()->printPretty(Out);
+ Out << ")\n";
+ } else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ Print(ND);
+ } else {
+ assert(0 && "Unknown decl type!");
+ }
+}
+
+void DeclPrinter::Print(NamedDecl *ND) {
+ switch (ND->getKind()) {
+ default:
+ // FIXME: Handle the rest of the NamedDecls.
+ Out << "### NamedDecl " << ND->getNameAsString() << "\n";
+ break;
+ case Decl::Field:
+ case Decl::Var: {
+ // Emit storage class for vardecls.
+ if (VarDecl *V = dyn_cast<VarDecl>(ND)) {
+ switch (V->getStorageClass()) {
+ default: assert(0 && "Unknown storage class!");
+ case VarDecl::None: break;
+ case VarDecl::Auto: Out << "auto "; break;
+ case VarDecl::Register: Out << "register "; break;
+ case VarDecl::Extern: Out << "extern "; break;
+ case VarDecl::Static: Out << "static "; break;
+ case VarDecl::PrivateExtern: Out << "__private_extern__ "; break;
+ }
+ }
+ std::string Name = ND->getNameAsString();
+ // This forms: "int a".
+ dyn_cast<ValueDecl>(ND)->getType().getAsStringInternal(Name);
+ Out << Name << ";\n";
+ break;
+ }
+ case Decl::Namespace:
+ Print(dyn_cast<NamespaceDecl>(ND));
+ break;
+ }
+}
+
+void DeclPrinter::Print(NamespaceDecl *NS) {
+ Out << "namespace " << NS->getNameAsString() << " {\n";
+ ChangeIndent(1);
+ for (DeclContext::decl_iterator i = NS->decls_begin();
+ i != NS->decls_end();
+ ++i)
+ PrintDecl(*i);
+ ChangeIndent(-1);
+ Indent();
+ Out << "}\n";
+}
+
+void DeclPrinter::PrintFunctionDeclStart(FunctionDecl *FD) {
+ bool HasBody = FD->getBody();
+
+ Out << '\n';
+
+ Indent();
+ switch (FD->getStorageClass()) {
+ default: assert(0 && "Unknown storage class");
+ case FunctionDecl::None: break;
+ case FunctionDecl::Extern: Out << "extern "; break;
+ case FunctionDecl::Static: Out << "static "; break;
+ case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break;
+ }
+
+ if (FD->isInline())
+ Out << "inline ";
+
+ std::string Proto = FD->getNameAsString();
+ const FunctionType *AFT = FD->getType()->getAsFunctionType();
+
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) {
+ Proto += "(";
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ if (i) Proto += ", ";
+ std::string ParamStr;
+ if (HasBody) ParamStr = FD->getParamDecl(i)->getNameAsString();
+
+ FT->getArgType(i).getAsStringInternal(ParamStr);
+ Proto += ParamStr;
+ }
+
+ if (FT->isVariadic()) {
+ if (FD->getNumParams()) Proto += ", ";
+ Proto += "...";
+ }
+ Proto += ")";
+ } else {
+ assert(isa<FunctionNoProtoType>(AFT));
+ Proto += "()";
+ }
+
+ AFT->getResultType().getAsStringInternal(Proto);
+ Out << Proto;
+
+ if (!FD->getBody())
+ Out << ";\n";
+ // Doesn't print the body.
+}
+
+void DeclPrinter::PrintTypeDefDecl(TypedefDecl *TD) {
+ std::string S = TD->getNameAsString();
+ TD->getUnderlyingType().getAsStringInternal(S);
+ Out << "typedef " << S << ";\n";
+}
+
+void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) {
+ const char *l;
+ if (LS->getLanguage() == LinkageSpecDecl::lang_c)
+ l = "C";
+ else {
+ assert(LS->getLanguage() == LinkageSpecDecl::lang_cxx &&
+ "unknown language in linkage specification");
+ l = "C++";
+ }
+
+ Out << "extern \"" << l << "\" ";
+ if (LS->hasBraces()) {
+ Out << "{\n";
+ ChangeIndent(1);
+ }
+
+ for (LinkageSpecDecl::decl_iterator D = LS->decls_begin(),
+ DEnd = LS->decls_end();
+ D != DEnd; ++D)
+ PrintDecl(*D);
+
+ if (LS->hasBraces()) {
+ ChangeIndent(-1);
+ Indent() << "}";
+ }
+ Out << "\n";
+}
+
+void DeclPrinter::PrintObjCMethodDecl(ObjCMethodDecl *OMD) {
+ if (OMD->isInstanceMethod())
+ Out << "\n- ";
+ else
+ Out << "\n+ ";
+ if (!OMD->getResultType().isNull())
+ Out << '(' << OMD->getResultType().getAsString() << ")";
+
+ std::string name = OMD->getSelector().getAsString();
+ std::string::size_type pos, lastPos = 0;
+ for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ E = OMD->param_end(); PI != E; ++PI) {
+ // FIXME: selector is missing here!
+ pos = name.find_first_of(":", lastPos);
+ Out << " " << name.substr(lastPos, pos - lastPos);
+ Out << ":(" << (*PI)->getType().getAsString() << ")"
+ << (*PI)->getNameAsString();
+ lastPos = pos + 1;
+ }
+
+ if (OMD->param_begin() == OMD->param_end())
+ Out << " " << name;
+
+ if (OMD->isVariadic())
+ Out << ", ...";
+
+ Out << ";";
+}
+
+void DeclPrinter::PrintObjCImplementationDecl(ObjCImplementationDecl *OID) {
+ std::string I = OID->getNameAsString();
+ ObjCInterfaceDecl *SID = OID->getSuperClass();
+
+ if (SID)
+ Out << "@implementation " << I << " : " << SID->getNameAsString();
+ else
+ Out << "@implementation " << I;
+
+ for (ObjCImplementationDecl::instmeth_iterator I = OID->instmeth_begin(),
+ E = OID->instmeth_end(); I != E; ++I) {
+ ObjCMethodDecl *OMD = *I;
+ PrintObjCMethodDecl(OMD);
+ if (OMD->getBody()) {
+ Out << ' ';
+ OMD->getBody()->printPretty(Out);
+ Out << '\n';
+ }
+ }
+
+ for (ObjCImplementationDecl::classmeth_iterator I = OID->classmeth_begin(),
+ E = OID->classmeth_end(); I != E; ++I) {
+ ObjCMethodDecl *OMD = *I;
+ PrintObjCMethodDecl(OMD);
+ if (OMD->getBody()) {
+ Out << ' ';
+ OMD->getBody()->printPretty(Out);
+ Out << '\n';
+ }
+ }
+
+ for (ObjCImplementationDecl::propimpl_iterator I = OID->propimpl_begin(),
+ E = OID->propimpl_end(); I != E; ++I)
+ PrintObjCPropertyImplDecl(*I);
+
+ Out << "@end\n";
+}
+
+
+void DeclPrinter::PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
+ std::string I = OID->getNameAsString();
+ ObjCInterfaceDecl *SID = OID->getSuperClass();
+
+ if (SID)
+ Out << "@interface " << I << " : " << SID->getNameAsString();
+ else
+ Out << "@interface " << I;
+
+ // Protocols?
+ const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
+ if (!Protocols.empty()) {
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString();
+ }
+
+ if (!Protocols.empty())
+ Out << ">";
+ Out << '\n';
+
+ if (OID->ivar_size() > 0) {
+ Out << '{';
+ for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
+ E = OID->ivar_end(); I != E; ++I) {
+ Out << '\t' << (*I)->getType().getAsString()
+ << ' ' << (*I)->getNameAsString() << ";\n";
+ }
+ Out << "}\n";
+ }
+
+ for (ObjCInterfaceDecl::prop_iterator I = OID->prop_begin(),
+ E = OID->prop_end(); I != E; ++I)
+ PrintObjCPropertyDecl(*I);
+ bool eol_needed = false;
+ for (ObjCInterfaceDecl::classmeth_iterator I = OID->classmeth_begin(),
+ E = OID->classmeth_end(); I != E; ++I)
+ eol_needed = true, PrintObjCMethodDecl(*I);
+
+ for (ObjCInterfaceDecl::instmeth_iterator I = OID->instmeth_begin(),
+ E = OID->instmeth_end(); I != E; ++I)
+ eol_needed = true, PrintObjCMethodDecl(*I);
+
+ Out << (eol_needed ? "\n@end\n" : "@end\n");
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::PrintObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ Out << "@protocol " << PID->getNameAsString() << '\n';
+
+ for (ObjCProtocolDecl::prop_iterator I = PID->prop_begin(),
+ E = PID->prop_end(); I != E; ++I)
+ PrintObjCPropertyDecl(*I);
+ Out << "@end\n";
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::PrintObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
+ Out << "@implementation "
+ << PID->getClassInterface()->getNameAsString()
+ << '(' << PID->getNameAsString() << ");\n";
+ for (ObjCCategoryImplDecl::propimpl_iterator I = PID->propimpl_begin(),
+ E = PID->propimpl_end(); I != E; ++I)
+ PrintObjCPropertyImplDecl(*I);
+ Out << "@end\n";
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::PrintObjCCategoryDecl(ObjCCategoryDecl *PID) {
+ Out << "@interface "
+ << PID->getClassInterface()->getNameAsString()
+ << '(' << PID->getNameAsString() << ");\n";
+ // Output property declarations.
+ for (ObjCCategoryDecl::prop_iterator I = PID->prop_begin(),
+ E = PID->prop_end(); I != E; ++I)
+ PrintObjCPropertyDecl(*I);
+ Out << "@end\n";
+
+ // FIXME: implement the rest...
+}
+
+void DeclPrinter::PrintObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) {
+ Out << "@compatibility_alias " << AID->getNameAsString()
+ << ' ' << AID->getClassInterface()->getNameAsString() << ";\n";
+}
+
+/// PrintObjCPropertyDecl - print a property declaration.
+///
+void DeclPrinter::PrintObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
+ if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ Out << "@required\n";
+ else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ Out << "@optional\n";
+
+ Out << "@property";
+ if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
+ bool first = true;
+ Out << " (";
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readonly) {
+ Out << (first ? ' ' : ',') << "readonly";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
+ Out << (first ? ' ' : ',') << "getter = "
+ << PDecl->getGetterName().getAsString();
+ first = false;
+ }
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
+ Out << (first ? ' ' : ',') << "setter = "
+ << PDecl->getSetterName().getAsString();
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) {
+ Out << (first ? ' ' : ',') << "assign";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readwrite) {
+ Out << (first ? ' ' : ',') << "readwrite";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) {
+ Out << (first ? ' ' : ',') << "retain";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) {
+ Out << (first ? ' ' : ',') << "copy";
+ first = false;
+ }
+
+ if (PDecl->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_nonatomic) {
+ Out << (first ? ' ' : ',') << "nonatomic";
+ first = false;
+ }
+ Out << " )";
+ }
+ Out << ' ' << PDecl->getType().getAsString()
+ << ' ' << PDecl->getNameAsString();
+
+ Out << ";\n";
+}
+
+/// PrintObjCPropertyImplDecl - Print an objective-c property implementation
+/// declaration syntax.
+///
+void DeclPrinter::PrintObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
+ if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ Out << "\n@synthesize ";
+ else
+ Out << "\n@dynamic ";
+ Out << PID->getPropertyDecl()->getNameAsString();
+ if (PID->getPropertyIvarDecl())
+ Out << "=" << PID->getPropertyIvarDecl()->getNameAsString();
+ Out << ";\n";
+}
+
+/// PrintTemplateParams - Print a template parameter list and recursively print
+/// it's underlying top-level definition.
+void DeclPrinter::PrintTemplateDecl(TemplateDecl *TD) {
+ // TODO: Write template parameters.
+ Out << "template <...> ";
+ PrintDecl(TD->getTemplatedDecl());
+}
+
+
+
+//===----------------------------------------------------------------------===//
+/// ASTPrinter - Pretty-printer of ASTs
+
+namespace {
+ class ASTPrinter : public ASTConsumer, public DeclPrinter {
+ public:
+ ASTPrinter(llvm::raw_ostream* o = NULL) : DeclPrinter(o) {}
+
+ virtual void HandleTopLevelDecl(Decl *D) {
+ PrintDecl(D);
+ }
+ };
+}
+
+ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) {
+ return new ASTPrinter(out);
+}
+
+//===----------------------------------------------------------------------===//
+/// ASTDumper - Low-level dumper of ASTs
+
+namespace {
+ class ASTDumper : public ASTConsumer, public DeclPrinter {
+ SourceManager *SM;
+ public:
+ ASTDumper() : DeclPrinter() {}
+
+ void Initialize(ASTContext &Context) {
+ SM = &Context.getSourceManager();
+ }
+
+ virtual void HandleTopLevelDecl(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ PrintFunctionDeclStart(FD);
+
+ if (FD->getBody()) {
+ Out << '\n';
+ // FIXME: convert dumper to use std::ostream?
+ FD->getBody()->dumpAll(*SM);
+ Out << '\n';
+ }
+ } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ PrintTypeDefDecl(TD);
+ } else if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(D)) {
+ Out << "Read objc interface '" << OID->getNameAsString() << "'\n";
+ } else if (ObjCProtocolDecl *OPD = dyn_cast<ObjCProtocolDecl>(D)) {
+ Out << "Read objc protocol '" << OPD->getNameAsString() << "'\n";
+ } else if (ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(D)) {
+ Out << "Read objc category '" << OCD->getNameAsString() << "'\n";
+ } else if (isa<ObjCForwardProtocolDecl>(D)) {
+ Out << "Read objc fwd protocol decl\n";
+ } else if (isa<ObjCClassDecl>(D)) {
+ Out << "Read objc fwd class decl\n";
+ } else if (isa<FileScopeAsmDecl>(D)) {
+ Out << "Read file scope asm decl\n";
+ } else if (ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) {
+ Out << "Read objc method decl: '" << MD->getSelector().getAsString()
+ << "'\n";
+ if (MD->getBody()) {
+ // FIXME: convert dumper to use std::ostream?
+ MD->getBody()->dumpAll(*SM);
+ Out << '\n';
+ }
+ } else if (isa<ObjCImplementationDecl>(D)) {
+ Out << "Read objc implementation decl\n";
+ } else if (isa<ObjCCategoryImplDecl>(D)) {
+ Out << "Read objc category implementation decl\n";
+ } else if (isa<LinkageSpecDecl>(D)) {
+ Out << "Read linkage spec decl\n";
+ } else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ Out << "Read top-level variable decl: '" << ND->getNameAsString()
+ << "'\n";
+ } else {
+ assert(0 && "Unknown decl type!");
+ }
+ }
+ };
+}
+
+ASTConsumer *clang::CreateASTDumper() { return new ASTDumper(); }
+
+//===----------------------------------------------------------------------===//
+/// ASTViewer - AST Visualization
+
+namespace {
+ class ASTViewer : public ASTConsumer {
+ SourceManager *SM;
+ public:
+ void Initialize(ASTContext &Context) {
+ SM = &Context.getSourceManager();
+ }
+
+ virtual void HandleTopLevelDecl(Decl *D) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ DeclPrinter().PrintFunctionDeclStart(FD);
+
+ if (FD->getBody()) {
+ llvm::cerr << '\n';
+ FD->getBody()->viewAST();
+ llvm::cerr << '\n';
+ }
+ }
+ else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ DeclPrinter().PrintObjCMethodDecl(MD);
+
+ 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(TranslationUnit& TU) {
+ TranslationUnitDecl* TUD = TU.getContext().getTranslationUnitDecl();
+ PrintDeclContext(TUD, 4);
+ }
+
+ void PrintDeclContext(const DeclContext* DC, unsigned Indentation);
+};
+
+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.
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+ for (unsigned i = 0; i < Indentation; ++i)
+ Out << " ";
+
+ Decl::Kind DK = I->getKind();
+ switch (DK) {
+ case Decl::Namespace:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ObjCMethod:
+ case Decl::ObjCInterface:
+ case Decl::ObjCCategory:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCCategoryImpl:
+ case Decl::LinkageSpec:
+ case Decl::Block:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ {
+ DeclContext* DC = cast<DeclContext>(*I);
+ PrintDeclContext(DC, Indentation+2);
+ break;
+ }
+ case Decl::Field: {
+ FieldDecl* FD = cast<FieldDecl>(*I);
+ Out << "<field> " << FD->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::ObjCProperty: {
+ ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I);
+ Out << "<objc property> " << OPD->getNameAsString() << "\n";
+ break;
+ }
+ default:
+ fprintf(stderr, "DeclKind: %d\n", DK);
+ 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(TranslationUnit& TU) {
+ ASTContext& C = TU.getContext();
+ 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);
+}
+
+//===----------------------------------------------------------------------===//
+// AST Serializer
+
+namespace {
+
+class ASTSerializer : public ASTConsumer {
+protected:
+ Diagnostic& Diags;
+
+public:
+ ASTSerializer(Diagnostic& diags) : Diags(diags) {}
+};
+
+class SingleFileSerializer : public ASTSerializer {
+ const llvm::sys::Path FName;
+public:
+ SingleFileSerializer(const llvm::sys::Path& F, Diagnostic& diags)
+ : ASTSerializer(diags), FName(F) {}
+
+ virtual void HandleTranslationUnit(TranslationUnit& TU) {
+ if (Diags.hasErrorOccurred())
+ return;
+ EmitASTBitcodeFile(&TU, FName);
+ }
+};
+
+class BuildSerializer : public ASTSerializer {
+ llvm::sys::Path EmitDir;
+public:
+ BuildSerializer(const llvm::sys::Path& dir, Diagnostic& diags)
+ : ASTSerializer(diags), EmitDir(dir) {}
+
+ virtual void HandleTranslationUnit(TranslationUnit& TU) {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ SourceManager& SourceMgr = TU.getContext().getSourceManager();
+ FileID ID = SourceMgr.getMainFileID();
+ assert(!ID.isInvalid() && "MainFileID not set!");
+ const FileEntry* FE = SourceMgr.getFileEntryForID(ID);
+ assert(FE && "No FileEntry for main file.");
+
+ // FIXME: This is not portable to Windows.
+ // FIXME: This logic should probably be moved elsewhere later.
+
+ llvm::sys::Path FName(EmitDir);
+
+ std::vector<char> buf;
+ buf.reserve(strlen(FE->getName())+100);
+
+ sprintf(&buf[0], "dev_%llx", (unsigned long long) FE->getDevice());
+ FName.appendComponent(&buf[0]);
+ FName.createDirectoryOnDisk(true);
+ if (!FName.canWrite() || !FName.isDirectory()) {
+ assert (false && "Could not create 'device' serialization directory.");
+ return;
+ }
+
+ sprintf(&buf[0], "%s-%llX.ast", FE->getName(),
+ (unsigned long long) FE->getInode());
+ FName.appendComponent(&buf[0]);
+ EmitASTBitcodeFile(&TU, FName);
+
+ // Now emit the sources.
+
+ }
+};
+
+
+} // end anonymous namespace
+
+
+ASTConsumer* clang::CreateASTSerializer(const std::string& InFile,
+ const std::string& OutputFile,
+ Diagnostic &Diags) {
+
+ if (OutputFile.size()) {
+ if (InFile == "-") {
+ llvm::cerr <<
+ "error: Cannot use --serialize with -o for source read from STDIN.\n";
+ return NULL;
+ }
+
+ // The user specified an AST-emission directory. Determine if the path
+ // is absolute.
+ llvm::sys::Path EmitDir(OutputFile);
+
+ if (!EmitDir.isAbsolute()) {
+ llvm::cerr <<
+ "error: Output directory for --serialize must be an absolute path.\n";
+
+ return NULL;
+ }
+
+ // Create the directory if it does not exist.
+ EmitDir.createDirectoryOnDisk(true);
+ if (!EmitDir.canWrite() || !EmitDir.isDirectory()) {
+ llvm::cerr <<
+ "error: Could not create output directory for --serialize.\n";
+
+ return NULL;
+ }
+
+ // FIXME: We should probably only allow using BuildSerializer when
+ // the ASTs come from parsed source files, and not from .ast files.
+ return new BuildSerializer(EmitDir, Diags);
+ }
+
+ // The user did not specify an output directory for serialized ASTs.
+ // Serialize the translation to a single file whose name is the same
+ // as the input file with the ".ast" extension appended.
+
+ llvm::sys::Path FName(InFile.c_str());
+ FName.appendSuffix("ast");
+ return new SingleFileSerializer(FName, Diags);
+}
diff --git a/clang/tools/clang-cc/ASTConsumers.h b/clang/tools/clang-cc/ASTConsumers.h
new file mode 100644
index 00000000000..fd8416da0ea
--- /dev/null
+++ b/clang/tools/clang-cc/ASTConsumers.h
@@ -0,0 +1,85 @@
+//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// AST Consumers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DRIVER_ASTCONSUMERS_H
+#define DRIVER_ASTCONSUMERS_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <iosfwd>
+
+namespace llvm {
+ class Module;
+ namespace sys { class Path; }
+}
+namespace clang {
+
+class ASTConsumer;
+class Diagnostic;
+class FileManager;
+class Preprocessor;
+class PreprocessorFactory;
+struct CompileOptions;
+class LangOptions;
+
+ASTConsumer *CreateASTPrinter(llvm::raw_ostream* OS = NULL);
+
+ASTConsumer *CreateASTDumper();
+
+ASTConsumer *CreateASTViewer();
+
+ASTConsumer *CreateDeclContextPrinter();
+
+ASTConsumer *CreateCodeRewriterTest(const std::string& InFile,
+ const std::string& OutFile,
+ Diagnostic &Diags,
+ const LangOptions &LOpts);
+
+enum BackendAction {
+ Backend_EmitAssembly,
+ Backend_EmitBC,
+ Backend_EmitLL,
+ Backend_EmitNothing
+};
+ASTConsumer *CreateBackendConsumer(BackendAction Action,
+ Diagnostic &Diags,
+ const LangOptions &Features,
+ const CompileOptions &CompileOpts,
+ const std::string& InFile,
+ const std::string& OutFile);
+
+ASTConsumer* CreateHTMLPrinter(const std::string &OutFile, Diagnostic &D,
+ Preprocessor *PP, PreprocessorFactory* PPF);
+
+ASTConsumer *CreateSerializationTest(Diagnostic &Diags,
+ FileManager& FMgr);
+
+ASTConsumer *CreateASTSerializer(const std::string& InFile,
+ const std::string& EmitDir,
+ Diagnostic &Diags);
+
+ASTConsumer *CreateBlockRewriter(const std::string& InFile,
+ const std::string& OutFile,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts);
+
+ASTConsumer *CreateInheritanceViewer(const std::string& clsname);
+
+ASTConsumer* CreateAnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& output);
+
+} // end clang namespace
+
+#endif
diff --git a/clang/tools/clang-cc/Analyses.def b/clang/tools/clang-cc/Analyses.def
new file mode 100644
index 00000000000..3492d09c10a
--- /dev/null
+++ b/clang/tools/clang-cc/Analyses.def
@@ -0,0 +1,77 @@
+//===-- Analyses.def - Metadata about Static Analyses -----------*- 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 set of static analyses used by AnalysisConsumer.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ANALYSIS
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)
+#endif
+
+ANALYSIS(CFGDump, "cfg-dump",
+ "Display Control-Flow Graphs", Code)
+
+ANALYSIS(CFGView, "cfg-view",
+ "View Control-Flow Graphs using GraphViz", Code)
+
+ANALYSIS(DisplayLiveVariables, "dump-live-variables",
+ "Print results of live variable analysis", Code)
+
+ANALYSIS(WarnDeadStores, "warn-dead-stores",
+ "Warn about stores to dead variables", Code)
+
+ANALYSIS(WarnUninitVals, "warn-uninit-values",
+ "Warn about uses of uninitialized variables", Code)
+
+ANALYSIS(WarnObjCMethSigs, "warn-objc-methodsigs",
+ "Warn about Objective-C method signatures with type incompatibilities",
+ ObjCImplementation)
+
+ANALYSIS(WarnObjCDealloc, "warn-objc-missing-dealloc",
+ "Warn about Objective-C classes that lack a correct implementation of -dealloc",
+ ObjCImplementation)
+
+ANALYSIS(WarnObjCUnusedIvars, "warn-objc-unused-ivars",
+ "Warn about private ivars that are never used", ObjCImplementation)
+
+ANALYSIS(CheckerSimple, "checker-simple",
+ "Perform simple path-sensitive checks.", Code)
+
+ANALYSIS(CheckerCFRef, "checker-cfref",
+ "Run the [Core] Foundation reference count checker", Code)
+
+
+#ifndef ANALYSIS_STORE
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)
+#endif
+
+ANALYSIS_STORE(BasicStore, "basic", "Use basic analyzer store", CreateBasicStoreManager)
+ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager)
+
+#ifndef ANALYSIS_CONSTRAINTS
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)
+#endif
+
+ANALYSIS_CONSTRAINTS(BasicConstraints, "basic", "Use basic constraint tracking", CreateBasicConstraintManager)
+ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager)
+
+#ifndef ANALYSIS_DIAGNOSTICS
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)
+#endif
+
+ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", CreateHTMLDiagnosticClient, false)
+ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", CreatePlistDiagnosticClient, true)
+
+#undef ANALYSIS
+#undef ANALYSIS_STORE
+#undef ANALYSIS_CONSTRAINTS
+#undef ANALYSIS_DIAGNOSTICS
+#undef ANALYSIS_STORE
+
diff --git a/clang/tools/clang-cc/AnalysisConsumer.cpp b/clang/tools/clang-cc/AnalysisConsumer.cpp
new file mode 100644
index 00000000000..f19ff1787eb
--- /dev/null
+++ b/clang/tools/clang-cc/AnalysisConsumer.cpp
@@ -0,0 +1,770 @@
+//===--- 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 "ASTConsumers.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/AST/TranslationUnit.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"
+#include <vector>
+
+using namespace clang;
+
+static ExplodedNodeImpl::Auditor* CreateUbiViz();
+
+//===----------------------------------------------------------------------===//
+// Analyzer Options: available analyses.
+//===----------------------------------------------------------------------===//
+
+/// Analysis - Set of available source code analyses.
+enum Analyses {
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
+#include "Analyses.def"
+NumAnalyses
+};
+
+static llvm::cl::list<Analyses>
+AnalysisList(llvm::cl::desc("Source Code Analysis - Checks and Analyses"),
+llvm::cl::values(
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
+clEnumValN(NAME, CMDFLAG, DESC),
+#include "Analyses.def"
+clEnumValEnd));
+
+//===----------------------------------------------------------------------===//
+// Analyzer Options: store model.
+//===----------------------------------------------------------------------===//
+
+/// AnalysisStores - Set of available analysis store models.
+enum AnalysisStores {
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "Analyses.def"
+NumStores
+};
+
+static llvm::cl::opt<AnalysisStores>
+AnalysisStoreOpt("analyzer-store",
+ llvm::cl::desc("Source Code Analysis - Abstract Memory Store Models"),
+ llvm::cl::init(BasicStoreModel),
+ llvm::cl::values(
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN)\
+clEnumValN(NAME##Model, CMDFLAG, DESC),
+#include "Analyses.def"
+clEnumValEnd));
+
+//===----------------------------------------------------------------------===//
+// Analyzer Options: constraint engines.
+//===----------------------------------------------------------------------===//
+
+/// AnalysisConstraints - Set of available constraint models.
+enum AnalysisConstraints {
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model,
+#include "Analyses.def"
+NumConstraints
+};
+
+static llvm::cl::opt<AnalysisConstraints>
+AnalysisConstraintsOpt("analyzer-constraints",
+ llvm::cl::desc("Source Code Analysis - Symbolic Constraint Engines"),
+ llvm::cl::init(RangeConstraintsModel),
+ llvm::cl::values(
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN)\
+clEnumValN(NAME##Model, CMDFLAG, DESC),
+#include "Analyses.def"
+clEnumValEnd));
+
+//===----------------------------------------------------------------------===//
+// Analyzer Options: diagnostic clients.
+//===----------------------------------------------------------------------===//
+
+/// AnalysisDiagClients - Set of available diagnostic clients for rendering
+/// analysis results.
+enum AnalysisDiagClients {
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME,
+#include "Analyses.def"
+NUM_ANALYSIS_DIAG_CLIENTS
+};
+
+static llvm::cl::opt<AnalysisDiagClients>
+AnalysisDiagOpt("analyzer-output",
+ llvm::cl::desc("Source Code Analysis - Output Options"),
+ llvm::cl::init(PD_HTML),
+ llvm::cl::values(
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE)\
+clEnumValN(PD_##NAME, CMDFLAG, DESC),
+#include "Analyses.def"
+clEnumValEnd));
+
+//===----------------------------------------------------------------------===//
+// Misc. fun options.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+VisualizeEGDot("analyzer-viz-egraph-graphviz",
+ llvm::cl::desc("Display exploded graph using GraphViz"));
+
+static llvm::cl::opt<bool>
+VisualizeEGUbi("analyzer-viz-egraph-ubigraph",
+ llvm::cl::desc("Display exploded graph using Ubigraph"));
+
+static llvm::cl::opt<bool>
+AnalyzeAll("analyzer-opt-analyze-headers",
+ llvm::cl::desc("Force the static analyzer to analyze "
+ "functions defined in header files"));
+
+static llvm::cl::opt<bool>
+AnalyzerDisplayProgress("analyzer-display-progress",
+ llvm::cl::desc("Emit verbose output about the analyzer's progress."));
+
+static llvm::cl::opt<bool>
+PurgeDead("analyzer-purge-dead",
+ llvm::cl::init(true),
+ llvm::cl::desc("Remove dead symbols, bindings, and constraints before"
+ " processing a statement."));
+
+static llvm::cl::opt<bool>
+EagerlyAssume("analyzer-eagerly-assume",
+ llvm::cl::init(false),
+ llvm::cl::desc("Eagerly assume the truth/falseness of some "
+ "symbolic constraints."));
+
+static llvm::cl::opt<std::string>
+AnalyzeSpecificFunction("analyze-function",
+ llvm::cl::desc("Run analysis on specific function"));
+
+static llvm::cl::opt<bool>
+TrimGraph("trim-egraph",
+ llvm::cl::desc("Only show error-related paths in the analysis graph"));
+
+//===----------------------------------------------------------------------===//
+// 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;
+ llvm::OwningPtr<PathDiagnosticClient> PD;
+
+ AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+ PreprocessorFactory* ppf,
+ const LangOptions& lopts,
+ const std::string& outdir)
+ : LOpts(lopts), Diags(diags),
+ Ctx(0), PP(pp), PPF(ppf),
+ OutDir(outdir) {}
+
+ 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(Decl *D);
+ virtual void HandleTranslationUnit(TranslationUnit &TU);
+
+ void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+ };
+
+
+ class VISIBILITY_HIDDEN AnalysisManager : public BugReporterData {
+ Decl* D; Stmt* Body;
+ TranslationUnit* TU;
+
+ 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), TU(0), AScope(ScopeDecl), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ AnalysisManager(AnalysisConsumer& c, TranslationUnit* tu,
+ bool displayProgress)
+ : D(0), Body(0), TU(tu), AScope(ScopeTU), C(c),
+ DisplayedFunction(!displayProgress) {
+ setManagerCreators();
+ }
+
+ Decl* getCodeDecl() const {
+ assert (AScope == ScopeDecl);
+ return D;
+ }
+
+ Stmt* getBody() const {
+ assert (AScope == ScopeDecl);
+ return Body;
+ }
+
+ TranslationUnit* getTranslationUnit() const {
+ assert (AScope == ScopeTU);
+ return TU;
+ }
+
+ 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 (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 "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 VisualizeEGDot; }
+
+ bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
+
+ bool shouldVisualize() const {
+ return VisualizeEGDot || VisualizeEGUbi;
+ }
+
+ bool shouldTrimGraph() const { return TrimGraph; }
+
+ 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 (AnalysisStoreOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
+ case NAME##Model: CreateStoreMgr = CREATEFN; break;
+#include "Analyses.def"
+ }
+ }
+
+ if (ManagerRegistry::ConstraintMgrCreator != 0)
+ CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+ else {
+ switch (AnalysisConstraintsOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
+ case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+#include "Analyses.def"
+ }
+ }
+
+
+ // Some DiagnosticClients should be created all the time instead of
+ // lazily. Create those now.
+ switch (AnalysisDiagOpt) {
+ default: break;
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE)\
+case PD_##NAME: if (AUTOCREATE) getPathDiagnosticClient(); break;
+#include "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::HandleTopLevelDecl(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
+
+ if (AnalyzeSpecificFunction.size() > 0 &&
+ AnalyzeSpecificFunction != FD->getIdentifier()->getName())
+ break;
+
+ Stmt* Body = FD->getBody();
+ if (Body) HandleCode(FD, Body, FunctionActions);
+ break;
+ }
+
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+
+ if (AnalyzeSpecificFunction.size() > 0 &&
+ AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ return;
+
+ Stmt* Body = MD->getBody();
+ if (Body) HandleCode(MD, Body, ObjCMethodActions);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void AnalysisConsumer::HandleTranslationUnit(TranslationUnit& TU) {
+
+ if(!TranslationUnitActions.empty()) {
+ AnalysisManager mgr(*this, &TU, AnalyzerDisplayProgress);
+ for (Actions::iterator I = TranslationUnitActions.begin(),
+ E = TranslationUnitActions.end(); I != E; ++I)
+ (*I)(mgr);
+ }
+
+ if (!ObjCImplementationActions.empty())
+ for (TranslationUnit::iterator I = TU.begin(), E = TU.end(); 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 (!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, 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,
+ PurgeDead, EagerlyAssume,
+ 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) {
+
+ llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(diags, pp, ppf,
+ lopts, OutDir));
+
+ for (unsigned i = 0; i < AnalysisList.size(); ++i)
+ switch (AnalysisList[i]) {
+#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
+ case NAME:\
+ C->add ## SCOPE ## Action(&Action ## NAME);\
+ break;
+#include "Analyses.def"
+ default: break;
+ }
+
+ 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/clang/tools/clang-cc/Backend.cpp b/clang/tools/clang-cc/Backend.cpp
new file mode 100644
index 00000000000..459bd696b05
--- /dev/null
+++ b/clang/tools/clang-cc/Backend.cpp
@@ -0,0 +1,436 @@
+//===--- 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 "ASTConsumers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/TranslationUnit.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompileOptions.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;
+ const std::string &InputFile;
+ std::string OutputFile;
+ ASTContext *Context;
+
+ Timer LLVMIRGeneration;
+ Timer CodeGenerationTime;
+
+ llvm::OwningPtr<CodeGenerator> Gen;
+
+ llvm::Module *TheModule;
+ llvm::TargetData *TheTargetData;
+ llvm::raw_ostream *AsmOutStream;
+
+ 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, const std::string &outfile) :
+ Action(action),
+ CompileOpts(compopts),
+ InputFile(infile),
+ OutputFile(outfile),
+ LLVMIRGeneration("LLVM IR Generation Time"),
+ CodeGenerationTime("Code Generation Time"),
+ Gen(CreateLLVMCodeGen(Diags, langopts, InputFile, compopts.DebugInfo)),
+ TheModule(0), TheTargetData(0), AsmOutStream(0), ModuleProvider(0),
+ CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {
+
+ // Enable -time-passes if -ftime-report is enabled.
+ llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
+ }
+
+ ~BackendConsumer() {
+ delete AsmOutStream;
+ delete TheTargetData;
+ delete ModuleProvider;
+ delete CodeGenPasses;
+ delete PerModulePasses;
+ delete PerFunctionPasses;
+ }
+
+ virtual void InitializeTU(TranslationUnit& TU) {
+ Context = &TU.getContext();
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->InitializeTU(TU);
+
+ TheModule = Gen->GetModule();
+ ModuleProvider = new ExistingModuleProvider(TheModule);
+ TheTargetData =
+ new llvm::TargetData(TU.getContext().Target.getTargetDescription());
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTopLevelDecl(Decl *D) {
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ Context->getSourceManager(),
+ "LLVM IR generation of declaration");
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTopLevelDecl(D);
+
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.stopTimer();
+ }
+
+ virtual void HandleTranslationUnit(TranslationUnit& TU) {
+ {
+ PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
+ if (CompileOpts.TimePasses)
+ LLVMIRGeneration.startTimer();
+
+ Gen->HandleTranslationUnit(TU);
+
+ 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);
+ }
+ };
+}
+
+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 (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) {
+ AsmOutStream = new raw_stdout_ostream();
+ sys::Program::ChangeStdoutToBinary();
+ } else {
+ if (OutputFile.empty()) {
+ llvm::sys::Path Path(InputFile);
+ Path.eraseSuffix();
+ if (Action == Backend_EmitBC) {
+ Path.appendSuffix("bc");
+ } else if (Action == Backend_EmitLL) {
+ Path.appendSuffix("ll");
+ } else {
+ Path.appendSuffix("s");
+ }
+ OutputFile = Path.toString();
+ }
+
+ AsmOutStream = new raw_fd_ostream(OutputFile.c_str(), true, Error);
+ if (!Error.empty())
+ return false;
+ }
+
+ 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();
+
+ // 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, Fast)) {
+ default:
+ case FileModel::Error:
+ Error = "Unable to interface with target machine!\n";
+ return false;
+ case FileModel::AsmFile:
+ break;
+ }
+
+ if (TM->addPassesToEmitFileFinish(*CodeGenPasses, 0, Fast)) {
+ 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,
+ const std::string& OutFile) {
+ // FIXME: If optimizing, disable all debug info generation. The LLVM
+ // optimizer and backend is not ready to handle it when optimizations
+ // are enabled.
+ if (CompileOpts.OptimizationLevel > 0)
+ const_cast<CompileOptions&>(CompileOpts).DebugInfo = false;
+
+ return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
+ InFile, OutFile);
+}
diff --git a/clang/tools/clang-cc/CMakeLists.txt b/clang/tools/clang-cc/CMakeLists.txt
new file mode 100644
index 00000000000..9dd596c2ce1
--- /dev/null
+++ b/clang/tools/clang-cc/CMakeLists.txt
@@ -0,0 +1,41 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ clangCodeGen
+ clangAnalysis
+ clangRewrite
+ clangSema
+ clangDriver
+ clangAST
+ clangParse
+ clangLex
+ clangBasic
+ )
+
+set( LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ bitreader
+ bitwriter
+ codegen
+ ipo
+ selectiondag
+ )
+
+add_clang_executable(clang-cc
+ AnalysisConsumer.cpp
+ ASTConsumers.cpp
+ Backend.cpp
+ CacheTokens.cpp
+ clang.cpp
+ DependencyFile.cpp
+ DiagChecker.cpp
+ HTMLPrint.cpp
+ PrintParserCallbacks.cpp
+ PrintPreprocessedOutput.cpp
+ RewriteBlocks.cpp
+ RewriteMacros.cpp
+ RewriteObjC.cpp
+ RewriteTest.cpp
+ SerializationTest.cpp
+ Warnings.cpp
+ )
diff --git a/clang/tools/clang-cc/CacheTokens.cpp b/clang/tools/clang-cc/CacheTokens.cpp
new file mode 100644
index 00000000000..4ca350e6fb0
--- /dev/null
+++ b/clang/tools/clang-cc/CacheTokens.cpp
@@ -0,0 +1,824 @@
+//===--- 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.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/Diagnostic.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;
+
+typedef uint32_t Offset;
+
+static void Emit8(llvm::raw_ostream& Out, uint32_t V) {
+ Out << (unsigned char)(V);
+}
+
+static void Emit16(llvm::raw_ostream& Out, uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ assert((V >> 16) == 0);
+}
+
+static void Emit32(llvm::raw_ostream& Out, uint32_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ Out << (unsigned char)(V >> 24);
+}
+
+static void Emit64(llvm::raw_ostream& Out, uint64_t V) {
+ Out << (unsigned char)(V);
+ Out << (unsigned char)(V >> 8);
+ Out << (unsigned char)(V >> 16);
+ Out << (unsigned char)(V >> 24);
+ Out << (unsigned char)(V >> 32);
+ Out << (unsigned char)(V >> 40);
+ Out << (unsigned char)(V >> 48);
+ Out << (unsigned char)(V >> 56);
+}
+
+static void Pad(llvm::raw_fd_ostream& Out, unsigned A) {
+ Offset off = (Offset) Out.tell();
+ uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off;
+ for ( ; n ; --n ) Emit8(Out, 0);
+}
+
+// Bernstein hash function:
+// This is basically copy-and-paste from StringMap. This likely won't
+// stay here, which is why I didn't both to expose this function from
+// String Map.
+static unsigned BernsteinHash(const char* x) {
+ unsigned int R = 0;
+ for ( ; *x != '\0' ; ++x) R = R * 33 + *x;
+ return R + (R >> 5);
+}
+
+//===----------------------------------------------------------------------===//
+// On Disk Hashtable Logic. This will eventually get refactored and put
+// elsewhere.
+//===----------------------------------------------------------------------===//
+
+template<typename Info>
+class OnDiskChainedHashTableGenerator {
+ unsigned NumBuckets;
+ unsigned NumEntries;
+ llvm::BumpPtrAllocator BA;
+
+ class Item {
+ public:
+ typename Info::key_type key;
+ typename Info::data_type data;
+ Item *next;
+ const uint32_t hash;
+
+ Item(typename Info::key_type_ref k, typename Info::data_type_ref d)
+ : key(k), data(d), next(0), hash(Info::ComputeHash(k)) {}
+ };
+
+ class Bucket {
+ public:
+ Offset off;
+ Item* head;
+ unsigned length;
+
+ Bucket() {}
+ };
+
+ Bucket* Buckets;
+
+private:
+ void insert(Bucket* b, size_t size, Item* E) {
+ unsigned idx = E->hash & (size - 1);
+ Bucket& B = b[idx];
+ E->next = B.head;
+ ++B.length;
+ B.head = E;
+ }
+
+ void resize(size_t newsize) {
+ Bucket* newBuckets = (Bucket*) calloc(newsize, sizeof(Bucket));
+ // Populate newBuckets with the old entries.
+ for (unsigned i = 0; i < NumBuckets; ++i)
+ for (Item* E = Buckets[i].head; E ; ) {
+ Item* N = E->next;
+ E->next = 0;
+ insert(newBuckets, newsize, E);
+ E = N;
+ }
+
+ free(Buckets);
+ NumBuckets = newsize;
+ Buckets = newBuckets;
+ }
+
+public:
+
+ void insert(typename Info::key_type_ref key,
+ typename Info::data_type_ref data) {
+
+ ++NumEntries;
+ if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2);
+ insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data));
+ }
+
+ Offset Emit(llvm::raw_fd_ostream& out) {
+ // Emit the payload of the table.
+ for (unsigned i = 0; i < NumBuckets; ++i) {
+ Bucket& B = Buckets[i];
+ if (!B.head) continue;
+
+ // Store the offset for the data of this bucket.
+ B.off = out.tell();
+
+ // Write out the number of items in the bucket.
+ Emit16(out, B.length);
+
+ // Write out the entries in the bucket.
+ for (Item *I = B.head; I ; I = I->next) {
+ Emit32(out, I->hash);
+ const std::pair<unsigned, unsigned>& Len =
+ Info::EmitKeyDataLength(out, I->key, I->data);
+ Info::EmitKey(out, I->key, Len.first);
+ Info::EmitData(out, I->key, I->data, Len.second);
+ }
+ }
+
+ // Emit the hashtable itself.
+ Pad(out, 4);
+ Offset TableOff = out.tell();
+ Emit32(out, NumBuckets);
+ Emit32(out, NumEntries);
+ for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off);
+
+ return TableOff;
+ }
+
+ OnDiskChainedHashTableGenerator() {
+ NumEntries = 0;
+ NumBuckets = 64;
+ // Note that we do not need to run the constructors of the individual
+ // Bucket objects since 'calloc' returns bytes that are all 0.
+ Buckets = (Bucket*) calloc(NumBuckets, sizeof(Bucket));
+ }
+
+ ~OnDiskChainedHashTableGenerator() {
+ free(Buckets);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// 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* I, const char* E) {
+ for ( ; I != E ; ++I) Out << *I;
+ }
+
+ /// 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();
+
+ /// 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;
+ }
+ };
+
+public:
+ PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
+ : Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
+
+ void GeneratePTH(const std::string *MainFile = 0);
+
+ StatSysCallCache *createStatListener() {
+ return new StatListener(PM);
+ }
+};
+} // 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()) {
+ IM[II] = ++idcount; // Pre-increment since '0' is reserved for NULL.
+ return idcount;
+ }
+
+ return I->second; // We've already added 1.
+}
+
+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()) {
+ // 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());
+ }
+ else
+ Emit32(ResolveID(T.getIdentifierInfo()));
+
+ // 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);
+
+ assert(!Tok.isAtStartOfLine());
+
+ // Did we see 'include'/'import'/'include_next'?
+ if (!Tok.is(tok::identifier)) {
+ EmitToken(Tok);
+ continue;
+ }
+
+ IdentifierInfo* II = PP.LookUpIdentifierInfo(Tok);
+ Tok.setIdentifierInfo(II);
+ tok::PPKeywordKind K = II->getPPKeywordID();
+
+ assert(K != tok::pp_not_keyword);
+ ParsingPreprocessorDirective = true;
+
+ switch (K) {
+ 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.is(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) {
+
+ const char* data = (*I)->getKeyData();
+ EmitBuf(data, data + (*I)->getKeyLength());
+ Emit8('\0');
+ }
+
+ 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 * sizeof(uint32_t); ++i) Emit8(0);
+
+ // Write the name of the MainFile.
+ if (MainFile && MainFile->length() > 0) {
+ Emit16(MainFile->length());
+ EmitBuf(&((*MainFile)[0]), &((*MainFile)[0]) + 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);
+}
+
+void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
+ // Open up the PTH file.
+ std::string ErrMsg;
+ llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
+
+ if (!ErrMsg.empty()) {
+ llvm::errs() << "PTH error: " << ErrMsg << "\n";
+ return;
+ }
+
+ // 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(Out, PP);
+
+ // Install the 'stat' system call listener in the FileManager.
+ PP.getFileManager().setStatCache(PW.createStatListener());
+
+ // 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);
+}
+
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PTHIdKey {
+public:
+ const IdentifierInfo* II;
+ uint32_t FileOffset;
+};
+
+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_fd_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/clang/tools/clang-cc/DependencyFile.cpp b/clang/tools/clang-cc/DependencyFile.cpp
new file mode 100644
index 00000000000..2140afcfefb
--- /dev/null
+++ b/clang/tools/clang-cc/DependencyFile.cpp
@@ -0,0 +1,272 @@
+//===--- 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.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/System/Path.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <string>
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN DependencyFileCallback : public PPCallbacks {
+ std::vector<std::string> Files;
+ llvm::StringSet<> FilesSet;
+ const Preprocessor *PP;
+ std::ofstream OS;
+ const std::string &InputFile;
+ std::vector<std::string> Targets;
+
+private:
+ bool FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType);
+ void OutputDependencyFile();
+
+public:
+ DependencyFileCallback(const Preprocessor *PP,
+ const std::string &InputFile,
+ const std::string &DepFile,
+ const std::vector<std::string> &Targets,
+ const char *&ErrStr);
+ ~DependencyFileCallback();
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType);
+};
+}
+
+static const char *DependencyFileExt = "d";
+static const char *ObjectFileExt = "o";
+
+//===----------------------------------------------------------------------===//
+// Dependency file options
+//===----------------------------------------------------------------------===//
+static llvm::cl::opt<bool>
+GenerateDependencyFile("MD",
+ llvm::cl::desc("Generate dependency for main source file "
+ "(system headers included)"));
+
+static llvm::cl::opt<bool>
+GenerateDependencyFileNoSysHeaders("MMD",
+ llvm::cl::desc("Generate dependency for main source file "
+ "(no system headers)"));
+
+static llvm::cl::opt<std::string>
+DependencyOutputFile("MF",
+ llvm::cl::desc("Specify dependency output file"));
+
+static llvm::cl::list<std::string>
+DependencyTargets("MT",
+ llvm::cl::desc("Specify target for dependency"));
+
+// FIXME: Implement feature
+static llvm::cl::opt<bool>
+PhonyDependencyTarget("MP",
+ llvm::cl::desc("Create phony target for each dependency "
+ "(other than main file)"));
+
+bool clang::CreateDependencyFileGen(Preprocessor *PP,
+ std::string &OutputFile,
+ const std::string &InputFile,
+ const char *&ErrStr) {
+ assert(!InputFile.empty() && "No file given");
+
+ ErrStr = NULL;
+
+ if (!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) {
+ if (!DependencyOutputFile.empty() || !DependencyTargets.empty() ||
+ PhonyDependencyTarget)
+ ErrStr = "Error: to generate dependencies you must specify -MD or -MMD\n";
+ return false;
+ }
+
+ // Handle conflicting options
+ if (GenerateDependencyFileNoSysHeaders)
+ GenerateDependencyFile = false;
+
+ // Determine name of dependency output filename
+ llvm::sys::Path DepFile;
+ if (!DependencyOutputFile.empty())
+ DepFile = DependencyOutputFile;
+ else if (!OutputFile.empty()) {
+ DepFile = OutputFile;
+ DepFile.eraseSuffix();
+ DepFile.appendSuffix(DependencyFileExt);
+ }
+ else {
+ DepFile = InputFile;
+ DepFile.eraseSuffix();
+ DepFile.appendSuffix(DependencyFileExt);
+ }
+
+ std::vector<std::string> Targets(DependencyTargets);
+
+ // Infer target name if unspecified
+ if (Targets.empty()) {
+ if (!OutputFile.empty()) {
+ llvm::sys::Path TargetPath(OutputFile);
+ TargetPath.eraseSuffix();
+ TargetPath.appendSuffix(ObjectFileExt);
+ Targets.push_back(TargetPath.toString());
+ } else {
+ llvm::sys::Path TargetPath(InputFile);
+ TargetPath.eraseSuffix();
+ TargetPath.appendSuffix(ObjectFileExt);
+ Targets.push_back(TargetPath.toString());
+ }
+ }
+
+ DependencyFileCallback *PPDep =
+ new DependencyFileCallback(PP, InputFile, DepFile.toString(),
+ Targets, ErrStr);
+ if (ErrStr){
+ delete PPDep;
+ return false;
+ }
+ else {
+ PP->setPPCallbacks(PPDep);
+ return true;
+ }
+}
+
+/// FileMatchesDepCriteria - Determine whether the given Filename should be
+/// considered as a dependency.
+bool DependencyFileCallback::FileMatchesDepCriteria(const char *Filename,
+ SrcMgr::CharacteristicKind FileType) {
+ if (strcmp(InputFile.c_str(), Filename) != 0 &&
+ strcmp("<built-in>", Filename) != 0) {
+ if (GenerateDependencyFileNoSysHeaders)
+ return FileType == SrcMgr::C_User;
+ else
+ return true;
+ }
+
+ return false;
+}
+
+void DependencyFileCallback::FileChanged(SourceLocation Loc,
+ FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType) {
+ if (Reason != PPCallbacks::EnterFile)
+ return;
+
+ // Depedency 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 (PhonyDependencyTarget) {
+ // 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";
+ }
+ }
+}
+
+DependencyFileCallback::DependencyFileCallback(const Preprocessor *PP,
+ const std::string &InputFile,
+ const std::string &DepFile,
+ const std::vector<std::string>
+ &Targets,
+ const char *&ErrStr)
+ : PP(PP), InputFile(InputFile), Targets(Targets) {
+
+ OS.open(DepFile.c_str());
+ if (OS.fail())
+ ErrStr = "Could not open dependency output file\n";
+ else
+ ErrStr = NULL;
+
+ Files.push_back(InputFile);
+}
+
+DependencyFileCallback::~DependencyFileCallback() {
+ if ((!GenerateDependencyFile && !GenerateDependencyFileNoSysHeaders) ||
+ OS.fail())
+ return;
+
+ OutputDependencyFile();
+ OS.close();
+}
+
diff --git a/clang/tools/clang-cc/DiagChecker.cpp b/clang/tools/clang-cc/DiagChecker.cpp
new file mode 100644
index 00000000000..e5be10abd52
--- /dev/null
+++ b/clang/tools/clang-cc/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.h"
+#include "ASTConsumers.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"
+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/clang/tools/clang-cc/HTMLPrint.cpp b/clang/tools/clang-cc/HTMLPrint.cpp
new file mode 100644
index 00000000000..b2bb29c9eb3
--- /dev/null
+++ b/clang/tools/clang-cc/HTMLPrint.cpp
@@ -0,0 +1,97 @@
+//===--- 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 "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"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Functional HTML pretty-printing.
+//===----------------------------------------------------------------------===//
+
+namespace {
+ class HTMLPrinter : public ASTConsumer {
+ Rewriter R;
+ std::string OutFilename;
+ Diagnostic &Diags;
+ Preprocessor *PP;
+ PreprocessorFactory *PPF;
+ public:
+ HTMLPrinter(const std::string &OutFile, Diagnostic &D, Preprocessor *pp,
+ PreprocessorFactory* ppf)
+ : OutFilename(OutFile), Diags(D), PP(pp), PPF(ppf) {}
+ virtual ~HTMLPrinter();
+
+ void Initialize(ASTContext &context);
+ };
+}
+
+ASTConsumer* clang::CreateHTMLPrinter(const std::string &OutFile,
+ Diagnostic &D, Preprocessor *PP,
+ PreprocessorFactory* PPF) {
+
+ return new HTMLPrinter(OutFile, D, PP, PPF);
+}
+
+void HTMLPrinter::Initialize(ASTContext &context) {
+ R.setSourceMgr(context.getSourceManager());
+}
+
+HTMLPrinter::~HTMLPrinter() {
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Format the file.
+ FileID FID = R.getSourceMgr().getMainFileID();
+ const FileEntry* Entry = R.getSourceMgr().getFileEntryForID(FID);
+
+ html::AddLineNumbers(R, FID);
+ html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
+
+ // 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);
+
+ // Open the output.
+ FILE *OutputFILE;
+ if (OutFilename.empty() || OutFilename == "-")
+ OutputFILE = stdout;
+ else {
+ OutputFILE = fopen(OutFilename.c_str(), "w+");
+ if (OutputFILE == 0) {
+ fprintf(stderr, "Error opening output file '%s'.\n", OutFilename.c_str());
+ exit(1);
+ }
+ }
+
+ // Emit the HTML.
+ const RewriteBuffer &RewriteBuf = R.getEditBuffer(FID);
+ char *Buffer = (char*)malloc(RewriteBuf.size());
+ std::copy(RewriteBuf.begin(), RewriteBuf.end(), Buffer);
+ fwrite(Buffer, 1, RewriteBuf.size(), OutputFILE);
+ free(Buffer);
+
+ if (OutputFILE != stdout) fclose(OutputFILE);
+}
diff --git a/clang/tools/clang-cc/Makefile b/clang/tools/clang-cc/Makefile
new file mode 100644
index 00000000000..4539665d2e8
--- /dev/null
+++ b/clang/tools/clang-cc/Makefile
@@ -0,0 +1,28 @@
+##===- tools/clang-cc/Makefile -----------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+LEVEL = ../../../..
+
+TOOLNAME = clang-cc
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+
+# Clang has no plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Include this here so we can get the configuration of the targets
+# that have been configured for construction. We have to do this
+# early so we can set up LINK_COMPONENTS before including Makefile.rules
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
+USEDLIBS = clangCodeGen.a clangAnalysis.a clangRewrite.a clangSema.a \
+ clangFrontend.a clangAST.a clangParse.a clangLex.a \
+ clangBasic.a
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/clang/tools/clang-cc/PrintParserCallbacks.cpp b/clang/tools/clang-cc/PrintParserCallbacks.cpp
new file mode 100644
index 00000000000..6230591ffcc
--- /dev/null
+++ b/clang/tools/clang-cc/PrintParserCallbacks.cpp
@@ -0,0 +1,819 @@
+//===--- 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.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/Streams.h"
+using namespace clang;
+
+namespace {
+ class ParserPrintActions : public MinimalAction {
+
+ public:
+ ParserPrintActions(Preprocessor &PP) : MinimalAction(PP) {}
+
+ // 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 DeclTy *ActOnDeclarator(Scope *S, Declarator &D,
+ DeclTy *LastInGroup) {
+ llvm::cout << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ llvm::cout << "'" << II->getName() << "'";
+ } else {
+ llvm::cout << "<anon>";
+ }
+ llvm::cout << "\n";
+
+ // Pass up to EmptyActions so that the symbol table is maintained right.
+ return MinimalAction::ActOnDeclarator(S, D, LastInGroup);
+ }
+ /// ActOnPopScope - This callback is called immediately before the specified
+ /// scope is popped and deleted.
+ virtual void ActOnPopScope(SourceLocation Loc, Scope *S) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ MinimalAction::ActOnTranslationUnitScope(Loc, S);
+ }
+
+
+ Action::DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
+ IdentifierInfo *ClassName,
+ SourceLocation ClassLoc,
+ IdentifierInfo *SuperName,
+ SourceLocation SuperLoc,
+ DeclTy * const *ProtoRefs,
+ unsigned NumProtocols,
+ SourceLocation EndProtoLoc,
+ AttributeList *AttrList) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc,
+ ClassName, ClassLoc,
+ SuperName, SuperLoc,
+ ProtoRefs, NumProtocols,
+ EndProtoLoc, AttrList);
+ }
+
+ /// ActOnForwardClassDeclaration -
+ /// Scope will always be top level file scope.
+ Action::DeclTy *ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
+ IdentifierInfo **IdentList,
+ unsigned NumElts) {
+ llvm::cout << __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 DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D) {
+ llvm::cout << __FUNCTION__ << " ";
+ if (IdentifierInfo *II = D.getIdentifier()) {
+ llvm::cout << "'" << II->getName() << "'";
+ } else {
+ llvm::cout << "<anon>";
+ }
+ llvm::cout << "\n";
+ return 0;
+ }
+
+ /// 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(DeclTy *Dcl, ExprArg Init) {
+ llvm::cout << __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 DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// 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 DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// ActOnStartOfFunctionDef - This is called at the start of a function
+ /// definition, after the FunctionDecl has already been created.
+ virtual DeclTy *ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclTy *D) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ /// ActOnFunctionDefBody - This is called when a function body has completed
+ /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef.
+ virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual DeclTy *ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg AsmString) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
+ /// no declarator (e.g. "struct foo;") is parsed.
+ virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// 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 DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace,
+ SourceLocation RBrace, const char *Lang,
+ unsigned StrSize,
+ DeclTy **Decls, unsigned NumDecls) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// 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 DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+ unsigned StrSize, DeclTy *D) {
+ return 0;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Type Parsing Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+ SourceLocation KWLoc, const CXXScopeSpec &SS,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ AttributeList *Attr) {
+ // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
+ // is (struct/union/enum/class).
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ /// Act on @defs() element found when parsing a structure. ClassName is the
+ /// name of the referenced class.
+ virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart,
+ IdentifierInfo *ClassName,
+ llvm::SmallVectorImpl<DeclTy*> &Decls) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD,
+ SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual DeclTy *ActOnIvar(Scope *S, SourceLocation DeclStart,
+ Declarator &D, ExprTy *BitfieldWidth,
+ tok::ObjCKeywordKind visibility) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclTy *TagDecl,
+ DeclTy **Fields, unsigned NumFields,
+ SourceLocation LBrac, SourceLocation RBrac,
+ AttributeList *AttrList) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl,
+ DeclTy *LastEnumConstant,
+ SourceLocation IdLoc, IdentifierInfo *Id,
+ SourceLocation EqualLoc, ExprTy *Val) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual void ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDecl,
+ DeclTy **Elements, unsigned NumElements) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Statement Parsing Callbacks.
+ //===--------------------------------------------------------------------===//
+
+ virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L,
+ SourceLocation R,
+ MultiStmtArg Elts,
+ bool isStmtExpr) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDeclStmt(DeclTy *Decl,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnExprStmt(ExprArg Expr) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt, Scope *CurScope){
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc,
+ IdentifierInfo *II,
+ SourceLocation ColonLoc,
+ StmtArg SubStmt) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, ExprArg CondVal,
+ StmtArg ThenVal,SourceLocation ElseLoc,
+ StmtArg ElseVal) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnStartOfSwitchStmt(ExprArg Cond) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc,
+ StmtArg Switch,
+ StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc,
+ ExprArg Cond, StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body,
+ SourceLocation WhileLoc, ExprArg Cond){
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ ExprArg Third, SourceLocation RParenLoc,
+ StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnObjCForCollectionStmt(
+ SourceLocation ForColLoc,
+ SourceLocation LParenLoc,
+ StmtArg First, ExprArg Second,
+ SourceLocation RParenLoc, StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc,
+ SourceLocation LabelLoc,
+ IdentifierInfo *LabelII) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc,
+ SourceLocation StarLoc,
+ ExprArg DestExp) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc,
+ Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc,
+ Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+ virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc,
+ ExprArg RetValExp) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // Objective-c statements
+ virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc,
+ SourceLocation RParen,
+ DeclTy *Parm, StmtArg Body,
+ StmtArg CatchList) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc,
+ StmtArg Body) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc,
+ StmtArg Try, StmtArg Catch,
+ StmtArg Finally) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
+ ExprArg Throw,
+ Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg SynchExpr,
+ StmtArg SynchBody) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ // C++ Statements
+ virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
+ DeclTy *ExceptionDecl,
+ StmtArg HandlerBlock) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return StmtEmpty();
+ }
+
+ virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
+ StmtArg TryBlock,
+ MultiStmtArg Handlers) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ OverloadedOperatorKind Op,
+ bool HasTrailingLParen, const CXXScopeSpec &SS,
+ bool isAddressOfOperand) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConversionFunctionExpr(
+ Scope *S, SourceLocation OperatorLoc,
+ TypeTy *Type, bool HasTrailingLParen,
+ const CXXScopeSpec &SS,bool isAddressOfOperand) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
+ tok::TokenKind Kind) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCharacterConstant(const Token &) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnNumericConstant(const Token &) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R,
+ ExprArg Val) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return move(Val); // Default impl returns operand.
+ }
+
+ // Postfix Expressions.
+ virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ ExprArg Input) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base,
+ SourceLocation LLoc,
+ ExprArg Idx,
+ SourceLocation RLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
+ SourceLocation OpLoc,
+ tok::TokenKind OpKind,
+ SourceLocation MemberLoc,
+ IdentifierInfo &Member,
+ DeclTy *ImplDecl) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn,
+ SourceLocation LParenLoc,
+ MultiExprArg Args,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult
+ ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType,
+ void *TyOrEx, const SourceRange &ArgRange) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen,
+ ExprArg Op) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
+ MultiExprArg InitList,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ virtual OwningExprResult ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
+ SourceLocation RParenLoc,ExprArg Op){
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc,
+ tok::TokenKind Kind,
+ ExprArg LHS, ExprArg RHS) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ //===--------------------- GNU Extension Expressions ------------------===//
+
+ virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc,
+ SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {// "&&foo"
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc,
+ StmtArg SubStmt,
+ SourceLocation RPLoc) { // "({..})"
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
+ SourceLocation BuiltinLoc,
+ SourceLocation TypeLoc,
+ TypeTy *Arg1,
+ OffsetOfComponent *CompPtr,
+ unsigned NumComponents,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_types_compatible_p(type1, type2)
+ virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc,
+ TypeTy *arg1,TypeTy *arg2,
+ SourceLocation RPLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ // __builtin_choose_expr(constExpr, expr1, expr2)
+ virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc,
+ ExprArg cond, ExprArg expr1,
+ ExprArg expr2,
+ SourceLocation RPLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ // __builtin_va_arg(expr, type)
+ virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc,
+ ExprArg expr, TypeTy *type,
+ SourceLocation RPLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc,
+ StmtArg Body,
+ Scope *CurScope) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual DeclTy *ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc,
+ IdentifierInfo *Ident,
+ SourceLocation LBrace) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual void ActOnFinishNamespaceDef(DeclTy *Dcl,SourceLocation RBrace) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return;
+ }
+
+#if 0
+ // FIXME: AttrList should be deleted by this function, but the definition
+ // would have to be available.
+ virtual DeclTy *ActOnUsingDirective(Scope *CurScope,
+ SourceLocation UsingLoc,
+ SourceLocation NamespcLoc,
+ const CXXScopeSpec &SS,
+ SourceLocation IdentLoc,
+ IdentifierInfo *NamespcName,
+ AttributeList *AttrList) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+#endif
+
+ virtual void ActOnParamDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc,
+ ExprArg defarg) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnParamDefaultArgumentError(DeclTy *param) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void AddCXXDirectInitializerToDecl(DeclTy *Dcl,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return;
+ }
+
+ virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method)
+ {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S,
+ DeclTy *Method) {
+ llvm::cout << __FUNCTION__ << "\n";
+ }
+
+ virtual DeclTy *ActOnStaticAssertDeclaration(SourceLocation AssertLoc,
+ ExprArg AssertExpr,
+ ExprArg AssertMessageExpr) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return 0;
+ }
+
+ virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ SourceLocation LAngleBracketLoc,
+ TypeTy *Ty,
+ SourceLocation RAngleBracketLoc,
+ SourceLocation LParenLoc,
+ ExprArg Op,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
+ SourceLocation LParenLoc,
+ bool isType, void *TyOrExpr,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc,
+ tok::TokenKind Kind) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange,
+ TypeTy *TypeRep,
+ SourceLocation LParenLoc,
+ MultiExprArg Exprs,
+ SourceLocation *CommaLocs,
+ SourceLocation RParenLoc) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+ SourceLocation StartLoc,
+ Declarator &D,
+ SourceLocation EqualLoc,
+ ExprArg AssignExprVal) {
+ llvm::cout << __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) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc,
+ bool UseGlobal, bool ArrayForm,
+ ExprArg Operand) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+
+ virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT,
+ SourceLocation KWLoc,
+ SourceLocation LParen,
+ TypeTy *Ty,
+ SourceLocation RParen) {
+ llvm::cout << __FUNCTION__ << "\n";
+ return ExprEmpty();
+ }
+ };
+}
+
+MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP) {
+ return new ParserPrintActions(PP);
+}
diff --git a/clang/tools/clang-cc/PrintPreprocessedOutput.cpp b/clang/tools/clang-cc/PrintPreprocessedOutput.cpp
new file mode 100644
index 00000000000..0e95c914c4a
--- /dev/null
+++ b/clang/tools/clang-cc/PrintPreprocessedOutput.cpp
@@ -0,0 +1,469 @@
+//===--- 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/Basic/SourceManager.h"
+#include "clang.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/System/Path.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdio>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Preprocessed token printer
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+DisableLineMarkers("P", llvm::cl::desc("Disable linemarker output in -E mode"));
+static llvm::cl::opt<bool>
+EnableCommentOutput("C", llvm::cl::desc("Enable comment output in -E mode"));
+static llvm::cl::opt<bool>
+EnableMacroCommentOutput("CC",
+ llvm::cl::desc("Enable comment output in -E mode, "
+ "even from macro expansions"));
+static llvm::cl::opt<bool>
+DumpMacros("dM", llvm::cl::desc("Print macro definitions in -E mode instead of"
+ " normal output"));
+
+
+namespace {
+class PrintPPOutputPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ TokenConcatenation ConcatInfo;
+public:
+ llvm::raw_ostream &OS;
+private:
+ unsigned CurLine;
+ bool EmittedTokensOnThisLine;
+ SrcMgr::CharacteristicKind FileType;
+ llvm::SmallString<512> CurFilename;
+ bool Initialized;
+public:
+ PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os)
+ : PP(pp), ConcatInfo(PP), OS(os) {
+ CurLine = 0;
+ CurFilename += "<uninit>";
+ EmittedTokensOnThisLine = 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);
+};
+} // end anonymous namespace
+
+void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
+ const char *Extra,
+ unsigned ExtraLen) {
+ if (EmittedTokensOnThisLine) {
+ OS << '\n';
+ EmittedTokensOnThisLine = 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)
+ return true;
+
+ OS << '\n';
+ EmittedTokensOnThisLine = 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);
+ 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;
+}
+
+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);
+ }
+}
+
+/// PrintMacroDefinition - Print a macro definition in a form that will be
+/// properly accepted back as a definition.
+static void PrintMacroDefinition(IdentifierInfo &II, const MacroInfo &MI,
+ Preprocessor &PP, llvm::raw_ostream &OS) {
+ // Ignore computed macros like __LINE__ and friends.
+ if (MI.isBuiltinMacro()) return;
+ 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[0];
+ unsigned SpellingLen = PP.getSpelling(*I, Buffer);
+ OS.write(Buffer, SpellingLen);
+ }
+ OS << "\n";
+}
+
+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;
+ }
+ };
+}
+
+/// DoPrintPreprocessedInput - This implements -E mode.
+///
+void clang::DoPrintPreprocessedInput(Preprocessor &PP,
+ const std::string &OutFile) {
+ // Inform the preprocessor whether we want it to retain comments or not, due
+ // to -C or -CC.
+ PP.SetCommentRetentionState(EnableCommentOutput, EnableMacroCommentOutput);
+
+ // Open the output buffer.
+ std::string Err;
+ llvm::raw_fd_ostream OS(OutFile.empty() ? "-" : OutFile.c_str(), false, Err);
+ if (!Err.empty()) {
+ fprintf(stderr, "%s\n", Err.c_str());
+ exit(1);
+ }
+
+ OS.SetBufferSize(64*1024);
+
+ if (DumpMacros) {
+ // -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)
+ PrintMacroDefinition(*MacrosByID[i].first, *MacrosByID[i].second, PP, OS);
+
+ } else {
+ PrintPPOutputPPCallbacks *Callbacks
+ = new PrintPPOutputPPCallbacks(PP, OS);
+ 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';
+ }
+
+ // Flush the ostream.
+ OS.flush();
+
+ // If an error occurred, remove the output file.
+ if (PP.getDiagnostics().hasErrorOccurred() && !OutFile.empty())
+ llvm::sys::Path(OutFile).eraseFromDisk();
+}
+
diff --git a/clang/tools/clang-cc/RewriteBlocks.cpp b/clang/tools/clang-cc/RewriteBlocks.cpp
new file mode 100644
index 00000000000..2672d32ef05
--- /dev/null
+++ b/clang/tools/clang-cc/RewriteBlocks.cpp
@@ -0,0 +1,1146 @@
+//===--- 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 "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 InFileName;
+ std::string OutFileName;
+
+ std::string Preamble;
+public:
+ RewriteBlocks(std::string inFile, std::string outFile, 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(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, std::string outFile,
+ Diagnostic &D, const LangOptions &LOpts) :
+ Diags(D), LangOpts(LOpts) {
+ IsHeader = IsHeaderFile(inFile);
+ InFileName = inFile;
+ OutFileName = outFile;
+ CurFunctionDef = 0;
+ CurMethodDef = 0;
+ RewriteFailedDiag = Diags.getCustomDiagID(Diagnostic::Warning,
+ "rewriting failed");
+}
+
+ASTConsumer *clang::CreateBlockRewriter(const std::string& InFile,
+ const std::string& OutFile,
+ Diagnostic &Diags,
+ const LangOptions &LangOpts) {
+ return new RewriteBlocks(InFile, OutFile, 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());
+
+ 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(),
+ E = ClassDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
+ E = ClassDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
+ for (ObjCCategoryDecl::instmeth_iterator I = CatDecl->instmeth_begin(),
+ E = CatDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
+ E = CatDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+void RewriteBlocks::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
+ E = PDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+ for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
+ E = PDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDecl(*I);
+}
+
+//===----------------------------------------------------------------------===//
+// Top Level Driver Code
+//===----------------------------------------------------------------------===//
+
+void RewriteBlocks::HandleTopLevelDecl(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);
+ 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);
+ 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);
+ 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);
+ (*I)->getType().getAsStringInternal(ArgName);
+ 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->getPointerType((*I)->getType()).getAsStringInternal(ArgName);
+ 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);
+ 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);
+ 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);
+
+ // 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);
+
+ if (CompoundStmt *Body = FD->getBody()) {
+ 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()) {
+ 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());
+
+ // 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(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+}
diff --git a/clang/tools/clang-cc/RewriteMacros.cpp b/clang/tools/clang-cc/RewriteMacros.cpp
new file mode 100644
index 00000000000..809a3b510b2
--- /dev/null
+++ b/clang/tools/clang-cc/RewriteMacros.cpp
@@ -0,0 +1,236 @@
+//===--- 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.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,const std::string &InFileName,
+ const std::string &OutFileName) {
+ SourceManager &SM = PP.getSourceManager();
+
+ Rewriter Rewrite;
+ Rewrite.setSourceMgr(SM);
+ 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());
+ }
+
+ // Create the output file.
+ llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
+ llvm::raw_ostream *OutFile;
+ if (OutFileName == "-") {
+ OutFile = &llvm::outs();
+ } else if (!OutFileName.empty()) {
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), false, Err);
+ OwnedStream.reset(OutFile);
+ } else if (InFileName == "-") {
+ OutFile = &llvm::outs();
+ } else {
+ llvm::sys::Path Path(InFileName);
+ Path.eraseSuffix();
+ Path.appendSuffix("cpp");
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(), false, Err);
+ OwnedStream.reset(OutFile);
+ }
+
+ // 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");
+ *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
+ } else {
+ fprintf(stderr, "No changes\n");
+ }
+ OutFile->flush();
+}
diff --git a/clang/tools/clang-cc/RewriteObjC.cpp b/clang/tools/clang-cc/RewriteObjC.cpp
new file mode 100644
index 00000000000..c3cc2c3852a
--- /dev/null
+++ b/clang/tools/clang-cc/RewriteObjC.cpp
@@ -0,0 +1,4588 @@
+//===--- 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 "ASTConsumers.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/TranslationUnit.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/CommandLine.h"
+#include "llvm/Support/Streams.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+using llvm::utostr;
+
+static llvm::cl::opt<bool>
+SilenceRewriteMacroWarning("Wno-rewrite-macros", llvm::cl::init(false),
+ llvm::cl::desc("Silence ObjC rewriting warnings"));
+
+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;
+
+ unsigned NumObjCStringLiterals;
+
+ FunctionDecl *MsgSendFunctionDecl;
+ FunctionDecl *MsgSendSuperFunctionDecl;
+ FunctionDecl *MsgSendStretFunctionDecl;
+ FunctionDecl *MsgSendSuperStretFunctionDecl;
+ FunctionDecl *MsgSendFpretFunctionDecl;
+ FunctionDecl *GetClassFunctionDecl;
+ FunctionDecl *GetMetaClassFunctionDecl;
+ FunctionDecl *SelGetUidFunctionDecl;
+ FunctionDecl *CFStringFunctionDecl;
+ FunctionDecl *GetProtocolFunctionDecl;
+ 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;
+
+ // Needed for header files being rewritten
+ bool IsHeader;
+
+ std::string InFileName;
+ std::string OutFileName;
+
+ 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);
+
+ virtual void InitializeTU(TranslationUnit &TU) {
+ TU.SetOwnsDecls(false);
+ Initialize(TU.getContext());
+ }
+
+
+ // Top Level Driver code.
+ virtual void HandleTopLevelDecl(Decl *D);
+ void HandleDeclInMainFile(Decl *D);
+ RewriteObjC(std::string inFile, std::string outFile,
+ Diagnostic &D, const LangOptions &LOpts);
+
+ ~RewriteObjC() {}
+
+ virtual void HandleTranslationUnit(TranslationUnit& TU);
+
+ 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);
+ 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 SynthGetProtocolFunctionDecl();
+ void SynthSuperContructorFunctionDecl();
+
+ // Metadata emission.
+ void RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl,
+ std::string &Result);
+
+ void RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *CDecl,
+ std::string &Result);
+
+ typedef ObjCCategoryImplDecl::instmeth_iterator instmeth_iterator;
+ void RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
+ instmeth_iterator MethodEnd,
+ bool IsInstanceMethod,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result);
+
+ void RewriteObjCProtocolsMetaData(const ObjCList<ObjCProtocolDecl>
+ &Protocols,
+ 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);
+ 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);
+ 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 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, std::string outFile,
+ Diagnostic &D, const LangOptions &LOpts)
+ : Diags(D), LangOpts(LOpts) {
+ IsHeader = IsHeaderFile(inFile);
+ InFileName = inFile;
+ OutFileName = outFile;
+ 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::CreateCodeRewriterTest(const std::string& InFile,
+ const std::string& OutFile,
+ Diagnostic &Diags,
+ const LangOptions &LOpts) {
+ return new RewriteObjC(InFile, OutFile, Diags, LOpts);
+}
+
+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;
+ GetProtocolFunctionDecl = 0;
+ ConstantStringClassReference = 0;
+ NSStringRecord = 0;
+ CurMethodDef = 0;
+ CurFunctionDef = 0;
+ GlobalVarDecl = 0;
+ SuperStructDecl = 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());
+
+ // 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::HandleTopLevelDecl(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(),
+ DIEnd = LSD->decls_end();
+ DI != DIEnd; ++DI)
+ HandleTopLevelDecl(*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());
+
+ // Add the rewritten getter to trigger meta data generation. An alternate, and
+ // possibly cleaner approach is to hack RewriteObjCMethodsMetaData() to deal
+ // with properties explicitly. The following addInstanceMethod() required far
+ // less code change (and actually models what the rewriter is doing).
+ if (IMD)
+ IMD->addInstanceMethod(PD->getGetterMethodDecl());
+ else
+ CID->addInstanceMethod(PD->getGetterMethodDecl());
+
+ 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());
+
+ // Add the rewritten setter to trigger meta data generation.
+ if (IMD)
+ IMD->addInstanceMethod(PD->getSetterMethodDecl());
+ else
+ CID->addInstanceMethod(PD->getSetterMethodDecl());
+}
+
+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(),
+ E = CatDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCCategoryDecl::classmeth_iterator I = CatDecl->classmeth_begin(),
+ E = CatDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(CatDecl->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(),
+ E = PDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
+ E = PDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ SourceLocation LocEnd = PDecl->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->getObjCIdType().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);
+ } else
+ PDecl->getType().getAsStringInternal(Name);
+ 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() : CID->instmeth_begin(),
+ E = IMD ? IMD->instmeth_end() : CID->instmeth_end(); I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getBody()->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() : CID->classmeth_begin(),
+ E = IMD ? IMD->classmeth_end() : CID->classmeth_end(); I != E; ++I) {
+ std::string ResultStr;
+ ObjCMethodDecl *OMD = *I;
+ RewriteObjCMethodDecl(OMD, ResultStr);
+ SourceLocation LocStart = OMD->getLocStart();
+ SourceLocation LocEnd = OMD->getBody()->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() : CID->propimpl_begin(),
+ E = IMD ? IMD->propimpl_end() : CID->propimpl_end(); 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(),
+ E = ClassDecl->prop_end(); I != E; ++I)
+ RewriteProperty(*I);
+ for (ObjCInterfaceDecl::instmeth_iterator I = ClassDecl->instmeth_begin(),
+ E = ClassDecl->instmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+ for (ObjCInterfaceDecl::classmeth_iterator I = ClassDecl->classmeth_begin(),
+ E = ClassDecl->classmeth_end(); I != E; ++I)
+ RewriteMethodDeclaration(*I);
+
+ // Lastly, comment out the @end.
+ ReplaceText(ClassDecl->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(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(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->getSolitaryDecl());
+ 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.
+ 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 += " 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);
+ 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);
+}
+
+// SynthGetProtocolFunctionDecl - Protocol objc_getProtocol(const char *proto);
+void RewriteObjC::SynthGetProtocolFunctionDecl() {
+ IdentifierInfo *SelGetProtoIdent = &Context->Idents.get("objc_getProtocol");
+ llvm::SmallVector<QualType, 16> ArgTys;
+ ArgTys.push_back(Context->getPointerType(
+ Context->CharTy.getQualifiedType(QualType::Const)));
+ QualType getFuncType = Context->getFunctionType(Context->getObjCProtoType(),
+ &ArgTys[0], ArgTys.size(),
+ false /*isVariadic*/, 0);
+ GetProtocolFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
+ SourceLocation(),
+ SelGetProtoIdent, 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);
+ 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(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(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 *OMD = Exp->getMethodDecl()) {
+ QualType resultType = OMD->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) DeclRefExpr(
+ CurMethodDef->getSelfDecl(),
+ Context->getObjCIdType(),
+ SourceLocation()));
+ 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. Null out the argument in
+ // the original expression, since we will delete it below.
+ 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);
+ }
+ return ReplacingStmt;
+}
+
+Stmt *RewriteObjC::RewriteMessageExpr(ObjCMessageExpr *Exp) {
+ Stmt *ReplacingStmt = SynthMessageExpr(Exp);
+
+ //ReplacingStmt->dump();
+ // Now do the actual rewrite.
+ ReplaceStmt(Exp, ReplacingStmt);
+
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return ReplacingStmt;
+}
+
+/// RewriteObjCProtocolExpr - Rewrite a protocol expression into
+/// call to objc_getProtocol("proto-name").
+Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
+ if (!GetProtocolFunctionDecl)
+ SynthGetProtocolFunctionDecl();
+ // Create a call to objc_getProtocol("ProtocolName").
+ llvm::SmallVector<Expr*, 8> ProtoExprs;
+ QualType argType = Context->getPointerType(Context->CharTy);
+ ProtoExprs.push_back(StringLiteral::Create(*Context,
+ Exp->getProtocol()->getNameAsCString(),
+ strlen(Exp->getProtocol()->getNameAsCString()),
+ false, argType, SourceLocation()));
+ CallExpr *ProtoExp = SynthesizeCallToFunctionDecl(GetProtocolFunctionDecl,
+ &ProtoExprs[0],
+ ProtoExprs.size());
+ ReplaceStmt(Exp, ProtoExp);
+ // delete Exp; leak for now, see RewritePropertySetter() usage for more info.
+ return ProtoExp;
+
+}
+
+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);
+ 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);
+
+ 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);
+ 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.
+void RewriteObjC::RewriteObjCMethodsMetaData(instmeth_iterator MethodBegin,
+ instmeth_iterator 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[];
+ }
+ */
+ 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(MethodEnd-MethodBegin);
+ 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(MethodEnd-MethodBegin) + "\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";
+}
+
+/// RewriteObjCProtocolsMetaData - Rewrite protocols meta-data.
+void RewriteObjC::
+RewriteObjCProtocolsMetaData(const ObjCList<ObjCProtocolDecl> &Protocols,
+ const char *prefix,
+ const char *ClassName,
+ std::string &Result) {
+ static bool objc_protocol_methods = false;
+ if (Protocols.empty()) return;
+
+ for (unsigned i = 0; i != Protocols.size(); i++) {
+ ObjCProtocolDecl *PDecl = Protocols[i];
+ // 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 += "\tSEL _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))
+ continue;
+
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ unsigned NumMethods = std::distance(PDecl->instmeth_begin(),
+ PDecl->instmeth_end());
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct protocol_methods protocols[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_inst_meth\")))= "
+ "{\n\t" + utostr(NumMethods) + "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
+ E = PDecl->instmeth_end(); I != E; ++I) {
+ if (I == PDecl->instmeth_begin())
+ Result += "\t ,{{(SEL)\"";
+ else
+ Result += "\t ,{(SEL)\"";
+ Result += (*I)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output class methods declared in this protocol.
+ unsigned NumMethods = std::distance(PDecl->classmeth_begin(),
+ PDecl->classmeth_end());
+ if (NumMethods > 0) {
+ /* struct _objc_protocol_method_list {
+ int protocol_method_count;
+ struct protocol_methods protocols[];
+ }
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint protocol_method_count;\n";
+ Result += "\tstruct protocol_methods protocols[";
+ Result += utostr(NumMethods);
+ Result += "];\n} _OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __cat_cls_meth\")))= "
+ "{\n\t";
+ Result += utostr(NumMethods);
+ Result += "\n";
+
+ // Output instance methods declared in this protocol.
+ for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
+ E = PDecl->classmeth_end(); I != E; ++I) {
+ if (I == PDecl->classmeth_begin())
+ Result += "\t ,{{(SEL)\"";
+ else
+ Result += "\t ,{(SEL)\"";
+ Result += (*I)->getSelector().getAsString().c_str();
+ std::string MethodTypeString;
+ Context->getObjCEncodingForMethodDecl((*I), MethodTypeString);
+ Result += "\", \"";
+ Result += MethodTypeString;
+ Result += "\"}\n";
+ }
+ Result += "\t }\n};\n";
+ }
+
+ // Output:
+ /* struct _objc_protocol {
+ // Objective-C 1.0 extensions
+ struct _objc_protocol_extension *isa;
+ char *protocol_name;
+ struct _objc_protocol **protocol_list;
+ struct _objc_protocol_method_list *instance_methods;
+ struct _objc_protocol_method_list *class_methods;
+ };
+ */
+ static bool objc_protocol = false;
+ if (!objc_protocol) {
+ Result += "\nstruct _objc_protocol {\n";
+ Result += "\tstruct _objc_protocol_extension *isa;\n";
+ Result += "\tchar *protocol_name;\n";
+ Result += "\tstruct _objc_protocol **protocol_list;\n";
+ Result += "\tstruct _objc_protocol_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_protocol_method_list *class_methods;\n";
+ Result += "};\n";
+
+ objc_protocol = true;
+ }
+
+ Result += "\nstatic struct _objc_protocol _OBJC_PROTOCOL_";
+ Result += PDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __protocol\")))= "
+ "{\n\t0, \"";
+ Result += PDecl->getNameAsString();
+ Result += "\", 0, ";
+ if (PDecl->instmeth_begin() != PDecl->instmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_INSTANCE_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += ", ";
+ }
+ else
+ Result += "0, ";
+ if (PDecl->classmeth_begin() != PDecl->classmeth_end()) {
+ Result += "(struct _objc_protocol_method_list *)&_OBJC_PROTOCOL_CLASS_METHODS_";
+ Result += PDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += "0\n";
+ Result += "};\n";
+
+ // Mark this protocol as having been generated.
+ if (!ObjCSynthesizedProtocols.insert(PDecl))
+ assert(false && "protocol already synthesized");
+ }
+ // 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
+ RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
+ true, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "CATEGORY_", FullCategoryName.c_str(),
+ Result);
+
+ // Protocols referenced in class declaration?
+ // Null CDecl is case of a category implementation with no category interface
+ if (CDecl)
+ RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(), "CATEGORY",
+ FullCategoryName.c_str(), Result);
+
+ /* struct _objc_category {
+ char *category_name;
+ char *class_name;
+ struct _objc_method_list *instance_methods;
+ struct _objc_method_list *class_methods;
+ struct _objc_protocol_list *protocols;
+ // Objective-C 1.0 extensions
+ uint32_t size; // sizeof (struct _objc_category)
+ struct _objc_property_list *instance_properties; // category's own
+ // @property decl.
+ };
+ */
+
+ static bool objc_category = false;
+ if (!objc_category) {
+ Result += "\nstruct _objc_category {\n";
+ Result += "\tchar *category_name;\n";
+ Result += "\tchar *class_name;\n";
+ Result += "\tstruct _objc_method_list *instance_methods;\n";
+ Result += "\tstruct _objc_method_list *class_methods;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tunsigned int size;\n";
+ Result += "\tstruct _objc_property_list *instance_properties;\n";
+ Result += "};\n";
+ objc_category = true;
+ }
+ Result += "\nstatic struct _objc_category _OBJC_CATEGORY_";
+ Result += FullCategoryName;
+ Result += " __attribute__ ((used, section (\"__OBJC, __category\")))= {\n\t\"";
+ Result += IDecl->getNameAsString();
+ Result += "\"\n\t, \"";
+ Result += ClassDecl->getNameAsString();
+ Result += "\"\n";
+
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_INSTANCE_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\t, (struct _objc_method_list *)"
+ "&_OBJC_CATEGORY_CLASS_METHODS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+
+ if (CDecl && CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t, (struct _objc_protocol_list *)&_OBJC_CATEGORY_PROTOCOLS_";
+ Result += FullCategoryName;
+ Result += "\n";
+ }
+ else
+ Result += "\t, 0\n";
+ Result += "\t, sizeof(struct _objc_category), 0\n};\n";
+}
+
+/// SynthesizeIvarOffsetComputation - This rutine synthesizes computation of
+/// ivar offset.
+void RewriteObjC::SynthesizeIvarOffsetComputation(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->ImplicitInterfaceDecl()) {
+ // FIXME: Implementation of a class with no @interface (legacy) doese not
+ // produce correct synthesis as yet.
+ SynthesizeObjCInternalStruct(CDecl, Result);
+ }
+
+ // Build _objc_ivar_list metadata for classes ivars if needed
+ unsigned NumIvars = !IDecl->ivar_empty()
+ ? IDecl->ivar_size()
+ : (CDecl ? CDecl->ivar_size() : 0);
+ if (NumIvars > 0) {
+ static bool objc_ivar = false;
+ if (!objc_ivar) {
+ /* struct _objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ };
+ */
+ Result += "\nstruct _objc_ivar {\n";
+ Result += "\tchar *ivar_name;\n";
+ Result += "\tchar *ivar_type;\n";
+ Result += "\tint ivar_offset;\n";
+ Result += "};\n";
+
+ objc_ivar = true;
+ }
+
+ /* struct {
+ int ivar_count;
+ struct _objc_ivar ivar_list[nIvars];
+ };
+ */
+ Result += "\nstatic struct {\n";
+ Result += "\tint ivar_count;\n";
+ Result += "\tstruct _objc_ivar ivar_list[";
+ Result += utostr(NumIvars);
+ Result += "];\n} _OBJC_INSTANCE_VARIABLES_";
+ Result += IDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __instance_vars\")))= "
+ "{\n\t";
+ Result += utostr(NumIvars);
+ Result += "\n";
+
+ ObjCInterfaceDecl::ivar_iterator IVI, IVE;
+ if (!IDecl->ivar_empty()) {
+ IVI = IDecl->ivar_begin();
+ IVE = IDecl->ivar_end();
+ } else {
+ IVI = CDecl->ivar_begin();
+ IVE = CDecl->ivar_end();
+ }
+ Result += "\t,{{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), StrEncoding);
+ Result += StrEncoding;
+ Result += "\", ";
+ SynthesizeIvarOffsetComputation(IDecl, *IVI, Result);
+ Result += "}\n";
+ for (++IVI; IVI != IVE; ++IVI) {
+ Result += "\t ,{\"";
+ Result += (*IVI)->getNameAsString();
+ Result += "\", \"";
+ std::string StrEncoding;
+ Context->getObjCEncodingForType((*IVI)->getType(), 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
+ RewriteObjCMethodsMetaData(IDecl->instmeth_begin(), IDecl->instmeth_end(),
+ true, "", IDecl->getNameAsCString(), Result);
+
+ // Build _objc_method_list for class's class methods if needed
+ RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(),
+ false, "", IDecl->getNameAsCString(), Result);
+
+ // Protocols referenced in class declaration?
+ RewriteObjCProtocolsMetaData(CDecl->getReferencedProtocols(),
+ "CLASS", CDecl->getNameAsCString(), Result);
+
+
+ // Declaration of class/meta-class metadata
+ /* struct _objc_class {
+ struct _objc_class *isa; // or const char *root_class_name when metadata
+ const char *super_class_name;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct _objc_ivar_list *ivars;
+ struct _objc_method_list *methods;
+ struct objc_cache *cache;
+ struct objc_protocol_list *protocols;
+ const char *ivar_layout;
+ struct _objc_class_ext *ext;
+ };
+ */
+ static bool objc_class = false;
+ if (!objc_class) {
+ Result += "\nstruct _objc_class {\n";
+ Result += "\tstruct _objc_class *isa;\n";
+ Result += "\tconst char *super_class_name;\n";
+ Result += "\tchar *name;\n";
+ Result += "\tlong version;\n";
+ Result += "\tlong info;\n";
+ Result += "\tlong instance_size;\n";
+ Result += "\tstruct _objc_ivar_list *ivars;\n";
+ Result += "\tstruct _objc_method_list *methods;\n";
+ Result += "\tstruct objc_cache *cache;\n";
+ Result += "\tstruct _objc_protocol_list *protocols;\n";
+ Result += "\tconst char *ivar_layout;\n";
+ Result += "\tstruct _objc_class_ext *ext;\n";
+ Result += "};\n";
+ objc_class = true;
+ }
+
+ // Meta-class metadata generation.
+ ObjCInterfaceDecl *RootClass = 0;
+ ObjCInterfaceDecl *SuperClass = CDecl->getSuperClass();
+ while (SuperClass) {
+ RootClass = SuperClass;
+ SuperClass = SuperClass->getSuperClass();
+ }
+ SuperClass = CDecl->getSuperClass();
+
+ Result += "\nstatic struct _objc_class _OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __meta_class\")))= "
+ "{\n\t(struct _objc_class *)\"";
+ Result += (RootClass ? RootClass->getNameAsString() : CDecl->getNameAsString());
+ Result += "\"";
+
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // Set 'ivars' field for root class to 0. ObjC1 runtime does not use it.
+ // 'info' field is initialized to CLS_META(2) for metaclass
+ Result += ", 0,2, sizeof(struct _objc_class), 0";
+ if (IDecl->classmeth_begin() != IDecl->classmeth_end()) {
+ Result += "\n\t, (struct _objc_method_list *)&_OBJC_CLASS_METHODS_";
+ Result += IDecl->getNameAsString();
+ Result += "\n";
+ }
+ else
+ Result += ", 0\n";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += "\t,0, (struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ",0,0\n";
+ }
+ else
+ Result += "\t,0,0,0,0\n";
+ Result += "};\n";
+
+ // class metadata generation.
+ Result += "\nstatic struct _objc_class _OBJC_CLASS_";
+ Result += CDecl->getNameAsString();
+ Result += " __attribute__ ((used, section (\"__OBJC, __class\")))= "
+ "{\n\t&_OBJC_METACLASS_";
+ Result += CDecl->getNameAsString();
+ if (SuperClass) {
+ Result += ", \"";
+ Result += SuperClass->getNameAsString();
+ Result += "\", \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ else {
+ Result += ", 0, \"";
+ Result += CDecl->getNameAsString();
+ Result += "\"";
+ }
+ // 'info' field is initialized to CLS_CLASS(1) for class
+ Result += ", 0,1";
+ if (!ObjCSynthesizedStructs.count(CDecl))
+ Result += ",0";
+ else {
+ // class has size. Must synthesize its size.
+ Result += ",sizeof(struct ";
+ Result += CDecl->getNameAsString();
+ if (LangOpts.Microsoft)
+ Result += "_IMPL";
+ Result += ")";
+ }
+ if (NumIvars > 0) {
+ Result += ", (struct _objc_ivar_list *)&_OBJC_INSTANCE_VARIABLES_";
+ Result += CDecl->getNameAsString();
+ Result += "\n\t";
+ }
+ else
+ Result += ",0";
+ if (IDecl->instmeth_begin() != IDecl->instmeth_end()) {
+ Result += ", (struct _objc_method_list *)&_OBJC_INSTANCE_METHODS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0\n\t";
+ }
+ else
+ Result += ",0,0";
+ if (CDecl->protocol_begin() != CDecl->protocol_end()) {
+ Result += ", (struct _objc_protocol_list*)&_OBJC_CLASS_PROTOCOLS_";
+ Result += CDecl->getNameAsString();
+ Result += ", 0,0\n";
+ }
+ else
+ Result += ",0,0,0\n";
+ Result += "};\n";
+}
+
+/// RewriteImplementations - This routine rewrites all method implementations
+/// and emits meta-data.
+
+void RewriteObjC::RewriteImplementations() {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // Rewrite implemented methods
+ for (int i = 0; i < ClsDefCount; i++)
+ RewriteImplementationDecl(ClassImplementation[i]);
+
+ for (int i = 0; i < CatDefCount; i++)
+ RewriteImplementationDecl(CategoryImplementation[i]);
+}
+
+void RewriteObjC::SynthesizeMetaDataIntoBuffer(std::string &Result) {
+ int ClsDefCount = ClassImplementation.size();
+ int CatDefCount = CategoryImplementation.size();
+
+ // 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) {
+ 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);
+ 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);
+ 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);
+ 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);
+ (*I)->getType().getAsStringInternal(ArgName);
+ 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->getPointerType((*I)->getType()).getAsStringInternal(ArgName);
+ 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 (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.
+ // 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 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);
+}
+
+void 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);
+}
+
+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())
+ 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);
+ 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);
+
+ if (CompoundStmt *Body = FD->getBody()) {
+ 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(),
+ e = RD->field_end(); i != e; ++i) {
+ FieldDecl *FD = *i;
+ if (isTopLevelBlockPointerType(FD->getType()))
+ RewriteBlockPointerDecl(FD);
+ }
+ }
+ return;
+ }
+ // Nothing yet.
+}
+
+void RewriteObjC::HandleTranslationUnit(TranslationUnit& TU) {
+ // Get the top-level buffer that this corresponds to.
+
+ // Rewrite tabs if we care.
+ //RewriteTabs();
+
+ if (Diags.hasErrorOccurred())
+ return;
+
+ // Create the output file.
+
+ llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
+ llvm::raw_ostream *OutFile;
+ if (OutFileName == "-") {
+ OutFile = &llvm::outs();
+ } else 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);
+ Path.eraseSuffix();
+ Path.appendSuffix("cpp");
+ std::string Err;
+ OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(),
+ // set binary mode (critical for Windoze)
+ true,
+ Err);
+ OwnedStream.reset(OutFile);
+ }
+
+ RewriteInclude();
+
+ 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()) {
+ // Rewrite Objective-c meta data*
+ std::string ResultStr;
+ SynthesizeMetaDataIntoBuffer(ResultStr);
+ // Emit metadata.
+ *OutFile << ResultStr;
+ }
+ OutFile->flush();
+}
+
diff --git a/clang/tools/clang-cc/RewriteTest.cpp b/clang/tools/clang-cc/RewriteTest.cpp
new file mode 100644
index 00000000000..1d0c6f9e9c0
--- /dev/null
+++ b/clang/tools/clang-cc/RewriteTest.cpp
@@ -0,0 +1,40 @@
+//===--- 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.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/TokenRewriter.h"
+#include <iostream>
+
+void clang::DoRewriteTest(Preprocessor &PP, const std::string &InFileName,
+ const std::string &OutFileName) {
+ 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)
+ std::cout << PP.getSpelling(*I);
+}
diff --git a/clang/tools/clang-cc/SerializationTest.cpp b/clang/tools/clang-cc/SerializationTest.cpp
new file mode 100644
index 00000000000..e489a19ff83
--- /dev/null
+++ b/clang/tools/clang-cc/SerializationTest.cpp
@@ -0,0 +1,193 @@
+//===--- SerializationTest.cpp - Experimental Object 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 prototype code for serialization of objects in clang.
+// It is not intended yet for public use, but simply is a placeholder to
+// experiment with new serialization features. Serialization will eventually
+// be integrated as a proper component of the clang libraries.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/CFG.h"
+#include "clang/AST/Decl.h"
+#include "clang.h"
+#include "ASTConsumers.h"
+#include "clang/AST/TranslationUnit.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Streams.h"
+#include <fstream>
+#include <cstring>
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Driver code.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class SerializationTest : public ASTConsumer {
+ Diagnostic &Diags;
+ FileManager &FMgr;
+public:
+ SerializationTest(Diagnostic &d, FileManager& fmgr)
+ : Diags(d), FMgr(fmgr) {}
+
+ ~SerializationTest() {}
+
+ virtual void HandleTranslationUnit(TranslationUnit& TU);
+
+private:
+ bool Serialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint,
+ TranslationUnit& TU);
+
+ bool Deserialize(llvm::sys::Path& Filename, llvm::sys::Path& FNameDeclPrint);
+};
+
+} // end anonymous namespace
+
+ASTConsumer*
+clang::CreateSerializationTest(Diagnostic &Diags, FileManager& FMgr) {
+ return new SerializationTest(Diags, FMgr);
+}
+
+
+bool SerializationTest::Serialize(llvm::sys::Path& Filename,
+ llvm::sys::Path& FNameDeclPrint,
+ TranslationUnit& TU) {
+ {
+ // Pretty-print the decls to a temp file.
+ std::string Err;
+ llvm::raw_fd_ostream DeclPP(FNameDeclPrint.c_str(), true, Err);
+ assert (Err.empty() && "Could not open file for printing out decls.");
+ llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
+
+ for (TranslationUnit::iterator I=TU.begin(), E=TU.end(); I!=E; ++I)
+ FilePrinter->HandleTopLevelDecl(*I);
+ }
+
+ // Serialize the translation unit.
+ return EmitASTBitcodeFile(TU,Filename);
+}
+
+bool SerializationTest::Deserialize(llvm::sys::Path& Filename,
+ llvm::sys::Path& FNameDeclPrint) {
+
+ // Deserialize the translation unit.
+ TranslationUnit* NewTU = ReadASTBitcodeFile(Filename, FMgr);
+
+ if (!NewTU)
+ return false;
+
+ {
+ // Pretty-print the deserialized decls to a temp file.
+ std::string Err;
+ llvm::raw_fd_ostream DeclPP(FNameDeclPrint.c_str(), true, Err);
+ assert (Err.empty() && "Could not open file for printing out decls.");
+ llvm::OwningPtr<ASTConsumer> FilePrinter(CreateASTPrinter(&DeclPP));
+
+ for (TranslationUnit::iterator I=NewTU->begin(), E=NewTU->end(); I!=E; ++I)
+ FilePrinter->HandleTopLevelDecl(*I);
+ }
+
+ delete NewTU;
+
+ return true;
+}
+
+namespace {
+ class TmpDirJanitor {
+ llvm::sys::Path& Dir;
+ public:
+ explicit TmpDirJanitor(llvm::sys::Path& dir) : Dir(dir) {}
+
+ ~TmpDirJanitor() {
+ llvm::cerr << "Removing: " << Dir.c_str() << '\n';
+ Dir.eraseFromDisk(true);
+ }
+ };
+}
+
+void SerializationTest::HandleTranslationUnit(TranslationUnit& TU) {
+
+ std::string ErrMsg;
+ llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
+
+ if (Dir.isEmpty()) {
+ llvm::cerr << "Error: " << ErrMsg << "\n";
+ return;
+ }
+
+ TmpDirJanitor RemoveTmpOnExit(Dir);
+
+ llvm::sys::Path FNameDeclBefore = Dir;
+ FNameDeclBefore.appendComponent("test.decl_before.txt");
+
+ if (FNameDeclBefore.makeUnique(true,&ErrMsg)) {
+ llvm::cerr << "Error: " << ErrMsg << "\n";
+ return;
+ }
+
+ llvm::sys::Path FNameDeclAfter = Dir;
+ FNameDeclAfter.appendComponent("test.decl_after.txt");
+
+ if (FNameDeclAfter.makeUnique(true,&ErrMsg)) {
+ llvm::cerr << "Error: " << ErrMsg << "\n";
+ return;
+ }
+
+ llvm::sys::Path ASTFilename = Dir;
+ ASTFilename.appendComponent("test.ast");
+
+ if (ASTFilename.makeUnique(true,&ErrMsg)) {
+ llvm::cerr << "Error: " << ErrMsg << "\n";
+ return;
+ }
+
+ // Serialize and then deserialize the ASTs.
+ bool status = Serialize(ASTFilename, FNameDeclBefore, TU);
+ assert (status && "Serialization failed.");
+ status = Deserialize(ASTFilename, FNameDeclAfter);
+ assert (status && "Deserialization failed.");
+
+ // Read both pretty-printed files and compare them.
+
+ using llvm::MemoryBuffer;
+
+ llvm::OwningPtr<MemoryBuffer>
+ MBufferSer(MemoryBuffer::getFile(FNameDeclBefore.c_str()));
+
+ if(!MBufferSer) {
+ llvm::cerr << "ERROR: Cannot read pretty-printed file (pre-pickle).\n";
+ return;
+ }
+
+ llvm::OwningPtr<MemoryBuffer>
+ MBufferDSer(MemoryBuffer::getFile(FNameDeclAfter.c_str()));
+
+ if(!MBufferDSer) {
+ llvm::cerr << "ERROR: Cannot read pretty-printed file (post-pickle).\n";
+ return;
+ }
+
+ const char *p1 = MBufferSer->getBufferStart();
+ const char *e1 = MBufferSer->getBufferEnd();
+ const char *p2 = MBufferDSer->getBufferStart();
+ const char *e2 = MBufferDSer->getBufferEnd();
+
+ if (MBufferSer->getBufferSize() == MBufferDSer->getBufferSize())
+ for ( ; p1 != e1 ; ++p1, ++p2 )
+ if (*p1 != *p2) break;
+
+ if (p1 != e1 || p2 != e2 )
+ llvm::cerr << "ERROR: Pretty-printed files are not the same.\n";
+ else
+ llvm::cerr << "SUCCESS: Pretty-printed files are the same.\n";
+}
diff --git a/clang/tools/clang-cc/Warnings.cpp b/clang/tools/clang-cc/Warnings.cpp
new file mode 100644
index 00000000000..18e44d72e3c
--- /dev/null
+++ b/clang/tools/clang-cc/Warnings.cpp
@@ -0,0 +1,222 @@
+//===--- 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.
+//
+// Warning options control the handling of the warnings that Clang emits. There
+// are three possible reactions to any given warning:
+// ignore: Do nothing
+// warn: Emit a message, but don't fail the compilation
+// error: Emit a message and fail the compilation
+//
+// Each warning option controls any number of actual warnings.
+// Given a warning option 'foo', the following are valid:
+// -Wfoo=ignore -> Ignore the controlled warnings.
+// -Wfoo=warn -> Warn about the controlled warnings.
+// -Wfoo=error -> Fail on the controlled warnings.
+// -Wfoo -> alias of -Wfoo=warn
+// -Wno-foo -> alias of -Wfoo=ignore
+// -Werror=foo -> alias of -Wfoo=error
+//
+// Because of this complex handling of options, the default parser is replaced.
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "llvm/Support/CommandLine.h"
+#include <vector>
+#include <string>
+#include <utility>
+#include <algorithm>
+#include <string.h>
+
+using namespace clang;
+
+namespace {
+ struct ParsedOption {
+ std::string Name;
+ diag::Mapping Mapping;
+
+ ParsedOption() {}
+ // Used by -Werror, implicitly.
+ ParsedOption(const std::string& name) : Name(name), Mapping(diag::MAP_ERROR)
+ {}
+ };
+
+ typedef std::vector<ParsedOption> OptionsList;
+
+ OptionsList Options;
+
+ struct WarningParser : public llvm::cl::basic_parser<ParsedOption> {
+ diag::Mapping StrToMapping(const std::string &S) {
+ if (S == "ignore")
+ return diag::MAP_IGNORE;
+ if (S == "warn")
+ return diag::MAP_WARNING;
+ if (S == "error")
+ return diag::MAP_ERROR;
+ return diag::MAP_DEFAULT;
+ }
+ bool parse(llvm::cl::Option &O, const char *ArgName,
+ const std::string &ArgValue, ParsedOption &Val)
+ {
+ size_t Eq = ArgValue.find("=");
+ if (Eq == std::string::npos) {
+ // Could be -Wfoo or -Wno-foo
+ if (ArgValue.compare(0, 3, "no-") == 0) {
+ Val.Name = ArgValue.substr(3);
+ Val.Mapping = diag::MAP_IGNORE;
+ } else {
+ Val.Name = ArgValue;
+ Val.Mapping = diag::MAP_WARNING;
+ }
+ } else {
+ Val.Name = ArgValue.substr(0, Eq);
+ Val.Mapping = StrToMapping(ArgValue.substr(Eq+1));
+ if (Val.Mapping == diag::MAP_DEFAULT) {
+ fprintf(stderr, "Illegal warning option value: %s\n",
+ ArgValue.substr(Eq+1).c_str());
+ return true;
+ }
+ }
+ return false;
+ }
+ };
+}
+
+static llvm::cl::list<ParsedOption, OptionsList, WarningParser>
+OptWarnings("W", llvm::cl::location(Options), llvm::cl::Prefix);
+
+static llvm::cl::list<ParsedOption, OptionsList, llvm::cl::parser<std::string> >
+OptWError("Werror", llvm::cl::location(Options), llvm::cl::CommaSeparated,
+ llvm::cl::ValueOptional);
+
+static llvm::cl::opt<bool> OptPedantic("pedantic");
+static llvm::cl::opt<bool> OptPedanticErrors("pedantic-errors");
+static llvm::cl::opt<bool> OptNoWarnings("w");
+static llvm::cl::opt<bool>
+OptWarnInSystemHeaders("Wsystem-headers",
+ llvm::cl::desc("Do not suppress warnings issued in system headers"));
+
+namespace {
+ struct WarningOption {
+ const char *Name;
+ const diag::kind *Members;
+ size_t NumMembers;
+ };
+ bool operator <(const WarningOption& lhs, const WarningOption& rhs) {
+ return strcmp(lhs.Name, rhs.Name) < 0;
+ }
+}
+#define DIAGS(a) a, (sizeof(a) / sizeof(a[0]))
+// These tables will be TableGenerated later.
+// First the table sets describing the diagnostics controlled by each option.
+static const diag::kind UnusedMacrosDiags[] = { diag::pp_macro_not_used };
+static const diag::kind FloatEqualDiags[] = { diag::warn_floatingpoint_eq };
+static const diag::kind ReadOnlySetterAttrsDiags[] = {
+ diag::warn_objc_property_attr_mutually_exclusive
+};
+static const diag::kind FormatNonLiteralDiags[] = {
+ diag::warn_printf_not_string_constant
+};
+static const diag::kind UndefDiags[] = { diag::warn_pp_undef_identifier };
+static const diag::kind ImplicitFunctionDeclarationDiags[] = {
+ diag::ext_implicit_function_decl, diag::warn_implicit_function_decl
+};
+// Hmm ... this option is currently actually completely ignored.
+//static const diag::kind StrictSelectorMatchDiags[] = { };
+// Second the table of options. MUST be sorted by name! Binary lookup is done.
+static const WarningOption OptionTable[] = {
+ { "float-equal", DIAGS(FloatEqualDiags) },
+ { "format-nonliteral", DIAGS(FormatNonLiteralDiags) },
+ { "implicit-function-declaration", DIAGS(ImplicitFunctionDeclarationDiags) },
+ { "readonly-setter-attrs", DIAGS(ReadOnlySetterAttrsDiags) },
+ { "undef", DIAGS(UndefDiags) },
+ { "unused-macros", DIAGS(UnusedMacrosDiags) },
+// { "strict-selector-match", DIAGS(StrictSelectorMatchDiags) }
+};
+static const size_t OptionTableSize =
+ sizeof(OptionTable) / sizeof(OptionTable[0]);
+
+namespace clang {
+
+bool ProcessWarningOptions(Diagnostic &Diags) {
+ // FIXME: These should be mapped to group options.
+ Diags.setIgnoreAllWarnings(OptNoWarnings);
+ Diags.setWarnOnExtensions(OptPedantic);
+ Diags.setErrorOnExtensions(OptPedanticErrors);
+
+ // Set some defaults that are currently set manually. This, too, should
+ // be in the tablegen stuff later.
+ Diags.setDiagnosticMapping(diag::pp_macro_not_used, diag::MAP_IGNORE);
+ Diags.setDiagnosticMapping(diag::warn_floatingpoint_eq, diag::MAP_IGNORE);
+ Diags.setDiagnosticMapping(diag::warn_objc_property_attr_mutually_exclusive,
+ diag::MAP_IGNORE);
+ Diags.setDiagnosticMapping(diag::warn_pp_undef_identifier, diag::MAP_IGNORE);
+ Diags.setDiagnosticMapping(diag::warn_implicit_function_decl,
+ diag::MAP_IGNORE);
+
+ Diags.setDiagnosticMapping(diag::err_pp_file_not_found, diag::MAP_FATAL);
+ Diags.setDiagnosticMapping(diag::err_template_recursion_depth_exceeded,
+ diag::MAP_FATAL);
+ Diags.setSuppressSystemWarnings(!OptWarnInSystemHeaders);
+
+ for (OptionsList::iterator it = Options.begin(), e = Options.end();
+ it != e; ++it) {
+ if (it->Name.empty()) {
+ // Empty string is "everything". This way, -Werror does the right thing.
+ // FIXME: These flags do not participate in proper option overriding.
+ switch(it->Mapping) {
+ default:
+ assert(false && "Illegal mapping");
+ break;
+
+ case diag::MAP_IGNORE:
+ Diags.setIgnoreAllWarnings(true);
+ Diags.setWarningsAsErrors(false);
+ break;
+
+ case diag::MAP_WARNING:
+ Diags.setIgnoreAllWarnings(false);
+ Diags.setWarningsAsErrors(false);
+ break;
+
+ case diag::MAP_ERROR:
+ Diags.setIgnoreAllWarnings(false);
+ Diags.setWarningsAsErrors(true);
+ break;
+ }
+ continue;
+ }
+ WarningOption Key = { it->Name.c_str(), 0, 0 };
+ const WarningOption *Found = std::lower_bound(OptionTable,
+ OptionTable + OptionTableSize,
+ Key);
+ if (Found == OptionTable + OptionTableSize ||
+ strcmp(Found->Name, Key.Name) != 0) {
+ fprintf(stderr, "Unknown warning option: -W%s\n", Key.Name);
+ return true;
+ }
+
+ // Option exists.
+ for (size_t i = 0; i < Found->NumMembers; ++i) {
+ Diags.setDiagnosticMapping(Found->Members[i], it->Mapping);
+ }
+ }
+ return false;
+}
+
+}
diff --git a/clang/tools/clang-cc/clang.cpp b/clang/tools/clang-cc/clang.cpp
new file mode 100644
index 00000000000..2ae1b6ec737
--- /dev/null
+++ b/clang/tools/clang-cc/clang.cpp
@@ -0,0 +1,1703 @@
+//===--- clang.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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This utility may be invoked in the following manner:
+// clang --help - Output help info.
+// clang [options] - Read from stdin.
+// clang [options] file - Read from "file".
+// clang [options] file1 file2 - Read these files.
+//
+//===----------------------------------------------------------------------===//
+//
+// TODO: Options to support:
+//
+// -Wfatal-errors
+// -ftabstop=width
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang.h"
+#include "ASTConsumers.h"
+#include "clang/Frontend/CompileOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/InitHeaderSearch.h"
+#include "clang/Frontend/PathDiagnosticClients.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/TranslationUnit.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Sema/ParseAST.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PluginLoader.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
+#include "llvm/System/Signals.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Global options.
+//===----------------------------------------------------------------------===//
+
+/// ClangFrontendTimer - The front-end activities should charge time to it with
+/// TimeRegion. The -ftime-report option controls whether this will do
+/// anything.
+llvm::Timer *ClangFrontendTimer = 0;
+
+static bool HadErrors = false;
+
+static llvm::cl::opt<bool>
+Verbose("v", llvm::cl::desc("Enable verbose output"));
+static llvm::cl::opt<bool>
+Stats("print-stats",
+ llvm::cl::desc("Print performance metrics and statistics"));
+static llvm::cl::opt<bool>
+DisableFree("disable-free",
+ llvm::cl::desc("Disable freeing of memory on exit"),
+ llvm::cl::init(false));
+
+enum ProgActions {
+ RewriteObjC, // ObjC->C Rewriter.
+ RewriteBlocks, // ObjC->C Rewriter for Blocks.
+ RewriteMacros, // Expand macros but not #includes.
+ RewriteTest, // Rewriter playground
+ HTMLTest, // HTML displayer testing stuff.
+ EmitAssembly, // Emit a .s file.
+ EmitLLVM, // Emit a .ll file.
+ EmitBC, // Emit a .bc file.
+ EmitLLVMOnly, // Generate LLVM IR, but do not
+ SerializeAST, // Emit a .ast file.
+ EmitHTML, // Translate input source into HTML.
+ ASTPrint, // Parse ASTs and print them.
+ ASTDump, // Parse ASTs and dump them.
+ ASTView, // Parse ASTs and view them in Graphviz.
+ PrintDeclContext, // Print DeclContext and their Decls.
+ TestSerialization, // Run experimental serialization code.
+ ParsePrintCallbacks, // Parse and print each callback.
+ ParseSyntaxOnly, // Parse and perform semantic analysis.
+ ParseNoop, // Parse with noop callbacks.
+ RunPreprocessorOnly, // Just lex, no output.
+ PrintPreprocessedInput, // -E mode.
+ DumpTokens, // Dump out preprocessed tokens.
+ DumpRawTokens, // Dump out raw tokens.
+ RunAnalysis, // Run one or more source code analyses.
+ GeneratePCH, // Generate precompiled header.
+ InheritanceView // View C++ inheritance for a specified class.
+};
+
+static llvm::cl::opt<ProgActions>
+ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
+ llvm::cl::init(ParseSyntaxOnly),
+ llvm::cl::values(
+ clEnumValN(RunPreprocessorOnly, "Eonly",
+ "Just run preprocessor, no output (for timings)"),
+ clEnumValN(PrintPreprocessedInput, "E",
+ "Run preprocessor, emit preprocessed file"),
+ clEnumValN(DumpRawTokens, "dump-raw-tokens",
+ "Lex file in raw mode and dump raw tokens"),
+ clEnumValN(RunAnalysis, "analyze",
+ "Run static analysis engine"),
+ clEnumValN(DumpTokens, "dump-tokens",
+ "Run preprocessor, dump internal rep of tokens"),
+ clEnumValN(ParseNoop, "parse-noop",
+ "Run parser with noop callbacks (for timings)"),
+ clEnumValN(ParseSyntaxOnly, "fsyntax-only",
+ "Run parser and perform semantic analysis"),
+ clEnumValN(ParsePrintCallbacks, "parse-print-callbacks",
+ "Run parser and print each callback invoked"),
+ clEnumValN(EmitHTML, "emit-html",
+ "Output input source as HTML"),
+ clEnumValN(ASTPrint, "ast-print",
+ "Build ASTs and then pretty-print them"),
+ clEnumValN(ASTDump, "ast-dump",
+ "Build ASTs and then debug dump them"),
+ clEnumValN(ASTView, "ast-view",
+ "Build ASTs and view them with GraphViz"),
+ clEnumValN(PrintDeclContext, "print-decl-contexts",
+ "Print DeclContexts and their Decls."),
+ clEnumValN(TestSerialization, "test-pickling",
+ "Run prototype serialization code"),
+ clEnumValN(EmitAssembly, "S",
+ "Emit native assembly code"),
+ clEnumValN(EmitLLVM, "emit-llvm",
+ "Build ASTs then convert to LLVM, emit .ll file"),
+ clEnumValN(EmitBC, "emit-llvm-bc",
+ "Build ASTs then convert to LLVM, emit .bc file"),
+ clEnumValN(EmitLLVMOnly, "emit-llvm-only",
+ "Build ASTs and convert to LLVM, discarding output"),
+ clEnumValN(SerializeAST, "serialize",
+ "Build ASTs and emit .ast file"),
+ clEnumValN(RewriteTest, "rewrite-test",
+ "Rewriter playground"),
+ clEnumValN(RewriteObjC, "rewrite-objc",
+ "Rewrite ObjC into C (code rewriter example)"),
+ clEnumValN(RewriteMacros, "rewrite-macros",
+ "Expand macros without full preprocessing"),
+ clEnumValN(RewriteBlocks, "rewrite-blocks",
+ "Rewrite Blocks to C"),
+ clEnumValEnd));
+
+
+static llvm::cl::opt<std::string>
+OutputFile("o",
+ llvm::cl::value_desc("path"),
+ llvm::cl::desc("Specify output file (for --serialize, this is a directory)"));
+
+
+//===----------------------------------------------------------------------===//
+// PTH.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+TokenCache("token-cache", llvm::cl::value_desc("path"),
+ llvm::cl::desc("Use specified token cache file"));
+
+//===----------------------------------------------------------------------===//
+// Diagnostic Options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+VerifyDiagnostics("verify",
+ llvm::cl::desc("Verify emitted diagnostics and warnings"));
+
+static llvm::cl::opt<std::string>
+HTMLDiag("html-diags",
+ llvm::cl::desc("Generate HTML to report diagnostics"),
+ llvm::cl::value_desc("HTML directory"));
+
+static llvm::cl::opt<bool>
+NoShowColumn("fno-show-column",
+ llvm::cl::desc("Do not include column number on diagnostics"));
+
+static llvm::cl::opt<bool>
+NoShowLocation("fno-show-source-location",
+ llvm::cl::desc("Do not include source location information with"
+ " diagnostics"));
+
+static llvm::cl::opt<bool>
+NoCaretDiagnostics("fno-caret-diagnostics",
+ llvm::cl::desc("Do not include source line and caret with"
+ " diagnostics"));
+
+static llvm::cl::opt<bool>
+PrintSourceRangeInfo("fprint-source-range-info",
+ llvm::cl::desc("Print source range spans in numeric form"));
+
+
+//===----------------------------------------------------------------------===//
+// C++ Visualization.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+InheritanceViewCls("cxx-inheritance-view",
+ llvm::cl::value_desc("class name"),
+ llvm::cl::desc("View C++ inheritance for a specified class"));
+
+//===----------------------------------------------------------------------===//
+// Builtin Options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+TimeReport("ftime-report",
+ llvm::cl::desc("Print the amount of time each "
+ "phase of compilation takes"));
+
+static llvm::cl::opt<bool>
+Freestanding("ffreestanding",
+ llvm::cl::desc("Assert that the compilation takes place in a "
+ "freestanding environment"));
+
+static llvm::cl::opt<bool>
+AllowBuiltins("fbuiltin",
+ llvm::cl::desc("Disable implicit builtin knowledge of functions"),
+ llvm::cl::init(true), llvm::cl::AllowInverse);
+
+
+static llvm::cl::opt<bool>
+MathErrno("fmath-errno",
+ llvm::cl::desc("Require math functions to respect errno"),
+ llvm::cl::init(true), llvm::cl::AllowInverse);
+
+//===----------------------------------------------------------------------===//
+// Language Options
+//===----------------------------------------------------------------------===//
+
+enum LangKind {
+ langkind_unspecified,
+ langkind_c,
+ langkind_c_cpp,
+ langkind_asm_cpp,
+ langkind_c_pch,
+ langkind_cxx,
+ langkind_cxx_cpp,
+ langkind_cxx_pch,
+ langkind_objc,
+ langkind_objc_cpp,
+ langkind_objc_pch,
+ langkind_objcxx,
+ langkind_objcxx_cpp,
+ langkind_objcxx_pch
+};
+
+static llvm::cl::opt<LangKind>
+BaseLang("x", llvm::cl::desc("Base language to compile"),
+ llvm::cl::init(langkind_unspecified),
+ llvm::cl::values(clEnumValN(langkind_c, "c", "C"),
+ clEnumValN(langkind_cxx, "c++", "C++"),
+ clEnumValN(langkind_objc, "objective-c", "Objective C"),
+ clEnumValN(langkind_objcxx,"objective-c++","Objective C++"),
+ clEnumValN(langkind_c_cpp, "cpp-output",
+ "Preprocessed C"),
+ clEnumValN(langkind_asm_cpp, "assembler-with-cpp",
+ "Preprocessed asm"),
+ clEnumValN(langkind_cxx_cpp, "c++-cpp-output",
+ "Preprocessed C++"),
+ clEnumValN(langkind_objc_cpp, "objective-c-cpp-output",
+ "Preprocessed Objective C"),
+ clEnumValN(langkind_objcxx_cpp, "objective-c++-cpp-output",
+ "Preprocessed Objective C++"),
+ clEnumValN(langkind_c_pch, "c-header",
+ "Precompiled C header"),
+ clEnumValN(langkind_objc_pch, "objective-c-header",
+ "Precompiled Objective-C header"),
+ clEnumValN(langkind_cxx_pch, "c++-header",
+ "Precompiled C++ header"),
+ clEnumValN(langkind_objcxx_pch, "objective-c++-header",
+ "Precompiled Objective-C++ header"),
+ clEnumValEnd));
+
+static llvm::cl::opt<bool>
+LangObjC("ObjC", llvm::cl::desc("Set base language to Objective-C"),
+ llvm::cl::Hidden);
+static llvm::cl::opt<bool>
+LangObjCXX("ObjC++", llvm::cl::desc("Set base language to Objective-C++"),
+ llvm::cl::Hidden);
+
+/// InitializeBaseLanguage - Handle the -x foo options.
+static void InitializeBaseLanguage() {
+ if (LangObjC)
+ BaseLang = langkind_objc;
+ else if (LangObjCXX)
+ BaseLang = langkind_objcxx;
+}
+
+static LangKind GetLanguage(const std::string &Filename) {
+ if (BaseLang != langkind_unspecified)
+ return BaseLang;
+
+ std::string::size_type DotPos = Filename.rfind('.');
+
+ if (DotPos == std::string::npos) {
+ BaseLang = langkind_c; // Default to C if no extension.
+ return langkind_c;
+ }
+
+ std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end());
+ // C header: .h
+ // C++ header: .hh or .H;
+ // assembler no preprocessing: .s
+ // assembler: .S
+ if (Ext == "c")
+ return langkind_c;
+ else if (Ext == "S" ||
+ // If the compiler is run on a .s file, preprocess it as .S
+ Ext == "s")
+ return langkind_asm_cpp;
+ else if (Ext == "i")
+ return langkind_c_cpp;
+ else if (Ext == "ii")
+ return langkind_cxx_cpp;
+ else if (Ext == "m")
+ return langkind_objc;
+ else if (Ext == "mi")
+ return langkind_objc_cpp;
+ else if (Ext == "mm" || Ext == "M")
+ return langkind_objcxx;
+ else if (Ext == "mii")
+ return langkind_objcxx_cpp;
+ else if (Ext == "C" || Ext == "cc" || Ext == "cpp" || Ext == "CPP" ||
+ Ext == "c++" || Ext == "cp" || Ext == "cxx")
+ return langkind_cxx;
+ else
+ return langkind_c;
+}
+
+
+static void InitializeCOptions(LangOptions &Options) {
+ // Do nothing.
+}
+
+static void InitializeObjCOptions(LangOptions &Options) {
+ Options.ObjC1 = Options.ObjC2 = 1;
+}
+
+
+static bool InitializeLangOptions(LangOptions &Options, LangKind LK){
+ // FIXME: implement -fpreprocessed mode.
+ bool NoPreprocess = false;
+ bool PCH = false;
+
+ // Test for 'PCH'.
+ switch (LK) {
+ default:
+ break;
+ case langkind_c_pch:
+ LK = langkind_c;
+ PCH = true;
+ break;
+ case langkind_objc_pch:
+ LK = langkind_objc;
+ PCH = true;
+ break;
+ case langkind_cxx_pch:
+ LK = langkind_cxx;
+ PCH = true;
+ break;
+ case langkind_objcxx_pch:
+ LK = langkind_objcxx;
+ PCH = true;
+ break;
+ }
+
+ switch (LK) {
+ default: assert(0 && "Unknown language kind!");
+ case langkind_asm_cpp:
+ Options.AsmPreprocessor = 1;
+ // FALLTHROUGH
+ case langkind_c_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_c:
+ InitializeCOptions(Options);
+ break;
+ case langkind_cxx_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_cxx:
+ Options.CPlusPlus = 1;
+ break;
+ case langkind_objc_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_objc:
+ InitializeObjCOptions(Options);
+ break;
+ case langkind_objcxx_cpp:
+ NoPreprocess = true;
+ // FALLTHROUGH
+ case langkind_objcxx:
+ Options.ObjC1 = Options.ObjC2 = 1;
+ Options.CPlusPlus = 1;
+ break;
+ }
+
+ return PCH;
+}
+
+/// LangStds - Language standards we support.
+enum LangStds {
+ lang_unspecified,
+ lang_c89, lang_c94, lang_c99,
+ lang_gnu_START,
+ lang_gnu89 = lang_gnu_START, lang_gnu99,
+ lang_cxx98, lang_gnucxx98,
+ lang_cxx0x, lang_gnucxx0x
+};
+
+static llvm::cl::opt<LangStds>
+LangStd("std", llvm::cl::desc("Language standard to compile for"),
+ llvm::cl::init(lang_unspecified),
+ llvm::cl::values(clEnumValN(lang_c89, "c89", "ISO C 1990"),
+ clEnumValN(lang_c89, "c90", "ISO C 1990"),
+ clEnumValN(lang_c89, "iso9899:1990", "ISO C 1990"),
+ clEnumValN(lang_c94, "iso9899:199409",
+ "ISO C 1990 with amendment 1"),
+ clEnumValN(lang_c99, "c99", "ISO C 1999"),
+// clEnumValN(lang_c99, "c9x", "ISO C 1999"),
+ clEnumValN(lang_c99, "iso9899:1999", "ISO C 1999"),
+// clEnumValN(lang_c99, "iso9899:199x", "ISO C 1999"),
+ clEnumValN(lang_gnu89, "gnu89",
+ "ISO C 1990 with GNU extensions"),
+ clEnumValN(lang_gnu99, "gnu99",
+ "ISO C 1999 with GNU extensions (default for C)"),
+ clEnumValN(lang_gnu99, "gnu9x",
+ "ISO C 1999 with GNU extensions"),
+ clEnumValN(lang_cxx98, "c++98",
+ "ISO C++ 1998 with amendments"),
+ clEnumValN(lang_gnucxx98, "gnu++98",
+ "ISO C++ 1998 with amendments and GNU "
+ "extensions (default for C++)"),
+ clEnumValN(lang_cxx0x, "c++0x",
+ "Upcoming ISO C++ 200x with amendments"),
+ clEnumValN(lang_gnucxx0x, "gnu++0x",
+ "Upcoming ISO C++ 200x with amendments and GNU "
+ "extensions"),
+ clEnumValEnd));
+
+static llvm::cl::opt<bool>
+NoOperatorNames("fno-operator-names",
+ llvm::cl::desc("Do not treat C++ operator name keywords as "
+ "synonyms for operators"));
+
+static llvm::cl::opt<bool>
+PascalStrings("fpascal-strings",
+ llvm::cl::desc("Recognize and construct Pascal-style "
+ "string literals"));
+
+static llvm::cl::opt<bool>
+MSExtensions("fms-extensions",
+ llvm::cl::desc("Accept some non-standard constructs used in "
+ "Microsoft header files "));
+
+static llvm::cl::opt<bool>
+WritableStrings("fwritable-strings",
+ llvm::cl::desc("Store string literals as writable data"));
+
+static llvm::cl::opt<bool>
+NoLaxVectorConversions("fno-lax-vector-conversions",
+ llvm::cl::desc("Disallow implicit conversions between "
+ "vectors with a different number of "
+ "elements or different element types"));
+
+static llvm::cl::opt<bool>
+EnableBlocks("fblocks", llvm::cl::desc("enable the 'blocks' language feature"),
+ llvm::cl::ValueDisallowed, llvm::cl::AllowInverse,
+ llvm::cl::ZeroOrMore);
+
+static llvm::cl::opt<bool>
+EnableHeinousExtensions("fheinous-gnu-extensions",
+ llvm::cl::desc("enable GNU extensions that you really really shouldn't use"),
+ llvm::cl::ValueDisallowed, llvm::cl::Hidden);
+
+static llvm::cl::opt<bool>
+ObjCNonFragileABI("fobjc-nonfragile-abi",
+ llvm::cl::desc("enable objective-c's nonfragile abi"));
+
+static llvm::cl::opt<bool>
+EmitAllDecls("femit-all-decls",
+ llvm::cl::desc("Emit all declarations, even if unused"));
+
+// FIXME: This (and all GCC -f options) really come in -f... and
+// -fno-... forms, and additionally support automagic behavior when
+// they are not defined. For example, -fexceptions defaults to on or
+// off depending on the language. We should support this behavior in
+// some form (perhaps just add a facility for distinguishing when an
+// has its default value from when it has been set to its default
+// value).
+static llvm::cl::opt<bool>
+Exceptions("fexceptions",
+ llvm::cl::desc("Enable support for exception handling."));
+
+static llvm::cl::opt<bool>
+GNURuntime("fgnu-runtime",
+ llvm::cl::desc("Generate output compatible with the standard GNU "
+ "Objective-C runtime."));
+
+static llvm::cl::opt<bool>
+NeXTRuntime("fnext-runtime",
+ llvm::cl::desc("Generate output compatible with the NeXT "
+ "runtime."));
+
+
+
+static llvm::cl::opt<bool>
+Trigraphs("trigraphs", llvm::cl::desc("Process trigraph sequences."));
+
+static llvm::cl::opt<bool>
+Ansi("ansi", llvm::cl::desc("Equivalent to specifying -std=c89."));
+
+static llvm::cl::list<std::string>
+TargetFeatures("mattr", llvm::cl::CommaSeparated,
+ llvm::cl::desc("Target specific attributes (-mattr=help for details)"));
+
+static llvm::cl::opt<unsigned>
+TemplateDepth("ftemplate-depth", llvm::cl::init(99),
+ llvm::cl::desc("Maximum depth of recursive template "
+ "instantiation"));
+
+// FIXME: add:
+// -fdollars-in-identifiers
+static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
+ TargetInfo *Target) {
+ // Allow the target to set the default the langauge options as it sees fit.
+ Target->getDefaultLangOptions(Options);
+
+ // If there are any -mattr options, pass them to the target for validation and
+ // processing. The driver should have already consolidated all the
+ // target-feature settings and passed them to us in the -mattr list. The
+ // -mattr list is treated by the code generator as a diff against the -mcpu
+ // setting, but the driver should pass all enabled options as "+" settings.
+ // This means that the target should only look at + settings.
+ if (!TargetFeatures.empty()
+ // FIXME: The driver is not quite yet ready for this.
+ && 0) {
+ std::string ErrorStr;
+ int Opt = Target->HandleTargetFeatures(&TargetFeatures[0],
+ TargetFeatures.size(), ErrorStr);
+ if (Opt != -1) {
+ if (ErrorStr.empty())
+ fprintf(stderr, "invalid feature '%s'\n",
+ TargetFeatures[Opt].c_str());
+ else
+ fprintf(stderr, "feature '%s': %s\n",
+ TargetFeatures[Opt].c_str(), ErrorStr.c_str());
+ exit(1);
+ }
+ }
+
+ if (Ansi) // "The -ansi option is equivalent to -std=c89."
+ LangStd = lang_c89;
+
+ if (LangStd == lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (LK) {
+ case lang_unspecified: assert(0 && "Unknown base language");
+ case langkind_c:
+ case langkind_asm_cpp:
+ case langkind_c_cpp:
+ case langkind_c_pch:
+ case langkind_objc:
+ case langkind_objc_cpp:
+ case langkind_objc_pch:
+ LangStd = lang_gnu99;
+ break;
+ case langkind_cxx:
+ case langkind_cxx_cpp:
+ case langkind_cxx_pch:
+ case langkind_objcxx:
+ case langkind_objcxx_cpp:
+ case langkind_objcxx_pch:
+ LangStd = lang_gnucxx98;
+ break;
+ }
+ }
+
+ switch (LangStd) {
+ default: assert(0 && "Unknown language standard!");
+
+ // Fall through from newer standards to older ones. This isn't really right.
+ // FIXME: Enable specifically the right features based on the language stds.
+ case lang_gnucxx0x:
+ case lang_cxx0x:
+ Options.CPlusPlus0x = 1;
+ // FALL THROUGH
+ case lang_gnucxx98:
+ case lang_cxx98:
+ Options.CPlusPlus = 1;
+ Options.CXXOperatorNames = !NoOperatorNames;
+ Options.Boolean = 1;
+ // FALL THROUGH.
+ case lang_gnu99:
+ case lang_c99:
+ Options.C99 = 1;
+ Options.HexFloats = 1;
+ // FALL THROUGH.
+ case lang_gnu89:
+ Options.BCPLComment = 1; // Only for C99/C++.
+ // FALL THROUGH.
+ case lang_c94:
+ Options.Digraphs = 1; // C94, C99, C++.
+ // FALL THROUGH.
+ case lang_c89:
+ break;
+ }
+
+ // GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
+ Options.GNUMode = LangStd >= lang_gnu_START;
+
+ if (Options.CPlusPlus) {
+ Options.C99 = 0;
+ Options.HexFloats = Options.GNUMode;
+ }
+
+ if (LangStd == lang_c89 || LangStd == lang_c94 || LangStd == lang_gnu89)
+ Options.ImplicitInt = 1;
+ else
+ Options.ImplicitInt = 0;
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs or -ansi
+ // is specified, or -std is set to a conforming mode.
+ Options.Trigraphs = !Options.GNUMode;
+ if (Trigraphs.getPosition())
+ Options.Trigraphs = Trigraphs; // Command line option wins if specified.
+
+ // If in a conformant language mode (e.g. -std=c99) Blocks defaults to off
+ // even if they are normally on for the target. In GNU modes (e.g.
+ // -std=gnu99) the default for blocks depends on the target settings.
+ // However, blocks are not turned off when compiling Obj-C or Obj-C++ code.
+ if (!Options.ObjC1 && !Options.GNUMode)
+ Options.Blocks = 0;
+
+ // Never accept '$' in identifiers when preprocessing assembler.
+ if (LK != langkind_asm_cpp)
+ Options.DollarIdents = 1; // FIXME: Really a target property.
+ if (PascalStrings.getPosition())
+ Options.PascalStrings = PascalStrings;
+ Options.Microsoft = MSExtensions;
+ Options.WritableStrings = WritableStrings;
+ if (NoLaxVectorConversions.getPosition())
+ Options.LaxVectorConversions = 0;
+ Options.Exceptions = Exceptions;
+ if (EnableBlocks.getPosition())
+ Options.Blocks = EnableBlocks;
+
+ if (!AllowBuiltins)
+ Options.NoBuiltin = 1;
+ if (Freestanding)
+ Options.Freestanding = Options.NoBuiltin = 1;
+
+ if (EnableHeinousExtensions)
+ Options.HeinousExtensions = 1;
+
+ Options.MathErrno = MathErrno;
+
+ Options.InstantiationDepth = TemplateDepth;
+
+ // Override the default runtime if the user requested it.
+ if (NeXTRuntime)
+ Options.NeXTRuntime = 1;
+ else if (GNURuntime)
+ Options.NeXTRuntime = 0;
+
+ if (ObjCNonFragileABI)
+ Options.ObjCNonFragileABI = 1;
+
+ if (EmitAllDecls)
+ Options.EmitAllDecls = 1;
+}
+
+static llvm::cl::opt<bool>
+ObjCExclusiveGC("fobjc-gc-only",
+ llvm::cl::desc("Use GC exclusively for Objective-C related "
+ "memory management"));
+
+static llvm::cl::opt<bool>
+ObjCEnableGC("fobjc-gc",
+ llvm::cl::desc("Enable Objective-C garbage collection"));
+
+void InitializeGCMode(LangOptions &Options) {
+ if (ObjCExclusiveGC)
+ Options.setGCMode(LangOptions::GCOnly);
+ else if (ObjCEnableGC)
+ Options.setGCMode(LangOptions::HybridGC);
+}
+
+//===----------------------------------------------------------------------===//
+// Target Triple Processing.
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<std::string>
+TargetTriple("triple",
+ llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)"));
+
+static llvm::cl::opt<std::string>
+Arch("arch", llvm::cl::desc("Specify target architecture (e.g. i686)"));
+
+static llvm::cl::opt<std::string>
+MacOSVersionMin("mmacosx-version-min",
+ llvm::cl::desc("Specify target Mac OS/X version (e.g. 10.5)"));
+
+// If -mmacosx-version-min=10.3.9 is specified, change the triple from being
+// something like powerpc-apple-darwin9 to powerpc-apple-darwin7
+static void HandleMacOSVersionMin(std::string &Triple) {
+ std::string::size_type DarwinDashIdx = Triple.find("-darwin");
+ if (DarwinDashIdx == std::string::npos) {
+ fprintf(stderr,
+ "-mmacosx-version-min only valid for darwin (Mac OS/X) targets\n");
+ exit(1);
+ }
+ unsigned DarwinNumIdx = DarwinDashIdx + strlen("-darwin");
+
+ // Remove the number.
+ Triple.resize(DarwinNumIdx);
+
+ // Validate that MacOSVersionMin is a 'version number', starting with 10.[3-9]
+ bool MacOSVersionMinIsInvalid = false;
+ int VersionNum = 0;
+ if (MacOSVersionMin.size() < 4 ||
+ MacOSVersionMin.substr(0, 3) != "10." ||
+ !isdigit(MacOSVersionMin[3])) {
+ MacOSVersionMinIsInvalid = true;
+ } else {
+ const char *Start = MacOSVersionMin.c_str()+3;
+ char *End = 0;
+ VersionNum = (int)strtol(Start, &End, 10);
+
+ // The version number must be in the range 0-9.
+ MacOSVersionMinIsInvalid = (unsigned)VersionNum > 9;
+
+ // Turn MacOSVersionMin into a darwin number: e.g. 10.3.9 is 3 -> 7.
+ Triple += llvm::itostr(VersionNum+4);
+
+ if (End[0] == '.' && isdigit(End[1]) && End[2] == '\0') { // 10.4.7 is ok.
+ // Add the period piece (.7) to the end of the triple. This gives us
+ // something like ...-darwin8.7
+ Triple += End;
+ } else if (End[0] != '\0') { // "10.4" is ok. 10.4x is not.
+ MacOSVersionMinIsInvalid = true;
+ }
+ }
+
+ if (MacOSVersionMinIsInvalid) {
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ MacOSVersionMin.c_str());
+ exit(1);
+ }
+}
+
+/// CreateTargetTriple - Process the various options that affect the target
+/// triple and build a final aggregate triple that we are compiling for.
+static std::string CreateTargetTriple() {
+ // Initialize base triple. If a -triple option has been specified, use
+ // that triple. Otherwise, default to the host triple.
+ std::string Triple = TargetTriple;
+ if (Triple.empty()) {
+ Triple = LLVM_HOSTTRIPLE;
+
+ // Force i<N>86 to i386 when using LLVM_HOSTTRIPLE.
+ if (Triple[0] == 'i' && isdigit(Triple[1]) &&
+ Triple[2] == '8' && Triple[3] == '6')
+ Triple[1] = '3';
+
+ // On darwin, we want to update the version to match that of the
+ // host.
+ std::string::size_type DarwinDashIdx = Triple.find("-darwin");
+ if (DarwinDashIdx != std::string::npos) {
+ Triple.resize(DarwinDashIdx + strlen("-darwin"));
+
+ // Only add the major part of the os version.
+ std::string Version = llvm::sys::getOSVersion();
+ Triple += Version.substr(0, Version.find('.'));
+ }
+ }
+
+ // If -arch foo was specified, remove the architecture from the triple we have
+ // so far and replace it with the specified one.
+ if (!Arch.empty()) {
+ // Decompose the base triple into "arch" and suffix.
+ std::string::size_type FirstDashIdx = Triple.find('-');
+
+ if (FirstDashIdx == std::string::npos) {
+ fprintf(stderr,
+ "Malformed target triple: \"%s\" ('-' could not be found).\n",
+ Triple.c_str());
+ exit(1);
+ }
+
+ Triple = Arch + std::string(Triple.begin()+FirstDashIdx, Triple.end());
+ }
+
+ // If -mmacosx-version-min=10.3.9 is specified, change the triple from being
+ // something like powerpc-apple-darwin9 to powerpc-apple-darwin7
+ if (!MacOSVersionMin.empty())
+ HandleMacOSVersionMin(Triple);
+
+ return Triple;
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Initialization
+//===----------------------------------------------------------------------===//
+
+// FIXME: Preprocessor builtins to support.
+// -A... - Play with #assertions
+// -undef - Undefine all predefined macros
+
+// FIXME: -imacros
+
+static llvm::cl::list<std::string>
+D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
+ llvm::cl::desc("Predefine the specified macro"));
+static llvm::cl::list<std::string>
+U_macros("U", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
+ llvm::cl::desc("Undefine the specified macro"));
+
+static llvm::cl::list<std::string>
+ImplicitIncludes("include", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include file before parsing"));
+
+static llvm::cl::opt<std::string>
+ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
+ llvm::cl::desc("Include file before parsing"));
+
+// 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(' ');
+ Buf.insert(Buf.end(), Equal+1, Equal+strlen(Equal));
+ } else {
+ // Push "macroname 1".
+ Buf.insert(Buf.end(), Macro, Macro+strlen(Macro));
+ Buf.push_back(' ');
+ Buf.push_back('1');
+ }
+ Buf.push_back('\n');
+}
+
+/// 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));
+ Buf.insert(Buf.end(), File.begin(), File.end());
+ Buf.push_back('"');
+ Buf.push_back('\n');
+}
+
+/// AddImplicitIncludePTH - Add an implicit #include using the original file
+/// used to generate a PTH cache.
+static void AddImplicitIncludePTH(std::vector<char> &Buf, Preprocessor & PP) {
+ 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);
+}
+
+/// InitializePreprocessor - Initialize the preprocessor getting it and the
+/// environment ready to process a single file. This returns true on error.
+///
+static bool InitializePreprocessor(Preprocessor &PP,
+ bool InitializeSourceMgr,
+ const std::string &InFile) {
+ FileManager &FileMgr = PP.getFileManager();
+
+ // Figure out where to get and map in the main file.
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ if (InitializeSourceMgr) {
+ if (InFile != "-") {
+ const FileEntry *File = FileMgr.getFile(InFile);
+ if (File) SourceMgr.createMainFileID(File, SourceLocation());
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ PP.getDiagnostics().Report(FullSourceLoc(), diag::err_fe_error_reading)
+ << InFile.c_str();
+ return true;
+ }
+ } else {
+ llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
+
+ // If stdin was empty, SB is null. Cons up an empty memory
+ // buffer now.
+ if (!SB) {
+ const char *EmptyStr = "";
+ SB = llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<stdin>");
+ }
+
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ PP.getDiagnostics().Report(FullSourceLoc(),
+ diag::err_fe_error_reading_stdin);
+ return true;
+ }
+ }
+ }
+
+ std::vector<char> PredefineBuffer;
+
+ // Add macros from the command line.
+ unsigned d = 0, D = D_macros.size();
+ unsigned u = 0, U = U_macros.size();
+ while (d < D || u < U) {
+ if (u == U || (d < D && D_macros.getPosition(d) < U_macros.getPosition(u)))
+ DefineBuiltinMacro(PredefineBuffer, D_macros[d++].c_str());
+ else
+ DefineBuiltinMacro(PredefineBuffer, U_macros[u++].c_str(), "#undef ");
+ }
+
+ // FIXME: Read any files specified by -imacros.
+
+ // Add implicit #includes from -include and -include-pth.
+ bool handledPTH = ImplicitIncludePTH.empty();
+ for (unsigned i = 0, e = ImplicitIncludes.size(); i != e; ++i) {
+ if (!handledPTH &&
+ ImplicitIncludePTH.getPosition() < ImplicitIncludes.getPosition(i)) {
+ AddImplicitIncludePTH(PredefineBuffer, PP);
+ handledPTH = true;
+ }
+
+ AddImplicitInclude(PredefineBuffer, ImplicitIncludes[i]);
+ }
+ if (!handledPTH && !ImplicitIncludePTH.empty())
+ AddImplicitIncludePTH(PredefineBuffer, PP);
+
+ // Null terminate PredefinedBuffer and add it.
+ PredefineBuffer.push_back(0);
+ PP.setPredefines(&PredefineBuffer[0]);
+
+ // Once we've read this, we're done.
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor include path information.
+//===----------------------------------------------------------------------===//
+
+// This tool exports a large number of command line options to control how the
+// preprocessor searches for header files. At root, however, the Preprocessor
+// object takes a very simple interface: a list of directories to search for
+//
+// FIXME: -nostdinc,-nostdinc++
+// FIXME: -imultilib
+//
+
+static llvm::cl::opt<bool>
+nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
+
+// Various command line options. These four add directories to each chain.
+static llvm::cl::list<std::string>
+F_dirs("F", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to framework include search path"));
+static llvm::cl::list<std::string>
+I_dirs("I", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to include search path"));
+static llvm::cl::list<std::string>
+idirafter_dirs("idirafter", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to AFTER include search path"));
+static llvm::cl::list<std::string>
+iquote_dirs("iquote", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to QUOTE include search path"));
+static llvm::cl::list<std::string>
+isystem_dirs("isystem", llvm::cl::value_desc("directory"), llvm::cl::Prefix,
+ llvm::cl::desc("Add directory to SYSTEM include search path"));
+
+// These handle -iprefix/-iwithprefix/-iwithprefixbefore.
+static llvm::cl::list<std::string>
+iprefix_vals("iprefix", llvm::cl::value_desc("prefix"), llvm::cl::Prefix,
+ llvm::cl::desc("Set the -iwithprefix/-iwithprefixbefore prefix"));
+static llvm::cl::list<std::string>
+iwithprefix_vals("iwithprefix", llvm::cl::value_desc("dir"), llvm::cl::Prefix,
+ llvm::cl::desc("Set directory to SYSTEM include search path with prefix"));
+static llvm::cl::list<std::string>
+iwithprefixbefore_vals("iwithprefixbefore", llvm::cl::value_desc("dir"),
+ llvm::cl::Prefix,
+ llvm::cl::desc("Set directory to include search path with prefix"));
+
+static llvm::cl::opt<std::string>
+isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
+ llvm::cl::desc("Set the system root directory (usually /)"));
+
+// Finally, implement the code that groks the options above.
+
+/// InitializeIncludePaths - Process the -I options and set them in the
+/// HeaderSearch object.
+void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
+ FileManager &FM, const LangOptions &Lang) {
+ InitHeaderSearch Init(Headers, Verbose, isysroot);
+
+ // Handle -I... and -F... options, walking the lists in parallel.
+ unsigned Iidx = 0, Fidx = 0;
+ while (Iidx < I_dirs.size() && Fidx < F_dirs.size()) {
+ if (I_dirs.getPosition(Iidx) < F_dirs.getPosition(Fidx)) {
+ Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
+ ++Iidx;
+ } else {
+ Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
+ ++Fidx;
+ }
+ }
+
+ // Consume what's left from whatever list was longer.
+ for (; Iidx != I_dirs.size(); ++Iidx)
+ Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
+ for (; Fidx != F_dirs.size(); ++Fidx)
+ Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
+
+ // Handle -idirafter... options.
+ for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i)
+ Init.AddPath(idirafter_dirs[i], InitHeaderSearch::After,
+ false, true, false);
+
+ // Handle -iquote... options.
+ for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i)
+ Init.AddPath(iquote_dirs[i], InitHeaderSearch::Quoted, false, true, false);
+
+ // Handle -isystem... options.
+ for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i)
+ Init.AddPath(isystem_dirs[i], InitHeaderSearch::System, false, true, false);
+
+ // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in
+ // parallel, processing the values in order of occurance to get the right
+ // prefixes.
+ {
+ std::string Prefix = ""; // FIXME: this isn't the correct default prefix.
+ unsigned iprefix_idx = 0;
+ unsigned iwithprefix_idx = 0;
+ unsigned iwithprefixbefore_idx = 0;
+ bool iprefix_done = iprefix_vals.empty();
+ bool iwithprefix_done = iwithprefix_vals.empty();
+ bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
+ while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
+ if (!iprefix_done &&
+ (iwithprefix_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefix_vals.getPosition(iwithprefix_idx)) &&
+ (iwithprefixbefore_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ Prefix = iprefix_vals[iprefix_idx];
+ ++iprefix_idx;
+ iprefix_done = iprefix_idx == iprefix_vals.size();
+ } else if (!iwithprefix_done &&
+ (iwithprefixbefore_done ||
+ iwithprefix_vals.getPosition(iwithprefix_idx) <
+ iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
+ Init.AddPath(Prefix+iwithprefix_vals[iwithprefix_idx],
+ InitHeaderSearch::System, false, false, false);
+ ++iwithprefix_idx;
+ iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size();
+ } else {
+ Init.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
+ InitHeaderSearch::Angled, false, false, false);
+ ++iwithprefixbefore_idx;
+ iwithprefixbefore_done =
+ iwithprefixbefore_idx == iwithprefixbefore_vals.size();
+ }
+ }
+ }
+
+ Init.AddDefaultEnvVarPaths(Lang);
+
+ // Add the clang headers, which are relative to the clang binary.
+ llvm::sys::Path MainExecutablePath =
+ llvm::sys::Path::GetMainExecutable(Argv0,
+ (void*)(intptr_t)InitializeIncludePaths);
+ if (!MainExecutablePath.isEmpty()) {
+ MainExecutablePath.eraseComponent(); // Remove /clang from foo/bin/clang
+ MainExecutablePath.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/1.0/include
+ //
+ // FIXME: Don't embed version here.
+ MainExecutablePath.appendComponent("lib");
+ MainExecutablePath.appendComponent("clang");
+ MainExecutablePath.appendComponent("1.0");
+ MainExecutablePath.appendComponent("include");
+
+ // We pass true to ignore sysroot so that we *always* look for clang headers
+ // relative to our executable, never relative to -isysroot.
+ Init.AddPath(MainExecutablePath.c_str(), InitHeaderSearch::System,
+ false, false, false, true /*ignore sysroot*/);
+ }
+
+ if (!nostdinc)
+ Init.AddDefaultSystemIncludePaths(Lang);
+
+ // Now that we have collected all of the include paths, merge them all
+ // together and tell the preprocessor about them.
+
+ Init.Realize();
+}
+
+//===----------------------------------------------------------------------===//
+// Driver PreprocessorFactory - For lazily generating preprocessors ...
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN DriverPreprocessorFactory : public PreprocessorFactory {
+ const std::string &InFile;
+ Diagnostic &Diags;
+ const LangOptions &LangInfo;
+ TargetInfo &Target;
+ SourceManager &SourceMgr;
+ HeaderSearch &HeaderInfo;
+ bool InitializeSourceMgr;
+
+public:
+ DriverPreprocessorFactory(const std::string &infile,
+ Diagnostic &diags, const LangOptions &opts,
+ TargetInfo &target, SourceManager &SM,
+ HeaderSearch &Headers)
+ : InFile(infile), Diags(diags), LangInfo(opts), Target(target),
+ SourceMgr(SM), HeaderInfo(Headers), InitializeSourceMgr(true) {}
+
+
+ virtual ~DriverPreprocessorFactory() {}
+
+ virtual Preprocessor* CreatePreprocessor() {
+ llvm::OwningPtr<PTHManager> PTHMgr;
+
+ if (!TokenCache.empty() && !ImplicitIncludePTH.empty()) {
+ fprintf(stderr, "error: cannot use both -token-cache and -include-pth "
+ "options\n");
+ exit(1);
+ }
+
+ // Use PTH?
+ if (!TokenCache.empty() || !ImplicitIncludePTH.empty()) {
+ const std::string& x = TokenCache.empty() ? ImplicitIncludePTH:TokenCache;
+ PTHMgr.reset(PTHManager::Create(x, &Diags,
+ TokenCache.empty() ? Diagnostic::Error
+ : Diagnostic::Warning));
+ }
+
+ if (Diags.hasErrorOccurred())
+ exit(1);
+
+ // Create the Preprocessor.
+ llvm::OwningPtr<Preprocessor> PP(new Preprocessor(Diags, LangInfo, Target,
+ SourceMgr, HeaderInfo,
+ PTHMgr.get()));
+
+ // Note that this is different then passing PTHMgr to Preprocessor's ctor.
+ // That argument is used as the IdentifierInfoLookup argument to
+ // IdentifierTable's ctor.
+ if (PTHMgr) {
+ PTHMgr->setPreprocessor(PP.get());
+ PP->setPTHManager(PTHMgr.take());
+ }
+
+ if (InitializePreprocessor(*PP, InitializeSourceMgr, InFile)) {
+ return NULL;
+ }
+
+ /// FIXME: PP can only handle one callback
+ if (ProgAction != PrintPreprocessedInput) {
+ const char* ErrStr;
+ bool DFG = CreateDependencyFileGen(PP.get(), OutputFile, InFile, ErrStr);
+ if (!DFG && ErrStr) {
+ fprintf(stderr, "%s", ErrStr);
+ return NULL;
+ }
+ }
+
+ InitializeSourceMgr = false;
+ return PP.take();
+ }
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Basic Parser driver
+//===----------------------------------------------------------------------===//
+
+static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+
+ // Parsing the specified input file.
+ P.ParseTranslationUnit();
+ delete PA;
+}
+
+//===----------------------------------------------------------------------===//
+// Code generation options
+//===----------------------------------------------------------------------===//
+
+static llvm::cl::opt<bool>
+GenerateDebugInfo("g",
+ llvm::cl::desc("Generate source level debug information"));
+
+static llvm::cl::opt<bool>
+OptSize("Os", llvm::cl::desc("Optimize for size"));
+
+// It might be nice to add bounds to the CommandLine library directly.
+struct OptLevelParser : public llvm::cl::parser<unsigned> {
+ bool parse(llvm::cl::Option &O, const char *ArgName,
+ const std::string &Arg, unsigned &Val) {
+ if (llvm::cl::parser<unsigned>::parse(O, ArgName, Arg, Val))
+ return true;
+ // FIXME: Support -O4.
+ if (Val > 3)
+ return O.error(": '" + Arg + "' invalid optimization level!");
+ return false;
+ }
+};
+static llvm::cl::opt<unsigned, false, OptLevelParser>
+OptLevel("O", llvm::cl::Prefix,
+ llvm::cl::desc("Optimization level"),
+ llvm::cl::init(0));
+
+static llvm::cl::opt<std::string>
+TargetCPU("mcpu",
+ llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)"));
+
+static void InitializeCompileOptions(CompileOptions &Opts,
+ const LangOptions &LangOpts) {
+ Opts.OptimizeSize = OptSize;
+ Opts.DebugInfo = GenerateDebugInfo;
+ if (OptSize) {
+ // -Os implies -O2
+ // FIXME: Diagnose conflicting options.
+ Opts.OptimizationLevel = 2;
+ } else {
+ Opts.OptimizationLevel = OptLevel;
+ }
+
+ // FIXME: There are llvm-gcc options to control these selectively.
+ Opts.InlineFunctions = (Opts.OptimizationLevel > 1);
+ Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize);
+ Opts.SimplifyLibCalls = !LangOpts.NoBuiltin;
+
+#ifdef NDEBUG
+ Opts.VerifyModule = 0;
+#endif
+
+ Opts.CPU = TargetCPU;
+ Opts.Features.insert(Opts.Features.end(),
+ TargetFeatures.begin(), TargetFeatures.end());
+
+ // Handle -ftime-report.
+ Opts.TimePasses = TimeReport;
+}
+
+//===----------------------------------------------------------------------===//
+// Main driver
+//===----------------------------------------------------------------------===//
+
+/// CreateASTConsumer - Create the ASTConsumer for the corresponding program
+/// action. These consumers can operate on both ASTs that are freshly
+/// parsed from source files as well as those deserialized from Bitcode.
+/// Note that PP and PPF may be null here.
+static ASTConsumer *CreateASTConsumer(const std::string& InFile,
+ Diagnostic& Diag, FileManager& FileMgr,
+ const LangOptions& LangOpts,
+ Preprocessor *PP,
+ PreprocessorFactory *PPF) {
+ switch (ProgAction) {
+ default:
+ return NULL;
+
+ case ASTPrint:
+ return CreateASTPrinter();
+
+ case ASTDump:
+ return CreateASTDumper();
+
+ case ASTView:
+ return CreateASTViewer();
+
+ case PrintDeclContext:
+ return CreateDeclContextPrinter();
+
+ case EmitHTML:
+ return CreateHTMLPrinter(OutputFile, Diag, PP, PPF);
+
+ case InheritanceView:
+ return CreateInheritanceViewer(InheritanceViewCls);
+
+ case TestSerialization:
+ return CreateSerializationTest(Diag, FileMgr);
+
+ case EmitAssembly:
+ case EmitLLVM:
+ case EmitBC:
+ case EmitLLVMOnly: {
+ BackendAction Act;
+ if (ProgAction == EmitAssembly)
+ Act = Backend_EmitAssembly;
+ else if (ProgAction == EmitLLVM)
+ Act = Backend_EmitLL;
+ else if (ProgAction == EmitLLVMOnly)
+ Act = Backend_EmitNothing;
+ else
+ Act = Backend_EmitBC;
+
+ CompileOptions Opts;
+ InitializeCompileOptions(Opts, LangOpts);
+ return CreateBackendConsumer(Act, Diag, LangOpts, Opts,
+ InFile, OutputFile);
+ }
+
+ case SerializeAST:
+ // FIXME: Allow user to tailor where the file is written.
+ return CreateASTSerializer(InFile, OutputFile, Diag);
+
+ case RewriteObjC:
+ return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
+
+ case RewriteBlocks:
+ return CreateBlockRewriter(InFile, OutputFile, Diag, LangOpts);
+
+ case RunAnalysis:
+ return CreateAnalysisConsumer(Diag, PP, PPF, LangOpts, OutputFile);
+ }
+}
+
+/// ProcessInputFile - Process a single input file with the specified state.
+///
+static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
+ const std::string &InFile, ProgActions PA) {
+ llvm::OwningPtr<ASTConsumer> Consumer;
+ bool ClearSourceMgr = false;
+
+ switch (PA) {
+ default:
+ Consumer.reset(CreateASTConsumer(InFile, PP.getDiagnostics(),
+ PP.getFileManager(), PP.getLangOptions(),
+ &PP, &PPF));
+
+ if (!Consumer) {
+ fprintf(stderr, "Unexpected program action!\n");
+ HadErrors = true;
+ return;
+ }
+
+ break;
+
+ case DumpRawTokens: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ SourceManager &SM = PP.getSourceManager();
+ // Start lexing the specified input file.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ RawLex.SetKeepWhitespaceMode(true);
+
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+ PP.DumpToken(RawTok, true);
+ fprintf(stderr, "\n");
+ RawLex.LexFromRawLexer(RawTok);
+ }
+ ClearSourceMgr = true;
+ break;
+ }
+ case DumpTokens: { // Token dump mode.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Token Tok;
+ // Start preprocessing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ PP.DumpToken(Tok, true);
+ fprintf(stderr, "\n");
+ } while (Tok.isNot(tok::eof));
+ ClearSourceMgr = true;
+ break;
+ }
+ case RunPreprocessorOnly: { // Just lex as fast as we can, no output.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Token Tok;
+ // Start parsing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::eof));
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case GeneratePCH: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ CacheTokens(PP, OutputFile);
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case PrintPreprocessedInput: { // -E mode.
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ DoPrintPreprocessedInput(PP, OutputFile);
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case ParseNoop: { // -parse-noop
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ ParseFile(PP, new MinimalAction(PP));
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case ParsePrintCallbacks: {
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ ParseFile(PP, CreatePrintParserActionsAction(PP));
+ ClearSourceMgr = true;
+ break;
+ }
+
+ case ParseSyntaxOnly: { // -fsyntax-only
+ llvm::TimeRegion Timer(ClangFrontendTimer);
+ Consumer.reset(new ASTConsumer());
+ break;
+ }
+
+ case RewriteMacros:
+ RewriteMacrosInInput(PP, InFile, OutputFile);
+ ClearSourceMgr = true;
+ break;
+
+ case RewriteTest: {
+ DoRewriteTest(PP, InFile, OutputFile);
+ ClearSourceMgr = true;
+ break;
+ }
+ }
+
+ if (Consumer) {
+ TranslationUnit *TU = 0;
+ if (DisableFree) {
+ ASTContext *Context = new ASTContext(PP.getLangOptions(),
+ PP.getSourceManager(),
+ PP.getTargetInfo(),
+ PP.getIdentifierTable(),
+ PP.getSelectorTable(),
+ /* FreeMemory = */ false);
+ TU = new TranslationUnit(*Context);
+ }
+ ParseAST(PP, Consumer.get(), TU, Stats);
+ }
+
+ if (VerifyDiagnostics)
+ if (CheckDiagnostics(PP))
+ exit(1);
+
+ if (Stats) {
+ fprintf(stderr, "\nSTATISTICS FOR '%s':\n", InFile.c_str());
+ PP.PrintStats();
+ PP.getIdentifierTable().PrintStats();
+ PP.getHeaderSearchInfo().PrintStats();
+ PP.getSourceManager().PrintStats();
+ fprintf(stderr, "\n");
+ }
+
+ // For a multi-file compilation, some things are ok with nuking the source
+ // manager tables, other require stable fileid/macroid's across multiple
+ // files.
+ if (ClearSourceMgr)
+ PP.getSourceManager().clearIDTables();
+
+ if (DisableFree)
+ Consumer.take();
+}
+
+static void ProcessSerializedFile(const std::string& InFile, Diagnostic& Diag,
+ FileManager& FileMgr) {
+
+ if (VerifyDiagnostics) {
+ fprintf(stderr, "-verify does not yet work with serialized ASTs.\n");
+ exit (1);
+ }
+
+ llvm::sys::Path Filename(InFile);
+
+ if (!Filename.isValid()) {
+ fprintf(stderr, "serialized file '%s' not available.\n",InFile.c_str());
+ exit (1);
+ }
+
+ llvm::OwningPtr<TranslationUnit> TU(ReadASTBitcodeFile(Filename, FileMgr));
+
+ if (!TU) {
+ fprintf(stderr, "error: file '%s' could not be deserialized\n",
+ InFile.c_str());
+ exit (1);
+ }
+
+ // Observe that we use the source file name stored in the deserialized
+ // translation unit, rather than InFile.
+ llvm::OwningPtr<ASTConsumer>
+ Consumer(CreateASTConsumer(InFile, Diag, FileMgr, TU->getLangOptions(),
+ 0, 0));
+
+ if (!Consumer) {
+ fprintf(stderr, "Unsupported program action with serialized ASTs!\n");
+ exit (1);
+ }
+
+ Consumer->Initialize(TU->getContext());
+
+ // FIXME: We need to inform Consumer about completed TagDecls as well.
+ for (TranslationUnit::iterator I=TU->begin(), E=TU->end(); I!=E; ++I)
+ Consumer->HandleTopLevelDecl(*I);
+}
+
+
+static llvm::cl::list<std::string>
+InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>"));
+
+static bool isSerializedFile(const std::string& InFile) {
+ if (InFile.size() < 4)
+ return false;
+
+ const char* s = InFile.c_str()+InFile.size()-4;
+ return s[0] == '.' && s[1] == 'a' && s[2] == 's' && s[3] == 't';
+}
+
+
+int main(int argc, char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+ llvm::cl::ParseCommandLineOptions(argc, argv,
+ "LLVM 'Clang' Compiler: http://clang.llvm.org\n");
+
+ if (TimeReport)
+ ClangFrontendTimer = new llvm::Timer("Clang front-end time");
+
+ // If no input was specified, read from stdin.
+ if (InputFilenames.empty())
+ InputFilenames.push_back("-");
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ FileManager FileMgr;
+
+ // Create the diagnostic client for reporting errors or for
+ // implementing -verify.
+ DiagnosticClient* TextDiagClient = 0;
+
+ if (!VerifyDiagnostics) {
+ // Print diagnostics to stderr by default.
+ TextDiagClient = new TextDiagnosticPrinter(llvm::errs(),
+ !NoShowColumn,
+ !NoCaretDiagnostics,
+ !NoShowLocation,
+ PrintSourceRangeInfo);
+ } else {
+ // When checking diagnostics, just buffer them up.
+ TextDiagClient = new TextDiagnosticBuffer();
+
+ if (InputFilenames.size() != 1) {
+ fprintf(stderr,
+ "-verify only works on single input files for now.\n");
+ return 1;
+ }
+ }
+
+ // Configure our handling of diagnostics.
+ llvm::OwningPtr<DiagnosticClient> DiagClient(TextDiagClient);
+ Diagnostic Diags(DiagClient.get());
+ if (ProcessWarningOptions(Diags))
+ return 1;
+
+ // -I- is a deprecated GCC feature, scan for it and reject it.
+ for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) {
+ if (I_dirs[i] == "-") {
+ Diags.Report(FullSourceLoc(), diag::err_pp_I_dash_not_supported);
+ I_dirs.erase(I_dirs.begin()+i);
+ --i;
+ }
+ }
+
+ // Get information about the target being compiled for.
+ std::string Triple = CreateTargetTriple();
+ llvm::OwningPtr<TargetInfo> Target(TargetInfo::CreateTargetInfo(Triple));
+
+ if (Target == 0) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
+ << Triple.c_str();
+ return 1;
+ }
+
+ if (!InheritanceViewCls.empty()) // C++ visualization?
+ ProgAction = InheritanceView;
+
+ llvm::OwningPtr<SourceManager> SourceMgr;
+
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
+
+ if (isSerializedFile(InFile)) {
+ Diags.setClient(TextDiagClient);
+ ProcessSerializedFile(InFile,Diags,FileMgr);
+ continue;
+ }
+
+ /// Create a SourceManager object. This tracks and owns all the file
+ /// buffers allocated to a translation unit.
+ if (!SourceMgr)
+ SourceMgr.reset(new SourceManager());
+ else
+ SourceMgr->clearIDTables();
+
+ // Initialize language options, inferring file types from input filenames.
+ LangOptions LangInfo;
+ InitializeBaseLanguage();
+ LangKind LK = GetLanguage(InFile);
+ bool PCH = InitializeLangOptions(LangInfo, LK);
+ InitializeGCMode(LangInfo);
+ InitializeLanguageStandard(LangInfo, LK, Target.get());
+
+ // Process the -I options and set them in the HeaderInfo.
+ HeaderSearch HeaderInfo(FileMgr);
+
+ InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo);
+
+ // Set up the preprocessor with these options.
+ DriverPreprocessorFactory PPFactory(InFile, Diags, LangInfo, *Target,
+ *SourceMgr.get(), HeaderInfo);
+
+ llvm::OwningPtr<Preprocessor> PP(PPFactory.CreatePreprocessor());
+
+ if (!PP)
+ continue;
+
+ // Create the HTMLDiagnosticsClient if we are using one. Otherwise,
+ // always reset to using TextDiagClient.
+ llvm::OwningPtr<DiagnosticClient> TmpClient;
+
+ if (!HTMLDiag.empty()) {
+ TmpClient.reset(CreateHTMLDiagnosticClient(HTMLDiag, PP.get(),
+ &PPFactory));
+ Diags.setClient(TmpClient.get());
+ }
+ else
+ Diags.setClient(TextDiagClient);
+
+ // Process the source file.
+ ProcessInputFile(*PP, PPFactory, InFile, PCH ? GeneratePCH : ProgAction);
+
+ HeaderInfo.ClearFileInfo();
+ }
+
+ if (Verbose)
+ fprintf(stderr, "clang version 1.0 based upon " PACKAGE_STRING
+ " hosted on " LLVM_HOSTTRIPLE "\n");
+
+ if (unsigned NumDiagnostics = Diags.getNumDiagnostics())
+ fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
+ (NumDiagnostics == 1 ? "" : "s"));
+
+ if (Stats) {
+ FileMgr.PrintStats();
+ fprintf(stderr, "\n");
+ }
+
+ // If verifying diagnostics and we reached here, all is well.
+ if (VerifyDiagnostics)
+ return 0;
+
+ delete ClangFrontendTimer;
+
+ // Managed static deconstruction. Useful for making things like
+ // -time-passes usable.
+ llvm::llvm_shutdown();
+
+ return HadErrors || (Diags.getNumErrors() != 0);
+}
diff --git a/clang/tools/clang-cc/clang.h b/clang/tools/clang-cc/clang.h
new file mode 100644
index 00000000000..33bc7fe5832
--- /dev/null
+++ b/clang/tools/clang-cc/clang.h
@@ -0,0 +1,63 @@
+//===--- clang.h - 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.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the header file that pulls together the top-level driver.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CLANG_H
+#define LLVM_CLANG_CLANG_H
+
+#include <vector>
+#include <string>
+
+namespace clang {
+class Preprocessor;
+class MinimalAction;
+class TargetInfo;
+class Diagnostic;
+class ASTConsumer;
+class IdentifierTable;
+class SourceManager;
+
+/// ProcessWarningOptions - Initialize the diagnostic client and process the
+/// warning options specified on the command line.
+bool ProcessWarningOptions(Diagnostic &Diags);
+
+/// DoPrintPreprocessedInput - Implement -E mode.
+void DoPrintPreprocessedInput(Preprocessor &PP, const std::string& OutFile);
+
+/// RewriteMacrosInInput - Implement -rewrite-macros mode.
+void RewriteMacrosInInput(Preprocessor &PP, const std::string &InFileName,
+ const std::string& OutFile);
+
+void DoRewriteTest(Preprocessor &PP, const std::string &InFileName,
+ const std::string &OutFileName);
+
+
+/// CreatePrintParserActionsAction - Return the actions implementation that
+/// implements the -parse-print-callbacks option.
+MinimalAction *CreatePrintParserActionsAction(Preprocessor &PP);
+
+/// CheckDiagnostics - Gather the expected diagnostics and check them.
+bool CheckDiagnostics(Preprocessor &PP);
+
+/// CreateDependencyFileGen - Create dependency file generator.
+/// This is only done if either -MD or -MMD has been specified.
+bool CreateDependencyFileGen(Preprocessor *PP,
+ std::string &OutputFile,
+ const std::string &InputFile,
+ const char *&ErrStr);
+
+/// CacheTokens - Cache tokens for use with PCH.
+void CacheTokens(Preprocessor& PP, const std::string& OutFile);
+
+} // end namespace clang
+
+#endif
OpenPOWER on IntegriCloud