summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CIndex/CIndex.cpp745
-rw-r--r--tools/CIndex/CIndex.exports29
-rw-r--r--tools/CIndex/CMakeLists.txt27
-rw-r--r--tools/CIndex/Makefile54
-rw-r--r--tools/CMakeLists.txt9
-rw-r--r--tools/Makefile2
-rw-r--r--tools/c-index-test/CMakeLists.txt25
-rw-r--r--tools/c-index-test/Makefile24
-rw-r--r--tools/c-index-test/c-index-test.c106
-rw-r--r--tools/clang-cc/CMakeLists.txt3
-rw-r--r--tools/clang-cc/clang-cc.cpp905
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/Makefile6
-rw-r--r--tools/driver/driver.cpp126
-rw-r--r--tools/index-test/CMakeLists.txt2
-rw-r--r--tools/index-test/Makefile5
-rw-r--r--tools/index-test/index-test.cpp271
-rw-r--r--tools/wpa/CMakeLists.txt20
-rw-r--r--tools/wpa/Makefile16
-rw-r--r--tools/wpa/clang-wpa.cpp62
20 files changed, 1960 insertions, 479 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
new file mode 100644
index 000000000000..9204d1863d67
--- /dev/null
+++ b/tools/CIndex/CIndex.cpp
@@ -0,0 +1,745 @@
+//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Clang-C Source Indexing library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang-c/Index.h"
+#include "clang/Index/Program.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/Utils.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/ASTUnit.h"
+#include <cstdio>
+using namespace clang;
+using namespace idx;
+
+namespace {
+
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
+{
+ NamedDecl *D = DRE->getDecl();
+ if (isa<VarDecl>(D))
+ return CXCursor_VarRef;
+ else if (isa<FunctionDecl>(D))
+ return CXCursor_FunctionRef;
+ else if (isa<EnumConstantDecl>(D))
+ return CXCursor_EnumConstantRef;
+ else
+ return CXCursor_NotImplemented;
+}
+
+#if 0
+// Will be useful one day.
+class CRefVisitor : public StmtVisitor<CRefVisitor> {
+ CXDecl CDecl;
+ CXDeclIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, Stmt *SRef) {
+ CXCursor C = { CK, CDecl, SRef };
+ Callback(CDecl, C, CData);
+ }
+
+public:
+ CRefVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
+ CDecl(C), Callback(cback), CData(D) {}
+
+ void VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
+ C != CEnd; ++C)
+ Visit(*C);
+ }
+ void VisitDeclRefExpr(DeclRefExpr *Node) {
+ Call(TranslateDeclRefExpr(Node), Node);
+ }
+ void VisitMemberExpr(MemberExpr *Node) {
+ Call(CXCursor_MemberRef, Node);
+ }
+ void VisitObjCMessageExpr(ObjCMessageExpr *Node) {
+ Call(CXCursor_ObjCSelectorRef, Node);
+ }
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
+ Call(CXCursor_ObjCIvarRef, Node);
+ }
+};
+#endif
+
+// Translation Unit Visitor.
+class TUVisitor : public DeclVisitor<TUVisitor> {
+ CXTranslationUnit TUnit;
+ CXTranslationUnitIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, NamedDecl *ND) {
+ CXCursor C = { CK, ND, 0 };
+ Callback(TUnit, C, CData);
+ }
+public:
+ TUVisitor(CXTranslationUnit CTU,
+ CXTranslationUnitIterator cback, CXClientData D) :
+ TUnit(CTU), Callback(cback), CData(D) {}
+
+ void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+ }
+ void VisitTypedefDecl(TypedefDecl *ND) {
+ Call(CXCursor_TypedefDecl, ND);
+ }
+ void VisitTagDecl(TagDecl *ND) {
+ switch (ND->getTagKind()) {
+ case TagDecl::TK_struct:
+ Call(CXCursor_StructDecl, ND);
+ break;
+ case TagDecl::TK_class:
+ Call(CXCursor_ClassDecl, ND);
+ break;
+ case TagDecl::TK_union:
+ Call(CXCursor_UnionDecl, ND);
+ break;
+ case TagDecl::TK_enum:
+ Call(CXCursor_EnumDecl, ND);
+ break;
+ }
+ }
+ void VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
+ }
+ void VisitFunctionDecl(FunctionDecl *ND) {
+ Call(ND->isThisDeclarationADefinition() ? CXCursor_FunctionDefn
+ : CXCursor_FunctionDecl, ND);
+ }
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
+ Call(CXCursor_ObjCInterfaceDecl, ND);
+ }
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ Call(CXCursor_ObjCCategoryDecl, ND);
+ }
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
+ Call(CXCursor_ObjCProtocolDecl, ND);
+ }
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *ND) {
+ Call(CXCursor_ObjCClassDefn, ND);
+ }
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *ND) {
+ Call(CXCursor_ObjCCategoryDefn, ND);
+ }
+};
+
+// Declaration visitor.
+class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
+ CXDecl CDecl;
+ CXDeclIterator Callback;
+ CXClientData CData;
+
+ void Call(enum CXCursorKind CK, NamedDecl *ND) {
+ // Disable the callback when the context is equal to the visiting decl.
+ if (CDecl == ND && !clang_isReference(CK))
+ return;
+ CXCursor C = { CK, ND, 0 };
+ Callback(CDecl, C, CData);
+ }
+public:
+ CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D) :
+ CDecl(C), Callback(cback), CData(D) {}
+
+ void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
+ // Issue callbacks for the containing class.
+ Call(CXCursor_ObjCClassRef, ND);
+ // FIXME: Issue callbacks for protocol refs.
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+ }
+ void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ // Issue callbacks for super class.
+ if (D->getSuperClass())
+ Call(CXCursor_ObjCSuperClassRef, D);
+
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
+ E = PID->protocol_end(); I != E; ++I)
+ Call(CXCursor_ObjCProtocolRef, *I);
+
+ VisitDeclContext(dyn_cast<DeclContext>(PID));
+ }
+ void VisitTagDecl(TagDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ VisitDeclContext(dyn_cast<DeclContext>(D));
+ }
+ void VisitDeclContext(DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
+ Visit(*I);
+ }
+ void VisitEnumConstantDecl(EnumConstantDecl *ND) {
+ Call(CXCursor_EnumConstantDecl, ND);
+ }
+ void VisitFieldDecl(FieldDecl *ND) {
+ Call(CXCursor_FieldDecl, ND);
+ }
+ void VisitVarDecl(VarDecl *ND) {
+ Call(CXCursor_VarDecl, ND);
+ }
+ void VisitParmVarDecl(ParmVarDecl *ND) {
+ Call(CXCursor_ParmDecl, ND);
+ }
+ void VisitObjCPropertyDecl(ObjCPropertyDecl *ND) {
+ Call(CXCursor_ObjCPropertyDecl, ND);
+ }
+ void VisitObjCIvarDecl(ObjCIvarDecl *ND) {
+ Call(CXCursor_ObjCIvarDecl, ND);
+ }
+ void VisitFunctionDecl(FunctionDecl *ND) {
+ if (ND->isThisDeclarationADefinition()) {
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+#if 0
+ // Not currently needed.
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(ND->getBody());
+ CRefVisitor RVisit(CDecl, Callback, CData);
+ RVisit.Visit(Body);
+#endif
+ }
+ }
+ void VisitObjCMethodDecl(ObjCMethodDecl *ND) {
+ if (ND->getBody()) {
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDefn
+ : CXCursor_ObjCClassMethodDefn, ND);
+ VisitDeclContext(dyn_cast<DeclContext>(ND));
+ } else
+ Call(ND->isInstanceMethod() ? CXCursor_ObjCInstanceMethodDecl
+ : CXCursor_ObjCClassMethodDecl, ND);
+ }
+};
+
+}
+
+extern "C" {
+
+CXIndex clang_createIndex()
+{
+ // FIXME: Program is leaked.
+ return new Indexer(*new Program());
+}
+
+void clang_disposeIndex(CXIndex CIdx)
+{
+ assert(CIdx && "Passed null CXIndex");
+ delete static_cast<Indexer *>(CIdx);
+}
+
+// FIXME: need to pass back error info.
+CXTranslationUnit clang_createTranslationUnit(
+ CXIndex CIdx, const char *ast_filename)
+{
+ assert(CIdx && "Passed null CXIndex");
+ Indexer *CXXIdx = static_cast<Indexer *>(CIdx);
+ std::string astName(ast_filename);
+ std::string ErrMsg;
+
+ return ASTUnit::LoadFromPCHFile(astName, CXXIdx->getDiagnostics(),
+ CXXIdx->getFileManager(), &ErrMsg);
+}
+
+void clang_disposeTranslationUnit(
+ CXTranslationUnit CTUnit)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ delete static_cast<ASTUnit *>(CTUnit);
+}
+
+const char *clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+ return CXXUnit->getOriginalSourceFileName().c_str();
+}
+
+void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
+ CXTranslationUnitIterator callback,
+ CXClientData CData)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+ ASTContext &Ctx = CXXUnit->getASTContext();
+
+ TUVisitor DVisit(CTUnit, callback, CData);
+ DVisit.Visit(Ctx.getTranslationUnitDecl());
+}
+
+void clang_loadDeclaration(CXDecl Dcl,
+ CXDeclIterator callback,
+ CXClientData CData)
+{
+ assert(Dcl && "Passed null CXDecl");
+
+ CDeclVisitor DVisit(Dcl, callback, CData);
+ DVisit.Visit(static_cast<Decl *>(Dcl));
+}
+
+// Some notes on CXEntity:
+//
+// - Since the 'ordinary' namespace includes functions, data, typedefs,
+// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
+// entity for 2 different types). For example:
+//
+// module1.m: @interface Foo @end Foo *x;
+// module2.m: void Foo(int);
+//
+// - Since the unique name spans translation units, static data/functions
+// within a CXTranslationUnit are *not* currently represented by entities.
+// As a result, there will be no entity for the following:
+//
+// module.m: static void Foo() { }
+//
+
+
+const char *clang_getDeclarationName(CXEntity)
+{
+ return "";
+}
+const char *clang_getURI(CXEntity)
+{
+ return "";
+}
+
+CXEntity clang_getEntity(const char *URI)
+{
+ return 0;
+}
+
+//
+// CXDecl Operations.
+//
+CXEntity clang_getEntityFromDecl(CXDecl)
+{
+ return 0;
+}
+const char *clang_getDeclSpelling(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+
+ if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
+ return OMD->getSelector().getAsString().c_str();
+ }
+ if (ND->getIdentifier())
+ return ND->getIdentifier()->getName();
+ else
+ return "";
+}
+
+unsigned clang_getDeclLine(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getSpellingLineNumber(ND->getLocation());
+}
+
+unsigned clang_getDeclColumn(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getSpellingColumnNumber(ND->getLocation());
+}
+
+const char *clang_getDeclSource(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+ return SourceMgr.getBufferName(ND->getLocation());
+}
+
+const char *clang_getCursorSpelling(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCSuperClassRef:
+ {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return OID->getSuperClass()->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCClassRef:
+ {
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND)) {
+ return OID->getIdentifier()->getName();
+ }
+ ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing category decl");
+ return OID->getClassInterface()->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCProtocolRef:
+ {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return OID->getIdentifier()->getName();
+ }
+ case CXCursor_ObjCSelectorRef:
+ {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return OME->getSelector().getAsString().c_str();
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef:
+ {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return DRE->getDecl()->getIdentifier()->getName();
+ }
+ default:
+ return "<not implemented>";
+ }
+ }
+ return clang_getDeclSpelling(C.decl);
+}
+
+const char *clang_getCursorKindSpelling(enum CXCursorKind Kind)
+{
+ switch (Kind) {
+ case CXCursor_FunctionDecl: return "FunctionDecl";
+ case CXCursor_TypedefDecl: return "TypedefDecl";
+ case CXCursor_EnumDecl: return "EnumDecl";
+ case CXCursor_EnumConstantDecl: return "EnumConstantDecl";
+ case CXCursor_StructDecl: return "StructDecl";
+ case CXCursor_UnionDecl: return "UnionDecl";
+ case CXCursor_ClassDecl: return "ClassDecl";
+ case CXCursor_FieldDecl: return "FieldDecl";
+ case CXCursor_VarDecl: return "VarDecl";
+ case CXCursor_ParmDecl: return "ParmDecl";
+ case CXCursor_ObjCInterfaceDecl: return "ObjCInterfaceDecl";
+ case CXCursor_ObjCCategoryDecl: return "ObjCCategoryDecl";
+ case CXCursor_ObjCProtocolDecl: return "ObjCProtocolDecl";
+ case CXCursor_ObjCPropertyDecl: return "ObjCPropertyDecl";
+ case CXCursor_ObjCIvarDecl: return "ObjCIvarDecl";
+ case CXCursor_ObjCInstanceMethodDecl: return "ObjCInstanceMethodDecl";
+ case CXCursor_ObjCClassMethodDecl: return "ObjCClassMethodDecl";
+ case CXCursor_FunctionDefn: return "FunctionDefn";
+ case CXCursor_ObjCInstanceMethodDefn: return "ObjCInstanceMethodDefn";
+ case CXCursor_ObjCClassMethodDefn: return "ObjCClassMethodDefn";
+ case CXCursor_ObjCClassDefn: return "ObjCClassDefn";
+ case CXCursor_ObjCCategoryDefn: return "ObjCCategoryDefn";
+ case CXCursor_ObjCSuperClassRef: return "ObjCSuperClassRef";
+ case CXCursor_ObjCProtocolRef: return "ObjCProtocolRef";
+ case CXCursor_ObjCClassRef: return "ObjCClassRef";
+ case CXCursor_ObjCSelectorRef: return "ObjCSelectorRef";
+
+ case CXCursor_VarRef: return "VarRef";
+ case CXCursor_FunctionRef: return "FunctionRef";
+ case CXCursor_EnumConstantRef: return "EnumConstantRef";
+ case CXCursor_MemberRef: return "MemberRef";
+
+ case CXCursor_InvalidFile: return "InvalidFile";
+ case CXCursor_NoDeclFound: return "NoDeclFound";
+ case CXCursor_NotImplemented: return "NotImplemented";
+ default: return "<not implemented>";
+ }
+}
+
+static enum CXCursorKind TranslateKind(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Function: return CXCursor_FunctionDecl;
+ case Decl::Typedef: return CXCursor_TypedefDecl;
+ case Decl::Enum: return CXCursor_EnumDecl;
+ case Decl::EnumConstant: return CXCursor_EnumConstantDecl;
+ case Decl::Record: return CXCursor_StructDecl; // FIXME: union/class
+ case Decl::Field: return CXCursor_FieldDecl;
+ case Decl::Var: return CXCursor_VarDecl;
+ case Decl::ParmVar: return CXCursor_ParmDecl;
+ case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl;
+ case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl;
+ case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
+ if (MD->isInstanceMethod())
+ return CXCursor_ObjCInstanceMethodDecl;
+ return CXCursor_ObjCClassMethodDecl;
+ }
+ default: break;
+ }
+ return CXCursor_NotImplemented;
+}
+//
+// CXCursor Operations.
+//
+CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
+ unsigned line, unsigned column)
+{
+ assert(CTUnit && "Passed null CXTranslationUnit");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
+
+ FileManager &FMgr = CXXUnit->getFileManager();
+ const FileEntry *File = FMgr.getFile(source_name,
+ source_name+strlen(source_name));
+ if (!File) {
+ CXCursor C = { CXCursor_InvalidFile, 0, 0 };
+ return C;
+ }
+ SourceLocation SLoc =
+ CXXUnit->getSourceManager().getLocation(File, line, column);
+
+ ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc);
+
+ Decl *Dcl = ALoc.getParentDecl();
+ if (ALoc.isNamedRef())
+ Dcl = ALoc.AsNamedRef().ND;
+ Stmt *Stm = ALoc.dyn_AsStmt();
+ if (Dcl) {
+ if (Stm) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Stm)) {
+ CXCursor C = { TranslateDeclRefExpr(DRE), Dcl, Stm };
+ return C;
+ } else if (ObjCMessageExpr *MExp = dyn_cast<ObjCMessageExpr>(Stm)) {
+ CXCursor C = { CXCursor_ObjCSelectorRef, Dcl, MExp };
+ return C;
+ }
+ // Fall through...treat as a decl, not a ref.
+ }
+ if (ALoc.isNamedRef()) {
+ if (isa<ObjCInterfaceDecl>(Dcl)) {
+ CXCursor C = { CXCursor_ObjCClassRef, Dcl, ALoc.getParentDecl() };
+ return C;
+ }
+ if (isa<ObjCProtocolDecl>(Dcl)) {
+ CXCursor C = { CXCursor_ObjCProtocolRef, Dcl, ALoc.getParentDecl() };
+ return C;
+ }
+ }
+ CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
+ return C;
+ }
+ CXCursor C = { CXCursor_NoDeclFound, 0, 0 };
+ return C;
+}
+
+CXCursor clang_getCursorFromDecl(CXDecl AnonDecl)
+{
+ assert(AnonDecl && "Passed null CXDecl");
+ NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
+
+ CXCursor C = { TranslateKind(ND), ND, 0 };
+ return C;
+}
+
+unsigned clang_isInvalid(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
+}
+
+unsigned clang_isDeclaration(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
+}
+
+unsigned clang_isReference(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
+}
+
+unsigned clang_isDefinition(enum CXCursorKind K)
+{
+ return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn;
+}
+
+CXCursorKind clang_getCursorKind(CXCursor C)
+{
+ return C.kind;
+}
+
+static Decl *getDeclFromExpr(Stmt *E) {
+ if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ return RefExpr->getDecl();
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ return RE->getDecl();
+
+ if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ return getDeclFromExpr(CE->getCallee());
+ if (CastExpr *CE = dyn_cast<CastExpr>(E))
+ return getDeclFromExpr(CE->getSubExpr());
+ if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ return OME->getMethodDecl();
+
+ return 0;
+}
+
+CXDecl clang_getCursorDecl(CXCursor C)
+{
+ if (clang_isDeclaration(C.kind))
+ return C.decl;
+
+ if (clang_isReference(C.kind)) {
+ if (C.stmt) {
+ if (C.kind == CXCursor_ObjCClassRef ||
+ C.kind == CXCursor_ObjCProtocolRef)
+ return static_cast<Stmt *>(C.stmt);
+ else
+ return getDeclFromExpr(static_cast<Stmt *>(C.stmt));
+ } else
+ return C.decl;
+ }
+ return 0;
+}
+
+
+static SourceLocation getLocationFromCursor(CXCursor C,
+ SourceManager &SourceMgr,
+ NamedDecl *ND) {
+ if (clang_isReference(C.kind)) {
+ switch (C.kind) {
+ case CXCursor_ObjCClassRef:
+ {
+ if (isa<ObjCInterfaceDecl>(ND)) {
+ // FIXME: This is a hack (storing the parent decl in the stmt slot).
+ NamedDecl *parentDecl = static_cast<NamedDecl *>(C.stmt);
+ return parentDecl->getLocation();
+ }
+ ObjCCategoryDecl *OID = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing category decl");
+ return OID->getClassInterface()->getLocation();
+ }
+ case CXCursor_ObjCSuperClassRef:
+ {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return OID->getSuperClassLoc();
+ }
+ case CXCursor_ObjCProtocolRef:
+ {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return OID->getLocation();
+ }
+ case CXCursor_ObjCSelectorRef:
+ {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return OME->getLeftLoc(); /* FIXME: should be a range */
+ }
+ case CXCursor_VarRef:
+ case CXCursor_FunctionRef:
+ case CXCursor_EnumConstantRef:
+ {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(DRE && "clang_getCursorLine(): Missing decl ref expr");
+ return DRE->getLocation();
+ }
+ default:
+ return SourceLocation();
+ }
+ } else { // We have a declaration or a definition.
+ SourceLocation SLoc;
+ switch (ND->getKind()) {
+ case Decl::ObjCInterface:
+ {
+ SLoc = dyn_cast<ObjCInterfaceDecl>(ND)->getClassLoc();
+ break;
+ }
+ case Decl::ObjCProtocol:
+ {
+ SLoc = ND->getLocation(); /* FIXME: need to get the name location. */
+ break;
+ }
+ default:
+ {
+ SLoc = ND->getLocation();
+ break;
+ }
+ }
+ if (SLoc.isInvalid())
+ return SourceLocation();
+ return SourceMgr.getSpellingLoc(SLoc); // handles macro instantiations.
+ }
+}
+
+unsigned clang_getCursorLine(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getSpellingLineNumber(SLoc);
+}
+
+unsigned clang_getCursorColumn(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getSpellingColumnNumber(SLoc);
+}
+const char *clang_getCursorSource(CXCursor C)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
+
+ SourceLocation SLoc = getLocationFromCursor(C, SourceMgr, ND);
+ return SourceMgr.getBufferName(SLoc);
+}
+
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
+ const char **startBuf,
+ const char **endBuf,
+ unsigned *startLine,
+ unsigned *startColumn,
+ unsigned *endLine,
+ unsigned *endColumn)
+{
+ assert(C.decl && "CXCursor has null decl");
+ NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
+
+ SourceManager &SM = FD->getASTContext().getSourceManager();
+ *startBuf = SM.getCharacterData(Body->getLBracLoc());
+ *endBuf = SM.getCharacterData(Body->getRBracLoc());
+ *startLine = SM.getSpellingLineNumber(Body->getLBracLoc());
+ *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc());
+ *endLine = SM.getSpellingLineNumber(Body->getRBracLoc());
+ *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
+}
+
+
+} // end extern "C"
diff --git a/tools/CIndex/CIndex.exports b/tools/CIndex/CIndex.exports
new file mode 100644
index 000000000000..c1ca0c773519
--- /dev/null
+++ b/tools/CIndex/CIndex.exports
@@ -0,0 +1,29 @@
+_clang_createIndex
+_clang_disposeIndex
+_clang_getCursor
+_clang_getCursorColumn
+_clang_getCursorDecl
+_clang_getCursorFromDecl
+_clang_getCursorKind
+_clang_getCursorLine
+_clang_getCursorSource
+_clang_getDeclarationName
+_clang_getDeclSpelling
+_clang_getDeclLine
+_clang_getDeclColumn
+_clang_getDeclSource
+_clang_getEntity
+_clang_getEntityFromDecl
+_clang_getURI
+_clang_loadDeclaration
+_clang_loadTranslationUnit
+_clang_createTranslationUnit
+_clang_disposeTranslationUnit
+_clang_isDeclaration
+_clang_isReference
+_clang_isDefinition
+_clang_isInvalid
+_clang_getCursorSpelling
+_clang_getCursorKindSpelling
+_clang_getDefinitionSpellingAndExtent
+_clang_getTranslationUnitSpelling
diff --git a/tools/CIndex/CMakeLists.txt b/tools/CIndex/CMakeLists.txt
new file mode 100644
index 000000000000..71bbde546a6e
--- /dev/null
+++ b/tools/CIndex/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(SHARED_LIBRARY TRUE)
+
+set(LLVM_NO_RTTI 1)
+
+set(LLVM_USED_LIBS
+ clangFrontend clangIndex clangSema clangAST clangLex clangBasic)
+
+set( LLVM_LINK_COMPONENTS
+ MC
+ support
+ )
+
+add_clang_library(CIndex CIndex.cpp)
+
+if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ # FIXME: Deal with LLVM_SUBMIT_VERSION?
+
+ set_target_properties(CIndex
+ PROPERTIES
+ LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/CIndex.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000"
+ INSTALL_NAME_DIR "@executable_path/../lib"
+ )
+endif()
+
+set_target_properties(CIndex
+ PROPERTIES
+ LINKER_LANGUAGE CXX)
diff --git a/tools/CIndex/Makefile b/tools/CIndex/Makefile
new file mode 100644
index 000000000000..a9ff394f3399
--- /dev/null
+++ b/tools/CIndex/Makefile
@@ -0,0 +1,54 @@
+##===- tools/CIndex/Makefile -------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../../..
+LIBRARYNAME = CIndex
+
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+
+# 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_LIBS_IN_SHARED = 1
+SHARED_LIBRARY = 1
+
+LINK_COMPONENTS := MC support
+USEDLIBS = clangFrontend.a clangIndex.a clangSema.a clangAST.a clangLex.a clangBasic.a
+
+include $(LEVEL)/Makefile.common
+
+##===----------------------------------------------------------------------===##
+# FIXME: This is copied from the 'lto' makefile. Should we share this?
+##===----------------------------------------------------------------------===##
+
+ifeq ($(HOST_OS),Darwin)
+ # set dylib internal version number to llvmCore submission number
+ ifdef LLVM_SUBMIT_VERSION
+ LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \
+ -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \
+ -Wl,-compatibility_version -Wl,1
+ endif
+ # extra options to override libtool defaults
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -avoid-version \
+ -Wl,-exported_symbols_list -Wl,$(PROJ_SRC_DIR)/CIndex.exports \
+ -Wl,-dead_strip \
+ -Wl,-seg1addr -Wl,0xE0000000
+
+ # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line
+ DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/')
+ ifneq ($(DARWIN_VERS),8)
+ LLVMLibsOptions := $(LLVMLibsOptions) \
+ -no-undefined -Wl,-install_name \
+ -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)"
+ endif
+endif
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index fc30fb848e75..cb2aa2004ce7 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,3 +1,12 @@
add_subdirectory(clang-cc)
add_subdirectory(driver)
add_subdirectory(index-test)
+option(CLANG_BUILD_EXPERIMENTAL "Build experimenal Clang tools" OFF)
+if (CLANG_BUILD_EXPERIMENTAL)
+ add_subdirectory(wpa)
+endif ()
+add_subdirectory(CIndex)
+if (MSVC)
+else ()
+ add_subdirectory(c-index-test)
+endif ()
diff --git a/tools/Makefile b/tools/Makefile
index 5b49cc8ad0d1..0e98439c3821 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,6 +8,6 @@
##===----------------------------------------------------------------------===##
LEVEL := ../../..
-DIRS := clang-cc driver index-test
+DIRS := clang-cc driver index-test CIndex c-index-test
include $(LEVEL)/Makefile.common
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
new file mode 100644
index 000000000000..4c724659f6f6
--- /dev/null
+++ b/tools/c-index-test/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ CIndex
+ clangIndex
+ clangFrontend
+ clangSema
+ clangAST
+ clangLex
+ clangBasic
+ )
+
+set( LLVM_LINK_COMPONENTS
+ bitreader
+ mc
+ )
+
+add_clang_executable(c-index-test
+ c-index-test.c
+ )
+
+set_target_properties(c-index-test
+ PROPERTIES
+ LINKER_LANGUAGE CXX)
+
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
new file mode 100644
index 000000000000..81fee40b66e2
--- /dev/null
+++ b/tools/c-index-test/Makefile
@@ -0,0 +1,24 @@
+##===- tools/index-test/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 = c-index-test
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
new file mode 100644
index 000000000000..c514b63d94be
--- /dev/null
+++ b/tools/c-index-test/c-index-test.c
@@ -0,0 +1,106 @@
+/* c-index-test.c */
+
+#include "clang-c/Index.h"
+#include <stdio.h>
+#include <string.h>
+
+extern char *basename(const char *);
+
+static void PrintCursor(CXCursor Cursor) {
+ if (clang_isInvalid(Cursor.kind))
+ printf("Invalid Cursor => %s\n", clang_getCursorKindSpelling(Cursor.kind));
+ else {
+ CXDecl DeclReferenced;
+ printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
+ clang_getCursorSpelling(Cursor));
+ DeclReferenced = clang_getCursorDecl(Cursor);
+ if (DeclReferenced)
+ printf(":%d:%d", clang_getDeclLine(DeclReferenced),
+ clang_getDeclColumn(DeclReferenced));
+ }
+}
+
+static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
+{
+ if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
+ clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
+ PrintCursor(Cursor);
+ printf(" [Context=%s]\n", clang_getDeclSpelling(Dcl));
+ }
+}
+static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
+ CXClientData Filter)
+{
+ if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)),
+ clang_getCursorLine(Cursor),
+ clang_getCursorColumn(Cursor));
+ PrintCursor(Cursor);
+ printf(" [Context=%s]\n", basename(clang_getTranslationUnitSpelling(Unit)));
+
+ clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
+
+ if (Cursor.kind == CXCursor_FunctionDefn) {
+ const char *startBuf, *endBuf;
+ unsigned startLine, startColumn, endLine, endColumn;
+ clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
+ &startLine, &startColumn,
+ &endLine, &endColumn);
+ {
+ /* Probe the entire body, looking for both decls and refs. */
+ unsigned curLine = startLine, curColumn = startColumn;
+ CXCursor Ref;
+
+ while (startBuf <= endBuf) {
+ if (*startBuf == '\n') {
+ startBuf++;
+ curLine++;
+ curColumn = 1;
+ } else if (*startBuf != '\t')
+ curColumn++;
+
+ Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
+ curLine, curColumn);
+ if (Ref.kind != CXCursor_FunctionDecl) {
+ printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Ref)),
+ curLine, curColumn);
+ PrintCursor(Ref);
+ printf(" [Context:%s]\n", clang_getDeclSpelling(Ref.decl));
+ }
+ startBuf++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * First sign of life:-)
+ */
+int main(int argc, char **argv) {
+ if (argc != 3) {
+ printf("Incorrect usage of c-index-test (requires 3 arguments)\n");
+ return 0;
+ }
+ {
+ CXIndex Idx = clang_createIndex();
+ CXTranslationUnit TU = clang_createTranslationUnit(Idx, argv[1]);
+ enum CXCursorKind K = CXCursor_NotImplemented;
+
+ if (!strcmp(argv[2], "all")) {
+ clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0);
+ return 1;
+ }
+ /* Perform some simple filtering. */
+ if (!strcmp(argv[2], "category")) K = CXCursor_ObjCCategoryDecl;
+ else if (!strcmp(argv[2], "interface")) K = CXCursor_ObjCInterfaceDecl;
+ else if (!strcmp(argv[2], "protocol")) K = CXCursor_ObjCProtocolDecl;
+ else if (!strcmp(argv[2], "function")) K = CXCursor_FunctionDecl;
+ else if (!strcmp(argv[2], "typedef")) K = CXCursor_TypedefDecl;
+
+ clang_loadTranslationUnit(TU, TranslationUnitVisitor, &K);
+ return 1;
+ }
+}
diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt
index e224d40f6c8c..85e4c7c20653 100644
--- a/tools/clang-cc/CMakeLists.txt
+++ b/tools/clang-cc/CMakeLists.txt
@@ -25,3 +25,6 @@ add_clang_executable(clang-cc
clang-cc.cpp
)
add_dependencies(clang-cc clang-headers)
+
+install(TARGETS clang-cc
+ RUNTIME DESTINATION libexec)
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
index 9433c1752e53..0ad7efbc4839 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -24,6 +24,7 @@
#include "clang/Frontend/AnalysisConsumer.h"
#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompileOptions.h"
#include "clang/Frontend/FixItRewriter.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -37,6 +38,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/ParseAST.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
@@ -58,12 +60,13 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Streams.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
#include "llvm/System/Process.h"
@@ -108,14 +111,14 @@ 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",
+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));
static llvm::cl::opt<bool>
-EmptyInputOnly("empty-input-only",
+EmptyInputOnly("empty-input-only",
llvm::cl::desc("Force running on an empty input file"));
enum ProgActions {
@@ -128,13 +131,14 @@ enum ProgActions {
EmitAssembly, // Emit a .s file.
EmitLLVM, // Emit a .ll file.
EmitBC, // Emit a .bc file.
- EmitLLVMOnly, // Generate LLVM IR, but do not
+ EmitLLVMOnly, // Generate LLVM IR, but do not
EmitHTML, // Translate input source into HTML.
ASTPrint, // Parse ASTs and print them.
ASTPrintXML, // Parse ASTs and print them in XML.
ASTDump, // Parse ASTs and dump them.
ASTView, // Parse ASTs and view them in Graphviz.
PrintDeclContext, // Print DeclContext and their Decls.
+ DumpRecordLayouts, // Dump record layout information.
ParsePrintCallbacks, // Parse and print each callback.
ParseSyntaxOnly, // Parse and perform semantic analysis.
ParseNoop, // Parse with noop callbacks.
@@ -142,13 +146,13 @@ enum ProgActions {
PrintPreprocessedInput, // -E mode.
DumpTokens, // Dump out preprocessed tokens.
DumpRawTokens, // Dump out raw tokens.
- RunAnalysis, // Run one or more source code analyses.
+ RunAnalysis, // Run one or more source code analyses.
GeneratePTH, // Generate pre-tokenized header.
GeneratePCH, // Generate pre-compiled header.
InheritanceView // View C++ inheritance for a specified class.
};
-static llvm::cl::opt<ProgActions>
+static llvm::cl::opt<ProgActions>
ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
llvm::cl::init(ParseSyntaxOnly),
llvm::cl::values(
@@ -180,6 +184,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
"Build ASTs and view them with GraphViz"),
clEnumValN(PrintDeclContext, "print-decl-contexts",
"Print DeclContexts and their Decls"),
+ clEnumValN(DumpRecordLayouts, "dump-record-layouts",
+ "Dump record layout information"),
clEnumValN(GeneratePTH, "emit-pth",
"Generate pre-tokenized header file"),
clEnumValN(GeneratePCH, "emit-pch",
@@ -211,6 +217,17 @@ OutputFile("o",
llvm::cl::desc("Specify output file"));
+static llvm::cl::opt<ParsedSourceLocation>
+CodeCompletionAt("code-completion-at",
+ llvm::cl::value_desc("file:line:column"),
+ llvm::cl::desc("Dump code-completion information at a location"));
+
+/// \brief Buld a new code-completion consumer that prints the results of
+/// code completion to standard output.
+static CodeCompleteConsumer *BuildPrintingCodeCompleter(Sema &S, void *) {
+ return new PrintingCodeCompleteConsumer(S, llvm::outs());
+}
+
//===----------------------------------------------------------------------===//
// PTH.
//===----------------------------------------------------------------------===//
@@ -261,13 +278,13 @@ PrintDiagnosticOption("fdiagnostics-show-option",
static llvm::cl::opt<unsigned>
MessageLength("fmessage-length",
- llvm::cl::desc("Format message diagnostics so that they fit "
- "within N columns or fewer, when possible."),
- llvm::cl::value_desc("N"));
+ llvm::cl::desc("Format message diagnostics so that they fit "
+ "within N columns or fewer, when possible."),
+ llvm::cl::value_desc("N"));
static llvm::cl::opt<bool>
NoColorDiagnostic("fno-color-diagnostics",
- llvm::cl::desc("Don't use colors when showing diagnostics "
+ llvm::cl::desc("Don't use colors when showing diagnostics "
"(automatically turned off if output is not a "
"terminal)."));
//===----------------------------------------------------------------------===//
@@ -317,7 +334,8 @@ enum LangKind {
langkind_objc_cpp,
langkind_objcxx,
langkind_objcxx_cpp,
- langkind_ocl
+ langkind_ocl,
+ langkind_ast
};
static llvm::cl::opt<LangKind>
@@ -346,20 +364,21 @@ BaseLang("x", llvm::cl::desc("Base language to compile"),
"C++ header"),
clEnumValN(langkind_objcxx, "objective-c++-header",
"Objective-C++ header"),
+ clEnumValN(langkind_ast, "ast",
+ "Clang AST"),
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);
-
-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<std::string>
+ObjCConstantStringClass("fconstant-string-class",
+ llvm::cl::value_desc("class name"),
+ llvm::cl::desc("Specify the class to use for constant "
+ "Objective-C string objects."));
+
static llvm::cl::opt<bool>
ObjCEnableGC("fobjc-gc",
llvm::cl::desc("Enable Objective-C garbage collection"));
@@ -386,39 +405,23 @@ OverflowChecking("ftrapv",
llvm::cl::init(false));
static llvm::cl::opt<bool>
-ObjCSenderDispatch("fobjc-sender-dependent-dispatch",
- llvm::cl::desc("Enable sender-dependent dispatch for"
- "Objective-C messages"), llvm::cl::init(false));
+AltiVec("faltivec", llvm::cl::desc("Enable AltiVec vector initializer syntax"),
+ llvm::cl::init(false));
-/// InitializeBaseLanguage - Handle the -x foo options.
-static void InitializeBaseLanguage() {
- if (LangObjC)
- BaseLang = langkind_objc;
- else if (LangObjCXX)
- BaseLang = langkind_objcxx;
-}
+static llvm::cl::opt<bool>
+PThread("pthread", llvm::cl::desc("Support POSIX threads in generated code"),
+ llvm::cl::init(false));
-static LangKind GetLanguage(const std::string &Filename) {
+static LangKind GetLanguage(llvm::StringRef 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")
+ llvm::StringRef Ext = Filename.rsplit('.').second;
+ if (Ext == "ast")
+ return langkind_ast;
+ else 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")
+ else if (Ext == "S" || Ext == "s")
return langkind_asm_cpp;
else if (Ext == "i")
return langkind_c_cpp;
@@ -449,12 +452,12 @@ static void InitializeCOptions(LangOptions &Options) {
static void InitializeObjCOptions(LangOptions &Options) {
Options.ObjC1 = Options.ObjC2 = 1;
}
-
+
static void InitializeLangOptions(LangOptions &Options, LangKind LK){
// FIXME: implement -fpreprocessed mode.
bool NoPreprocess = false;
-
+
switch (LK) {
default: assert(0 && "Unknown language kind!");
case langkind_asm_cpp:
@@ -492,25 +495,30 @@ static void InitializeLangOptions(LangOptions &Options, LangKind LK){
Options.LaxVectorConversions = 1;
break;
}
-
+
if (ObjCExclusiveGC)
Options.setGCMode(LangOptions::GCOnly);
else if (ObjCEnableGC)
Options.setGCMode(LangOptions::HybridGC);
-
+
if (ObjCEnableGCBitmapPrint)
Options.ObjCGCBitmapPrint = 1;
-
+
+ if (AltiVec)
+ Options.AltiVec = 1;
+
+ if (PThread)
+ Options.POSIXThreads = 1;
+
Options.setVisibilityMode(SymbolVisibility);
Options.OverflowChecking = OverflowChecking;
}
/// LangStds - Language standards we support.
enum LangStds {
- lang_unspecified,
+ lang_unspecified,
lang_c89, lang_c94, lang_c99,
- lang_gnu_START,
- lang_gnu89 = lang_gnu_START, lang_gnu99,
+ lang_gnu89, lang_gnu99,
lang_cxx98, lang_gnucxx98,
lang_cxx0x, lang_gnucxx0x
};
@@ -554,7 +562,7 @@ 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 "
@@ -592,6 +600,10 @@ Exceptions("fexceptions",
llvm::cl::desc("Enable support for exception handling"));
static llvm::cl::opt<bool>
+Rtti("frtti", llvm::cl::init(true),
+ llvm::cl::desc("Enable generation of rtti information"));
+
+static llvm::cl::opt<bool>
GNURuntime("fgnu-runtime",
llvm::cl::desc("Generate output compatible with the standard GNU "
"Objective-C runtime"));
@@ -622,7 +634,7 @@ static llvm::cl::opt<bool>
OptSize("Os", llvm::cl::desc("Optimize for size"));
static llvm::cl::opt<bool>
-DisableLLVMOptimizations("disable-llvm-optzns",
+DisableLLVMOptimizations("disable-llvm-optzns",
llvm::cl::desc("Don't run LLVM optimization passes"));
static llvm::cl::opt<bool>
@@ -636,17 +648,26 @@ MainFileName("main-file-name",
// FIXME: Also add an "-fno-access-control" option.
static llvm::cl::opt<bool>
-AccessControl("faccess-control",
+AccessControl("faccess-control",
llvm::cl::desc("Enable C++ access control"));
+static llvm::cl::opt<bool>
+NoElideConstructors("fno-elide-constructors",
+ llvm::cl::desc("Disable C++ copy constructor elision"));
+
+static llvm::cl::opt<std::string>
+TargetABI("target-abi",
+ llvm::cl::desc("Target a particular ABI type"));
+
+
// 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) {
+ bool parse(llvm::cl::Option &O, llvm::StringRef ArgName,
+ llvm::StringRef Arg, unsigned &Val) {
if (llvm::cl::parser<unsigned>::parse(O, ArgName, Arg, Val))
return true;
if (Val > 3)
- return O.error(": '" + Arg + "' invalid optimization level!");
+ return O.error("'" + Arg + "' invalid optimization level!");
return false;
}
};
@@ -675,10 +696,11 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
// Pass the map of target features to the target for validation and
// processing.
Target->HandleTargetFeatures(Features);
-
+
if (LangStd == lang_unspecified) {
// Based on the base language, pick one.
switch (LK) {
+ case langkind_ast: assert(0 && "Invalid call for AST inputs");
case lang_unspecified: assert(0 && "Unknown base language");
case langkind_ocl:
LangStd = lang_c99;
@@ -698,7 +720,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
break;
}
}
-
+
switch (LangStd) {
default: assert(0 && "Unknown language standard!");
@@ -729,18 +751,33 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
}
// GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
- Options.GNUMode = LangStd >= lang_gnu_START;
-
+ switch (LangStd) {
+ default: assert(0 && "Unknown language standard!");
+ case lang_gnucxx0x:
+ case lang_gnucxx98:
+ case lang_gnu99:
+ case lang_gnu89:
+ Options.GNUMode = 1;
+ break;
+ case lang_cxx0x:
+ case lang_cxx98:
+ case lang_c99:
+ case lang_c94:
+ case lang_c89:
+ Options.GNUMode = 0;
+ break;
+ }
+
if (Options.CPlusPlus) {
Options.C99 = 0;
- Options.HexFloats = Options.GNUMode;
+ Options.HexFloats = 0;
}
-
+
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
// is specified, or -std is set to a conforming mode.
Options.Trigraphs = !Options.GNUMode;
@@ -753,14 +790,14 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
// However, blocks are not turned off when compiling Obj-C or Obj-C++ code.
if (!Options.ObjC1 && !Options.GNUMode)
Options.Blocks = 0;
-
+
// Default to not accepting '$' in identifiers when preprocessing assembler,
// but do accept when preprocessing C. FIXME: these defaults are right for
// darwin, are they right everywhere?
Options.DollarIdents = LK != langkind_asm_cpp;
if (DollarsInIdents.getPosition()) // Explicit setting overrides default.
Options.DollarIdents = DollarsInIdents;
-
+
if (PascalStrings.getPosition())
Options.PascalStrings = PascalStrings;
if (MSExtensions.getPosition())
@@ -769,6 +806,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
if (NoLaxVectorConversions.getPosition())
Options.LaxVectorConversions = 0;
Options.Exceptions = Exceptions;
+ Options.Rtti = Rtti;
if (EnableBlocks.getPosition())
Options.Blocks = EnableBlocks;
if (CharIsSigned.getPosition())
@@ -778,16 +816,18 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
Options.NoBuiltin = 1;
if (Freestanding)
Options.Freestanding = Options.NoBuiltin = 1;
-
+
if (EnableHeinousExtensions)
Options.HeinousExtensions = 1;
if (AccessControl)
Options.AccessControl = 1;
-
+
+ Options.ElideConstructors = !NoElideConstructors;
+
// OpenCL and C++ both have bool, true, false keywords.
Options.Bool = Options.OpenCL | Options.CPlusPlus;
-
+
Options.MathErrno = MathErrno;
Options.InstantiationDepth = TemplateDepth;
@@ -798,18 +838,19 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
else if (GNURuntime)
Options.NeXTRuntime = 0;
+ if (!ObjCConstantStringClass.empty())
+ Options.ObjCConstantStringClass = ObjCConstantStringClass.c_str();
+
if (ObjCNonFragileABI)
Options.ObjCNonFragileABI = 1;
- Options.ObjCSenderDispatch = ObjCSenderDispatch;
-
if (EmitAllDecls)
Options.EmitAllDecls = 1;
// The __OPTIMIZE_SIZE__ define is tied to -Oz, which we don't
// support.
Options.OptimizeSize = 0;
-
+
// -Os implies -O2
if (OptSize || OptLevel)
Options.Optimize = 1;
@@ -818,7 +859,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK,
Options.PICLevel = PICLevel;
Options.GNUInline = !Options.C99;
- // FIXME: This is affected by other options (-fno-inline).
+ // FIXME: This is affected by other options (-fno-inline).
Options.NoInline = !OptSize && !OptLevel;
Options.Static = StaticDefine;
@@ -845,70 +886,72 @@ TargetTriple("triple",
llvm::cl::desc("Specify target triple (e.g. i686-apple-darwin9)"));
static llvm::cl::opt<std::string>
-MacOSVersionMin("mmacosx-version-min",
+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
// FIXME: We should have the driver do this instead.
-static void HandleMacOSVersionMin(std::string &Triple) {
- std::string::size_type DarwinDashIdx = Triple.find("-darwin");
- if (DarwinDashIdx == std::string::npos) {
- fprintf(stderr,
+static void HandleMacOSVersionMin(llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin) {
+ 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;
- }
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ MacOSVersionMin.c_str());
+ exit(1);
}
- if (MacOSVersionMinIsInvalid) {
- fprintf(stderr,
- "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
+ unsigned VersionNum = MacOSVersionMin[3]-'0';
+
+ if (VersionNum <= 4 && Triple.getArch() == llvm::Triple::x86_64) {
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid with -arch x86_64.\n",
MacOSVersionMin.c_str());
exit(1);
}
- else if (VersionNum <= 4 &&
- !strncmp(Triple.c_str(), "x86_64", strlen("x86_64"))) {
- fprintf(stderr,
- "-mmacosx-version-min=%s is invalid with -arch x86_64.\n",
+
+
+ llvm::SmallString<16> NewDarwinString;
+ NewDarwinString += "darwin";
+
+ // Turn MacOSVersionMin into a darwin number: e.g. 10.3.9 is 3 -> darwin7.
+ VersionNum += 4;
+ if (VersionNum > 9) {
+ NewDarwinString += '1';
+ VersionNum -= 10;
+ }
+ NewDarwinString += (VersionNum+'0');
+
+ if (MacOSVersionMin.size() == 4) {
+ // "10.4" is ok.
+ } else if (MacOSVersionMin.size() == 6 &&
+ MacOSVersionMin[4] == '.' &&
+ isdigit(MacOSVersionMin[5])) { // 10.4.7 is ok.
+ // Add the period piece (.7) to the end of the triple. This gives us
+ // something like ...-darwin8.7
+ NewDarwinString += '.';
+ NewDarwinString += MacOSVersionMin[5];
+ } else { // "10.4" is ok. 10.4x is not.
+ fprintf(stderr,
+ "-mmacosx-version-min=%s is invalid, expected something like '10.4'.\n",
MacOSVersionMin.c_str());
exit(1);
}
+ Triple.setOSName(NewDarwinString.str());
}
static llvm::cl::opt<std::string>
-IPhoneOSVersionMin("miphoneos-version-min",
+IPhoneOSVersionMin("miphoneos-version-min",
llvm::cl::desc("Specify target iPhone OS version (e.g. 2.0)"));
// If -miphoneos-version-min=2.2 is specified, change the triple from being
@@ -917,68 +960,46 @@ IPhoneOSVersionMin("miphoneos-version-min",
// number in the minor version and revision.
// FIXME: We should have the driver do this instead.
-static void HandleIPhoneOSVersionMin(std::string &Triple) {
- std::string::size_type DarwinDashIdx = Triple.find("-darwin");
- if (DarwinDashIdx == std::string::npos) {
- fprintf(stderr,
- "-miphoneos-version-min only valid for darwin (Mac OS X) targets\n");
+static void HandleIPhoneOSVersionMin(llvm::Triple &Triple) {
+ if (Triple.getOS() != llvm::Triple::Darwin) {
+ fprintf(stderr,
+ "-miphoneos-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 IPhoneOSVersionMin is a 'version number', starting with [2-9].[0-9]
- bool IPhoneOSVersionMinIsInvalid = false;
- int VersionNum = 0;
- if (IPhoneOSVersionMin.size() < 3 ||
- !isdigit(IPhoneOSVersionMin[0])) {
- IPhoneOSVersionMinIsInvalid = true;
- } else {
- const char *Start = IPhoneOSVersionMin.c_str();
- char *End = 0;
- VersionNum = (int)strtol(Start, &End, 10);
-
- // The version number must be in the range 0-9.
- IPhoneOSVersionMinIsInvalid = (unsigned)VersionNum > 9;
-
- // Turn IPhoneOSVersionMin into a darwin number: e.g. 2.0 is 2 -> 9.2.
- Triple += "9." + llvm::itostr(VersionNum);
-
- if (End[0] == '.' && isdigit(End[1]) && End[2] == '\0') { // 2.2 is ok.
- // Add the period piece (.2) to the end of the triple. This gives us
- // something like ...-darwin9.2.2
- Triple += End;
- } else if (End[0] != '\0') { // "2.2" is ok. 2x is not.
- IPhoneOSVersionMinIsInvalid = true;
- }
- }
-
- if (IPhoneOSVersionMinIsInvalid) {
- fprintf(stderr,
- "-miphoneos-version-min=%s is invalid, expected something like '2.0'.\n",
+
+ // Validate that IPhoneOSVersionMin is a 'version number', starting with
+ // [2-9].[0-9]
+ if (IPhoneOSVersionMin.size() != 3 || !isdigit(IPhoneOSVersionMin[0]) ||
+ IPhoneOSVersionMin[1] != '.' || !isdigit(IPhoneOSVersionMin[2])) {
+ fprintf(stderr,
+ "-miphoneos-version-min=%s is invalid, expected something like '2.0'.\n",
IPhoneOSVersionMin.c_str());
exit(1);
}
+
+ // Turn IPhoneOSVersionMin into a darwin number: e.g. 2.0 is 2 -> 9.2.0
+ llvm::SmallString<16> NewDarwinString;
+ NewDarwinString += "darwin9.";
+ NewDarwinString += IPhoneOSVersionMin;
+ Triple.setOSName(NewDarwinString.str());
}
/// 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() {
+static llvm::Triple 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::sys::getHostTriple();
+ llvm::Triple Triple(TargetTriple);
+ if (Triple.getTriple().empty())
+ Triple = llvm::Triple(llvm::sys::getHostTriple());
// 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);
else if (!IPhoneOSVersionMin.empty())
- HandleIPhoneOSVersionMin(Triple);;
-
+ HandleIPhoneOSVersionMin(Triple);
+
return Triple;
}
@@ -994,14 +1015,14 @@ static bool InitializeSourceManager(Preprocessor &PP,
if (EmptyInputOnly) {
const char *EmptyStr = "";
- llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer *SB =
llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
SourceMgr.createMainFileIDForMemBuffer(SB);
} else 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)
+ PP.getDiagnostics().Report(FullSourceLoc(), diag::err_fe_error_reading)
<< InFile.c_str();
return true;
}
@@ -1017,7 +1038,7 @@ static bool InitializeSourceManager(Preprocessor &PP,
SourceMgr.createMainFileIDForMemBuffer(SB);
if (SourceMgr.getMainFileID().isInvalid()) {
- PP.getDiagnostics().Report(FullSourceLoc(),
+ PP.getDiagnostics().Report(FullSourceLoc(),
diag::err_fe_error_reading_stdin);
return true;
}
@@ -1057,6 +1078,10 @@ static llvm::cl::opt<std::string>
ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
llvm::cl::desc("Include file before parsing"));
+static llvm::cl::opt<bool>
+RelocatablePCH("relocatable-pch",
+ llvm::cl::desc("Whether to build a relocatable precompiled "
+ "header"));
//===----------------------------------------------------------------------===//
// Preprocessor include path information.
@@ -1065,7 +1090,7 @@ ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
// 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++
// FIXME: -imultilib
//
@@ -1073,6 +1098,10 @@ ImplicitIncludePTH("include-pth", llvm::cl::value_desc("file"),
static llvm::cl::opt<bool>
nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
+static llvm::cl::opt<bool>
+nostdclanginc("nostdclanginc",
+ llvm::cl::desc("Disable standard clang #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,
@@ -1108,10 +1137,37 @@ isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
// Finally, implement the code that groks the options above.
+// Add the clang headers, which are relative to the clang binary.
+void AddClangIncludePaths(const char *Argv0, InitHeaderSearch *Init) {
+ if (nostdclanginc)
+ return;
+
+ llvm::sys::Path MainExecutablePath =
+ llvm::sys::Path::GetMainExecutable(Argv0,
+ (void*)(intptr_t)AddClangIncludePaths);
+ if (MainExecutablePath.isEmpty())
+ return;
+
+ MainExecutablePath.eraseComponent(); // Remove /clang from foo/bin/clang
+ MainExecutablePath.eraseComponent(); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ MainExecutablePath.appendComponent("lib");
+ MainExecutablePath.appendComponent("clang");
+ MainExecutablePath.appendComponent(CLANG_VERSION_STRING);
+ 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*/);
+}
+
/// InitializeIncludePaths - Process the -I options and set them in the
/// HeaderSearch object.
void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
- FileManager &FM, const LangOptions &Lang) {
+ FileManager &FM, const LangOptions &Lang,
+ llvm::Triple &triple) {
InitHeaderSearch Init(Headers, Verbose, isysroot);
// Handle -I... and -F... options, walking the lists in parallel.
@@ -1125,22 +1181,22 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
++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);
@@ -1158,28 +1214,28 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
bool iwithprefixbefore_done = iwithprefixbefore_vals.empty();
while (!iprefix_done || !iwithprefix_done || !iwithprefixbefore_done) {
if (!iprefix_done &&
- (iwithprefix_done ||
- iprefix_vals.getPosition(iprefix_idx) <
+ (iwithprefix_done ||
+ iprefix_vals.getPosition(iprefix_idx) <
iwithprefix_vals.getPosition(iwithprefix_idx)) &&
- (iwithprefixbefore_done ||
- iprefix_vals.getPosition(iprefix_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_done ||
+ iwithprefix_vals.getPosition(iwithprefix_idx) <
iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
- Init.AddPath(Prefix+iwithprefix_vals[iwithprefix_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],
+ Init.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx],
InitHeaderSearch::Angled, false, false, false);
++iwithprefixbefore_idx;
- iwithprefixbefore_done =
+ iwithprefixbefore_done =
iwithprefixbefore_idx == iwithprefixbefore_vals.size();
}
}
@@ -1187,37 +1243,18 @@ void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
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
+ AddClangIncludePaths(Argv0, &Init);
- // Get foo/lib/clang/<version>/include
- MainExecutablePath.appendComponent("lib");
- MainExecutablePath.appendComponent("clang");
- MainExecutablePath.appendComponent(CLANG_VERSION_STRING);
- 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);
+ if (!nostdinc)
+ Init.AddDefaultSystemIncludePaths(Lang, triple);
// Now that we have collected all of the include paths, merge them all
// together and tell the preprocessor about them.
-
+
Init.Realize();
}
-void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts)
-{
+void InitializePreprocessorInitOptions(PreprocessorInitOptions &InitOpts) {
// Add macros from the command line.
unsigned d = 0, D = D_macros.size();
unsigned u = 0, U = U_macros.size();
@@ -1286,17 +1323,17 @@ class VISIBILITY_HIDDEN DriverPreprocessorFactory : public PreprocessorFactory {
TargetInfo &Target;
SourceManager &SourceMgr;
HeaderSearch &HeaderInfo;
-
+
public:
DriverPreprocessorFactory(Diagnostic &diags, const LangOptions &opts,
TargetInfo &target, SourceManager &SM,
- HeaderSearch &Headers)
+ HeaderSearch &Headers)
: Diags(diags), LangInfo(opts), Target(target),
SourceMgr(SM), HeaderInfo(Headers) {}
-
-
+
+
virtual ~DriverPreprocessorFactory() {}
-
+
virtual Preprocessor* CreatePreprocessor() {
llvm::OwningPtr<PTHManager> PTHMgr;
@@ -1305,23 +1342,23 @@ public:
"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,
+ 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.
@@ -1347,7 +1384,7 @@ public:
static void ParseFile(Preprocessor &PP, MinimalAction *PA) {
Parser P(PP, *PA);
PP.EnterMainSourceFile();
-
+
// Parsing the specified input file.
P.ParseTranslationUnit();
delete PA;
@@ -1384,24 +1421,24 @@ NoImplicitFloat("no-implicit-float",
/// and feature list.
static void ComputeFeatureMap(TargetInfo *Target,
llvm::StringMap<bool> &Features) {
- assert(Features.empty() && "invalid map");
+ assert(Features.empty() && "invalid map");
// Initialize the feature map based on the target.
Target->getDefaultFeatures(TargetCPU, Features);
// Apply the user specified deltas.
- for (llvm::cl::list<std::string>::iterator it = TargetFeatures.begin(),
+ for (llvm::cl::list<std::string>::iterator it = TargetFeatures.begin(),
ie = TargetFeatures.end(); it != ie; ++it) {
const char *Name = it->c_str();
-
+
// FIXME: Don't handle errors like this.
if (Name[0] != '-' && Name[0] != '+') {
- fprintf(stderr, "error: clang-cc: invalid target feature string: %s\n",
+ fprintf(stderr, "error: clang-cc: invalid target feature string: %s\n",
Name);
exit(1);
}
if (!Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) {
- fprintf(stderr, "error: clang-cc: invalid target feature name: %s\n",
+ fprintf(stderr, "error: clang-cc: invalid target feature name: %s\n",
Name + 1);
exit(1);
}
@@ -1442,7 +1479,7 @@ static void InitializeCompileOptions(CompileOptions &Opts,
Opts.CPU = TargetCPU;
Opts.Features.clear();
- for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
+ for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it) {
// FIXME: If we are completely confident that we have the right
// set, we only need to pass the minuses.
@@ -1450,9 +1487,9 @@ static void InitializeCompileOptions(CompileOptions &Opts,
Name += it->first();
Opts.Features.push_back(Name);
}
-
+
Opts.NoCommon = NoCommon | LangOpts.CPlusPlus;
-
+
// Handle -ftime-report.
Opts.TimePasses = TimeReport;
@@ -1539,7 +1576,7 @@ clEnumValN(NAME, CMDFLAG, DESC),
#include "clang/Frontend/Analyses.def"
clEnumValEnd));
-static llvm::cl::opt<AnalysisStores>
+static llvm::cl::opt<AnalysisStores>
AnalysisStoreOpt("analyzer-store",
llvm::cl::desc("Source Code Analysis - Abstract Memory Store Models"),
llvm::cl::init(BasicStoreModel),
@@ -1549,7 +1586,7 @@ clEnumValN(NAME##Model, CMDFLAG, DESC),
#include "clang/Frontend/Analyses.def"
clEnumValEnd));
-static llvm::cl::opt<AnalysisConstraints>
+static llvm::cl::opt<AnalysisConstraints>
AnalysisConstraintsOpt("analyzer-constraints",
llvm::cl::desc("Source Code Analysis - Symbolic Constraint Engines"),
llvm::cl::init(RangeConstraintsModel),
@@ -1641,7 +1678,7 @@ class LoggingDiagnosticClient : public DiagnosticClient {
llvm::OwningPtr<DiagnosticClient> Chain1;
llvm::OwningPtr<DiagnosticClient> Chain2;
public:
-
+
LoggingDiagnosticClient(DiagnosticClient *Normal) {
// Output diags both where requested...
Chain1.reset(Normal);
@@ -1655,12 +1692,12 @@ public:
!NoDiagnosticsFixIt,
MessageLength));
}
-
+
virtual void setLangOptions(const LangOptions *LO) {
Chain1->setLangOptions(LO);
Chain2->setLangOptions(LO);
}
-
+
virtual bool IncludeInDiagnosticCounts() const {
return Chain1->IncludeInDiagnosticCounts();
}
@@ -1675,11 +1712,11 @@ public:
static void SetUpBuildDumpLog(unsigned argc, char **argv,
llvm::OwningPtr<DiagnosticClient> &DiagClient) {
-
+
std::string ErrorInfo;
- BuildLogFile = new llvm::raw_fd_ostream(DumpBuildInformation.c_str(), false,
+ BuildLogFile = new llvm::raw_fd_ostream(DumpBuildInformation.c_str(),
ErrorInfo);
-
+
if (!ErrorInfo.empty()) {
llvm::errs() << "error opening -dump-build-information file '"
<< DumpBuildInformation << "', option ignored!\n";
@@ -1693,7 +1730,7 @@ static void SetUpBuildDumpLog(unsigned argc, char **argv,
for (unsigned i = 0; i != argc; ++i)
(*BuildLogFile) << argv[i] << ' ';
(*BuildLogFile) << '\n';
-
+
// LoggingDiagnosticClient - Insert a new logging diagnostic client in between
// the diagnostic producers and the normal receiver.
DiagClient.reset(new LoggingDiagnosticClient(DiagClient.take()));
@@ -1705,97 +1742,77 @@ static void SetUpBuildDumpLog(unsigned argc, char **argv,
// Main driver
//===----------------------------------------------------------------------===//
-static llvm::raw_ostream* ComputeOutFile(const std::string& InFile,
- const char* Extension,
+static llvm::raw_ostream *ComputeOutFile(const std::string &InFile,
+ const char *Extension,
bool Binary,
llvm::sys::Path& OutPath) {
- llvm::raw_ostream* Ret;
- bool UseStdout = false;
+ llvm::raw_ostream *Ret;
std::string OutFile;
- if (OutputFile == "-" || (OutputFile.empty() && InFile == "-")) {
- UseStdout = true;
- } else if (!OutputFile.empty()) {
+ if (!OutputFile.empty())
OutFile = OutputFile;
+ else if (InFile == "-") {
+ OutFile = "-";
} else if (Extension) {
llvm::sys::Path Path(InFile);
Path.eraseSuffix();
Path.appendSuffix(Extension);
- OutFile = Path.toString();
+ OutFile = Path.str();
} else {
- UseStdout = true;
+ OutFile = "-";
}
- if (UseStdout) {
- Ret = new llvm::raw_stdout_ostream();
- if (Binary)
- llvm::sys::Program::ChangeStdoutToBinary();
- } else {
- std::string Error;
- Ret = new llvm::raw_fd_ostream(OutFile.c_str(), Binary, Error);
- if (!Error.empty()) {
- // FIXME: Don't fail this way.
- llvm::cerr << "ERROR: " << Error << "\n";
- ::exit(1);
- }
- OutPath = OutFile;
+ std::string Error;
+ Ret = new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
+ if (!Error.empty()) {
+ // FIXME: Don't fail this way.
+ llvm::errs() << "ERROR: " << Error << "\n";
+ ::exit(1);
}
+ if (OutFile != "-")
+ OutPath = OutFile;
+
return Ret;
}
-/// ProcessInputFile - Process a single input file with the specified state.
-///
-static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
- const std::string &InFile, ProgActions PA,
- const llvm::StringMap<bool> &Features,
- llvm::LLVMContext& Context) {
- llvm::OwningPtr<llvm::raw_ostream> OS;
- llvm::OwningPtr<ASTConsumer> Consumer;
- bool ClearSourceMgr = false;
- FixItRewriter *FixItRewrite = 0;
- bool CompleteTranslationUnit = true;
- llvm::sys::Path OutPath;
-
+static ASTConsumer *CreateConsumerAction(Preprocessor &PP,
+ const std::string &InFile,
+ ProgActions PA,
+ llvm::OwningPtr<llvm::raw_ostream> &OS,
+ llvm::sys::Path &OutPath,
+ const llvm::StringMap<bool> &Features,
+ llvm::LLVMContext& Context) {
switch (PA) {
default:
- fprintf(stderr, "Unexpected program action!\n");
- HadErrors = true;
- return;
+ return 0;
case ASTPrint:
OS.reset(ComputeOutFile(InFile, 0, false, OutPath));
- Consumer.reset(CreateASTPrinter(OS.get()));
- break;
-
+ return CreateASTPrinter(OS.get());
+
case ASTPrintXML:
OS.reset(ComputeOutFile(InFile, "xml", false, OutPath));
- Consumer.reset(CreateASTPrinterXML(OS.get()));
- break;
+ return CreateASTPrinterXML(OS.get());
case ASTDump:
- Consumer.reset(CreateASTDumper());
- break;
+ return CreateASTDumper();
case ASTView:
- Consumer.reset(CreateASTViewer());
- break;
+ return CreateASTViewer();
case PrintDeclContext:
- Consumer.reset(CreateDeclContextPrinter());
- break;
+ return CreateDeclContextPrinter();
- case EmitHTML:
- OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
- Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
- break;
+ case DumpRecordLayouts:
+ return CreateRecordLayoutDumper();
case InheritanceView:
- Consumer.reset(CreateInheritanceViewer(InheritanceViewCls));
- break;
+ return CreateInheritanceViewer(InheritanceViewCls);
case EmitAssembly:
case EmitLLVM:
- case EmitBC:
+ case EmitBC:
case EmitLLVMOnly: {
BackendAction Act;
if (ProgAction == EmitAssembly) {
@@ -1813,36 +1830,71 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
CompileOptions Opts;
InitializeCompileOptions(Opts, PP.getLangOptions(), Features);
- Consumer.reset(CreateBackendConsumer(Act, PP.getDiagnostics(),
- PP.getLangOptions(), Opts, InFile,
- OS.get(), Context));
- break;
+ return CreateBackendConsumer(Act, PP.getDiagnostics(), PP.getLangOptions(),
+ Opts, InFile, OS.get(), Context);
}
- case GeneratePCH:
- OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
- Consumer.reset(CreatePCHGenerator(PP, OS.get()));
- CompleteTranslationUnit = false;
- break;
-
case RewriteObjC:
OS.reset(ComputeOutFile(InFile, "cpp", true, OutPath));
- Consumer.reset(CreateObjCRewriter(InFile, OS.get(), PP.getDiagnostics(),
- PP.getLangOptions(),
- SilenceRewriteMacroWarning));
- break;
+ return CreateObjCRewriter(InFile, OS.get(), PP.getDiagnostics(),
+ PP.getLangOptions(), SilenceRewriteMacroWarning);
case RewriteBlocks:
- Consumer.reset(CreateBlockRewriter(InFile, PP.getDiagnostics(),
- PP.getLangOptions()));
+ return CreateBlockRewriter(InFile, PP.getDiagnostics(),
+ PP.getLangOptions());
+ }
+}
+
+/// ProcessInputFile - Process a single input file with the specified state.
+///
+static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
+ const std::string &InFile, ProgActions PA,
+ const llvm::StringMap<bool> &Features,
+ llvm::LLVMContext& Context) {
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ llvm::OwningPtr<ASTConsumer> Consumer;
+ bool ClearSourceMgr = false;
+ FixItRewriter *FixItRewrite = 0;
+ bool CompleteTranslationUnit = true;
+ llvm::sys::Path OutPath;
+
+ switch (PA) {
+ default:
+ Consumer.reset(CreateConsumerAction(PP, InFile, PA, OS, OutPath,
+ Features, Context));
+
+ if (!Consumer.get()) {
+ fprintf(stderr, "Unexpected program action!\n");
+ HadErrors = true;
+ return;
+ }
+
+ break;;
+
+ case EmitHTML:
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ Consumer.reset(CreateHTMLPrinter(OS.get(), PP.getDiagnostics(), &PP, &PPF));
break;
- case RunAnalysis: {
+ case RunAnalysis:
Consumer.reset(CreateAnalysisConsumer(PP.getDiagnostics(), &PP, &PPF,
PP.getLangOptions(), OutputFile,
ReadAnalyzerOptions()));
break;
- }
+
+ case GeneratePCH:
+ if (RelocatablePCH.getValue() && !isysroot.getNumOccurrences()) {
+ PP.Diag(SourceLocation(), diag::err_relocatable_without_without_isysroot);
+ RelocatablePCH.setValue(false);
+ }
+
+ OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
+ if (RelocatablePCH.getValue())
+ Consumer.reset(CreatePCHGenerator(PP, OS.get(), isysroot.c_str()));
+ else
+ Consumer.reset(CreatePCHGenerator(PP, OS.get()));
+ CompleteTranslationUnit = false;
+ break;
case DumpRawTokens: {
llvm::TimeRegion Timer(ClangFrontendTimer);
@@ -1876,28 +1928,28 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
}
case RunPreprocessorOnly:
break;
-
+
case GeneratePTH: {
llvm::TimeRegion Timer(ClangFrontendTimer);
if (OutputFile.empty() || OutputFile == "-") {
// FIXME: Don't fail this way.
// FIXME: Verify that we can actually seek in the given file.
- llvm::cerr << "ERROR: PTH requires an seekable file for output!\n";
+ llvm::errs() << "ERROR: PTH requires an seekable file for output!\n";
::exit(1);
}
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
CacheTokens(PP, static_cast<llvm::raw_fd_ostream*>(OS.get()));
ClearSourceMgr = true;
break;
- }
+ }
case PrintPreprocessedInput:
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
break;
-
+
case ParseNoop:
break;
-
+
case ParsePrintCallbacks: {
llvm::TimeRegion Timer(ClangFrontendTimer);
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
@@ -1911,13 +1963,13 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
Consumer.reset(new ASTConsumer());
break;
}
-
+
case RewriteMacros:
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
RewriteMacrosInInput(PP, OS.get());
ClearSourceMgr = true;
break;
-
+
case RewriteTest:
OS.reset(ComputeOutFile(InFile, 0, true, OutPath));
DoRewriteTest(PP, OS.get());
@@ -1943,7 +1995,7 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
PP.getLangOptions());
bool AddedFixitLocation = false;
- for (unsigned Idx = 0, Last = FixItAtLocations.size();
+ for (unsigned Idx = 0, Last = FixItAtLocations.size();
Idx != Last; ++Idx) {
RequestedSourceLocation Requested;
if (ResolveParsedLocation(FixItAtLocations[Idx],
@@ -1973,13 +2025,19 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
PP.getBuiltinInfo(),
/* FreeMemory = */ !DisableFree,
/* size_reserve = */0));
-
+
llvm::OwningPtr<PCHReader> Reader;
llvm::OwningPtr<ExternalASTSource> Source;
-
+
if (!ImplicitIncludePCH.empty()) {
- Reader.reset(new PCHReader(PP, ContextOwner.get()));
-
+ // If the user specified -isysroot, it will be used for relocatable PCH
+ // files.
+ const char *isysrootPCH = 0;
+ if (isysroot.getNumOccurrences() != 0)
+ isysrootPCH = isysroot.c_str();
+
+ Reader.reset(new PCHReader(PP, ContextOwner.get(), isysrootPCH));
+
// The user has asked us to include a precompiled header. Load
// the precompiled header into the AST context.
switch (Reader->ReadPCH(ImplicitIncludePCH)) {
@@ -2026,12 +2084,34 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
if (InitializeSourceManager(PP, InFile))
return;
}
-
-
+
// If we have an ASTConsumer, run the parser with it.
- if (Consumer)
- ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
- CompleteTranslationUnit);
+ if (Consumer) {
+ CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0;
+ void *CreateCodeCompleterData = 0;
+
+ if (!CodeCompletionAt.FileName.empty()) {
+ // Tell the source manager to chop off the given file at a specific
+ // line and column.
+ if (const FileEntry *Entry
+ = PP.getFileManager().getFile(CodeCompletionAt.FileName)) {
+ // Truncate the named file at the given line/column.
+ PP.getSourceManager().truncateFileAt(Entry, CodeCompletionAt.Line,
+ CodeCompletionAt.Column);
+
+ // Set up the creation routine for code-completion.
+ CreateCodeCompleter = BuildPrintingCodeCompleter;
+ } else {
+ PP.getDiagnostics().Report(FullSourceLoc(),
+ diag::err_fe_invalid_code_complete_file)
+ << CodeCompletionAt.FileName;
+ }
+ }
+
+ ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
+ CompleteTranslationUnit,
+ CreateCodeCompleter, CreateCodeCompleterData);
+ }
if (PA == RunPreprocessorOnly) { // Just lex as fast as we can, no output.
llvm::TimeRegion Timer(ClangFrontendTimer);
@@ -2056,10 +2136,17 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
DisableLineMarkers, DumpDefines);
ClearSourceMgr = true;
}
-
+
if (FixItRewrite)
FixItRewrite->WriteFixedFile(InFile, OutputFile);
-
+
+ // Disable the consumer prior to the context, the consumer may perform actions
+ // in its destructor which require the context.
+ if (DisableFree)
+ Consumer.take();
+ else
+ Consumer.reset();
+
// If in -disable-free mode, don't deallocate ASTContext.
if (DisableFree)
ContextOwner.take();
@@ -2079,16 +2166,71 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
fprintf(stderr, "\n");
}
- // For a multi-file compilation, some things are ok with nuking the source
+ // 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)
+ // Always delete the output stream because we don't want to leak file
+ // handles. Also, we don't want to try to erase an open file.
+ OS.reset();
+
+ if ((HadErrors || (PP.getDiagnostics().getNumErrors() != 0)) &&
+ !OutPath.isEmpty()) {
+ // If we had errors, try to erase the output file.
+ OutPath.eraseFromDisk();
+ }
+}
+
+/// ProcessInputFile - Process a single AST input file with the specified state.
+///
+static void ProcessASTInputFile(const std::string &InFile, ProgActions PA,
+ const llvm::StringMap<bool> &Features,
+ Diagnostic &Diags, FileManager &FileMgr,
+ llvm::LLVMContext& Context) {
+ std::string Error;
+ llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr,
+ &Error));
+ if (!AST) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_file) << Error;
+ return;
+ }
+
+ Preprocessor &PP = AST->getPreprocessor();
+
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ llvm::sys::Path OutPath;
+ llvm::OwningPtr<ASTConsumer> Consumer(CreateConsumerAction(PP, InFile, PA, OS,
+ OutPath, Features,
+ Context));
+
+ if (!Consumer.get()) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_invalid_ast_action);
+ return;
+ }
+
+ // Set the main file ID to an empty file.
+ //
+ // FIXME: We probably shouldn't need this, but for now this is the simplest
+ // way to reuse the logic in ParseAST.
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
+ AST->getSourceManager().createMainFileIDForMemBuffer(SB);
+
+ // Stream the input AST to the consumer.
+ ParseAST(PP, Consumer.get(), AST->getASTContext(), Stats);
+
+ // Release the consumer and the AST, in that order since the consumer may
+ // perform actions in its destructor which require the context.
+ if (DisableFree) {
Consumer.take();
- else
+ AST.take();
+ } else {
Consumer.reset();
+ AST.reset();
+ }
// Always delete the output stream because we don't want to leak file
// handles. Also, we don't want to try to erase an open file.
@@ -2104,23 +2246,35 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input files>"));
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ Diagnostic &Diags = *static_cast<Diagnostic*>(UserData);
+
+ Diags.Report(FullSourceLoc(), diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ exit(1);
+}
+
int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
- llvm::LLVMContext Context;
- llvm::cl::ParseCommandLineOptions(argc, argv,
- "LLVM 'Clang' Compiler: http://clang.llvm.org\n");
-
+ llvm::LLVMContext &Context = llvm::getGlobalContext();
+
+ // Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
-
+
+ llvm::cl::ParseCommandLineOptions(argc, argv,
+ "LLVM 'Clang' Compiler: http://clang.llvm.org\n");
+
if (TimeReport)
ClangFrontendTimer = new llvm::Timer("Clang front-end time");
-
+
if (Verbose)
- fprintf(stderr, "clang-cc version 1.0 based upon " PACKAGE_STRING
- " hosted on " LLVM_HOSTTRIPLE "\n");
-
+ llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
+ << " based upon " << PACKAGE_STRING
+ << " hosted on " << llvm::sys::getHostTriple() << "\n";
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
@@ -2164,17 +2318,17 @@ int main(int argc, char **argv) {
} else {
DiagClient.reset(CreateHTMLDiagnosticClient(HTMLDiag));
}
-
+
if (!DumpBuildInformation.empty()) {
if (!HTMLDiag.empty()) {
fprintf(stderr,
"-dump-build-information and -html-diags don't work together\n");
return 1;
}
-
+
SetUpBuildDumpLog(argc, argv, DiagClient);
}
-
+
// Configure our handling of diagnostics.
Diagnostic Diags(DiagClient.get());
@@ -2182,30 +2336,45 @@ int main(int argc, char **argv) {
OptNoWarnings))
return 1;
+ // Set an error handler, so that any LLVM backend diagnostics go through our
+ // error handler.
+ llvm::llvm_install_error_handler(LLVMErrorHandler,
+ static_cast<void*>(&Diags));
+
// -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);
+ 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));
-
+ llvm::Triple Triple = CreateTargetTriple();
+ llvm::OwningPtr<TargetInfo>
+ Target(TargetInfo::CreateTargetInfo(Triple.getTriple()));
+
if (Target == 0) {
- Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
- << Triple.c_str();
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_triple)
+ << Triple.getTriple().c_str();
return 1;
}
-
+
+ // Set the target ABI if specified.
+ if (!TargetABI.empty()) {
+ if (!Target->setABI(TargetABI)) {
+ Diags.Report(FullSourceLoc(), diag::err_fe_unknown_target_abi)
+ << TargetABI;
+ return 1;
+ }
+ }
+
if (!InheritanceViewCls.empty()) // C++ visualization?
ProgAction = InheritanceView;
-
+
llvm::OwningPtr<SourceManager> SourceMgr;
-
+
// Create a file manager object to provide access to and cache the filesystem.
FileManager FileMgr;
@@ -2215,35 +2384,41 @@ int main(int argc, char **argv) {
for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
const std::string &InFile = InputFilenames[i];
-
+
+ LangKind LK = GetLanguage(InFile);
+ // AST inputs are handled specially.
+ if (LK == langkind_ast) {
+ ProcessASTInputFile(InFile, ProgAction, Features,
+ Diags, FileMgr, Context);
+ 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;
DiagClient->setLangOptions(&LangInfo);
-
- InitializeBaseLanguage();
- LangKind LK = GetLanguage(InFile);
+
InitializeLangOptions(LangInfo, LK);
InitializeLanguageStandard(LangInfo, LK, Target.get(), Features);
-
+
// Process the -I options and set them in the HeaderInfo.
HeaderSearch HeaderInfo(FileMgr);
-
-
- InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo);
-
+
+
+ InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo, Triple);
+
// Set up the preprocessor with these options.
DriverPreprocessorFactory PPFactory(Diags, LangInfo, *Target,
*SourceMgr.get(), HeaderInfo);
-
+
llvm::OwningPtr<Preprocessor> PP(PPFactory.CreatePreprocessor());
-
+
if (!PP)
continue;
@@ -2252,16 +2427,16 @@ int main(int argc, char **argv) {
llvm::raw_ostream *DependencyOS;
if (DependencyTargets.empty()) {
// FIXME: Use a proper diagnostic
- llvm::cerr << "-dependency-file requires at least one -MT option\n";
+ llvm::errs() << "-dependency-file requires at least one -MT option\n";
HadErrors = true;
continue;
}
std::string ErrStr;
DependencyOS =
- new llvm::raw_fd_ostream(DependencyFile.c_str(), false, ErrStr);
+ new llvm::raw_fd_ostream(DependencyFile.c_str(), ErrStr);
if (!ErrStr.empty()) {
// FIXME: Use a proper diagnostic
- llvm::cerr << "unable to open dependency file: " + ErrStr;
+ llvm::errs() << "unable to open dependency file: " + ErrStr;
HadErrors = true;
continue;
}
@@ -2274,7 +2449,7 @@ int main(int argc, char **argv) {
if (ImplicitIncludePCH.empty()) {
if (InitializeSourceManager(*PP.get(), InFile))
continue;
-
+
// Initialize builtin info.
PP->getBuiltinInfo().InitializeBuiltins(PP->getIdentifierTable(),
PP->getLangOptions().NoBuiltin);
@@ -2285,7 +2460,7 @@ int main(int argc, char **argv) {
// Process the source file.
ProcessInputFile(*PP, PPFactory, InFile, ProgAction, Features, Context);
-
+
HeaderInfo.ClearFileInfo();
DiagClient->setLangOptions(0);
}
@@ -2294,7 +2469,7 @@ int main(int argc, char **argv) {
if (unsigned NumDiagnostics = Diags.getNumDiagnostics())
fprintf(stderr, "%d diagnostic%s generated.\n", NumDiagnostics,
(NumDiagnostics == 1 ? "" : "s"));
-
+
if (Stats) {
FileMgr.PrintStats();
fprintf(stderr, "\n");
@@ -2302,11 +2477,11 @@ int main(int argc, char **argv) {
delete ClangFrontendTimer;
delete BuildLogFile;
-
+
// If verifying diagnostics and we reached here, all is well.
if (VerifyDiagnostics)
return 0;
-
+
// Managed static deconstruction. Useful for making things like
// -time-passes usable.
llvm::llvm_shutdown();
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f170aa2fa38c..1ad04c8dfde4 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -13,3 +13,5 @@ add_clang_executable(clang
add_dependencies(clang clang-cc)
+install(TARGETS clang
+ RUNTIME DESTINATION bin)
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 8e9c291cc80c..4b2fb4423445 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -21,3 +21,9 @@ LINK_COMPONENTS := system support bitreader bitwriter
USEDLIBS = clangDriver.a clangBasic.a
include $(LEVEL)/Makefile.common
+
+# Translate make variable to define when building a "production" clang.
+ifdef CLANG_IS_PRODUCTION
+CPP.Defines += -DCLANG_IS_PRODUCTION
+endif
+
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 323283e653b4..9d204ce6c0c2 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -34,7 +34,7 @@ class DriverDiagnosticPrinter : public DiagnosticClient {
llvm::raw_ostream &OS;
public:
- DriverDiagnosticPrinter(const std::string _ProgName,
+ DriverDiagnosticPrinter(const std::string _ProgName,
llvm::raw_ostream &_OS)
: ProgName(_ProgName),
OS(_OS) {}
@@ -54,7 +54,7 @@ void DriverDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
case Diagnostic::Error: OS << "error: "; break;
case Diagnostic::Fatal: OS << "fatal error: "; break;
}
-
+
llvm::SmallString<100> OutStr;
Info.FormatDiagnostic(OutStr);
OS.write(OutStr.begin(), OutStr.size());
@@ -68,7 +68,7 @@ llvm::sys::Path GetExecutablePath(const char *Argv0) {
return llvm::sys::Path::GetMainExecutable(Argv0, P);
}
-static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
+static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
const std::string &S) {
return SavedStrings.insert(S).first->c_str();
}
@@ -79,6 +79,8 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
/// they are applied in order to the input argument lists. Edits
/// should be one of the following forms:
///
+/// '#': Silence information about the changes to the command line arguments.
+///
/// '^': Add FOO as a new argument at the beginning of the command line.
///
/// '+': Add FOO as a new argument at the end of the command line.
@@ -93,61 +95,74 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings,
///
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
/// at the end of the command line.
-void ApplyOneQAOverride(std::vector<const char*> &Args,
+///
+/// \param OS - The stream to write edit information to.
+/// \param Args - The vector of command line arguments.
+/// \param Edit - The override command to perform.
+/// \param SavedStrings - Set to use for storing string representations.
+void ApplyOneQAOverride(llvm::raw_ostream &OS,
+ std::vector<const char*> &Args,
const std::string &Edit,
std::set<std::string> &SavedStrings) {
// This does not need to be efficient.
- if (Edit[0] == '^') {
- const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
- llvm::errs() << "### Adding argument " << Str << " at beginning\n";
- Args.insert(Args.begin() + 1, Str);
- } else if (Edit[0] == '+') {
- const char *Str =
- SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
- llvm::errs() << "### Adding argument " << Str << " at end\n";
- Args.push_back(Str);
- } else if (Edit[0] == 'x' || Edit[0] == 'X') {
- std::string Option = Edit.substr(1, std::string::npos);
- for (unsigned i = 1; i < Args.size();) {
- if (Option == Args[i]) {
- llvm::errs() << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- if (Edit[0] == 'X') {
- if (i < Args.size()) {
- llvm::errs() << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- } else
- llvm::errs() << "### Invalid X edit, end of command line!\n";
- }
- } else
- ++i;
- }
- } else if (Edit[0] == 'O') {
- for (unsigned i = 1; i < Args.size();) {
- const char *A = Args[i];
- if (A[0] == '-' && A[1] == 'O' &&
- (A[2] == '\0' ||
- (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
- ('0' <= A[2] && A[2] <= '9'))))) {
- llvm::errs() << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- } else
- ++i;
- }
- llvm::errs() << "### Adding argument " << Edit << " at end\n";
- Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit));
- } else {
- llvm::errs() << "### Unrecognized edit: " << Edit << "\n";
- }
+ if (Edit[0] == '^') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
+ OS << "### Adding argument " << Str << " at beginning\n";
+ Args.insert(Args.begin() + 1, Str);
+ } else if (Edit[0] == '+') {
+ const char *Str =
+ SaveStringInSet(SavedStrings, Edit.substr(1, std::string::npos));
+ OS << "### Adding argument " << Str << " at end\n";
+ Args.push_back(Str);
+ } else if (Edit[0] == 'x' || Edit[0] == 'X') {
+ std::string Option = Edit.substr(1, std::string::npos);
+ for (unsigned i = 1; i < Args.size();) {
+ if (Option == Args[i]) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ OS << "### Invalid X edit, end of command line!\n";
+ }
+ } else
+ ++i;
+ }
+ } else if (Edit[0] == 'O') {
+ for (unsigned i = 1; i < Args.size();) {
+ const char *A = Args[i];
+ if (A[0] == '-' && A[1] == 'O' &&
+ (A[2] == '\0' ||
+ (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
+ ('0' <= A[2] && A[2] <= '9'))))) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ OS << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(SaveStringInSet(SavedStrings, '-' + Edit));
+ } else {
+ OS << "### Unrecognized edit: " << Edit << "\n";
+ }
}
/// ApplyQAOverride - Apply a comma separate list of edits to the
/// input argument lists. See ApplyOneQAOverride.
void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
std::set<std::string> &SavedStrings) {
- llvm::errs() << "### QA_OVERRIDE_GCC3_OPTIONS: " << OverrideStr << "\n";
+ llvm::raw_ostream *OS = &llvm::errs();
+
+ if (OverrideStr[0] == '#') {
+ ++OverrideStr;
+ OS = &llvm::nulls();
+ }
+
+ *OS << "### QA_OVERRIDE_GCC3_OPTIONS: " << OverrideStr << "\n";
// This does not need to be efficient.
@@ -157,7 +172,7 @@ void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
if (!End)
End = S + strlen(S);
if (End != S)
- ApplyOneQAOverride(Args, std::string(S, End), SavedStrings);
+ ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
S = End;
if (*S != '\0')
++S;
@@ -173,9 +188,14 @@ int main(int argc, const char **argv) {
Diagnostic Diags(&DiagClient);
+#ifdef CLANG_IS_PRODUCTION
+ bool IsProduction = true;
+#else
+ bool IsProduction = false;
+#endif
Driver TheDriver(Path.getBasename().c_str(), Path.getDirname().c_str(),
llvm::sys::getHostTriple().c_str(),
- "a.out", Diags);
+ "a.out", IsProduction, Diags);
llvm::OwningPtr<Compilation> C;
@@ -188,7 +208,7 @@ int main(int argc, const char **argv) {
ApplyQAOverride(StringPointers, OverrideStr, SavedStrings);
- C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
&StringPointers[0]));
} else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
std::vector<const char*> StringPointers;
@@ -198,7 +218,7 @@ int main(int argc, const char **argv) {
for (;;) {
const char *Next = strchr(Cur, ',');
-
+
if (Next) {
StringPointers.push_back(SaveStringInSet(SavedStrings,
std::string(Cur, Next)));
@@ -212,7 +232,7 @@ int main(int argc, const char **argv) {
StringPointers.insert(StringPointers.end(), argv + 1, argv + argc);
- C.reset(TheDriver.BuildCompilation(StringPointers.size(),
+ C.reset(TheDriver.BuildCompilation(StringPointers.size(),
&StringPointers[0]));
} else
C.reset(TheDriver.BuildCompilation(argc, argv));
diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt
index 09f4fc12c1dd..9c9656a1130e 100644
--- a/tools/index-test/CMakeLists.txt
+++ b/tools/index-test/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
+ clangIndex
clangFrontend
clangSema
clangAST
@@ -10,6 +11,7 @@ set( LLVM_USED_LIBS
set( LLVM_LINK_COMPONENTS
bitreader
+ mc
)
add_clang_executable(index-test
diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile
index 4fbde291980a..76602e1d278d 100644
--- a/tools/index-test/Makefile
+++ b/tools/index-test/Makefile
@@ -11,13 +11,14 @@ LEVEL = ../../../..
TOOLNAME = index-test
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := bitreader
-USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/index-test/index-test.cpp b/tools/index-test/index-test.cpp
index 552b7b01498a..103874c77d7d 100644
--- a/tools/index-test/index-test.cpp
+++ b/tools/index-test/index-test.cpp
@@ -17,38 +17,191 @@
//
//===----------------------------------------------------------------------===//
//
-// -point-at [file:column:line]
+// -point-at [file:line:column]
// Point at a declaration/statement/expression. If no other operation is
// specified, prints some info about it.
//
+// -print-refs
+// Print ASTLocations that reference the -point-at node
+//
+// -print-defs
+// Print ASTLocations that define the -point-at node
+//
+// -print-decls
+// Print ASTLocations that declare the -point-at node
+//
//===----------------------------------------------------------------------===//
+#include "clang/Index/Program.h"
+#include "clang/Index/Indexer.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/TranslationUnit.h"
+#include "clang/Index/ASTLocation.h"
+#include "clang/Index/DeclReferenceMap.h"
+#include "clang/Index/SelectorMap.h"
+#include "clang/Index/Handlers.h"
+#include "clang/Index/Analyzer.h"
+#include "clang/Index/Utils.h"
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/Utils.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/Stmt.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Signals.h"
using namespace clang;
+using namespace idx;
+
+class TUnit : public TranslationUnit {
+public:
+ TUnit(ASTUnit *ast, const std::string &filename)
+ : AST(ast), Filename(filename),
+ DeclRefMap(ast->getASTContext()),
+ SelMap(ast->getASTContext()) { }
+ virtual ASTContext &getASTContext() { return AST->getASTContext(); }
+ virtual DeclReferenceMap &getDeclReferenceMap() { return DeclRefMap; }
+ virtual SelectorMap &getSelectorMap() { return SelMap; }
+
+ llvm::OwningPtr<ASTUnit> AST;
+ std::string Filename;
+ DeclReferenceMap DeclRefMap;
+ SelectorMap SelMap;
+};
static llvm::cl::list<ParsedSourceLocation>
PointAtLocation("point-at", llvm::cl::Optional,
llvm::cl::value_desc("source-location"),
llvm::cl::desc("Point at the given source location of the first AST file"));
+enum ProgActions {
+ PrintPoint, // Just print the point-at node
+ PrintRefs, // Print references of the point-at node
+ PrintDefs, // Print definitions of the point-at node
+ PrintDecls // Print declarations of the point-at node
+};
+
+static llvm::cl::opt<ProgActions>
+ProgAction(
+ llvm::cl::desc("Choose action to perform on the pointed-at AST node:"),
+ llvm::cl::ZeroOrMore,
+ llvm::cl::init(PrintPoint),
+ llvm::cl::values(
+ clEnumValN(PrintRefs, "print-refs",
+ "Print references"),
+ clEnumValN(PrintDefs, "print-defs",
+ "Print definitions"),
+ clEnumValN(PrintDecls, "print-decls",
+ "Print declarations"),
+ clEnumValEnd));
+
static llvm::cl::opt<bool>
DisableFree("disable-free",
llvm::cl::desc("Disable freeing of memory on exit"),
llvm::cl::init(false));
+static bool HadErrors = false;
+
+static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
+ llvm::raw_ostream &OS = llvm::outs();
+ typedef Storing<TULocationHandler> ResultsTy;
+ ResultsTy Results;
+
+ Analyzer Analyz(Idxer.getProgram(), Idxer);
+
+ switch (ProgAction) {
+ default: assert(0);
+ case PrintRefs:
+ llvm::errs() << "Error: Cannot -print-refs on a ObjC message expression\n";
+ HadErrors = true;
+ return;
+
+ case PrintDecls: {
+ Analyz.FindObjCMethods(Msg, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDefs: {
+ Analyz.FindObjCMethods(Msg, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I) {
+ const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->AsDecl());
+ if (D->isThisDeclarationADefinition())
+ I->print(OS);
+ }
+ break;
+ }
+
+ }
+}
+
+static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
+ assert(ASTLoc.isValid());
+
+ if (ObjCMessageExpr *Msg =
+ dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.dyn_AsStmt()))
+ return ProcessObjCMessage(Msg, Idxer);
+
+ Decl *D = ASTLoc.getReferencedDecl();
+ if (D == 0) {
+ llvm::errs() << "Error: Couldn't get referenced Decl for the ASTLocation\n";
+ HadErrors = true;
+ return;
+ }
+
+ llvm::raw_ostream &OS = llvm::outs();
+ typedef Storing<TULocationHandler> ResultsTy;
+ ResultsTy Results;
+
+ Analyzer Analyz(Idxer.getProgram(), Idxer);
+
+ switch (ProgAction) {
+ default: assert(0);
+ case PrintRefs: {
+ Analyz.FindReferences(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDecls: {
+ Analyz.FindDeclarations(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I)
+ I->print(OS);
+ break;
+ }
+
+ case PrintDefs: {
+ Analyz.FindDeclarations(D, Results);
+ for (ResultsTy::iterator
+ I = Results.begin(), E = Results.end(); I != E; ++I) {
+ const Decl *D = I->AsDecl();
+ bool isDef = false;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ isDef = FD->isThisDeclarationADefinition();
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ isDef = VD->getInit() != 0;
+ else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ isDef = MD->isThisDeclarationADefinition();
+
+ if (isDef)
+ I->print(OS);
+ }
+ break;
+ }
+
+ }
+}
+
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
@@ -57,97 +210,99 @@ int main(int argc, char **argv) {
llvm::PrettyStackTraceProgram X(argc, argv);
llvm::cl::ParseCommandLineOptions(argc, argv,
"LLVM 'Clang' Indexing Test Bed: http://clang.llvm.org\n");
-
- FileManager FileMgr;
-
+
+ Program Prog;
+ Indexer Idxer(Prog);
+ llvm::SmallVector<TUnit*, 4> TUnits;
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
- // FIXME: Only the first AST file is used for now.
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
- const std::string &InFile = InputFilenames[0];
-
- std::string ErrMsg;
- llvm::OwningPtr<ASTUnit> AST;
+ std::string ErrMsg;
+ llvm::OwningPtr<ASTUnit> AST;
- AST.reset(ASTUnit::LoadFromPCHFile(InFile, FileMgr, &ErrMsg));
- if (!AST) {
- llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
- return 1;
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, Idxer.getDiagnostics(),
+ Idxer.getFileManager(), &ErrMsg));
+ if (!AST) {
+ llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
+ return 1;
+ }
+
+ TUnit *TU = new TUnit(AST.take(), InFile);
+ TUnits.push_back(TU);
+
+ Idxer.IndexAST(TU);
}
- struct ASTPoint {
- Decl *D;
- Stmt *Node;
- ASTPoint() : D(0), Node(0) {}
- };
-
- ASTPoint Point;
+ ASTLocation ASTLoc;
+ const std::string &FirstFile = TUnits[0]->Filename;
+ ASTUnit *FirstAST = TUnits[0]->AST.get();
if (!PointAtLocation.empty()) {
const std::string &Filename = PointAtLocation[0].FileName;
- const FileEntry *File = FileMgr.getFile(Filename);
+ const FileEntry *File = Idxer.getFileManager().getFile(Filename);
+ if (File == 0) {
+ llvm::errs() << "File '" << Filename << "' does not exist\n";
+ return 1;
+ }
// Safety check. Using an out-of-date AST file will only lead to crashes
// or incorrect results.
// FIXME: Check all the source files that make up the AST file.
- const FileEntry *ASTFile = FileMgr.getFile(InFile);
+ const FileEntry *ASTFile = Idxer.getFileManager().getFile(FirstFile);
if (File->getModificationTime() > ASTFile->getModificationTime()) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Pointing at a source file which was modified after creating "
"the AST file\n";
return 1;
}
- if (File == 0) {
- llvm::errs() << "File '" << Filename << "' does not exist\n";
- return 1;
- }
unsigned Line = PointAtLocation[0].Line;
unsigned Col = PointAtLocation[0].Column;
- SourceLocation Loc = AST->getSourceManager().getLocation(File, Line, Col);
+ SourceLocation Loc =
+ FirstAST->getSourceManager().getLocation(File, Line, Col);
if (Loc.isInvalid()) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Couldn't resolve source location (invalid location)\n";
return 1;
}
-
- llvm::tie(Point.D, Point.Node) =
- ResolveLocationInAST(AST->getASTContext(), Loc);
- if (Point.D == 0) {
- llvm::errs() << "[" << InFile << "] Error: " <<
+
+ ASTLoc = ResolveLocationInAST(FirstAST->getASTContext(), Loc);
+ if (ASTLoc.isInvalid()) {
+ llvm::errs() << "[" << FirstFile << "] Error: " <<
"Couldn't resolve source location (no declaration found)\n";
return 1;
}
}
-
- if (Point.D) {
- llvm::raw_ostream &OS = llvm::outs();
- OS << "Declaration node at point: " << Point.D->getDeclKindName() << " ";
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Point.D))
- OS << ND->getNameAsString();
- OS << "\n";
-
- if (const char *Comment = AST->getASTContext().getCommentForDecl(Point.D))
- OS << "Comment associated with this declaration:\n" << Comment << "\n";
-
- if (Point.Node) {
- OS << "Statement node at point: " << Point.Node->getStmtClassName()
- << " ";
- Point.Node->printPretty(OS, AST->getASTContext(), 0,
- PrintingPolicy(AST->getASTContext().getLangOptions()));
- OS << "\n";
+
+ if (ASTLoc.isValid()) {
+ if (ProgAction == PrintPoint) {
+ llvm::raw_ostream &OS = llvm::outs();
+ ASTLoc.print(OS);
+ if (const char *Comment =
+ FirstAST->getASTContext().getCommentForDecl(ASTLoc.dyn_AsDecl()))
+ OS << "Comment associated with this declaration:\n" << Comment << "\n";
+ } else {
+ ProcessASTLocation(ASTLoc, Idxer);
}
}
- if (DisableFree)
- AST.take();
+ if (HadErrors)
+ return 1;
+
+ if (!DisableFree) {
+ for (int i=0, e=TUnits.size(); i != e; ++i)
+ delete TUnits[i];
+ }
// Managed static deconstruction. Useful for making things like
// -time-passes usable.
llvm::llvm_shutdown();
-
+
return 0;
}
diff --git a/tools/wpa/CMakeLists.txt b/tools/wpa/CMakeLists.txt
new file mode 100644
index 000000000000..5553474b4bcd
--- /dev/null
+++ b/tools/wpa/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(LLVM_NO_RTTI 1)
+
+set( LLVM_USED_LIBS
+ clangFrontend
+ clangAnalysis
+ clangSema
+ clangAST
+ clangLex
+ clangBasic
+ clangIndex
+ )
+
+set( LLVM_LINK_COMPONENTS
+ mc
+ )
+
+add_clang_executable(clang-wpa
+ clang-wpa.cpp
+ )
+add_dependencies(clang-wpa clang-headers)
diff --git a/tools/wpa/Makefile b/tools/wpa/Makefile
new file mode 100644
index 000000000000..01dbd11b8df5
--- /dev/null
+++ b/tools/wpa/Makefile
@@ -0,0 +1,16 @@
+LEVEL = ../../../..
+
+TOOLNAME = clang-wpa
+CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+CXXFLAGS = -fno-rtti
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := bitreader mc
+USEDLIBS = clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a clangAnalysis.a clangIndex.a
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/wpa/clang-wpa.cpp b/tools/wpa/clang-wpa.cpp
new file mode 100644
index 000000000000..fa2326dc2ba4
--- /dev/null
+++ b/tools/wpa/clang-wpa.cpp
@@ -0,0 +1,62 @@
+//===--- clang-wpa.cpp - clang whole program analyzer ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool reads a sequence of precompiled AST files, and do various
+// cross translation unit analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/CallGraph.h"
+
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace idx;
+
+static llvm::cl::list<std::string>
+InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
+
+int main(int argc, char **argv) {
+ llvm::cl::ParseCommandLineOptions(argc, argv, "clang-wpa");
+ FileManager FileMgr;
+ std::vector<ASTUnit*> ASTUnits;
+
+ if (InputFilenames.empty())
+ return 0;
+
+ TextDiagnosticBuffer DiagClient;
+ Diagnostic Diags(&DiagClient);
+
+ for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {
+ const std::string &InFile = InputFilenames[i];
+
+ std::string ErrMsg;
+ llvm::OwningPtr<ASTUnit> AST;
+
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, Diags, FileMgr, &ErrMsg));
+
+ if (!AST) {
+ llvm::errs() << "[" << InFile << "] error: " << ErrMsg << '\n';
+ return 1;
+ }
+
+ ASTUnits.push_back(AST.take());
+ }
+
+ llvm::OwningPtr<CallGraph> CG;
+ CG.reset(new CallGraph());
+
+ for (unsigned i = 0, e = ASTUnits.size(); i != e; ++i)
+ CG->addTU(*ASTUnits[i]);
+
+ CG->ViewCallGraph();
+}