summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CIndex/CIndex.cpp777
-rw-r--r--tools/CMakeLists.txt4
-rw-r--r--tools/c-index-test/CMakeLists.txt3
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c134
-rw-r--r--tools/clang-cc/CMakeLists.txt1
-rw-r--r--tools/clang-cc/Makefile2
-rw-r--r--tools/clang-cc/Options.cpp327
-rw-r--r--tools/clang-cc/Options.h7
-rw-r--r--tools/clang-cc/clang-cc.cpp173
-rw-r--r--tools/driver/CMakeLists.txt11
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1_main.cpp68
-rw-r--r--tools/driver/driver.cpp17
-rw-r--r--tools/index-test/CMakeLists.txt2
-rw-r--r--tools/index-test/Makefile3
-rw-r--r--tools/index-test/index-test.cpp33
-rwxr-xr-xtools/scan-build/ccc-analyzer632
-rwxr-xr-xtools/scan-build/scan-build1297
-rw-r--r--tools/scan-build/scanview.css62
-rw-r--r--tools/scan-build/sorttable.js493
-rw-r--r--tools/wpa/CMakeLists.txt20
-rw-r--r--tools/wpa/Makefile16
-rw-r--r--tools/wpa/clang-wpa.cpp62
24 files changed, 3243 insertions, 906 deletions
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index 46732de..4681b939 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -4,7 +4,7 @@
//
// 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.
@@ -24,7 +24,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -47,7 +46,7 @@ using namespace clang;
using namespace idx;
namespace {
-static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
+static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
{
NamedDecl *D = DRE->getDecl();
if (isa<VarDecl>(D))
@@ -56,7 +55,7 @@ static enum CXCursorKind TranslateDeclRefExpr(DeclRefExpr *DRE)
return CXCursor_FunctionRef;
else if (isa<EnumConstantDecl>(D))
return CXCursor_EnumConstantRef;
- else
+ else
return CXCursor_NotImplemented;
}
@@ -66,16 +65,16 @@ 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) :
+ 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)
@@ -95,13 +94,13 @@ public:
}
};
#endif
-
+
/// IgnoreDiagnosticsClient - A DiagnosticsClient that just ignores emitted
/// warnings and errors.
class VISIBILITY_HIDDEN IgnoreDiagnosticsClient : public DiagnosticClient {
public:
virtual ~IgnoreDiagnosticsClient() {}
- virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
+ virtual void HandleDiagnostic(Diagnostic::Level, const DiagnosticInfo &) {}
};
// Translation Unit Visitor.
@@ -109,30 +108,30 @@ class TUVisitor : public DeclVisitor<TUVisitor> {
CXTranslationUnit TUnit;
CXTranslationUnitIterator Callback;
CXClientData CData;
-
+
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
// to the visitor. Declarations with a PCH level greater than this value will
// be suppressed.
unsigned MaxPCHLevel;
-
+
void Call(enum CXCursorKind CK, NamedDecl *ND) {
// Filter any declarations that have a PCH level greater than what we allow.
if (ND->getPCHLevel() > MaxPCHLevel)
return;
-
+
// Filter any implicit declarations (since the source info will be bogus).
if (ND->isImplicit())
return;
-
+
CXCursor C = { CK, ND, 0 };
Callback(TUnit, C, CData);
}
public:
- TUVisitor(CXTranslationUnit CTU,
+ TUVisitor(CXTranslationUnit CTU,
CXTranslationUnitIterator cback, CXClientData D,
- unsigned MaxPCHLevel) :
+ unsigned MaxPCHLevel) :
TUnit(CTU), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
-
+
void VisitTranslationUnitDecl(TranslationUnitDecl *D) {
VisitDeclContext(dyn_cast<DeclContext>(D));
}
@@ -157,63 +156,63 @@ public:
}
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *ND) {
Call(CXCursor_ObjCInterfaceDecl, ND);
- }
+ }
void VisitObjCProtocolDecl(ObjCProtocolDecl *ND) {
Call(CXCursor_ObjCProtocolDecl, 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;
+ 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 VisitTypedefDecl(TypedefDecl *ND) {
- Call(CXCursor_TypedefDecl, ND);
- }
+ void VisitTypedefDecl(TypedefDecl *ND) {
+ Call(CXCursor_TypedefDecl, ND);
+ }
void VisitVarDecl(VarDecl *ND) {
Call(CXCursor_VarDecl, ND);
- }
+ }
};
-
+
// Declaration visitor.
class CDeclVisitor : public DeclVisitor<CDeclVisitor> {
CXDecl CDecl;
CXDeclIterator Callback;
CXClientData CData;
-
+
// MaxPCHLevel - the maximum PCH level of declarations that we will pass on
// to the visitor. Declarations with a PCH level greater than this value will
// be suppressed.
unsigned MaxPCHLevel;
-
+
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;
-
+
// Filter any declarations that have a PCH level greater than what we allow.
if (ND->getPCHLevel() > MaxPCHLevel)
return;
-
+
CXCursor C = { CK, ND, 0 };
Callback(CDecl, C, CData);
}
public:
- CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
- unsigned MaxPCHLevel) :
+ CDeclVisitor(CXDecl C, CXDeclIterator cback, CXClientData D,
+ unsigned MaxPCHLevel) :
CDecl(C), Callback(cback), CData(D), MaxPCHLevel(MaxPCHLevel) {}
-
+
void VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
// Issue callbacks for the containing class.
Call(CXCursor_ObjCClassRef, ND);
@@ -225,16 +224,16 @@ public:
if (D->getSuperClass())
Call(CXCursor_ObjCSuperClassRef, D);
- for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end(); I != E; ++I)
+ 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)
+ 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) {
@@ -292,9 +291,9 @@ public:
};
class CIndexer : public Indexer {
-public:
- explicit CIndexer(Program *prog) : Indexer(*prog),
- OnlyLocalDecls(false),
+public:
+ explicit CIndexer(Program *prog) : Indexer(*prog),
+ OnlyLocalDecls(false),
DisplayDiagnostics(false) {}
virtual ~CIndexer() { delete &getProgram(); }
@@ -305,17 +304,17 @@ public:
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; }
- void setDisplayDiagnostics(bool Display = true) {
+ void setDisplayDiagnostics(bool Display = true) {
DisplayDiagnostics = Display;
}
bool getDisplayDiagnostics() const { return DisplayDiagnostics; }
-
+
/// \brief Get the path of the clang binary.
const llvm::sys::Path& getClangPath();
private:
bool OnlyLocalDecls;
bool DisplayDiagnostics;
-
+
llvm::sys::Path ClangPath;
};
@@ -360,63 +359,63 @@ const llvm::sys::Path& CIndexer::getClangPath() {
}
-static SourceLocation getLocationFromCursor(CXCursor C,
+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_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();
}
- 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();
+ 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;
- }
+ 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();
@@ -439,8 +438,7 @@ static CXString createCXString(const char *String, bool DupString = false) {
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
- int displayDiagnostics)
-{
+ int displayDiagnostics) {
CIndexer *CIdxr = new CIndexer(new Program());
if (excludeDeclarationsFromPCH)
CIdxr->setOnlyLocalDecls();
@@ -449,56 +447,55 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
return CIdxr;
}
-void clang_disposeIndex(CXIndex CIdx)
-{
+void clang_disposeIndex(CXIndex CIdx) {
assert(CIdx && "Passed null CXIndex");
delete static_cast<CIndexer *>(CIdx);
}
// FIXME: need to pass back error info.
-CXTranslationUnit clang_createTranslationUnit(
- CXIndex CIdx, const char *ast_filename)
-{
+CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
+ const char *ast_filename) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
std::string astName(ast_filename);
std::string ErrMsg;
-
+
CXTranslationUnit TU =
- ASTUnit::LoadFromPCHFile(astName, &ErrMsg,
- CXXIdx->getDisplayDiagnostics() ?
- NULL : new IgnoreDiagnosticsClient(),
- CXXIdx->getOnlyLocalDecls(),
- /* UseBumpAllocator = */ true);
-
+ ASTUnit::LoadFromPCHFile(astName, &ErrMsg,
+ CXXIdx->getDisplayDiagnostics() ?
+ NULL : new IgnoreDiagnosticsClient(),
+ CXXIdx->getOnlyLocalDecls(),
+ /* UseBumpAllocator = */ true);
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty())
llvm::errs() << "clang_createTranslationUnit: " << ErrMsg << '\n';
-
+
return TU;
}
-CXTranslationUnit clang_createTranslationUnitFromSourceFile(
- CXIndex CIdx,
- const char *source_filename,
- int num_command_line_args, const char **command_line_args) {
+CXTranslationUnit
+clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
+ const char *source_filename,
+ int num_command_line_args,
+ const char **command_line_args) {
assert(CIdx && "Passed null CXIndex");
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
// Build up the arguments for invoking 'clang'.
std::vector<const char *> argv;
-
+
// First add the complete path to the 'clang' executable.
llvm::sys::Path ClangPath = static_cast<CIndexer *>(CIdx)->getClangPath();
argv.push_back(ClangPath.c_str());
-
+
// Add the '-emit-ast' option as our execution mode for 'clang'.
argv.push_back("-emit-ast");
-
+
// The 'source_filename' argument is optional. If the caller does not
// specify it then it is assumed that the source file is specified
// in the actual argument list.
- if (source_filename)
- argv.push_back(source_filename);
+ if (source_filename)
+ argv.push_back(source_filename);
// Generate a temporary name for the AST file.
argv.push_back("-o");
@@ -521,7 +518,7 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
// Keep the argument.
argv.push_back(arg);
}
-
+
// Add the null terminator.
argv.push_back(NULL);
@@ -533,10 +530,10 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ !CXXIdx->getDisplayDiagnostics() ? &Redirects[0] : NULL,
/* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
-
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
- << '\n' << "Arguments: \n";
+ llvm::errs() << "clang_createTranslationUnitFromSourceFile: " << ErrMsg
+ << '\n' << "Arguments: \n";
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
I!=E; ++I) {
if (*I)
@@ -547,45 +544,40 @@ CXTranslationUnit clang_createTranslationUnitFromSourceFile(
// Finally, we create the translation unit from the ast file.
ASTUnit *ATU = static_cast<ASTUnit *>(
- clang_createTranslationUnit(CIdx, astTmpFile));
+ clang_createTranslationUnit(CIdx, astTmpFile));
if (ATU)
ATU->unlinkTemporaryFile();
return ATU;
}
-void clang_disposeTranslationUnit(
- CXTranslationUnit CTUnit)
-{
+void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
assert(CTUnit && "Passed null CXTranslationUnit");
delete static_cast<ASTUnit *>(CTUnit);
}
-
-CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit)
-{
+
+CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
assert(CTUnit && "Passed null CXTranslationUnit");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
return createCXString(CXXUnit->getOriginalSourceFileName().c_str(), true);
}
-void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
+void clang_loadTranslationUnit(CXTranslationUnit CTUnit,
CXTranslationUnitIterator callback,
- CXClientData CData)
-{
+ CXClientData CData) {
assert(CTUnit && "Passed null CXTranslationUnit");
ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit);
ASTContext &Ctx = CXXUnit->getASTContext();
-
- TUVisitor DVisit(CTUnit, callback, CData,
+
+ TUVisitor DVisit(CTUnit, callback, CData,
CXXUnit->getOnlyLocalDecls()? 1 : Decl::MaxPCHLevel);
DVisit.Visit(Ctx.getTranslationUnitDecl());
}
-void clang_loadDeclaration(CXDecl Dcl,
- CXDeclIterator callback,
- CXClientData CData)
-{
+void clang_loadDeclaration(CXDecl Dcl,
+ CXDeclIterator callback,
+ CXClientData CData) {
assert(Dcl && "Passed null CXDecl");
-
+
CDeclVisitor DVisit(Dcl, callback, CData,
static_cast<Decl *>(Dcl)->getPCHLevel());
DVisit.Visit(static_cast<Decl *>(Dcl));
@@ -593,14 +585,14 @@ void clang_loadDeclaration(CXDecl Dcl,
// Some notes on CXEntity:
//
-// - Since the 'ordinary' namespace includes functions, data, typedefs,
-// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
+// - 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
+// - 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:
//
@@ -608,29 +600,27 @@ void clang_loadDeclaration(CXDecl Dcl,
//
-const char *clang_getDeclarationName(CXEntity)
-{
+const char *clang_getDeclarationName(CXEntity) {
return "";
}
-const char *clang_getURI(CXEntity)
-{
+
+const char *clang_getURI(CXEntity) {
return "";
}
-CXEntity clang_getEntity(const char *URI)
-{
+CXEntity clang_getEntity(const char *URI) {
return 0;
}
//
// CXDecl Operations.
//
-CXEntity clang_getEntityFromDecl(CXDecl)
-{
+
+CXEntity clang_getEntityFromDecl(CXDecl) {
return 0;
}
-CXString clang_getDeclSpelling(CXDecl AnonDecl)
-{
+
+CXString clang_getDeclSpelling(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
@@ -649,24 +639,21 @@ CXString clang_getDeclSpelling(CXDecl AnonDecl)
return createCXString("");
}
-unsigned clang_getDeclLine(CXDecl AnonDecl)
-{
+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)
-{
+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)
-{
+const char *clang_getDeclSource(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
FileEntry *FEnt = static_cast<FileEntry *>(clang_getDeclSourceFile(AnonDecl));
assert (FEnt && "Cannot find FileEntry for Decl");
@@ -674,8 +661,7 @@ const char *clang_getDeclSource(CXDecl AnonDecl)
}
static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
- SourceLocation SLoc)
-{
+ SourceLocation SLoc) {
FileID FID;
if (SLoc.isFileID())
FID = SMgr.getFileID(SLoc);
@@ -684,8 +670,7 @@ static const FileEntry *getFileEntryFromSourceLocation(SourceManager &SMgr,
return SMgr.getFileEntryForID(FID);
}
-CXFile clang_getDeclSourceFile(CXDecl AnonDecl)
-{
+CXFile clang_getDeclSourceFile(CXDecl AnonDecl) {
assert(AnonDecl && "Passed null CXDecl");
NamedDecl *ND = static_cast<NamedDecl *>(AnonDecl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
@@ -704,145 +689,143 @@ time_t clang_getFileTime(CXFile SFile) {
return FEnt->getModificationTime();
}
-CXString clang_getCursorSpelling(CXCursor C)
-{
+CXString 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 createCXString(OID->getSuperClass()->getIdentifier()
- ->getNameStart());
- }
- case CXCursor_ObjCClassRef: {
- if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND))
- return createCXString(OID->getIdentifier()->getNameStart());
-
- ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
- assert(OCD && "clang_getCursorLine(): Missing category decl");
- return createCXString(OCD->getClassInterface()->getIdentifier()
- ->getNameStart());
- }
- case CXCursor_ObjCProtocolRef: {
- ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
- assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ case CXCursor_ObjCSuperClassRef: {
+ ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing interface decl");
+ return createCXString(OID->getSuperClass()->getIdentifier()
+ ->getNameStart());
+ }
+ case CXCursor_ObjCClassRef: {
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ND))
return createCXString(OID->getIdentifier()->getNameStart());
- }
- case CXCursor_ObjCSelectorRef: {
- ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
- static_cast<Stmt *>(C.stmt));
- assert(OME && "clang_getCursorLine(): Missing message expr");
- return createCXString(OME->getSelector().getAsString().c_str(), true);
- }
- 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 createCXString(DRE->getDecl()->getIdentifier()->getNameStart());
- }
- default:
- return createCXString("<not implemented>");
+
+ ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(ND);
+ assert(OCD && "clang_getCursorLine(): Missing category decl");
+ return createCXString(OCD->getClassInterface()->getIdentifier()
+ ->getNameStart());
+ }
+ case CXCursor_ObjCProtocolRef: {
+ ObjCProtocolDecl *OID = dyn_cast<ObjCProtocolDecl>(ND);
+ assert(OID && "clang_getCursorLine(): Missing protocol decl");
+ return createCXString(OID->getIdentifier()->getNameStart());
+ }
+ case CXCursor_ObjCSelectorRef: {
+ ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(
+ static_cast<Stmt *>(C.stmt));
+ assert(OME && "clang_getCursorLine(): Missing message expr");
+ return createCXString(OME->getSelector().getAsString().c_str(), true);
+ }
+ 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 createCXString(DRE->getDecl()->getIdentifier()->getNameStart());
+ }
+ default:
+ return createCXString("<not implemented>");
}
}
return clang_getDeclSpelling(C.decl);
}
-const char *clang_getCursorKindSpelling(enum CXCursorKind Kind)
-{
+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>";
+ 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;
+ 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)
-{
+
+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));
+ const FileEntry *File = FMgr.getFile(source_name,
+ source_name+strlen(source_name));
if (!File) {
CXCursor C = { CXCursor_InvalidFile, 0, 0 };
return C;
}
- SourceLocation SLoc =
+ SourceLocation SLoc =
CXXUnit->getSourceManager().getLocation(File, line, column);
-
+
ASTLocation LastLoc = CXXUnit->getLastASTLocation();
- ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
+ ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
&LastLoc);
if (ALoc.isValid())
CXXUnit->setLastASTLocation(ALoc);
-
+
Decl *Dcl = ALoc.getParentDecl();
if (ALoc.isNamedRef())
Dcl = ALoc.AsNamedRef().ND;
@@ -855,7 +838,7 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
} 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()) {
@@ -868,7 +851,7 @@ CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
return C;
}
}
- CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
+ CXCursor C = { TranslateKind(Dcl), Dcl, 0 };
return C;
}
CXCursor C = { CXCursor_NoDeclFound, 0, 0 };
@@ -886,38 +869,32 @@ CXCursor clang_getNullCursor(void) {
unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
return X.kind == Y.kind && X.decl == Y.decl && X.stmt == Y.stmt;
}
-
-CXCursor clang_getCursorFromDecl(CXDecl AnonDecl)
-{
+
+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)
-{
+unsigned clang_isInvalid(enum CXCursorKind K) {
return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid;
}
-unsigned clang_isDeclaration(enum CXCursorKind K)
-{
+unsigned clang_isDeclaration(enum CXCursorKind K) {
return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
}
-unsigned clang_isReference(enum CXCursorKind K)
-{
+unsigned clang_isReference(enum CXCursorKind K) {
return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
}
-unsigned clang_isDefinition(enum CXCursorKind K)
-{
+unsigned clang_isDefinition(enum CXCursorKind K) {
return K >= CXCursor_FirstDefn && K <= CXCursor_LastDefn;
}
-CXCursorKind clang_getCursorKind(CXCursor C)
-{
+CXCursorKind clang_getCursorKind(CXCursor C) {
return C.kind;
}
@@ -939,14 +916,13 @@ static Decl *getDeclFromExpr(Stmt *E) {
return 0;
}
-CXDecl clang_getCursorDecl(CXCursor C)
-{
+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 ||
+ if (C.kind == CXCursor_ObjCClassRef ||
C.kind == CXCursor_ObjCProtocolRef)
return static_cast<Stmt *>(C.stmt);
else
@@ -957,44 +933,40 @@ CXDecl clang_getCursorDecl(CXCursor C)
return 0;
}
-unsigned clang_getCursorLine(CXCursor C)
-{
+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);
}
-// Access string.
const char *clang_getCString(CXString string) {
return string.Spelling;
}
-
-// Free CXString.
+
void clang_disposeString(CXString string) {
if (string.MustFreeString)
free((void*)string.Spelling);
}
-unsigned clang_getCursorColumn(CXCursor C)
-{
+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)
-{
+
+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);
-
+
if (SLoc.isFileID()) {
const char *bufferName = SourceMgr.getBufferName(SLoc);
return bufferName[0] == '<' ? NULL : bufferName;
@@ -1003,7 +975,7 @@ const char *clang_getCursorSource(CXCursor C)
// Retrieve the file in which the macro was instantiated, then provide that
// buffer name.
// FIXME: Do we want to give specific macro-instantiation information?
- const llvm::MemoryBuffer *Buffer
+ const llvm::MemoryBuffer *Buffer
= SourceMgr.getBuffer(SourceMgr.getDecomposedSpellingLoc(SLoc).first);
if (!Buffer)
return 0;
@@ -1011,29 +983,27 @@ const char *clang_getCursorSource(CXCursor C)
return Buffer->getBufferIdentifier();
}
-CXFile clang_getCursorSourceFile(CXCursor C)
-{
+CXFile clang_getCursorSourceFile(CXCursor C) {
assert(C.decl && "CXCursor has null decl");
NamedDecl *ND = static_cast<NamedDecl *>(C.decl);
SourceManager &SourceMgr = ND->getASTContext().getSourceManager();
-
+
return (void *)getFileEntryFromSourceLocation(SourceMgr,
- getLocationFromCursor(C,SourceMgr, ND));
+ getLocationFromCursor(C,SourceMgr, ND));
}
-void clang_getDefinitionSpellingAndExtent(CXCursor C,
+void clang_getDefinitionSpellingAndExtent(CXCursor C,
const char **startBuf,
const char **endBuf,
unsigned *startLine,
unsigned *startColumn,
unsigned *endLine,
- unsigned *endColumn)
-{
+ 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());
@@ -1043,20 +1013,20 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
*endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc());
}
-enum CXCompletionChunkKind
+enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return CXCompletionChunk_Text;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
return CXCompletionChunk_TypedText;
case CodeCompletionString::CK_Text:
return CXCompletionChunk_Text;
case CodeCompletionString::CK_Optional:
- return CXCompletionChunk_Optional;
+ return CXCompletionChunk_Optional;
case CodeCompletionString::CK_Placeholder:
return CXCompletionChunk_Placeholder;
case CodeCompletionString::CK_Informative:
@@ -1082,17 +1052,17 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
case CodeCompletionString::CK_Comma:
return CXCompletionChunk_Comma;
}
-
+
// Should be unreachable, but let's be careful.
return CXCompletionChunk_Text;
}
-
+
const char *clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
case CodeCompletionString::CK_Text:
@@ -1109,23 +1079,23 @@ const char *clang_getCompletionChunkText(CXCompletionString completion_string,
case CodeCompletionString::CK_RightAngle:
case CodeCompletionString::CK_Comma:
return (*CCStr)[chunk_number].Text;
-
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return 0;
}
-
+
// Should be unreachable, but let's be careful.
return 0;
}
-
+
CXCompletionString
clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
return 0;
-
+
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
case CodeCompletionString::CK_Text:
@@ -1142,51 +1112,34 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
case CodeCompletionString::CK_RightAngle:
case CodeCompletionString::CK_Comma:
return 0;
-
+
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
return (*CCStr)[chunk_number].Optional;
}
-
+
// Should be unreachable, but let's be careful.
return 0;
}
-
+
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
return CCStr? CCStr->size() : 0;
}
-static CXCursorKind parseResultKind(llvm::StringRef Str) {
- return llvm::StringSwitch<CXCursorKind>(Str)
- .Case("Typedef", CXCursor_TypedefDecl)
- .Case("Struct", CXCursor_StructDecl)
- .Case("Union", CXCursor_UnionDecl)
- .Case("Class", CXCursor_ClassDecl)
- .Case("Enum", CXCursor_EnumDecl)
- .Case("Field", CXCursor_FieldDecl)
- .Case("EnumConstant", CXCursor_EnumConstantDecl)
- .Case("Function", CXCursor_FunctionDecl)
- // FIXME: Hacks here to make C++ member functions look like C functions
- .Case("CXXMethod", CXCursor_FunctionDecl)
- .Case("CXXConstructor", CXCursor_FunctionDecl)
- .Case("CXXDestructor", CXCursor_FunctionDecl)
- .Case("CXXConversion", CXCursor_FunctionDecl)
- .Case("Var", CXCursor_VarDecl)
- .Case("ParmVar", CXCursor_ParmDecl)
- .Case("ObjCInterface", CXCursor_ObjCInterfaceDecl)
- .Case("ObjCCategory", CXCursor_ObjCCategoryDecl)
- .Case("ObjCProtocol", CXCursor_ObjCProtocolDecl)
- .Case("ObjCProperty", CXCursor_ObjCPropertyDecl)
- .Case("ObjCIvar", CXCursor_ObjCIvarDecl)
- .Case("ObjCInstanceMethod", CXCursor_ObjCInstanceMethodDecl)
- .Case("ObjCClassMethod", CXCursor_ObjCClassMethodDecl)
- .Default(CXCursor_NotImplemented);
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+ unsigned &Value) {
+ if (Memory + sizeof(unsigned) > MemoryEnd)
+ return true;
+
+ memmove(&Value, Memory, sizeof(unsigned));
+ Memory += sizeof(unsigned);
+ return false;
}
-
-void clang_codeComplete(CXIndex CIdx,
+
+void clang_codeComplete(CXIndex CIdx,
const char *source_filename,
- int num_command_line_args,
+ int num_command_line_args,
const char **command_line_args,
const char *complete_filename,
unsigned complete_line,
@@ -1195,15 +1148,15 @@ void clang_codeComplete(CXIndex CIdx,
CXClientData client_data) {
// The indexer, which is mainly used to determine where diagnostics go.
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
-
+
// Build up the arguments for invoking 'clang'.
std::vector<const char *> argv;
-
+
// First add the complete path to the 'clang' executable.
llvm::sys::Path ClangPath = CXXIdx->getClangPath();
argv.push_back(ClangPath.c_str());
-
- // Add the '-fsyntax-only' argument so that we only perform a basic
+
+ // Add the '-fsyntax-only' argument so that we only perform a basic
// syntax check of the code.
argv.push_back("-fsyntax-only");
@@ -1220,12 +1173,12 @@ void clang_codeComplete(CXIndex CIdx,
argv.push_back(code_complete_at.c_str());
argv.push_back("-Xclang");
argv.push_back("-no-code-completion-debug-printer");
-
+
// Add the source file name (FIXME: later, we'll want to build temporary
// file from the buffer, or just feed the source text via standard input).
if (source_filename)
- argv.push_back(source_filename);
-
+ argv.push_back(source_filename);
+
// Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
for (int i = 0; i < num_command_line_args; ++i)
if (const char *arg = command_line_args[i]) {
@@ -1238,19 +1191,19 @@ void clang_codeComplete(CXIndex CIdx,
strcmp(arg, "-fsyntax-only") == 0) {
continue;
}
-
+
// Keep the argument.
argv.push_back(arg);
}
-
+
// Add the null terminator.
argv.push_back(NULL);
-
+
// Generate a temporary name for the AST file.
char tmpFile[L_tmpnam];
char *tmpFileName = tmpnam(tmpFile);
llvm::sys::Path ResultsFile(tmpFileName);
-
+
// Invoke 'clang'.
llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
// on Unix or NUL (Windows).
@@ -1258,12 +1211,12 @@ void clang_codeComplete(CXIndex CIdx,
const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
/* redirects */ &Redirects[0],
- /* secondsToWait */ 0,
+ /* secondsToWait */ 0,
/* memoryLimits */ 0, &ErrMsg);
-
+
if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
- llvm::errs() << "clang_codeComplete: " << ErrMsg
- << '\n' << "Arguments: \n";
+ llvm::errs() << "clang_codeComplete: " << ErrMsg
+ << '\n' << "Arguments: \n";
for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
I!=E; ++I) {
if (*I)
@@ -1277,84 +1230,32 @@ void clang_codeComplete(CXIndex CIdx,
using llvm::StringRef;
if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
StringRef Buffer = F->getBuffer();
- do {
- StringRef::size_type CompletionIdx = Buffer.find("COMPLETION:");
- StringRef::size_type OverloadIdx = Buffer.find("OVERLOAD:");
- if (CompletionIdx == StringRef::npos && OverloadIdx == StringRef::npos)
+ for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
+ Str < StrEnd;) {
+ unsigned KindValue;
+ if (ReadUnsigned(Str, StrEnd, KindValue))
break;
-
- if (OverloadIdx < CompletionIdx) {
- // Parse an overload result.
- Buffer = Buffer.substr(OverloadIdx);
-
- // Skip past the OVERLOAD:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
-
+
+ CodeCompletionString *CCStr
+ = CodeCompletionString::Deserialize(Str, StrEnd);
+ if (!CCStr)
+ continue;
+
+ if (!CCStr->empty()) {
// Vend the code-completion result to the caller.
CXCompletionResult Result;
- Result.CursorKind = CXCursor_NotImplemented;
+ Result.CursorKind = (CXCursorKind)KindValue;
Result.CompletionString = CCStr;
if (completion_iterator)
completion_iterator(&Result, client_data);
- delete CCStr;
-
- continue;
}
-
- // Parse a completion result.
- Buffer = Buffer.substr(CompletionIdx);
-
- // Skip past the COMPLETION:
- Buffer = Buffer.substr(Buffer.find(':') + 1);
-
- // Get the rank
- unsigned Rank = 0;
- StringRef::size_type AfterRank = Buffer.find(':');
- Buffer.substr(0, AfterRank).getAsInteger(10, Rank);
- Buffer = Buffer.substr(AfterRank + 1);
-
- // Get the kind of result.
- StringRef::size_type AfterKind = Buffer.find(':');
- StringRef Kind = Buffer.substr(0, AfterKind);
- Buffer = Buffer.substr(AfterKind + 1);
-
- // Skip over any whitespace.
- Buffer = Buffer.substr(Buffer.find_first_not_of(" \t"));
-
- // Find the entire completion string.
- StringRef::size_type EOL = Buffer.find_first_of("\n\r");
- if (EOL == StringRef::npos)
- continue;
-
- StringRef Line = Buffer.substr(0, EOL);
- Buffer = Buffer.substr(EOL + 1);
- CodeCompletionString *CCStr = CodeCompletionString::Deserialize(Line);
- if (!CCStr || CCStr->empty())
- continue;
-
- // Vend the code-completion result to the caller.
- CXCompletionResult Result;
- Result.CursorKind = parseResultKind(Kind);
- Result.CompletionString = CCStr;
- if (completion_iterator)
- completion_iterator(&Result, client_data);
+
delete CCStr;
- } while (true);
+ };
delete F;
- }
-
+ }
+
ResultsFile.eraseFromDisk();
}
-
+
} // end extern "C"
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 8cded43..8c666dd 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -1,5 +1,5 @@
+add_subdirectory(CIndex)
+add_subdirectory(c-index-test)
add_subdirectory(clang-cc)
add_subdirectory(driver)
add_subdirectory(index-test)
-add_subdirectory(CIndex)
-add_subdirectory(c-index-test)
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 4c72465..4678461 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -4,8 +4,11 @@ set( LLVM_USED_LIBS
CIndex
clangIndex
clangFrontend
+ clangDriver
+ clangAnalysis
clangSema
clangAST
+ clangParse
clangLex
clangBasic
)
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 81fee40..ae49bf4 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -19,6 +19,7 @@ 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
+USEDLIBS = CIndex.a clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a \
+ clangSema.a clangAST.a clangParse.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
index 289dee9..5364d794 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -38,7 +38,6 @@ static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
return 1;
}
-
/******************************************************************************/
/* Pretty-printing. */
/******************************************************************************/
@@ -71,8 +70,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
/* Logic for testing clang_loadTranslationUnit(). */
/******************************************************************************/
-static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
-{
+static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) {
if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
CXString string;
printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
@@ -84,9 +82,9 @@ static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter)
clang_disposeString(string);
}
}
+
static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
- CXClientData Filter)
-{
+ CXClientData Filter) {
if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
CXString string;
printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
@@ -99,58 +97,56 @@ static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
clang_disposeString(string);
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++;
+static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
+ CXClientData Filter) {
+ const char *startBuf, *endBuf;
+ unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
+ CXCursor Ref;
+
+ if (Cursor.kind != CXCursor_FunctionDefn)
+ return;
+
+ clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
+ &startLine, &startColumn,
+ &endLine, &endColumn);
+ /* Probe the entire body, looking for both decls and refs. */
+ curLine = startLine;
+ curColumn = startColumn;
+
+ 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_NoDeclFound) {
- /* Nothing found here; that's fine. */
- } else if (Ref.kind != CXCursor_FunctionDecl) {
- CXString string;
- printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
- curLine, curColumn);
- PrintCursor(Ref);
- string = clang_getDeclSpelling(Ref.decl);
- printf(" [Context:%s]\n", clang_getCString(string));
- clang_disposeString(string);
- }
- startBuf++;
- }
- }
+ Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
+ curLine, curColumn);
+ if (Ref.kind == CXCursor_NoDeclFound) {
+ /* Nothing found here; that's fine. */
+ } else if (Ref.kind != CXCursor_FunctionDecl) {
+ CXString string;
+ printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
+ curLine, curColumn);
+ PrintCursor(Ref);
+ string = clang_getDeclSpelling(Ref.decl);
+ printf(" [Context:%s]\n", clang_getCString(string));
+ clang_disposeString(string);
}
+ startBuf++;
}
}
-int perform_test_load_tu(const char *file, const char *filter) {
- CXIndex Idx;
- CXTranslationUnit TU;
+static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
+ const char *filter) {
enum CXCursorKind K = CXCursor_NotImplemented;
+ CXTranslationUnitIterator Visitor = TranslationUnitVisitor;
enum CXCursorKind *ck = &K;
- Idx = clang_createIndex(/* excludeDeclsFromPCH */
- !strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnostics */ 1);
-
- if (!CreateTranslationUnit(Idx, file, &TU))
- return 1;
-
+
/* Perform some simple filtering. */
if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
@@ -158,16 +154,46 @@ int perform_test_load_tu(const char *file, const char *filter) {
else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
+ else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
else {
fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
return 1;
}
- clang_loadTranslationUnit(TU, TranslationUnitVisitor, ck);
+ clang_loadTranslationUnit(TU, Visitor, ck);
clang_disposeTranslationUnit(TU);
return 0;
}
+int perform_test_load_tu(const char *file, const char *filter) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */
+ !strcmp(filter, "local") ? 1 : 0,
+ /* displayDiagnostics */ 1);
+
+ if (!CreateTranslationUnit(Idx, file, &TU))
+ return 1;
+
+ return perform_test_load(Idx, TU, filter);
+}
+
+int perform_test_load_source(int argc, const char **argv, const char *filter) {
+ CXIndex Idx;
+ CXTranslationUnit TU;
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */
+ !strcmp(filter, "local") ? 1 : 0,
+ /* displayDiagnostics */ 1);
+
+ TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv);
+ if (!TU) {
+ fprintf(stderr, "Unable to load translation unit!\n");
+ return 1;
+ }
+
+ return perform_test_load(Idx, TU, filter);
+}
+
/******************************************************************************/
/* Logic for testing clang_getCursor(). */
/******************************************************************************/
@@ -394,14 +420,16 @@ static void print_usage(void) {
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n"
" c-index-test -test-load-tu <AST file> <symbol filter>\n\n"
- " <symbol filter> options for -test-load-tu:\n%s",
+ " c-index-test -test-load-source <symbol filter> {<args>}*\n\n"
+ " <symbol filter> options for -test-load-tu and -test-load-source:\n%s",
" all - load all symbols, including those from PCH\n"
" local - load all symbols except those in PCH\n"
" category - only load ObjC categories (non-PCH)\n"
" interface - only load ObjC interfaces (non-PCH)\n"
" protocol - only load ObjC protocols (non-PCH)\n"
" function - only load functions (non-PCH)\n"
- " typedef - only load typdefs (non-PCH)\n\n");
+ " typedef - only load typdefs (non-PCH)\n"
+ " scan-function - scan function bodies (non-PCH)\n\n");
}
int main(int argc, const char **argv) {
@@ -409,6 +437,8 @@ int main(int argc, const char **argv) {
return perform_code_completion(argc, argv);
if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0)
return perform_test_load_tu(argv[2], argv[3]);
+ if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0)
+ return perform_test_load_source(argc - 3, argv + 3, argv[2]);
if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
return perform_file_scan(argv[2], argv[3],
argc >= 5 ? argv[4] : 0);
diff --git a/tools/clang-cc/CMakeLists.txt b/tools/clang-cc/CMakeLists.txt
index e7da908..c96e8b1 100644
--- a/tools/clang-cc/CMakeLists.txt
+++ b/tools/clang-cc/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
+ clangDriver
clangFrontend
clangCodeGen
clangAnalysis
diff --git a/tools/clang-cc/Makefile b/tools/clang-cc/Makefile
index 874a42f..ebcc1d5 100644
--- a/tools/clang-cc/Makefile
+++ b/tools/clang-cc/Makefile
@@ -21,7 +21,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader bitwriter codegen ipo selectiondag
-USEDLIBS = clangFrontend.a clangCodeGen.a clangAnalysis.a \
+USEDLIBS = clangDriver.a clangFrontend.a clangCodeGen.a clangAnalysis.a \
clangRewrite.a clangSema.a clangAST.a clangParse.a \
clangLex.a clangBasic.a
diff --git a/tools/clang-cc/Options.cpp b/tools/clang-cc/Options.cpp
index 584f957..a18598e 100644
--- a/tools/clang-cc/Options.cpp
+++ b/tools/clang-cc/Options.cpp
@@ -21,6 +21,7 @@
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/HeaderSearchOptions.h"
+#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/Frontend/PreprocessorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -81,7 +82,7 @@ static llvm::cl::opt<bool>
AnalyzeAll("analyzer-opt-analyze-headers",
llvm::cl::desc("Force the static analyzer to analyze "
"functions defined in header files"));
-
+
static llvm::cl::opt<bool>
AnalyzerDisplayProgress("analyzer-display-progress",
llvm::cl::desc("Emit verbose output about the analyzer's progress"));
@@ -93,7 +94,7 @@ AnalyzerExperimentalChecks("analyzer-experimental-checks",
static llvm::cl::opt<bool>
AnalyzerExperimentalInternalChecks("analyzer-experimental-internal-checks",
llvm::cl::desc("Use new default path-sensitive checks currently in testing"));
-
+
static llvm::cl::opt<std::string>
AnalyzeSpecificFunction("analyze-function",
llvm::cl::desc("Run analysis on specific function"));
@@ -141,6 +142,46 @@ GenerateDebugInfo("g",
llvm::cl::desc("Generate source level debug information"));
static llvm::cl::opt<bool>
+MAsmVerbose("masm-verbose", llvm::cl::desc("Generate verbose assembly output"));
+
+static llvm::cl::opt<std::string>
+MCodeModel("mcode-model", llvm::cl::desc("The code model to use"));
+
+static llvm::cl::opt<std::string>
+MDebugPass("mdebu-pass", llvm::cl::desc("Output additional debug information"));
+
+static llvm::cl::opt<bool>
+MDisableFPElim("mdisable-fp-elim",
+ llvm::cl::desc("Disable frame pointer elimination optimization"));
+
+static llvm::cl::opt<std::string>
+MFloatABI("mfloat-abi", llvm::cl::desc("The float ABI to use"));
+
+static llvm::cl::opt<std::string>
+MLimitFloatPrecision("mlimit-float-precision",
+ llvm::cl::desc("Limit float precision to the given value"));
+
+static llvm::cl::opt<bool>
+MNoZeroInitializedInBSS("mno-zero-initialized-in-bss",
+ llvm::cl::desc("Do not put zero initialized data in the BSS"));
+
+static llvm::cl::opt<bool>
+MSoftFloat("msoft-float", llvm::cl::desc("Use software floating point"));
+
+static llvm::cl::opt<std::string>
+MRelocationModel("mrelocation-model",
+ llvm::cl::desc("The relocation model to use"),
+ llvm::cl::init("pic"));
+
+static llvm::cl::opt<bool>
+MUnwindTables("munwind-tables",
+ llvm::cl::desc("Generate unwinding tables for all functions"));
+
+static llvm::cl::opt<std::string>
+MainFileName("main-file-name",
+ llvm::cl::desc("Main file name to use for debug info"));
+
+static llvm::cl::opt<bool>
NoCommon("fno-common",
llvm::cl::desc("Compile common globals like normal definitions"),
llvm::cl::ValueDisallowed);
@@ -436,6 +477,8 @@ TimeReport("ftime-report",
namespace langoptions {
+using namespace clang::frontend;
+
static llvm::cl::opt<bool>
NoBuiltin("fno-builtin",
llvm::cl::desc("Disable implicit builtin knowledge of functions"));
@@ -448,8 +491,8 @@ AccessControl("faccess-control",
llvm::cl::desc("Enable C++ access control"));
static llvm::cl::opt<bool>
-CharIsSigned("fsigned-char",
- llvm::cl::desc("Force char to be a signed/unsigned type"));
+NoSignedChar("fno-signed-char",
+ llvm::cl::desc("Char is unsigned"));
static llvm::cl::opt<bool>
DollarsInIdents("fdollars-in-identifiers",
@@ -481,42 +524,12 @@ GNURuntime("fgnu-runtime",
llvm::cl::desc("Generate output compatible with the standard GNU "
"Objective-C runtime"));
-/// LangStds - Language standards we support.
-enum LangStds {
- lang_unspecified,
- lang_c89, lang_c94, lang_c99,
- lang_gnu89, lang_gnu99,
- lang_cxx98, lang_gnucxx98,
- lang_cxx0x, lang_gnucxx0x
-};
-static llvm::cl::opt<LangStds>
+static llvm::cl::opt<LangStandard::Kind>
LangStd("std", llvm::cl::desc("Language standard to compile for"),
- llvm::cl::init(lang_unspecified),
- llvm::cl::values(clEnumValN(lang_c89, "c89", "ISO C 1990"),
- clEnumValN(lang_c89, "c90", "ISO C 1990"),
- clEnumValN(lang_c89, "iso9899:1990", "ISO C 1990"),
- clEnumValN(lang_c94, "iso9899:199409",
- "ISO C 1990 with amendment 1"),
- clEnumValN(lang_c99, "c99", "ISO C 1999"),
- clEnumValN(lang_c99, "c9x", "ISO C 1999"),
- clEnumValN(lang_c99, "iso9899:1999", "ISO C 1999"),
- clEnumValN(lang_c99, "iso9899:199x", "ISO C 1999"),
- clEnumValN(lang_gnu89, "gnu89",
- "ISO C 1990 with GNU extensions"),
- clEnumValN(lang_gnu99, "gnu99",
- "ISO C 1999 with GNU extensions (default for C)"),
- clEnumValN(lang_gnu99, "gnu9x",
- "ISO C 1999 with GNU extensions"),
- clEnumValN(lang_cxx98, "c++98",
- "ISO C++ 1998 with amendments"),
- clEnumValN(lang_gnucxx98, "gnu++98",
- "ISO C++ 1998 with amendments and GNU "
- "extensions (default for C++)"),
- clEnumValN(lang_cxx0x, "c++0x",
- "Upcoming ISO C++ 200x with amendments"),
- clEnumValN(lang_gnucxx0x, "gnu++0x",
- "Upcoming ISO C++ 200x with amendments and GNU "
- "extensions"),
+ llvm::cl::init(LangStandard::lang_unspecified), llvm::cl::values(
+#define LANGSTANDARD(id, name, desc, features) \
+ clEnumValN(LangStandard::lang_##id, name, desc),
+#include "clang/Frontend/LangStandards.def"
clEnumValEnd));
static llvm::cl::opt<bool>
@@ -524,10 +537,6 @@ MSExtensions("fms-extensions",
llvm::cl::desc("Accept some non-standard constructs used in "
"Microsoft header files "));
-static llvm::cl::opt<std::string>
-MainFileName("main-file-name",
- llvm::cl::desc("Main file name to use for debug info"));
-
static llvm::cl::opt<bool>
NoMathErrno("fno-math-errno",
llvm::cl::desc("Don't require math functions to respect errno"));
@@ -745,6 +754,7 @@ DumpDefines("dD", llvm::cl::desc("Print macro definitions in -E mode in "
"addition to normal output"));
}
+
//===----------------------------------------------------------------------===//
// Target Options
//===----------------------------------------------------------------------===//
@@ -757,7 +767,7 @@ TargetABI("target-abi",
static llvm::cl::opt<std::string>
TargetCPU("mcpu",
- llvm::cl::desc("Target a specific cpu type (-mcpu=help for details)"));
+ llvm::cl::desc("Target a specific cpu type ('-mcpu help' for details)"));
static llvm::cl::list<std::string>
TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes"));
@@ -791,8 +801,7 @@ void clang::InitializeAnalyzerOptions(AnalyzerOptions &Opts) {
}
void clang::InitializeCodeGenOptions(CodeGenOptions &Opts,
- const LangOptions &Lang,
- bool TimePasses) {
+ const LangOptions &Lang) {
using namespace codegenoptions;
// -Os implies -O2
@@ -810,19 +819,27 @@ void clang::InitializeCodeGenOptions(CodeGenOptions &Opts,
Opts.NoCommon = NoCommon;
Opts.NoImplicitFloat = NoImplicitFloat;
Opts.OptimizeSize = OptSize;
- Opts.SimplifyLibCalls = 1;
Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !OptSize);
- // FIXME: Eliminate this dependency?
- if (Lang.NoBuiltin)
- Opts.SimplifyLibCalls = 0;
- if (Lang.CPlusPlus)
- Opts.NoCommon = 1;
- Opts.TimePasses = TimePasses;
+ // LLVM Code Generator options.
+
+ Opts.AsmVerbose = MAsmVerbose;
+ Opts.CodeModel = MCodeModel;
+ Opts.DebugPass = MDebugPass;
+ Opts.DisableFPElim = MDisableFPElim;
+ Opts.FloatABI = MFloatABI;
+ Opts.LimitFloatPrecision = MLimitFloatPrecision;
+ Opts.NoZeroInitializedInBSS = MNoZeroInitializedInBSS;
+ Opts.SoftFloat = MSoftFloat;
+ Opts.RelocationModel = MRelocationModel;
+ Opts.UnwindTables = MUnwindTables;
#ifdef NDEBUG
Opts.VerifyModule = 0;
#endif
+
+ if (MainFileName.getPosition())
+ Opts.MainFileName = MainFileName;
}
void clang::InitializeDependencyOutputOptions(DependencyOutputOptions &Opts) {
@@ -857,13 +874,8 @@ void clang::InitializeDiagnosticOptions(DiagnosticOptions &Opts) {
void clang::InitializeFrontendOptions(FrontendOptions &Opts) {
using namespace frontendoptions;
- // Select program action.
Opts.ProgramAction = ProgAction;
- if (PluginActionName.getPosition()) {
- Opts.ProgramAction = frontend::PluginAction;
- Opts.ActionName = PluginActionName;
- }
-
+ Opts.ActionName = PluginActionName;
Opts.CodeCompletionAt = CodeCompletionAt;
Opts.DebugCodeCompletionPrinter = !NoCodeCompletionDebugPrinter;
Opts.DisableFree = DisableFree;
@@ -876,6 +888,14 @@ void clang::InitializeFrontendOptions(FrontendOptions &Opts) {
Opts.ShowTimers = TimeReport;
Opts.ViewClassInheritance = InheritanceViewCls;
+ // Enforce certain program action implications.
+ if (!Opts.ActionName.empty())
+ Opts.ProgramAction = frontend::PluginAction;
+ if (!Opts.ViewClassInheritance.empty())
+ Opts.ProgramAction = frontend::InheritanceView;
+ if (!Opts.FixItLocations.empty())
+ Opts.ProgramAction = frontend::FixIt;
+
// '-' is the default input if none is given.
if (InputFilenames.empty()) {
FrontendOptions::InputKind IK = InputType;
@@ -1054,145 +1074,87 @@ void clang::InitializePreprocessorOptions(PreprocessorOptions &Opts) {
}
void clang::InitializeLangOptions(LangOptions &Options,
- FrontendOptions::InputKind IK,
- TargetInfo &Target) {
+ FrontendOptions::InputKind IK) {
using namespace langoptions;
-
- switch (IK) {
- case FrontendOptions::IK_None:
- case FrontendOptions::IK_AST:
- assert(0 && "Invalid input kind!");
- case FrontendOptions::IK_Asm:
+ // Set some properties which depend soley on the input kind; it would be nice
+ // to move these to the language standard, and have the driver resolve the
+ // input kind + language standard.
+ if (IK == FrontendOptions::IK_Asm) {
Options.AsmPreprocessor = 1;
- // FALLTHROUGH
- case FrontendOptions::IK_PreprocessedC:
- // FALLTHROUGH
- case FrontendOptions::IK_C:
- // Do nothing.
- break;
- case FrontendOptions::IK_PreprocessedCXX:
- // FALLTHROUGH
- case FrontendOptions::IK_CXX:
- Options.CPlusPlus = 1;
- break;
- case FrontendOptions::IK_PreprocessedObjC:
- // FALLTHROUGH
- case FrontendOptions::IK_ObjC:
+ } else if (IK == FrontendOptions::IK_ObjC ||
+ IK == FrontendOptions::IK_ObjCXX ||
+ IK == FrontendOptions::IK_PreprocessedObjC ||
+ IK == FrontendOptions::IK_PreprocessedObjCXX) {
Options.ObjC1 = Options.ObjC2 = 1;
- break;
- case FrontendOptions::IK_PreprocessedObjCXX:
- // FALLTHROUGH
- case FrontendOptions::IK_ObjCXX:
- Options.ObjC1 = Options.ObjC2 = 1;
- Options.CPlusPlus = 1;
- break;
- case FrontendOptions::IK_OpenCL:
- Options.OpenCL = 1;
- Options.AltiVec = 1;
- Options.CXXOperatorNames = 1;
- 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;
-
- if (LangStd == lang_unspecified) {
+ if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
switch (IK) {
case FrontendOptions::IK_None:
case FrontendOptions::IK_AST:
assert(0 && "Invalid input kind!");
case FrontendOptions::IK_OpenCL:
- LangStd = lang_c99;
+ LangStd = LangStandard::lang_opencl;
break;
case FrontendOptions::IK_Asm:
case FrontendOptions::IK_C:
case FrontendOptions::IK_PreprocessedC:
case FrontendOptions::IK_ObjC:
case FrontendOptions::IK_PreprocessedObjC:
- LangStd = lang_gnu99;
+ LangStd = LangStandard::lang_gnu99;
break;
case FrontendOptions::IK_CXX:
case FrontendOptions::IK_PreprocessedCXX:
case FrontendOptions::IK_ObjCXX:
case FrontendOptions::IK_PreprocessedObjCXX:
- LangStd = lang_gnucxx98;
+ LangStd = LangStandard::lang_gnucxx98;
break;
}
}
- switch (LangStd) {
- default: assert(0 && "Unknown language standard!");
-
- // Fall through from newer standards to older ones. This isn't really right.
- // FIXME: Enable specifically the right features based on the language stds.
- case lang_gnucxx0x:
- case lang_cxx0x:
- Options.CPlusPlus0x = 1;
- // FALL THROUGH
- case lang_gnucxx98:
- case lang_cxx98:
- Options.CPlusPlus = 1;
- Options.CXXOperatorNames = !NoOperatorNames;
- // FALL THROUGH.
- case lang_gnu99:
- case lang_c99:
- Options.C99 = 1;
- Options.HexFloats = 1;
- // FALL THROUGH.
- case lang_gnu89:
- Options.BCPLComment = 1; // Only for C99/C++.
- // FALL THROUGH.
- case lang_c94:
- Options.Digraphs = 1; // C94, C99, C++.
- // FALL THROUGH.
- case lang_c89:
- break;
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Options.BCPLComment = Std.hasBCPLComments();
+ Options.C99 = Std.isC99();
+ Options.CPlusPlus = Std.isCPlusPlus();
+ Options.CPlusPlus0x = Std.isCPlusPlus0x();
+ Options.Digraphs = Std.hasDigraphs();
+ Options.GNUInline = !Std.isC99();
+ Options.GNUMode = Std.isGNUMode();
+ Options.HexFloats = Std.hasHexFloats();
+ Options.ImplicitInt = Std.hasImplicitInt();
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl) {
+ Options.OpenCL = 1;
+ Options.AltiVec = 1;
+ Options.CXXOperatorNames = 1;
+ Options.LaxVectorConversions = 1;
}
- // GNUMode - Set if we're in gnu99, gnu89, gnucxx98, etc.
- 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;
- }
+ // OpenCL and C++ both have bool, true, false keywords.
+ Options.Bool = Options.OpenCL || Options.CPlusPlus;
- if (Options.CPlusPlus) {
- Options.C99 = 0;
- Options.HexFloats = 0;
- }
+ if (Options.CPlusPlus)
+ Options.CXXOperatorNames = !NoOperatorNames;
- if (LangStd == lang_c89 || LangStd == lang_c94 || LangStd == lang_gnu89)
- Options.ImplicitInt = 1;
- else
- Options.ImplicitInt = 0;
+ 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;
// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
// is specified, or -std is set to a conforming mode.
@@ -1200,17 +1162,8 @@ void clang::InitializeLangOptions(LangOptions &Options,
if (Trigraphs.getPosition())
Options.Trigraphs = Trigraphs; // Command line option wins if specified.
- // If in a conformant language mode (e.g. -std=c99) Blocks defaults to off
- // even if they are normally on for the target. In GNU modes (e.g.
- // -std=gnu99) the default for blocks depends on the target settings.
- // However, blocks are not turned off when compiling Obj-C or Obj-C++ code.
- if (!Options.ObjC1 && !Options.GNUMode)
- Options.Blocks = 0;
-
- // 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 = IK != FrontendOptions::IK_Asm;
+ // Default to not accepting '$' in identifiers when preprocessing assembler.
+ Options.DollarIdents = !Options.AsmPreprocessor;
if (DollarsInIdents.getPosition()) // Explicit setting overrides default.
Options.DollarIdents = DollarsInIdents;
@@ -1223,10 +1176,8 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.LaxVectorConversions = 0;
Options.Exceptions = Exceptions;
Options.Rtti = !NoRtti;
- if (EnableBlocks.getPosition())
- Options.Blocks = EnableBlocks;
- if (CharIsSigned.getPosition())
- Options.CharIsSigned = CharIsSigned;
+ Options.Blocks = EnableBlocks;
+ Options.CharIsSigned = !NoSignedChar;
if (ShortWChar.getPosition())
Options.ShortWChar = ShortWChar;
@@ -1242,9 +1193,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.ElideConstructors = !NoElideConstructors;
- // OpenCL and C++ both have bool, true, false keywords.
- Options.Bool = Options.OpenCL | Options.CPlusPlus;
-
Options.MathErrno = !NoMathErrno;
if (TemplateDepth.getPosition())
@@ -1255,7 +1203,7 @@ void clang::InitializeLangOptions(LangOptions &Options,
Options.NeXTRuntime = 0;
if (!ObjCConstantStringClass.empty())
- Options.ObjCConstantStringClass = ObjCConstantStringClass.c_str();
+ Options.ObjCConstantStringClass = ObjCConstantStringClass;
if (ObjCNonFragileABI)
Options.ObjCNonFragileABI = 1;
@@ -1272,8 +1220,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
assert(PICLevel <= 2 && "Invalid value for -pic-level");
Options.PICLevel = PICLevel;
- Options.GNUInline = !Options.C99;
-
// This is the __NO_INLINE__ define, which just depends on things like the
// optimization level and -fno-inline, not actually whether the backend has
// inlining enabled.
@@ -1292,11 +1238,6 @@ void clang::InitializeLangOptions(LangOptions &Options,
case 2: Options.setStackProtectorMode(LangOptions::SSPReq); break;
}
}
-
- if (MainFileName.getPosition())
- Options.setMainFileName(MainFileName.c_str());
-
- Target.setForcedLangOptions(Options);
}
void
diff --git a/tools/clang-cc/Options.h b/tools/clang-cc/Options.h
index 9a2fd9d..91e37f2 100644
--- a/tools/clang-cc/Options.h
+++ b/tools/clang-cc/Options.h
@@ -30,8 +30,7 @@ class TargetOptions;
void InitializeAnalyzerOptions(AnalyzerOptions &Opts);
void InitializeCodeGenOptions(CodeGenOptions &Opts,
- const LangOptions &Lang,
- bool TimePasses);
+ const LangOptions &Lang);
void InitializeDependencyOutputOptions(DependencyOutputOptions &Opts);
@@ -42,9 +41,7 @@ void InitializeFrontendOptions(FrontendOptions &Opts);
void InitializeHeaderSearchOptions(HeaderSearchOptions &Opts,
llvm::StringRef BuiltinIncludePath);
-void InitializeLangOptions(LangOptions &Options,
- FrontendOptions::InputKind LK,
- TargetInfo &Target);
+void InitializeLangOptions(LangOptions &Options, FrontendOptions::InputKind LK);
void InitializePreprocessorOptions(PreprocessorOptions &Opts);
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp
index bae8697..2899684 100644
--- a/tools/clang-cc/clang-cc.cpp
+++ b/tools/clang-cc/clang-cc.cpp
@@ -21,11 +21,18 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/VerifyDiagnosticsClient.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/OwningPtr.h"
@@ -39,6 +46,7 @@
#include "llvm/System/Path.h"
#include "llvm/System/Signals.h"
#include "llvm/Target/TargetSelect.h"
+#include <cstdio>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -73,11 +81,6 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-/// ClangFrontendTimer - The front-end activities should charge time to it with
-/// TimeRegion. The -ftime-report option controls whether this will do
-/// anything.
-llvm::Timer *ClangFrontendTimer = 0;
-
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
using namespace clang::frontend;
@@ -139,18 +142,11 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
}
}
-static TargetInfo *
-ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
- const char *Argv0, bool &IsAST) {
+static bool ConstructCompilerInvocation(CompilerInvocation &Opts,
+ Diagnostic &Diags, const char *Argv0) {
// Initialize target options.
InitializeTargetOptions(Opts.getTargetOpts());
- // Get information about the target being compiled for.
- llvm::OwningPtr<TargetInfo> Target(
- TargetInfo::CreateTargetInfo(Diags, Opts.getTargetOpts()));
- if (!Target)
- return 0;
-
// Initialize frontend options.
InitializeFrontendOptions(Opts.getFrontendOpts());
@@ -160,7 +156,7 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
if (Opts.getFrontendOpts().Inputs[i].first != IK) {
llvm::errs() << "error: cannot have multiple input files of distinct "
<< "language kinds without -x\n";
- return 0;
+ return false;
}
}
@@ -168,9 +164,8 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
//
// FIXME: These aren't used during operations on ASTs. Split onto a separate
// code path to make this obvious.
- IsAST = (IK == FrontendOptions::IK_AST);
- if (!IsAST)
- InitializeLangOptions(Opts.getLangOpts(), IK, *Target);
+ if (IK != FrontendOptions::IK_AST)
+ InitializeLangOptions(Opts.getLangOpts(), IK);
// Initialize the static analyzer options.
InitializeAnalyzerOptions(Opts.getAnalyzerOpts());
@@ -188,12 +183,78 @@ ConstructCompilerInvocation(CompilerInvocation &Opts, Diagnostic &Diags,
// Initialize the preprocessed output options.
InitializePreprocessorOutputOptions(Opts.getPreprocessorOutputOpts());
- // Initialize backend options, which may also be used to key some language
- // options.
- InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts(),
- Opts.getFrontendOpts().ShowTimers);
+ // Initialize backend options.
+ InitializeCodeGenOptions(Opts.getCodeGenOpts(), Opts.getLangOpts());
+
+ return true;
+}
+
+static int cc1_main(Diagnostic &Diags,
+ const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
+ using namespace clang::driver;
+
+ llvm::errs() << "cc1 argv:";
+ for (const char **i = ArgBegin; i != ArgEnd; ++i)
+ llvm::errs() << " \"" << *i << '"';
+ llvm::errs() << "\n";
+
+ // Parse the arguments.
+ OptTable *Opts = createCC1OptTable();
+ unsigned MissingArgIndex, MissingArgCount;
+ InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
+ MissingArgIndex, MissingArgCount);
+
+ // Check for missing argument error.
+ if (MissingArgCount)
+ Diags.Report(clang::diag::err_drv_missing_argument)
+ << Args->getArgString(MissingArgIndex) << MissingArgCount;
+
+ // Dump the parsed arguments.
+ llvm::errs() << "cc1 parsed options:\n";
+ for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
+ it != ie; ++it)
+ (*it)->dump();
+
+ // Create a compiler invocation.
+ llvm::errs() << "cc1 creating invocation.\n";
+ CompilerInvocation Invocation;
+ CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd,
+ Argv0, MainAddr, Diags);
+
+ // Convert the invocation back to argument strings.
+ std::vector<std::string> InvocationArgs;
+ Invocation.toArgs(InvocationArgs);
+
+ // Dump the converted arguments.
+ llvm::SmallVector<const char*, 32> Invocation2Args;
+ llvm::errs() << "invocation argv :";
+ for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
+ Invocation2Args.push_back(InvocationArgs[i].c_str());
+ llvm::errs() << " \"" << InvocationArgs[i] << '"';
+ }
+ llvm::errs() << "\n";
+
+ // Convert those arguments to another invocation, and check that we got the
+ // same thing.
+ CompilerInvocation Invocation2;
+ CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
+ Invocation2Args.end(), Argv0, MainAddr,
+ Diags);
+
+ // FIXME: Implement CompilerInvocation comparison.
+ if (true) {
+ //llvm::errs() << "warning: Invocations differ!\n";
+
+ std::vector<std::string> Invocation2Args;
+ Invocation2.toArgs(Invocation2Args);
+ llvm::errs() << "invocation2 argv:";
+ for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
+ llvm::errs() << " \"" << Invocation2Args[i] << '"';
+ llvm::errs() << "\n";
+ }
- return Target.take();
+ return 0;
}
int main(int argc, char **argv) {
@@ -201,10 +262,19 @@ int main(int argc, char **argv) {
llvm::PrettyStackTraceProgram X(argc, argv);
CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ // Run clang -cc1 test.
+ if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1") {
+ TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
+ Diagnostic Diags(&DiagClient);
+ return cc1_main(Diags, (const char**) argv + 2, (const char**) argv + argc,
+ argv[0], (void*) (intptr_t) GetBuiltinIncludePath);
+ }
+
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
+#if 1
llvm::cl::ParseCommandLineOptions(argc, argv,
"LLVM 'Clang' Compiler: http://clang.llvm.org\n");
@@ -225,13 +295,49 @@ int main(int argc, char **argv) {
//
// FIXME: We should move .ast inputs to taking a separate path, they are
// really quite different.
- bool IsAST = false;
- Clang.setTarget(
- ConstructCompilerInvocation(Clang.getInvocation(), Clang.getDiagnostics(),
- argv[0], IsAST));
+ if (!ConstructCompilerInvocation(Clang.getInvocation(),
+ Clang.getDiagnostics(), argv[0]))
+ return 1;
+#else
+ // Buffer diagnostics from argument parsing.
+ TextDiagnosticBuffer DiagsBuffer;
+ Diagnostic Diags(&DiagsBuffer);
+
+ CompilerInvocation::CreateFromArgs(Clang.getInvocation(),
+ (const char**) argv + 1,
+ (const char**) argv + argc, argv[0],
+ (void*)(intptr_t) GetBuiltinIncludePath,
+ Diags);
+
+ // Create the actual diagnostics engine.
+ Clang.createDiagnostics(argc, argv);
+ if (!Clang.hasDiagnostics())
+ 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*>(&Clang.getDiagnostics()));
+
+ DiagsBuffer.FlushDiagnostics(Clang.getDiagnostics());
+
+ // If there were any errors in processing arguments, exit now.
+ if (Clang.getDiagnostics().getNumErrors())
+ return 1;
+#endif
+
+ // Create the target instance.
+ Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+ Clang.getTargetOpts()));
if (!Clang.hasTarget())
return 1;
+ // Inform the target of the language options
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+
// Validate/process some options
if (Clang.getHeaderSearchOpts().Verbose)
llvm::errs() << "clang-cc version " CLANG_VERSION_STRING
@@ -239,19 +345,15 @@ int main(int argc, char **argv) {
<< " hosted on " << llvm::sys::getHostTriple() << "\n";
if (Clang.getFrontendOpts().ShowTimers)
- ClangFrontendTimer = new llvm::Timer("Clang front-end time");
-
- // Enforce certain implications.
- if (!Clang.getFrontendOpts().ViewClassInheritance.empty())
- Clang.getFrontendOpts().ProgramAction = frontend::InheritanceView;
- if (!Clang.getFrontendOpts().FixItLocations.empty())
- Clang.getFrontendOpts().ProgramAction = frontend::FixIt;
+ Clang.createFrontendTimer();
for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) {
const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second;
// If we aren't using an AST file, setup the file and source managers and
// the preprocessor.
+ bool IsAST =
+ Clang.getFrontendOpts().Inputs[i].first == FrontendOptions::IK_AST;
if (!IsAST) {
if (!i) {
// Create a file manager object to provide access to and cache the
@@ -273,7 +375,6 @@ int main(int argc, char **argv) {
if (!Act)
break;
- Act->setCurrentTimer(ClangFrontendTimer);
if (Act->BeginSourceFile(Clang, InFile, IsAST)) {
Act->Execute();
Act->EndSourceFile();
@@ -290,8 +391,6 @@ int main(int argc, char **argv) {
fprintf(stderr, "\n");
}
- delete ClangFrontendTimer;
-
// Return the appropriate status when verifying diagnostics.
//
// FIXME: If we could make getNumErrors() do the right thing, we wouldn't need
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 1a95380..7900211 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -3,7 +3,6 @@ set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
clangDriver
clangBasic
- clangFrontend
)
set(LLVM_LINK_COMPONENTS system support bitreader bitwriter)
@@ -15,9 +14,15 @@ add_clang_executable(clang
add_dependencies(clang clang-cc)
+if(UNIX)
+ set(CLANGXX_LINK_OR_COPY create_symlink)
+else()
+ set(CLANGXX_LINK_OR_COPY copy)
+endif()
+
# Create the clang++ symlink in the build directory.
add_custom_target(clang++ ALL
- ${CMAKE_COMMAND} -E create_symlink
+ ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY}
"${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}"
"${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}"
DEPENDS clang)
@@ -26,4 +31,4 @@ install(TARGETS clang
RUNTIME DESTINATION bin)
# Create the clang++ symlink at installation time.
-install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E create_symlink \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
+install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -E ${CLANGXX_LINK_OR_COPY} \"${CMAKE_INSTALL_PREFIX}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}\" \"${CMAKE_INSTALL_PREFIX}/bin/clang++${CMAKE_EXECUTABLE_SUFFIX}\")")
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 19f93a2..f250651 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -19,7 +19,7 @@ TOOL_NO_EXPORTS = 1
# FIXME: It is unfortunate we need to pull in the bitcode reader and
# writer just to get the serializer stuff used by clangBasic.
LINK_COMPONENTS := system support bitreader bitwriter
-USEDLIBS = clangDriver.a clangBasic.a clangFrontend.a
+USEDLIBS = clangDriver.a clangBasic.a
include $(LEVEL)/Makefile.common
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index c516359..a9d27ef 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -11,78 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Driver/Arg.h"
-#include "clang/Driver/ArgList.h"
-#include "clang/Driver/CC1Options.h"
-#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Driver/Option.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "llvm/Support/raw_ostream.h"
-#include <cstdlib>
-#include <vector>
-using namespace clang;
-using namespace clang::driver;
-
-int cc1_main(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) {
+int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr) {
llvm::errs() << "cc1 argv:";
for (const char **i = ArgBegin; i != ArgEnd; ++i)
llvm::errs() << " \"" << *i << '"';
llvm::errs() << "\n";
- // Parse the arguments.
- OptTable *Opts = createCC1OptTable();
- unsigned MissingArgIndex, MissingArgCount;
- InputArgList *Args = Opts->ParseArgs(ArgBegin, ArgEnd,
- MissingArgIndex, MissingArgCount);
-
- // Check for missing argument error.
- if (MissingArgCount)
- Diags.Report(clang::diag::err_drv_missing_argument)
- << Args->getArgString(MissingArgIndex) << MissingArgCount;
-
- // Dump the parsed arguments.
- llvm::errs() << "cc1 parsed options:\n";
- for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
- it != ie; ++it)
- (*it)->dump();
-
- // Create a compiler invocation.
- llvm::errs() << "cc1 creating invocation.\n";
- CompilerInvocation Invocation;
- CompilerInvocation::CreateFromArgs(Invocation,
- llvm::SmallVector<llvm::StringRef, 32>(ArgBegin, ArgEnd));
-
- // Convert the invocation back to argument strings.
- std::vector<std::string> InvocationArgs;
- Invocation.toArgs(InvocationArgs);
-
- // Dump the converted arguments.
- llvm::SmallVector<llvm::StringRef, 32> Invocation2Args;
- llvm::errs() << "invocation argv:";
- for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) {
- Invocation2Args.push_back(InvocationArgs[i]);
- llvm::errs() << " \"" << InvocationArgs[i] << '"';
- }
- llvm::errs() << "\n";
-
- // Convert those arguments to another invocation, and check that we got the
- // same thing.
- CompilerInvocation Invocation2;
- CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args);
-
- // FIXME: Implement CompilerInvocation comparison.
- if (memcmp(&Invocation, &Invocation2, sizeof(Invocation)) != 0) {
- llvm::errs() << "warning: Invocations differ!\n";
-
- std::vector<std::string> Invocation2Args;
- Invocation2.toArgs(Invocation2Args);
- llvm::errs() << "invocation argv:";
- for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i)
- llvm::errs() << " \"" << Invocation2Args[i] << '"';
- llvm::errs() << "\n";
- }
-
return 0;
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index dbfc293..c61ee72 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -178,22 +178,23 @@ void ApplyQAOverride(std::vector<const char*> &Args, const char *OverrideStr,
}
}
-extern int cc1_main(Diagnostic &Diags,
- const char **ArgBegin, const char **ArgEnd);
+extern int cc1_main(const char **ArgBegin, const char **ArgEnd,
+ const char *Argv0, void *MainAddr);
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
+ // Dispatch to cc1_main if appropriate.
+ if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1")
+ return cc1_main(argv+2, argv+argc, argv[0],
+ (void*) (intptr_t) GetExecutablePath);
+
llvm::sys::Path Path = GetExecutablePath(argv[0]);
DriverDiagnosticPrinter DiagClient(Path.getBasename(), llvm::errs());
Diagnostic Diags(&DiagClient);
- // Dispatch to cc1_main if appropriate.
- if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1")
- return cc1_main(Diags, argv+2, argv+argc);
-
#ifdef CLANG_IS_PRODUCTION
bool IsProduction = true;
#else
@@ -208,7 +209,9 @@ int main(int argc, const char **argv) {
//
// Note that we intentionally want to use argv[0] here, to support "clang++"
// being a symlink.
- std::string ProgName(llvm::sys::Path(argv[0]).getBasename());
+ //
+ // We use *argv instead of argv[0] to work around a bogus g++ warning.
+ std::string ProgName(llvm::sys::Path(*argv).getBasename());
if (llvm::StringRef(ProgName).endswith("++") ||
llvm::StringRef(ProgName).rsplit('-').first.endswith("++"))
TheDriver.CCCIsCXX = true;
diff --git a/tools/index-test/CMakeLists.txt b/tools/index-test/CMakeLists.txt
index 9c9656a..163afc4 100644
--- a/tools/index-test/CMakeLists.txt
+++ b/tools/index-test/CMakeLists.txt
@@ -3,8 +3,10 @@ set(LLVM_NO_RTTI 1)
set( LLVM_USED_LIBS
clangIndex
clangFrontend
+ clangAnalysis
clangSema
clangAST
+ clangParse
clangLex
clangBasic
)
diff --git a/tools/index-test/Makefile b/tools/index-test/Makefile
index 76602e1..8e7bfe5 100644
--- a/tools/index-test/Makefile
+++ b/tools/index-test/Makefile
@@ -19,6 +19,7 @@ TOOL_NO_EXPORTS = 1
include $(LEVEL)/Makefile.config
LINK_COMPONENTS := bitreader mc
-USEDLIBS = clangIndex.a clangFrontend.a clangSema.a clangAST.a clangLex.a clangBasic.a
+USEDLIBS = clangIndex.a clangFrontend.a clangDriver.a clangAnalysis.a clangSema.a \
+ clangAST.a clangParse.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 fce48ed..dd7cbb2 100644
--- a/tools/index-test/index-test.cpp
+++ b/tools/index-test/index-test.cpp
@@ -43,6 +43,10 @@
#include "clang/Index/Analyzer.h"
#include "clang/Index/Utils.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
@@ -202,9 +206,24 @@ static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
}
}
+static llvm::cl::opt<bool>
+ASTFromSource("ast-from-source",
+ llvm::cl::desc("Treat the inputs as source files to parse."));
+
static llvm::cl::list<std::string>
InputFilenames(llvm::cl::Positional, llvm::cl::desc("<input AST files>"));
+void CreateCompilerInvocation(const std::string &Filename,
+ CompilerInvocation &CI, Diagnostic &Diags,
+ const char *argv0) {
+ llvm::SmallVector<const char *, 16> Args;
+ Args.push_back(Filename.c_str());
+
+ void *MainAddr = (void*) (intptr_t) CreateCompilerInvocation;
+ CompilerInvocation::CreateFromArgs(CI, Args.data(), Args.data() + Args.size(),
+ argv0, MainAddr, Diags);
+}
+
int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc, argv);
@@ -215,6 +234,10 @@ int main(int argc, char **argv) {
Indexer Idxer(Prog);
llvm::SmallVector<TUnit*, 4> TUnits;
+ TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions(), false);
+ llvm::OwningPtr<Diagnostic> Diags(
+ CompilerInstance::createDiagnostics(DiagnosticOptions(), argc, argv));
+
// If no input was specified, read from stdin.
if (InputFilenames.empty())
InputFilenames.push_back("-");
@@ -225,7 +248,15 @@ int main(int argc, char **argv) {
std::string ErrMsg;
llvm::OwningPtr<ASTUnit> AST;
- AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));
+ if (ASTFromSource) {
+ CompilerInvocation CI;
+ CreateCompilerInvocation(InFile, CI, *Diags, argv[0]);
+ AST.reset(ASTUnit::LoadFromCompilerInvocation(CI, *Diags));
+ if (!AST)
+ ErrMsg = "unable to create AST";
+ } else
+ AST.reset(ASTUnit::LoadFromPCHFile(InFile, &ErrMsg));
+
if (!AST) {
llvm::errs() << "[" << InFile << "] Error: " << ErrMsg << '\n';
return 1;
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
new file mode 100755
index 0000000..25b9800
--- /dev/null
+++ b/tools/scan-build/ccc-analyzer
@@ -0,0 +1,632 @@
+#!/usr/bin/env perl
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# A script designed to interpose between the build system and gcc. It invokes
+# both gcc and the static analyzer.
+#
+##===----------------------------------------------------------------------===##
+
+use strict;
+use warnings;
+use Cwd qw/ getcwd abs_path /;
+use File::Temp qw/ tempfile /;
+use File::Path qw / mkpath /;
+use File::Basename;
+use Text::ParseWords;
+
+my $CC = $ENV{'CCC_CC'};
+if (!defined $CC) { $CC = "gcc"; }
+
+my $ReportFailures = $ENV{'CCC_REPORT_FAILURES'};
+if (!defined $ReportFailures) { $ReportFailures = 1; }
+
+my $CleanupFile;
+my $ResultFile;
+
+# Remove any stale files at exit.
+END {
+ if (defined $CleanupFile && -z $CleanupFile) {
+ `rm -f $CleanupFile`;
+ }
+}
+
+##----------------------------------------------------------------------------##
+# Process Clang Crashes.
+##----------------------------------------------------------------------------##
+
+sub GetPPExt {
+ my $Lang = shift;
+ if ($Lang =~ /objective-c/) { return ".mi"; }
+ return ".i";
+}
+
+# Set this to 1 if we want to include 'parser rejects' files.
+my $IncludeParserRejects = 0;
+my $ParserRejects = "Parser Rejects";
+
+my $AttributeIgnored = "Attribute Ignored";
+
+sub ProcessClangFailure {
+ my ($ClangCC, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_;
+ my $Dir = "$HtmlDir/failures";
+ mkpath $Dir;
+
+ my $prefix = "clang_crash";
+ if ($ErrorType eq $ParserRejects) {
+ $prefix = "clang_parser_rejects";
+ }
+ elsif ($ErrorType eq $AttributeIgnored) {
+ $prefix = "clang_attribute_ignored";
+ }
+
+ # Generate the preprocessed file with Clang.
+ my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
+ SUFFIX => GetPPExt($Lang),
+ DIR => $Dir);
+ system $ClangCC, @$Args, "-E", "-o", $PPFile;
+ close ($PPH);
+
+ # Create the info file.
+ open (OUT, ">", "$PPFile.info.txt") or die "Cannot open $PPFile.info.txt\n";
+ print OUT abs_path($file), "\n";
+ print OUT "$ErrorType\n";
+ print OUT "@$Args\n";
+ close OUT;
+ `uname -a >> $PPFile.info.txt 2>&1`;
+ `$CC -v >> $PPFile.info.txt 2>&1`;
+ system 'mv',$ofile,"$PPFile.stderr.txt";
+ return (basename $PPFile);
+}
+
+##----------------------------------------------------------------------------##
+# Running the analyzer.
+##----------------------------------------------------------------------------##
+
+# Determine what clang executable to use.
+my $Clang = $ENV{'CLANG'};
+if (!defined $Clang) { $Clang = 'clang'; }
+
+sub GetCCArgs {
+ my $Args = shift;
+
+ pipe (FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, "-###", "-fsyntax-only", @$Args;
+ }
+ close(TO_PARENT);
+ my $line;
+ while (<FROM_CHILD>) {
+ next if (!/clang-cc/);
+ $line = $_;
+ }
+
+ waitpid($pid,0);
+ close(FROM_CHILD);
+
+ die "could not find clang-cc line\n" if (!defined $line);
+ # Strip the newline and initial whitspace
+ chomp $line;
+ $line =~ s/^\s+//;
+
+ my @items = quotewords('\s+', 1, $line);
+ for (my $i = 0 ; $ i < scalar(@items); ++$i) {
+ $items[$i] =~ s/^\"//;
+ $items[$i] =~ s/\"$//;
+ }
+ my $cmd = shift @items;
+ die "cannot find 'clang-cc' in 'clang' command\n" if (!($cmd =~ /clang-cc/));
+ return \@items;
+}
+
+sub Analyze {
+ my ($ClangCC, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir,
+ $file, $Analyses) = @_;
+
+ $Args = GetCCArgs($Args);
+
+ # Skip anything related to C++.
+ return if ($Lang =~ /c[+][+]/);
+
+ my $RunAnalyzer = 0;
+ my $Cmd;
+ my @CmdArgs;
+ my @CmdArgsSansAnalyses;
+
+ if ($Lang =~ /header/) {
+ exit 0 if (!defined ($Output));
+ $Cmd = 'cp';
+ push @CmdArgs,$file;
+ # Remove the PCH extension.
+ $Output =~ s/[.]gch$//;
+ push @CmdArgs,$Output;
+ @CmdArgsSansAnalyses = @CmdArgs;
+ }
+ else {
+ $Cmd = $ClangCC;
+ push @CmdArgs,'-DIBOutlet=__attribute__((iboutlet))';
+ push @CmdArgs,@$Args;
+ @CmdArgsSansAnalyses = @CmdArgs;
+ push @CmdArgs,'-analyze';
+ push @CmdArgs,"-analyzer-display-progress";
+ push @CmdArgs,"-analyzer-eagerly-assume";
+ push @CmdArgs,(split /\s/,$Analyses);
+
+ if (defined $ENV{"CCC_EXPERIMENTAL_CHECKS"}) {
+ push @CmdArgs,"-analyzer-experimental-internal-checks";
+ push @CmdArgs,"-analyzer-experimental-checks";
+ }
+
+ $RunAnalyzer = 1;
+ }
+
+ # Add the analysis arguments passed down from scan-build.
+ foreach my $Arg (@$AnalyzeArgs) {
+ push @CmdArgs, $Arg;
+ }
+
+ my @PrintArgs;
+ my $dir;
+
+ if ($RunAnalyzer) {
+ if (defined $ResultFile) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $ResultFile;
+ }
+ elsif (defined $HtmlDir) {
+ push @CmdArgs,'-o';
+ push @CmdArgs, $HtmlDir;
+ }
+ }
+
+ if ($Verbose) {
+ $dir = getcwd();
+ print STDERR "\n[LOCATION]: $dir\n";
+ push @PrintArgs,"'$Cmd'";
+ foreach my $arg (@CmdArgs) { push @PrintArgs,"\'$arg\'"; }
+ }
+
+ if ($Verbose == 1) {
+ # We MUST print to stderr. Some clients use the stdout output of
+ # gcc for various purposes.
+ print STDERR join(' ',@PrintArgs);
+ print STDERR "\n";
+ }
+ elsif ($Verbose == 2) {
+ print STDERR "#SHELL (cd '$dir' && @PrintArgs)\n";
+ }
+
+ if (defined $ENV{'CCC_UBI'}) {
+ push @CmdArgs,"--analyzer-viz-egraph-ubigraph";
+ }
+
+ # Capture the STDERR of clang and send it to a temporary file.
+ # Capture the STDOUT of clang and reroute it to ccc-analyzer's STDERR.
+ # We save the output file in the 'crashes' directory if clang encounters
+ # any problems with the file.
+ pipe (FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Cmd, @CmdArgs;
+ }
+
+ close TO_PARENT;
+ my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir);
+
+ while (<FROM_CHILD>) {
+ print $ofh $_;
+ print STDERR $_;
+ }
+
+ waitpid($pid,0);
+ close(FROM_CHILD);
+ my $Result = $?;
+
+ # Did the command die because of a signal?
+ if ($ReportFailures) {
+ if ($Result & 127 and $Cmd eq $ClangCC and defined $HtmlDir) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, "Crash", $ofile);
+ }
+ elsif ($Result) {
+ if ($IncludeParserRejects && !($file =~/conftest/)) {
+ ProcessClangFailure($ClangCC, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, $ParserRejects, $ofile);
+ }
+ }
+ else {
+ # Check if there were any unhandled attributes.
+ if (open(CHILD, $ofile)) {
+ my %attributes_not_handled;
+
+ # Don't flag warnings about the following attributes that we
+ # know are currently not supported by Clang.
+ $attributes_not_handled{"cdecl"} = 1;
+
+ my $ppfile;
+ while (<CHILD>) {
+ next if (! /warning: '([^\']+)' attribute ignored/);
+
+ # Have we already spotted this unhandled attribute?
+ next if (defined $attributes_not_handled{$1});
+ $attributes_not_handled{$1} = 1;
+
+ # Get the name of the attribute file.
+ my $dir = "$HtmlDir/failures";
+ my $afile = "$dir/attribute_ignored_$1.txt";
+
+ # Only create another preprocessed file if the attribute file
+ # doesn't exist yet.
+ next if (-e $afile);
+
+ # Add this file to the list of files that contained this attribute.
+ # Generate a preprocessed file if we haven't already.
+ if (!(defined $ppfile)) {
+ $ppfile = ProcessClangFailure($ClangCC, $Lang, $file,
+ \@CmdArgsSansAnalyses,
+ $HtmlDir, $AttributeIgnored, $ofile);
+ }
+
+ mkpath $dir;
+ open(AFILE, ">$afile");
+ print AFILE "$ppfile\n";
+ close(AFILE);
+ }
+ close CHILD;
+ }
+ }
+ }
+
+ unlink($ofile);
+}
+
+##----------------------------------------------------------------------------##
+# Lookup tables.
+##----------------------------------------------------------------------------##
+
+my %CompileOptionMap = (
+ '-nostdinc' => 0,
+ '-fblocks' => 0,
+ '-fobjc-gc-only' => 0,
+ '-fobjc-gc' => 0,
+ '-ffreestanding' => 0,
+ '-include' => 1,
+ '-idirafter' => 1,
+ '-iprefix' => 1,
+ '-iquote' => 1,
+ '-isystem' => 1,
+ '-iwithprefix' => 1,
+ '-iwithprefixbefore' => 1
+);
+
+my %LinkerOptionMap = (
+ '-framework' => 1
+);
+
+my %CompilerLinkerOptionMap = (
+ '-isysroot' => 1,
+ '-arch' => 1,
+ '-v' => 0,
+ '-fpascal-strings' => 0,
+ '-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '='
+ '-miphoneos-version-min' => 0 # This is really a 1 argument, but always has '='
+);
+
+my %IgnoredOptionMap = (
+ '-MT' => 1, # Ignore these preprocessor options.
+ '-MF' => 1,
+
+ '-fsyntax-only' => 0,
+ '-save-temps' => 0,
+ '-install_name' => 1,
+ '-exported_symbols_list' => 1,
+ '-current_version' => 1,
+ '-compatibility_version' => 1,
+ '-init' => 1,
+ '-e' => 1,
+ '-seg1addr' => 1,
+ '-bundle_loader' => 1,
+ '-multiply_defined' => 1,
+ '-sectorder' => 3,
+ '--param' => 1,
+ '-u' => 1
+);
+
+my %LangMap = (
+ 'c' => 'c',
+ 'cpp' => 'c++',
+ 'cc' => 'c++',
+ 'i' => 'c-cpp-output',
+ 'm' => 'objective-c',
+ 'mi' => 'objective-c-cpp-output'
+);
+
+my %UniqueOptions = (
+ '-isysroot' => 0
+);
+
+my %LangsAccepted = (
+ "objective-c" => 1,
+ "c" => 1
+);
+
+##----------------------------------------------------------------------------##
+# Main Logic.
+##----------------------------------------------------------------------------##
+
+my $Action = 'link';
+my @CompileOpts;
+my @LinkOpts;
+my @Files;
+my $Lang;
+my $Output;
+my %Uniqued;
+
+# Forward arguments to gcc.
+my $Status = system($CC,@ARGV);
+if ($Status) { exit($Status >> 8); }
+
+# Get the analysis options.
+my $Analyses = $ENV{'CCC_ANALYZER_ANALYSIS'};
+if (!defined($Analyses)) { $Analyses = '-checker-cfref'; }
+
+# Get the store model.
+my $StoreModel = $ENV{'CCC_ANALYZER_STORE_MODEL'};
+if (!defined $StoreModel) { $StoreModel = "region"; }
+
+# Get the constraints engine.
+my $ConstraintsModel = $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'};
+if (!defined $ConstraintsModel) { $ConstraintsModel = "range"; }
+
+# Get the output format.
+my $OutputFormat = $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'};
+if (!defined $OutputFormat) { $OutputFormat = "html"; }
+
+# Determine the level of verbosity.
+my $Verbose = 0;
+if (defined $ENV{CCC_ANALYZER_VERBOSE}) { $Verbose = 1; }
+if (defined $ENV{CCC_ANALYZER_LOG}) { $Verbose = 2; }
+
+# Determine what clang-cc executable to use.
+my $ClangCC = $ENV{'CLANG_CC'};
+if (!defined $ClangCC) { $ClangCC = 'clang-cc'; }
+
+# Get the HTML output directory.
+my $HtmlDir = $ENV{'CCC_ANALYZER_HTML'};
+
+my %DisabledArchs = ('ppc' => 1, 'ppc64' => 1);
+my %ArchsSeen;
+my $HadArch = 0;
+
+# Process the arguments.
+foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
+ my $Arg = $ARGV[$i];
+ my ($ArgKey) = split /=/,$Arg,2;
+
+ # Modes ccc-analyzer supports
+ if ($Arg =~ /^-(E|MM?)$/) { $Action = 'preprocess'; }
+ elsif ($Arg eq '-c') { $Action = 'compile'; }
+ elsif ($Arg =~ /^-print-prog-name/) { exit 0; }
+
+ # Specially handle duplicate cases of -arch
+ if ($Arg eq "-arch") {
+ my $arch = $ARGV[$i+1];
+ # We don't want to process 'ppc' because of Clang's lack of support
+ # for Altivec (also some #defines won't likely be defined correctly, etc.)
+ if (!(defined $DisabledArchs{$arch})) { $ArchsSeen{$arch} = 1; }
+ $HadArch = 1;
+ ++$i;
+ next;
+ }
+
+ # Options with possible arguments that should pass through to compiler.
+ if (defined $CompileOptionMap{$ArgKey}) {
+ my $Cnt = $CompileOptionMap{$ArgKey};
+ push @CompileOpts,$Arg;
+ while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
+ next;
+ }
+
+ # Options with possible arguments that should pass through to linker.
+ if (defined $LinkerOptionMap{$ArgKey}) {
+ my $Cnt = $LinkerOptionMap{$ArgKey};
+ push @LinkOpts,$Arg;
+ while ($Cnt > 0) { ++$i; --$Cnt; push @LinkOpts, $ARGV[$i]; }
+ next;
+ }
+
+ # Options with possible arguments that should pass through to both compiler
+ # and the linker.
+ if (defined $CompilerLinkerOptionMap{$ArgKey}) {
+ my $Cnt = $CompilerLinkerOptionMap{$ArgKey};
+
+ # Check if this is an option that should have a unique value, and if so
+ # determine if the value was checked before.
+ if ($UniqueOptions{$Arg}) {
+ if (defined $Uniqued{$Arg}) {
+ $i += $Cnt;
+ next;
+ }
+ $Uniqued{$Arg} = 1;
+ }
+
+ push @CompileOpts,$Arg;
+ push @LinkOpts,$Arg;
+
+ while ($Cnt > 0) {
+ ++$i; --$Cnt;
+ push @CompileOpts, $ARGV[$i];
+ push @LinkOpts, $ARGV[$i];
+ }
+ next;
+ }
+
+ # Ignored options.
+ if (defined $IgnoredOptionMap{$ArgKey}) {
+ my $Cnt = $IgnoredOptionMap{$ArgKey};
+ while ($Cnt > 0) {
+ ++$i; --$Cnt;
+ }
+ next;
+ }
+
+ # Compile mode flags.
+ if ($Arg =~ /^-[D,I,U](.*)$/) {
+ my $Tmp = $Arg;
+ if ($1 eq '') {
+ # FIXME: Check if we are going off the end.
+ ++$i;
+ $Tmp = $Arg . $ARGV[$i];
+ }
+ push @CompileOpts,$Tmp;
+ next;
+ }
+
+ # Language.
+ if ($Arg eq '-x') {
+ $Lang = $ARGV[$i+1];
+ ++$i; next;
+ }
+
+ # Output file.
+ if ($Arg eq '-o') {
+ ++$i;
+ $Output = $ARGV[$i];
+ next;
+ }
+
+ # Get the link mode.
+ if ($Arg =~ /^-[l,L,O]/) {
+ if ($Arg eq '-O') { push @LinkOpts,'-O1'; }
+ elsif ($Arg eq '-Os') { push @LinkOpts,'-O2'; }
+ else { push @LinkOpts,$Arg; }
+ next;
+ }
+
+ if ($Arg =~ /^-std=/) {
+ push @CompileOpts,$Arg;
+ next;
+ }
+
+# if ($Arg =~ /^-f/) {
+# # FIXME: Not sure if the remaining -fxxxx options have no arguments.
+# push @CompileOpts,$Arg;
+# push @LinkOpts,$Arg; # FIXME: Not sure if these are link opts.
+# }
+
+ # Get the compiler/link mode.
+ if ($Arg =~ /^-F(.+)$/) {
+ my $Tmp = $Arg;
+ if ($1 eq '') {
+ # FIXME: Check if we are going off the end.
+ ++$i;
+ $Tmp = $Arg . $ARGV[$i];
+ }
+ push @CompileOpts,$Tmp;
+ push @LinkOpts,$Tmp;
+ next;
+ }
+
+ # Input files.
+ if ($Arg eq '-filelist') {
+ # FIXME: Make sure we aren't walking off the end.
+ open(IN, $ARGV[$i+1]);
+ while (<IN>) { s/\015?\012//; push @Files,$_; }
+ close(IN);
+ ++$i;
+ next;
+ }
+
+ # Handle -Wno-. We don't care about extra warnings, but
+ # we should suppress ones that we don't want to see.
+ if ($Arg =~ /^-Wno-/) {
+ push @CompileOpts, $Arg;
+ next;
+ }
+
+ if (!($Arg =~ /^-/)) {
+ push @Files, $Arg;
+ next;
+ }
+}
+
+if ($Action eq 'compile' or $Action eq 'link') {
+ my @Archs = keys %ArchsSeen;
+ # Skip the file if we don't support the architectures specified.
+ exit 0 if ($HadArch && scalar(@Archs) == 0);
+
+ foreach my $file (@Files) {
+ # Determine the language for the file.
+ my $FileLang = $Lang;
+
+ if (!defined($FileLang)) {
+ # Infer the language from the extension.
+ if ($file =~ /[.]([^.]+)$/) {
+ $FileLang = $LangMap{$1};
+ }
+ }
+
+ next if (!defined $FileLang);
+ next if (!defined $LangsAccepted{$FileLang});
+
+ my @CmdArgs;
+ my @AnalyzeArgs;
+
+ if ($FileLang ne 'unknown') {
+ push @CmdArgs,'-x';
+ push @CmdArgs,$FileLang;
+ }
+
+ if (defined $StoreModel) {
+ push @AnalyzeArgs, "-analyzer-store=$StoreModel";
+ }
+
+ if (defined $ConstraintsModel) {
+ push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
+ }
+
+ if (defined $OutputFormat) {
+ push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;
+ if ($OutputFormat =~ /plist/) {
+ # Change "Output" to be a file.
+ my ($h, $f) = tempfile("report-XXXXXX", SUFFIX => ".plist",
+ DIR => $HtmlDir);
+ $ResultFile = $f;
+ $CleanupFile = $f;
+ }
+ }
+
+ push @CmdArgs,@CompileOpts;
+ push @CmdArgs,$file;
+
+ if (scalar @Archs) {
+ foreach my $arch (@Archs) {
+ my @NewArgs;
+ push @NewArgs, '-arch';
+ push @NewArgs, $arch;
+ push @NewArgs, @CmdArgs;
+ Analyze($ClangCC, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output,
+ $Verbose, $HtmlDir, $file, $Analyses);
+ }
+ }
+ else {
+ Analyze($ClangCC, \@CmdArgs, \@AnalyzeArgs, $FileLang, $Output,
+ $Verbose, $HtmlDir, $file, $Analyses);
+ }
+ }
+}
+
+exit($Status >> 8);
+
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
new file mode 100755
index 0000000..8d99f07
--- /dev/null
+++ b/tools/scan-build/scan-build
@@ -0,0 +1,1297 @@
+#!/usr/bin/env perl
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+#
+# A script designed to wrap a build so that all calls to gcc are intercepted
+# and piped to the static analyzer.
+#
+##===----------------------------------------------------------------------===##
+
+use strict;
+use warnings;
+use FindBin qw($RealBin);
+use Digest::MD5;
+use File::Basename;
+use Term::ANSIColor;
+use Term::ANSIColor qw(:constants);
+use Cwd qw/ getcwd abs_path /;
+use Sys::Hostname;
+
+my $Verbose = 0; # Verbose output from this script.
+my $Prog = "scan-build";
+my $BuildName;
+my $BuildDate;
+my $CXX; # Leave undefined initially.
+
+my $TERM = $ENV{'TERM'};
+my $UseColor = (defined $TERM and $TERM eq 'xterm-color' and -t STDOUT
+ and defined $ENV{'SCAN_BUILD_COLOR'});
+
+my $UserName = HtmlEscape(getpwuid($<) || 'unknown');
+my $HostName = HtmlEscape(hostname() || 'unknown');
+my $CurrentDir = HtmlEscape(getcwd());
+my $CurrentDirSuffix = basename($CurrentDir);
+
+my $CmdArgs;
+
+my $HtmlTitle;
+
+my $Date = localtime();
+
+##----------------------------------------------------------------------------##
+# Diagnostics
+##----------------------------------------------------------------------------##
+
+sub Diag {
+ if ($UseColor) {
+ print BOLD, MAGENTA "$Prog: @_";
+ print RESET;
+ }
+ else {
+ print "$Prog: @_";
+ }
+}
+
+sub DiagCrashes {
+ my $Dir = shift;
+ Diag ("The analyzer encountered problems on some source files.\n");
+ Diag ("Preprocessed versions of these sources were deposited in '$Dir/failures'.\n");
+ Diag ("Please consider submitting a bug report using these files:\n");
+ Diag (" http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\n")
+}
+
+sub DieDiag {
+ if ($UseColor) {
+ print BOLD, RED "$Prog: ";
+ print RESET, RED @_;
+ print RESET;
+ }
+ else {
+ print "$Prog: ", @_;
+ }
+ exit(0);
+}
+
+##----------------------------------------------------------------------------##
+# Some initial preprocessing of Clang options.
+##----------------------------------------------------------------------------##
+
+# First, look for 'clang-cc' in libexec.
+my $ClangCCSB = Cwd::realpath("$RealBin/libexec/clang-cc");
+# Second, look for 'clang-cc' in the same directory as scan-build.
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = Cwd::realpath("$RealBin/clang-cc");
+}
+# Third, look for 'clang-cc' in ../libexec
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = Cwd::realpath("$RealBin/../libexec/clang-cc");
+}
+# Finally, default to looking for 'clang-cc' in the path.
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ $ClangCCSB = "clang-cc";
+}
+my $ClangCC = $ClangCCSB;
+
+# Now find 'clang'
+my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = Cwd::realpath("$RealBin/clang");
+}
+# Third, look for 'clang' in ../bin
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = Cwd::realpath("$RealBin/../bin/clang");
+}
+# Finally, default to looking for 'clang-cc' in the path.
+if (!defined $ClangSB || ! -x $ClangSB) {
+ $ClangSB = "clang";
+}
+my $Clang = $ClangSB;
+
+
+my %AvailableAnalyses;
+
+# Query clang for analysis options.
+open(PIPE, "-|", $ClangCC, "--help") or
+ DieDiag("Cannot execute '$ClangCC'\n");
+
+my $FoundAnalysis = 0;
+
+while(<PIPE>) {
+ if ($FoundAnalysis == 0) {
+ if (/Checks and Analyses/) {
+ $FoundAnalysis = 1;
+ }
+ next;
+ }
+
+ if (/^\s\s\s\s([^\s]+)\s(.+)$/) {
+ next if ($1 =~ /-dump/ or $1 =~ /-view/
+ or $1 =~ /-warn-uninit/);
+
+ $AvailableAnalyses{$1} = $2;
+ next;
+ }
+ last;
+}
+
+close (PIPE);
+
+my %AnalysesDefaultEnabled = (
+ '-warn-dead-stores' => 1,
+ '-checker-cfref' => 1,
+ '-warn-objc-methodsigs' => 1,
+ # Do not enable the missing -dealloc check by default.
+ # '-warn-objc-missing-dealloc' => 1,
+ '-warn-objc-unused-ivars' => 1,
+ '-warn-security-syntactic' => 1
+);
+
+##----------------------------------------------------------------------------##
+# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
+##----------------------------------------------------------------------------##
+
+sub GetHTMLRunDir {
+
+ die "Not enough arguments." if (@_ == 0);
+ my $Dir = shift @_;
+
+ my $TmpMode = 0;
+ if (!defined $Dir) {
+ if (`uname` =~ /Darwin/) {
+ $Dir = $ENV{'TMPDIR'};
+ if (!defined $Dir) { $Dir = "/tmp"; }
+ }
+ else {
+ $Dir = "/tmp";
+ }
+
+ $TmpMode = 1;
+ }
+
+ # Chop off any trailing '/' characters.
+ while ($Dir =~ /\/$/) { chop $Dir; }
+
+ # Get current date and time.
+
+ my @CurrentTime = localtime();
+
+ my $year = $CurrentTime[5] + 1900;
+ my $day = $CurrentTime[3];
+ my $month = $CurrentTime[4] + 1;
+
+ my $DateString = sprintf("%d-%02d-%02d", $year, $month, $day);
+
+ # Determine the run number.
+
+ my $RunNumber;
+
+ if (-d $Dir) {
+
+ if (! -r $Dir) {
+ DieDiag("directory '$Dir' exists but is not readable.\n");
+ }
+
+ # Iterate over all files in the specified directory.
+
+ my $max = 0;
+
+ opendir(DIR, $Dir);
+ my @FILES = grep { -d "$Dir/$_" } readdir(DIR);
+ closedir(DIR);
+
+ foreach my $f (@FILES) {
+
+ # Strip the prefix '$Prog-' if we are dumping files to /tmp.
+ if ($TmpMode) {
+ next if (!($f =~ /^$Prog-(.+)/));
+ $f = $1;
+ }
+
+
+ my @x = split/-/, $f;
+ next if (scalar(@x) != 4);
+ next if ($x[0] != $year);
+ next if ($x[1] != $month);
+ next if ($x[2] != $day);
+
+ if ($x[3] > $max) {
+ $max = $x[3];
+ }
+ }
+
+ $RunNumber = $max + 1;
+ }
+ else {
+
+ if (-x $Dir) {
+ DieDiag("'$Dir' exists but is not a directory.\n");
+ }
+
+ if ($TmpMode) {
+ DieDiag("The directory '/tmp' does not exist or cannot be accessed.\n");
+ }
+
+ # $Dir does not exist. It will be automatically created by the
+ # clang driver. Set the run number to 1.
+
+ $RunNumber = 1;
+ }
+
+ die "RunNumber must be defined!" if (!defined $RunNumber);
+
+ # Append the run number.
+ my $NewDir;
+ if ($TmpMode) {
+ $NewDir = "$Dir/$Prog-$DateString-$RunNumber";
+ }
+ else {
+ $NewDir = "$Dir/$DateString-$RunNumber";
+ }
+ system 'mkdir','-p',$NewDir;
+ return $NewDir;
+}
+
+sub SetHtmlEnv {
+
+ die "Wrong number of arguments." if (scalar(@_) != 2);
+
+ my $Args = shift;
+ my $Dir = shift;
+
+ die "No build command." if (scalar(@$Args) == 0);
+
+ my $Cmd = $$Args[0];
+
+ if ($Cmd =~ /configure/) {
+ return;
+ }
+
+ if ($Verbose) {
+ Diag("Emitting reports for this run to '$Dir'.\n");
+ }
+
+ $ENV{'CCC_ANALYZER_HTML'} = $Dir;
+}
+
+##----------------------------------------------------------------------------##
+# ComputeDigest - Compute a digest of the specified file.
+##----------------------------------------------------------------------------##
+
+sub ComputeDigest {
+ my $FName = shift;
+ DieDiag("Cannot read $FName to compute Digest.\n") if (! -r $FName);
+
+ # Use Digest::MD5. We don't have to be cryptographically secure. We're
+ # just looking for duplicate files that come from a non-malicious source.
+ # We use Digest::MD5 because it is a standard Perl module that should
+ # come bundled on most systems.
+ open(FILE, $FName) or DieDiag("Cannot open $FName when computing Digest.\n");
+ binmode FILE;
+ my $Result = Digest::MD5->new->addfile(*FILE)->hexdigest;
+ close(FILE);
+
+ # Return the digest.
+ return $Result;
+}
+
+##----------------------------------------------------------------------------##
+# UpdatePrefix - Compute the common prefix of files.
+##----------------------------------------------------------------------------##
+
+my $Prefix;
+
+sub UpdatePrefix {
+ my $x = shift;
+ my $y = basename($x);
+ $x =~ s/\Q$y\E$//;
+
+ if (!defined $Prefix) {
+ $Prefix = $x;
+ return;
+ }
+
+ chop $Prefix while (!($x =~ /^\Q$Prefix/));
+}
+
+sub GetPrefix {
+ return $Prefix;
+}
+
+##----------------------------------------------------------------------------##
+# UpdateInFilePath - Update the path in the report file.
+##----------------------------------------------------------------------------##
+
+sub UpdateInFilePath {
+ my $fname = shift;
+ my $regex = shift;
+ my $newtext = shift;
+
+ open (RIN, $fname) or die "cannot open $fname";
+ open (ROUT, ">", "$fname.tmp") or die "cannot open $fname.tmp";
+
+ while (<RIN>) {
+ s/$regex/$newtext/;
+ print ROUT $_;
+ }
+
+ close (ROUT);
+ close (RIN);
+ system("mv", "$fname.tmp", $fname);
+}
+
+##----------------------------------------------------------------------------##
+# ScanFile - Scan a report file for various identifying attributes.
+##----------------------------------------------------------------------------##
+
+# Sometimes a source file is scanned more than once, and thus produces
+# multiple error reports. We use a cache to solve this problem.
+
+my %AlreadyScanned;
+
+sub ScanFile {
+
+ my $Index = shift;
+ my $Dir = shift;
+ my $FName = shift;
+
+ # Compute a digest for the report file. Determine if we have already
+ # scanned a file that looks just like it.
+
+ my $digest = ComputeDigest("$Dir/$FName");
+
+ if (defined $AlreadyScanned{$digest}) {
+ # Redundant file. Remove it.
+ system ("rm", "-f", "$Dir/$FName");
+ return;
+ }
+
+ $AlreadyScanned{$digest} = 1;
+
+ # At this point the report file is not world readable. Make it happen.
+ system ("chmod", "644", "$Dir/$FName");
+
+ # Scan the report file for tags.
+ open(IN, "$Dir/$FName") or DieDiag("Cannot open '$Dir/$FName'\n");
+
+ my $BugType = "";
+ my $BugFile = "";
+ my $BugCategory;
+ my $BugPathLength = 1;
+ my $BugLine = 0;
+
+ while (<IN>) {
+ last if (/<!-- BUGMETAEND -->/);
+
+ if (/<!-- BUGTYPE (.*) -->$/) {
+ $BugType = $1;
+ }
+ elsif (/<!-- BUGFILE (.*) -->$/) {
+ $BugFile = abs_path($1);
+ UpdatePrefix($BugFile);
+ }
+ elsif (/<!-- BUGPATHLENGTH (.*) -->$/) {
+ $BugPathLength = $1;
+ }
+ elsif (/<!-- BUGLINE (.*) -->$/) {
+ $BugLine = $1;
+ }
+ elsif (/<!-- BUGCATEGORY (.*) -->$/) {
+ $BugCategory = $1;
+ }
+ }
+
+ close(IN);
+
+ if (!defined $BugCategory) {
+ $BugCategory = "Other";
+ }
+
+ push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugLine,
+ $BugPathLength ];
+}
+
+##----------------------------------------------------------------------------##
+# CopyFiles - Copy resource files to target directory.
+##----------------------------------------------------------------------------##
+
+sub CopyFiles {
+
+ my $Dir = shift;
+
+ my $JS = Cwd::realpath("$RealBin/sorttable.js");
+
+ DieDiag("Cannot find 'sorttable.js'.\n")
+ if (! -r $JS);
+
+ system ("cp", $JS, "$Dir");
+
+ DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n")
+ if (! -r "$Dir/sorttable.js");
+
+ my $CSS = Cwd::realpath("$RealBin/scanview.css");
+
+ DieDiag("Cannot find 'scanview.css'.\n")
+ if (! -r $CSS);
+
+ system ("cp", $CSS, "$Dir");
+
+ DieDiag("Could not copy 'scanview.css' to '$Dir'.\n")
+ if (! -r $CSS);
+}
+
+##----------------------------------------------------------------------------##
+# Postprocess - Postprocess the results of an analysis scan.
+##----------------------------------------------------------------------------##
+
+sub Postprocess {
+
+ my $Dir = shift;
+ my $BaseDir = shift;
+
+ die "No directory specified." if (!defined $Dir);
+
+ if (! -d $Dir) {
+ Diag("No bugs found.\n");
+ return 0;
+ }
+
+ opendir(DIR, $Dir);
+ my @files = grep { /^report-.*\.html$/ } readdir(DIR);
+ closedir(DIR);
+
+ if (scalar(@files) == 0 and ! -e "$Dir/failures") {
+ Diag("Removing directory '$Dir' because it contains no reports.\n");
+ system ("rm", "-fR", $Dir);
+ return 0;
+ }
+
+ # Scan each report file and build an index.
+ my @Index;
+ foreach my $file (@files) { ScanFile(\@Index, $Dir, $file); }
+
+ # Scan the failures directory and use the information in the .info files
+ # to update the common prefix directory.
+ my @failures;
+ my @attributes_ignored;
+ if (-d "$Dir/failures") {
+ opendir(DIR, "$Dir/failures");
+ @failures = grep { /[.]info.txt$/ && !/attribute_ignored/; } readdir(DIR);
+ closedir(DIR);
+ opendir(DIR, "$Dir/failures");
+ @attributes_ignored = grep { /^attribute_ignored/; } readdir(DIR);
+ closedir(DIR);
+ foreach my $file (@failures) {
+ open IN, "$Dir/failures/$file" or DieDiag("cannot open $file\n");
+ my $Path = <IN>;
+ if (defined $Path) { UpdatePrefix($Path); }
+ close IN;
+ }
+ }
+
+ # Generate an index.html file.
+ my $FName = "$Dir/index.html";
+ open(OUT, ">", $FName) or DieDiag("Cannot create file '$FName'\n");
+
+ # Print out the header.
+
+print OUT <<ENDTEXT;
+<html>
+<head>
+<title>${HtmlTitle}</title>
+<link type="text/css" rel="stylesheet" href="scanview.css"/>
+<script src="sorttable.js"></script>
+<script language='javascript' type="text/javascript">
+function SetDisplay(RowClass, DisplayVal)
+{
+ var Rows = document.getElementsByTagName("tr");
+ for ( var i = 0 ; i < Rows.length; ++i ) {
+ if (Rows[i].className == RowClass) {
+ Rows[i].style.display = DisplayVal;
+ }
+ }
+}
+
+function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
+ var Inputs = document.getElementsByTagName("input");
+ for ( var i = 0 ; i < Inputs.length; ++i ) {
+ if (Inputs[i].type == "checkbox") {
+ if(Inputs[i] != SummaryCheckButton) {
+ Inputs[i].checked = SummaryCheckButton.checked;
+ Inputs[i].onclick();
+ }
+ }
+ }
+}
+
+function returnObjById( id ) {
+ if (document.getElementById)
+ var returnVar = document.getElementById(id);
+ else if (document.all)
+ var returnVar = document.all[id];
+ else if (document.layers)
+ var returnVar = document.layers[id];
+ return returnVar;
+}
+
+var NumUnchecked = 0;
+
+function ToggleDisplay(CheckButton, ClassName) {
+ if (CheckButton.checked) {
+ SetDisplay(ClassName, "");
+ if (--NumUnchecked == 0) {
+ returnObjById("AllBugsCheck").checked = true;
+ }
+ }
+ else {
+ SetDisplay(ClassName, "none");
+ NumUnchecked++;
+ returnObjById("AllBugsCheck").checked = false;
+ }
+}
+</script>
+<!-- SUMMARYENDHEAD -->
+</head>
+<body>
+<h1>${HtmlTitle}</h1>
+
+<table>
+<tr><th>User:</th><td>${UserName}\@${HostName}</td></tr>
+<tr><th>Working Directory:</th><td>${CurrentDir}</td></tr>
+<tr><th>Command Line:</th><td>${CmdArgs}</td></tr>
+<tr><th>Date:</th><td>${Date}</td></tr>
+ENDTEXT
+
+print OUT "<tr><th>Version:</th><td>${BuildName} (${BuildDate})</td></tr>\n"
+ if (defined($BuildName) && defined($BuildDate));
+
+print OUT <<ENDTEXT;
+</table>
+ENDTEXT
+
+ if (scalar(@files)) {
+ # Print out the summary table.
+ my %Totals;
+
+ for my $row ( @Index ) {
+ my $bug_type = ($row->[2]);
+ my $bug_category = ($row->[1]);
+ my $key = "$bug_category:$bug_type";
+
+ if (!defined $Totals{$key}) { $Totals{$key} = [1,$bug_category,$bug_type]; }
+ else { $Totals{$key}->[0]++; }
+ }
+
+ print OUT "<h2>Bug Summary</h2>";
+
+ if (defined $BuildName) {
+ print OUT "\n<p>Results in this analysis run are based on analyzer build <b>$BuildName</b>.</p>\n"
+ }
+
+ my $TotalBugs = scalar(@Index);
+print OUT <<ENDTEXT;
+<table>
+<thead><tr><td>Bug Type</td><td>Quantity</td><td class="sorttable_nosort">Display?</td></tr></thead>
+<tr style="font-weight:bold"><td class="SUMM_DESC">All Bugs</td><td class="Q">$TotalBugs</td><td><center><input type="checkbox" id="AllBugsCheck" onClick="CopyCheckedStateToCheckButtons(this);" checked/></center></td></tr>
+ENDTEXT
+
+ my $last_category;
+
+ for my $key (
+ sort {
+ my $x = $Totals{$a};
+ my $y = $Totals{$b};
+ my $res = $x->[1] cmp $y->[1];
+ $res = $x->[2] cmp $y->[2] if ($res == 0);
+ $res
+ } keys %Totals )
+ {
+ my $val = $Totals{$key};
+ my $category = $val->[1];
+ if (!defined $last_category or $last_category ne $category) {
+ $last_category = $category;
+ print OUT "<tr><th>$category</th><th colspan=2></th></tr>\n";
+ }
+ my $x = lc $key;
+ $x =~ s/[ ,'":\/()]+/_/g;
+ print OUT "<tr><td class=\"SUMM_DESC\">";
+ print OUT $val->[2];
+ print OUT "</td><td class=\"Q\">";
+ print OUT $val->[0];
+ print OUT "</td><td><center><input type=\"checkbox\" onClick=\"ToggleDisplay(this,'bt_$x');\" checked/></center></td></tr>\n";
+ }
+
+ # Print out the table of errors.
+
+print OUT <<ENDTEXT;
+</table>
+<h2>Reports</h2>
+
+<table class="sortable" style="table-layout:automatic">
+<thead><tr>
+ <td>Bug Group</td>
+ <td class="sorttable_sorted">Bug Type<span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span></td>
+ <td>File</td>
+ <td class="Q">Line</td>
+ <td class="Q">Path Length</td>
+ <td class="sorttable_nosort"></td>
+ <!-- REPORTBUGCOL -->
+</tr></thead>
+<tbody>
+ENDTEXT
+
+ my $prefix = GetPrefix();
+ my $regex;
+ my $InFileRegex;
+ my $InFilePrefix = "File:</td><td>";
+
+ if (defined $prefix) {
+ $regex = qr/^\Q$prefix\E/is;
+ $InFileRegex = qr/\Q$InFilePrefix$prefix\E/is;
+ }
+
+ for my $row ( sort { $a->[2] cmp $b->[2] } @Index ) {
+ my $x = "$row->[1]:$row->[2]";
+ $x = lc $x;
+ $x =~ s/[ ,'":\/()]+/_/g;
+
+ my $ReportFile = $row->[0];
+
+ print OUT "<tr class=\"bt_$x\">";
+ print OUT "<td class=\"DESC\">";
+ print OUT $row->[1];
+ print OUT "</td>";
+ print OUT "<td class=\"DESC\">";
+ print OUT $row->[2];
+ print OUT "</td>";
+
+ # Update the file prefix.
+ my $fname = $row->[3];
+
+ if (defined $regex) {
+ $fname =~ s/$regex//;
+ UpdateInFilePath("$Dir/$ReportFile", $InFileRegex, $InFilePrefix)
+ }
+
+ print OUT "<td>";
+ my @fname = split /\//,$fname;
+ if ($#fname > 0) {
+ while ($#fname >= 0) {
+ my $x = shift @fname;
+ print OUT $x;
+ if ($#fname >= 0) {
+ print OUT "<span class=\"W\"> </span>/";
+ }
+ }
+ }
+ else {
+ print OUT $fname;
+ }
+ print OUT "</td>";
+
+ # Print out the quantities.
+ for my $j ( 4 .. 5 ) {
+ print OUT "<td class=\"Q\">$row->[$j]</td>";
+ }
+
+ # Print the rest of the columns.
+ for (my $j = 6; $j <= $#{$row}; ++$j) {
+ print OUT "<td>$row->[$j]</td>"
+ }
+
+ # Emit the "View" link.
+ print OUT "<td><a href=\"$ReportFile#EndPath\">View Report</a></td>";
+
+ # Emit REPORTBUG markers.
+ print OUT "\n<!-- REPORTBUG id=\"$ReportFile\" -->\n";
+
+ # End the row.
+ print OUT "</tr>\n";
+ }
+
+ print OUT "</tbody>\n</table>\n\n";
+ }
+
+ if (scalar (@failures) || scalar(@attributes_ignored)) {
+ print OUT "<h2>Analyzer Failures</h2>\n";
+
+ if (scalar @attributes_ignored) {
+ print OUT "The analyzer's parser ignored the following attributes:<p>\n";
+ print OUT "<table>\n";
+ print OUT "<thead><tr><td>Attribute</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
+ foreach my $file (sort @attributes_ignored) {
+ die "cannot demangle attribute name\n" if (! ($file =~ /^attribute_ignored_(.+).txt/));
+ my $attribute = $1;
+ # Open the attribute file to get the first file that failed.
+ next if (!open (ATTR, "$Dir/failures/$file"));
+ my $ppfile = <ATTR>;
+ chomp $ppfile;
+ close ATTR;
+ next if (! -e "$Dir/failures/$ppfile");
+ # Open the info file and get the name of the source file.
+ open (INFO, "$Dir/failures/$ppfile.info.txt") or
+ die "Cannot open $Dir/failures/$ppfile.info.txt\n";
+ my $srcfile = <INFO>;
+ chomp $srcfile;
+ close (INFO);
+ # Print the information in the table.
+ my $prefix = GetPrefix();
+ if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
+ print OUT "<tr><td>$attribute</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
+ my $ppfile_clang = $ppfile;
+ $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
+ print OUT " <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
+ }
+ print OUT "</table>\n";
+ }
+
+ if (scalar @failures) {
+ print OUT "<p>The analyzer had problems processing the following files:</p>\n";
+ print OUT "<table>\n";
+ print OUT "<thead><tr><td>Problem</td><td>Source File</td><td>Preprocessed File</td><td>STDERR Output</td></tr></thead>\n";
+ foreach my $file (sort @failures) {
+ $file =~ /(.+).info.txt$/;
+ # Get the preprocessed file.
+ my $ppfile = $1;
+ # Open the info file and get the name of the source file.
+ open (INFO, "$Dir/failures/$file") or
+ die "Cannot open $Dir/failures/$file\n";
+ my $srcfile = <INFO>;
+ chomp $srcfile;
+ my $problem = <INFO>;
+ chomp $problem;
+ close (INFO);
+ # Print the information in the table.
+ my $prefix = GetPrefix();
+ if (defined $prefix) { $srcfile =~ s/^\Q$prefix//; }
+ print OUT "<tr><td>$problem</td><td>$srcfile</td><td><a href=\"failures/$ppfile\">$ppfile</a></td><td><a href=\"failures/$ppfile.stderr.txt\">$ppfile.stderr.txt</a></td></tr>\n";
+ my $ppfile_clang = $ppfile;
+ $ppfile_clang =~ s/[.](.+)$/.clang.$1/;
+ print OUT " <!-- REPORTPROBLEM src=\"$srcfile\" file=\"failures/$ppfile\" clangfile=\"failures/$ppfile_clang\" stderr=\"failures/$ppfile.stderr.txt\" info=\"failures/$ppfile.info.txt\" -->\n";
+ }
+ print OUT "</table>\n";
+ }
+ print OUT "<p>Please consider submitting preprocessed files as <a href=\"http://clang.llvm.org/StaticAnalysisUsage.html#filingbugs\">bug reports</a>. <!-- REPORTCRASHES --> </p>\n";
+ }
+
+ print OUT "</body></html>\n";
+ close(OUT);
+ CopyFiles($Dir);
+
+ # Make sure $Dir and $BaseDir are world readable/executable.
+ system("chmod", "755", $Dir);
+ if (defined $BaseDir) { system("chmod", "755", $BaseDir); }
+
+ my $Num = scalar(@Index);
+ Diag("$Num bugs found.\n");
+ if ($Num > 0 && -r "$Dir/index.html") {
+ Diag("Run 'scan-view $Dir' to examine bug reports.\n");
+ }
+
+ DiagCrashes($Dir) if (scalar @failures || scalar @attributes_ignored);
+
+ return $Num;
+}
+
+##----------------------------------------------------------------------------##
+# RunBuildCommand - Run the build command.
+##----------------------------------------------------------------------------##
+
+sub AddIfNotPresent {
+ my $Args = shift;
+ my $Arg = shift;
+ my $found = 0;
+
+ foreach my $k (@$Args) {
+ if ($k eq $Arg) {
+ $found = 1;
+ last;
+ }
+ }
+
+ if ($found == 0) {
+ push @$Args, $Arg;
+ }
+}
+
+sub RunBuildCommand {
+
+ my $Args = shift;
+ my $IgnoreErrors = shift;
+ my $Cmd = $Args->[0];
+ my $CCAnalyzer = shift;
+
+ # Get only the part of the command after the last '/'.
+ if ($Cmd =~ /\/([^\/]+)$/) {
+ $Cmd = $1;
+ }
+
+ if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?cc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?llvm-gcc[^\/]*$)/ or
+ $Cmd =~ /(.*\/?ccc-analyzer[^\/]*$)/) {
+
+ if (!($Cmd =~ /ccc-analyzer/) and !defined $ENV{"CCC_CC"}) {
+ $ENV{"CCC_CC"} = $1;
+ }
+
+ shift @$Args;
+ unshift @$Args, $CCAnalyzer;
+ }
+ elsif ($IgnoreErrors) {
+ if ($Cmd eq "make" or $Cmd eq "gmake") {
+ AddIfNotPresent($Args,"-k");
+ AddIfNotPresent($Args,"-i");
+ }
+ elsif ($Cmd eq "xcodebuild") {
+ AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
+ }
+ }
+
+ if ($Cmd eq "xcodebuild") {
+ # Check if using iPhone SDK 3.0 (simulator). If so the compiler being
+ # used should be gcc-4.2.
+ if (!defined $ENV{"CCC_CC"}) {
+ for (my $i = 0 ; $i < scalar(@$Args); ++$i) {
+ if ($Args->[$i] eq "-sdk" && $i + 1 < scalar(@$Args)) {
+ if (@$Args[$i+1] =~ /^iphonesimulator3/) {
+ $ENV{"CCC_CC"} = "gcc-4.2";
+ }
+ }
+ }
+ }
+
+ # Disable distributed builds for xcodebuild.
+ AddIfNotPresent($Args,"-nodistribute");
+
+ # Disable PCH files until clang supports them.
+ AddIfNotPresent($Args,"GCC_PRECOMPILE_PREFIX_HEADER=NO");
+
+ # When 'CC' is set, xcodebuild uses it to do all linking, even if we are
+ # linking C++ object files. Set 'LDPLUSPLUS' so that xcodebuild uses 'g++'
+ # when linking such files.
+ die if (!defined $CXX);
+ my $LDPLUSPLUS = `which $CXX`;
+ $LDPLUSPLUS =~ s/\015?\012//; # strip newlines
+ $ENV{'LDPLUSPLUS'} = $LDPLUSPLUS;
+ }
+
+ return (system(@$Args) >> 8);
+}
+
+##----------------------------------------------------------------------------##
+# DisplayHelp - Utility function to display all help options.
+##----------------------------------------------------------------------------##
+
+sub DisplayHelp {
+
+print <<ENDTEXT;
+USAGE: $Prog [options] <build command> [build options]
+
+ENDTEXT
+
+ if (defined $BuildName) {
+ print "ANALYZER BUILD: $BuildName ($BuildDate)\n\n";
+ }
+
+print <<ENDTEXT;
+OPTIONS:
+
+ -analyze-headers - Also analyze functions in #included files.
+
+ --experimental-checks - Enable experimental checks that are currently in heavy testing
+
+ -o - Target directory for HTML report files. Subdirectories
+ will be created as needed to represent separate "runs" of
+ the analyzer. If this option is not specified, a directory
+ is created in /tmp (TMPDIR on Mac OS X) to store the reports.
+
+ -h - Display this message.
+ --help
+
+ -k - Add a "keep on going" option to the specified build command.
+ --keep-going This option currently supports make and xcodebuild.
+ This is a convenience option; one can specify this
+ behavior directly using build options.
+
+ --html-title [title] - Specify the title used on generated HTML pages.
+ --html-title=[title] If not specified, a default title will be used.
+
+ -plist - By default the output of scan-build is a set of HTML files.
+ This option outputs the results as a set of .plist files.
+
+ --status-bugs - By default, the exit status of $Prog is the same as the
+ executed build command. Specifying this option causes the
+ exit status of $Prog to be 1 if it found potential bugs
+ and 0 otherwise.
+
+ --use-cc [compiler path] - By default, $Prog uses 'gcc' to compile and link
+ --use-cc=[compiler path] your C and Objective-C code. Use this option
+ to specify an alternate compiler.
+
+ --use-c++ [compiler path] - By default, $Prog uses 'g++' to compile and link
+ --use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
+ to specify an alternate compiler.
+
+ -v - Verbose output from $Prog and the analyzer.
+ A second and third '-v' increases verbosity.
+
+ -V - View analysis results in a web browser when the build
+ --view completes.
+
+ADVANCED OPTIONS:
+
+ -constraints [model] - Specify the contraint engine used by the analyzer.
+ By default the 'range' model is used. Specifying
+ 'basic' uses a simpler, less powerful constraint model
+ used by checker-0.160 and earlier.
+
+ -store [model] - Specify the store model used by the analyzer. By default,
+ the 'region' store model is used. 'region' specifies a field-
+ sensitive store model. Users can also specify 'basic', which
+ is far less precise but can more quickly analyze code.
+ 'basic' was the default store model for checker-0.221 and
+ earlier.
+
+ -no-failure-reports - Do not create a 'failures' subdirectory that includes
+ analyzer crash reports and preprocessed source files.
+
+AVAILABLE ANALYSES (multiple analyses may be specified):
+
+ENDTEXT
+
+ foreach my $Analysis (sort keys %AvailableAnalyses) {
+ if (defined $AnalysesDefaultEnabled{$Analysis}) {
+ print " (+)";
+ }
+ else {
+ print " ";
+ }
+
+ print " $Analysis $AvailableAnalyses{$Analysis}\n";
+ }
+
+print <<ENDTEXT
+
+ NOTE: "(+)" indicates that an analysis is enabled by default unless one
+ or more analysis options are specified
+
+BUILD OPTIONS
+
+ You can specify any build option acceptable to the build command.
+
+EXAMPLE
+
+ $Prog -o /tmp/myhtmldir make -j4
+
+ The above example causes analysis reports to be deposited into
+ a subdirectory of "/tmp/myhtmldir" and to run "make" with the "-j4" option.
+ A different subdirectory is created each time $Prog analyzes a project.
+ The analyzer should support most parallel builds, but not distributed builds.
+
+ENDTEXT
+}
+
+##----------------------------------------------------------------------------##
+# HtmlEscape - HTML entity encode characters that are special in HTML
+##----------------------------------------------------------------------------##
+
+sub HtmlEscape {
+ # copy argument to new variable so we don't clobber the original
+ my $arg = shift || '';
+ my $tmp = $arg;
+ $tmp =~ s/&/&amp;/g;
+ $tmp =~ s/</&lt;/g;
+ $tmp =~ s/>/&gt;/g;
+ return $tmp;
+}
+
+##----------------------------------------------------------------------------##
+# ShellEscape - backslash escape characters that are special to the shell
+##----------------------------------------------------------------------------##
+
+sub ShellEscape {
+ # copy argument to new variable so we don't clobber the original
+ my $arg = shift || '';
+ if ($arg =~ /["\s]/) { return "'" . $arg . "'"; }
+ return $arg;
+}
+
+##----------------------------------------------------------------------------##
+# Process command-line arguments.
+##----------------------------------------------------------------------------##
+
+my $AnalyzeHeaders = 0;
+my $HtmlDir; # Parent directory to store HTML files.
+my $IgnoreErrors = 0; # Ignore build errors.
+my $ViewResults = 0; # View results when the build terminates.
+my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
+my @AnalysesToRun;
+my $StoreModel;
+my $ConstraintsModel;
+my $OutputFormat = "html";
+
+if (!@ARGV) {
+ DisplayHelp();
+ exit 1;
+}
+
+while (@ARGV) {
+
+ # Scan for options we recognize.
+
+ my $arg = $ARGV[0];
+
+ if ($arg eq "-h" or $arg eq "--help") {
+ DisplayHelp();
+ exit 0;
+ }
+
+ if ($arg eq '-analyze-headers') {
+ shift @ARGV;
+ $AnalyzeHeaders = 1;
+ next;
+ }
+
+ if (defined $AvailableAnalyses{$arg}) {
+ shift @ARGV;
+ push @AnalysesToRun, $arg;
+ next;
+ }
+
+ if ($arg eq "-o") {
+ shift @ARGV;
+
+ if (!@ARGV) {
+ DieDiag("'-o' option requires a target directory name.\n");
+ }
+
+ # Construct an absolute path. Uses the current working directory
+ # as a base if the original path was not absolute.
+ $HtmlDir = abs_path(shift @ARGV);
+
+ next;
+ }
+
+ if ($arg =~ /^--html-title(=(.+))?$/) {
+ shift @ARGV;
+
+ if (!defined $2 || $2 eq '') {
+ if (!@ARGV) {
+ DieDiag("'--html-title' option requires a string.\n");
+ }
+
+ $HtmlTitle = shift @ARGV;
+ } else {
+ $HtmlTitle = $2;
+ }
+
+ next;
+ }
+
+ if ($arg eq "-k" or $arg eq "--keep-going") {
+ shift @ARGV;
+ $IgnoreErrors = 1;
+ next;
+ }
+
+ if ($arg eq "--experimental-checks") {
+ shift @ARGV;
+ $ENV{"CCC_EXPERIMENTAL_CHECKS"} = 1;
+ next;
+ }
+
+ if ($arg =~ /^--use-cc(=(.+))?$/) {
+ shift @ARGV;
+ my $cc;
+
+ if (!defined $2 || $2 eq "") {
+ if (!@ARGV) {
+ DieDiag("'--use-cc' option requires a compiler executable name.\n");
+ }
+ $cc = shift @ARGV;
+ }
+ else {
+ $cc = $2;
+ }
+
+ $ENV{"CCC_CC"} = $cc;
+ next;
+ }
+
+ if ($arg =~ /^--use-c\+\+(=(.+))?$/) {
+ shift @ARGV;
+
+ if (!defined $2 || $2 eq "") {
+ if (!@ARGV) {
+ DieDiag("'--use-c++' option requires a compiler executable name.\n");
+ }
+ $CXX = shift @ARGV;
+ }
+ else {
+ $CXX = $2;
+ }
+ next;
+ }
+
+ if ($arg eq "-v") {
+ shift @ARGV;
+ $Verbose++;
+ next;
+ }
+
+ if ($arg eq "-V" or $arg eq "--view") {
+ shift @ARGV;
+ $ViewResults = 1;
+ next;
+ }
+
+ if ($arg eq "--status-bugs") {
+ shift @ARGV;
+ $ExitStatusFoundBugs = 1;
+ next;
+ }
+
+ if ($arg eq "-store") {
+ shift @ARGV;
+ $StoreModel = shift @ARGV;
+ next;
+ }
+
+ if ($arg eq "-constraints") {
+ shift @ARGV;
+ $ConstraintsModel = shift @ARGV;
+ next;
+ }
+
+ if ($arg eq "-plist") {
+ shift @ARGV;
+ $OutputFormat = "plist";
+ next;
+ }
+ if ($arg eq "-plist-html") {
+ shift @ARGV;
+ $OutputFormat = "plist-html";
+ next;
+ }
+
+ if ($arg eq "-no-failure-reports") {
+ $ENV{"CCC_REPORT_FAILURES"} = 0;
+ next;
+ }
+
+ DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
+
+ last;
+}
+
+if (!@ARGV) {
+ Diag("No build command specified.\n\n");
+ DisplayHelp();
+ exit 1;
+}
+
+$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
+$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
+ unless (defined($HtmlTitle));
+
+# Determine the output directory for the HTML reports.
+my $BaseDir = $HtmlDir;
+$HtmlDir = GetHTMLRunDir($HtmlDir);
+
+# Set the appropriate environment variables.
+SetHtmlEnv(\@ARGV, $HtmlDir);
+
+my $Cmd = Cwd::realpath("$RealBin/libexec/ccc-analyzer");
+if (!defined $Cmd || ! -x $Cmd) {
+ $Cmd = Cwd::realpath("$RealBin/ccc-analyzer");
+ DieDiag("Executable 'ccc-analyzer' does not exist at '$Cmd'\n") if(! -x $Cmd);
+}
+
+if (!defined $ClangCCSB || ! -x $ClangCCSB) {
+ Diag("'clang-cc' executable not found in '$RealBin/libexec'.\n");
+ Diag("Using 'clang-cc' from path.\n");
+}
+if (!defined $ClangSB || ! -x $ClangSB) {
+ Diag("'clang' executable not found in '$RealBin/bin'.\n");
+ Diag("Using 'clang' from path.\n");
+}
+
+if (defined $CXX) {
+ $ENV{'CXX'} = $CXX;
+}
+else {
+ $CXX = 'g++'; # This variable is used by other parts of scan-build
+ # that need to know a default C++ compiler to fall back to.
+}
+
+$ENV{'CC'} = $Cmd;
+$ENV{'CLANG_CC'} = $ClangCC;
+$ENV{'CLANG'} = $Clang;
+
+if ($Verbose >= 2) {
+ $ENV{'CCC_ANALYZER_VERBOSE'} = 1;
+}
+
+if ($Verbose >= 3) {
+ $ENV{'CCC_ANALYZER_LOG'} = 1;
+}
+
+if (scalar(@AnalysesToRun) == 0) {
+ foreach my $key (keys %AnalysesDefaultEnabled) {
+ push @AnalysesToRun,$key;
+ }
+}
+
+if ($AnalyzeHeaders) {
+ push @AnalysesToRun,"-analyzer-opt-analyze-headers";
+}
+
+$ENV{'CCC_ANALYZER_ANALYSIS'} = join ' ',@AnalysesToRun;
+
+if (defined $StoreModel) {
+ $ENV{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel;
+}
+
+if (defined $ConstraintsModel) {
+ $ENV{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel;
+}
+
+if (defined $OutputFormat) {
+ $ENV{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat;
+}
+
+
+# Run the build.
+my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd);
+
+if (defined $OutputFormat) {
+ if ($OutputFormat =~ /plist/) {
+ Diag "Analysis run complete.\n";
+ Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
+ }
+ elsif ($OutputFormat =~ /html/) {
+ # Postprocess the HTML directory.
+ my $NumBugs = Postprocess($HtmlDir, $BaseDir);
+
+ if ($ViewResults and -r "$HtmlDir/index.html") {
+ Diag "Analysis run complete.\n";
+ Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n";
+ my $ScanView = Cwd::realpath("$RealBin/scan-view");
+ if (! -x $ScanView) { $ScanView = "scan-view"; }
+ exec $ScanView, "$HtmlDir";
+ }
+
+ if ($ExitStatusFoundBugs) {
+ exit 1 if ($NumBugs > 0);
+ exit 0;
+ }
+ }
+}
+
+exit $ExitStatus;
+
diff --git a/tools/scan-build/scanview.css b/tools/scan-build/scanview.css
new file mode 100644
index 0000000..a0406f3
--- /dev/null
+++ b/tools/scan-build/scanview.css
@@ -0,0 +1,62 @@
+body { color:#000000; background-color:#ffffff }
+body { font-family: Helvetica, sans-serif; font-size:9pt }
+h1 { font-size: 14pt; }
+h2 { font-size: 12pt; }
+table { font-size:9pt }
+table { border-spacing: 0px; border: 1px solid black }
+th, table thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:center;
+ font-weight: bold; font-family: Verdana;
+ white-space:nowrap;
+}
+.W { font-size:0px }
+th, td { padding:5px; padding-left:8px; text-align:left }
+td.SUMM_DESC { padding-left:12px }
+td.DESC { white-space:pre }
+td.Q { text-align:right }
+td { text-align:left }
+tbody.scrollContent { overflow:auto }
+
+table.form_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+table.form_inner_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 0px;
+}
+
+table.form {
+ background-color: #999;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+td.form_label {
+ text-align: right;
+ vertical-align: top;
+}
+/* For one line entires */
+td.form_clabel {
+ text-align: right;
+ vertical-align: center;
+}
+td.form_value {
+ text-align: left;
+ vertical-align: top;
+}
+td.form_submit {
+ text-align: right;
+ vertical-align: top;
+}
+
+h1.SubmitFail {
+ color: #f00;
+}
+h1.SubmitOk {
+}
diff --git a/tools/scan-build/sorttable.js b/tools/scan-build/sorttable.js
new file mode 100644
index 0000000..4352d3b
--- /dev/null
+++ b/tools/scan-build/sorttable.js
@@ -0,0 +1,493 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ makeSortable: function(table) {
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backwards compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ // work through each column and calculate its type
+ headrow = table.tHead.rows[0].cells;
+ for (var i=0; i<headrow.length; i++) {
+ // manually override the type with a sorttable_type attribute
+ if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) { override = mtch[1]; }
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
+ }
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = i;
+ headrow[i].sorttable_tbody = table.tBodies[0];
+ dean_addEvent(headrow[i],"click", function(e) {
+
+ if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted',
+ 'sorttable_sorted_reverse');
+ this.removeChild(document.getElementById('sorttable_sortfwdind'));
+ sortrevind = document.createElement('span');
+ sortrevind.id = "sorttable_sortrevind";
+ sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
+ this.appendChild(sortrevind);
+ return;
+ }
+ if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted_reverse',
+ 'sorttable_sorted');
+ this.removeChild(document.getElementById('sorttable_sortrevind'));
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+ return;
+ }
+
+ // remove sorttable_sorted classes
+ theadrow = this.parentNode;
+ forEach(theadrow.childNodes, function(cell) {
+ if (cell.nodeType == 1) { // an element
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ });
+ sortfwdind = document.getElementById('sorttable_sortfwdind');
+ if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
+ sortrevind = document.getElementById('sorttable_sortrevind');
+ if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
+
+ this.className += ' sorttable_sorted';
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ row_array = [];
+ col = this.sorttable_columnindex;
+ rows = this.sorttable_tbody.rows;
+ for (var j=0; j<rows.length; j++) {
+ row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
+ }
+ /* If you want a stable sort, uncomment the following line */
+ sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+ /* and comment out this one */
+ //row_array.sort(this.sorttable_sortfunction);
+
+ tb = this.sorttable_tbody;
+ for (var j=0; j<row_array.length; j++) {
+ tb.appendChild(row_array[j][1]);
+ }
+
+ delete row_array;
+ });
+ }
+ }
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.tBodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ reverse: function(tbody) {
+ // reverse the rows in a tbody
+ newrows = [];
+ for (var i=0; i<tbody.rows.length; i++) {
+ newrows[newrows.length] = tbody.rows[i];
+ }
+ for (var i=newrows.length-1; i>=0; i--) {
+ tbody.appendChild(newrows[i]);
+ }
+ delete newrows;
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a[0] and b[0] */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+ sort_alpha: function(a,b) {
+ if (a[0]==b[0]) return 0;
+ if (a[0]<b[0]) return -1;
+ return 1;
+ },
+ sort_ddmm: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+ sort_mmdd: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+ var script = document.getElementById("__ie_onload");
+ script.onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ sorttable.init(); // call the onload handler
+ }
+ };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
+
diff --git a/tools/wpa/CMakeLists.txt b/tools/wpa/CMakeLists.txt
deleted file mode 100644
index 5553474..0000000
--- a/tools/wpa/CMakeLists.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-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
deleted file mode 100644
index 01dbd11..0000000
--- a/tools/wpa/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-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
deleted file mode 100644
index 346634b..0000000
--- a/tools/wpa/clang-wpa.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===--- 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/Frontend/ASTUnit.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]->getASTContext());
-
- CG->ViewCallGraph();
-}
OpenPOWER on IntegriCloud