summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
committerdim <dim@FreeBSD.org>2012-12-02 13:20:44 +0000
commit056abd2059c65a3e908193aeae16fad98017437c (patch)
tree2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /tools
parentcc73504950eb7b5dff2dded9bedd67bc36d64641 (diff)
downloadFreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.zip
FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.tar.gz
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt6
-rw-r--r--tools/Makefile5
-rw-r--r--tools/arcmt-test/CMakeLists.txt2
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp10
-rw-r--r--tools/c-arcmt-test/Makefile8
-rw-r--r--tools/c-index-test/CMakeLists.txt7
-rw-r--r--tools/c-index-test/Makefile3
-rw-r--r--tools/c-index-test/c-index-test.c173
-rw-r--r--tools/clang-check/CMakeLists.txt1
-rw-r--r--tools/clang-check/ClangCheck.cpp130
-rw-r--r--tools/clang-check/Makefile4
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp4
-rw-r--r--tools/diagtool/TreeView.cpp51
-rw-r--r--tools/driver/CMakeLists.txt3
-rw-r--r--tools/driver/Makefile3
-rw-r--r--tools/driver/cc1_main.cpp78
-rw-r--r--tools/driver/cc1as_main.cpp17
-rw-r--r--tools/driver/driver.cpp12
-rw-r--r--tools/libclang/CIndex.cpp202
-rw-r--r--tools/libclang/CIndexCXX.cpp3
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp8
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp8
-rw-r--r--tools/libclang/CIndexUSRs.cpp44
-rw-r--r--tools/libclang/CMakeLists.txt3
-rw-r--r--tools/libclang/CXComment.cpp197
-rw-r--r--tools/libclang/CXComment.h23
-rw-r--r--tools/libclang/CXCursor.cpp204
-rw-r--r--tools/libclang/CXType.cpp3
-rw-r--r--tools/libclang/CursorVisitor.h20
-rw-r--r--tools/libclang/IndexBody.cpp14
-rw-r--r--tools/libclang/IndexDecl.cpp15
-rw-r--r--tools/libclang/Indexing.cpp104
-rw-r--r--tools/libclang/IndexingContext.cpp68
-rw-r--r--tools/libclang/IndexingContext.h26
-rw-r--r--tools/libclang/Makefile15
-rw-r--r--tools/libclang/RecursiveASTVisitor.h7
-rw-r--r--tools/libclang/libclang.exports7
-rwxr-xr-xtools/scan-build/ccc-analyzer2
-rwxr-xr-xtools/scan-build/scan-build338
-rw-r--r--tools/scan-build/scan-build.115
-rwxr-xr-xtools/scan-build/set-xcode-analyzer22
-rw-r--r--tools/scan-view/ScanView.py5
43 files changed, 1175 insertions, 697 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 3a6fef5..cccff5d 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -10,7 +10,5 @@ add_subdirectory(clang-check)
# subdirectory. It contains tools developed as part of the Clang/LLVM project
# on top of the Clang tooling platform. We keep them in a separate repository
# to keep the primary Clang repository small and focused.
-if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/extra AND
- EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extra/CMakeLists.txt)
- add_subdirectory(extra)
-endif()
+# It also may be included by LLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR.
+add_llvm_external_project(clang-tools-extra extra)
diff --git a/tools/Makefile b/tools/Makefile
index e7aa2fa..23197a1 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -17,4 +17,9 @@ DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
# Recurse into the extra repository of tools if present.
OPTIONAL_DIRS := extra
+ifeq ($(BUILD_CLANG_ONLY),YES)
+ DIRS := driver libclang c-index-test
+ OPTIONAL_DIRS :=
+endif
+
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index f36b14a..a7ce586 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -12,5 +12,5 @@ add_clang_executable(arcmt-test
target_link_libraries(arcmt-test
clangARCMigrate
clangEdit
- clangRewrite
+ clangRewriteCore
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index 719da75..06e2016 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -18,7 +18,7 @@ NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clangARCMigrate.a clangRewrite.a \
+USEDLIBS = clangARCMigrate.a clangRewriteCore.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 3983c24..b745893 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -105,11 +105,12 @@ public:
static bool checkForMigration(StringRef resourcesPath,
ArrayRef<const char *> Args) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
// Chain in -verify checker, if requested.
VerifyDiagnosticConsumer *verifyDiag = 0;
if (VerifyDiags) {
@@ -150,11 +151,12 @@ static bool performTransformations(StringRef resourcesPath,
if (checkForMigration(resourcesPath, Args))
return true;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
- new DiagnosticsEngine(DiagID, DiagClient));
+ new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient));
CompilerInvocation origCI;
if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index b59afda..3372dae 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -22,7 +22,13 @@ NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clang.a clangARCMigrate.a clangRewrite.a \
+
+# Note that 'USEDLIBS' must include all of the core clang libraries
+# as clang.dll is unavailable on cygming yet.
+USEDLIBS = clang.a \
+ clangARCMigrate.a \
+ clangRewriteFrontend.a \
+ clangRewriteCore.a \
clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 6379194..6f28c54 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -7,6 +7,13 @@ add_clang_executable(c-index-test
c-index-test.c
)
+if(NOT MSVC)
+ set_property(
+ SOURCE c-index-test.c
+ PROPERTY COMPILE_FLAGS "-std=c89"
+ )
+endif()
+
target_link_libraries(c-index-test
libclang
)
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index 09eff0f..b81678b 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -17,9 +17,6 @@ INTERNAL_TOOL = 1
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-# Don't install this. It is used for tests.
-NO_INSTALL = 1
-
# Include this here so we can get the configuration of the targets that have
# been configured for construction. We have to do this early so we can set up
# LINK_COMPONENTS before including Makefile.rules
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 5df21ec..3e4404c 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -512,8 +512,7 @@ static void ValidateCommentXML(const char *Str,
#endif
}
-static void PrintCursorComments(CXTranslationUnit TU,
- CXCursor Cursor,
+static void PrintCursorComments(CXCursor Cursor,
CommentXMLValidationData *ValidationData) {
{
CXString RawComment;
@@ -543,7 +542,7 @@ static void PrintCursorComments(CXTranslationUnit TU,
clang_FullComment_getAsHTML(Comment));
{
CXString XML;
- XML = clang_FullComment_getAsXML(TU, Comment);
+ XML = clang_FullComment_getAsXML(Comment);
PrintCXStringWithPrefix("FullCommentAsXML", XML);
ValidateCommentXML(clang_getCString(XML), ValidationData);
clang_disposeString(XML);
@@ -554,6 +553,19 @@ static void PrintCursorComments(CXTranslationUnit TU,
}
}
+typedef struct {
+ unsigned line;
+ unsigned col;
+} LineCol;
+
+static int lineCol_cmp(const void *p1, const void *p2) {
+ const LineCol *lhs = p1;
+ const LineCol *rhs = p2;
+ if (lhs->line != rhs->line)
+ return (int)lhs->line - (int)rhs->line;
+ return (int)lhs->col - (int)rhs->col;
+}
+
static void PrintCursor(CXCursor Cursor,
CommentXMLValidationData *ValidationData) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
@@ -718,13 +730,21 @@ static void PrintCursor(CXCursor Cursor,
clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
if (num_overridden) {
unsigned I;
+ LineCol lineCols[50];
+ assert(num_overridden <= 50);
printf(" [Overrides ");
for (I = 0; I != num_overridden; ++I) {
CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
+ lineCols[I].line = line;
+ lineCols[I].col = column;
+ }
+ /* Make the order of the override list deterministic. */
+ qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
+ for (I = 0; I != num_overridden; ++I) {
if (I)
printf(", ");
- printf("@%d:%d", line, column);
+ printf("@%d:%d", lineCols[I].line, lineCols[I].col);
}
printf("]");
clang_disposeOverriddenCursors(overridden);
@@ -760,7 +780,7 @@ static void PrintCursor(CXCursor Cursor,
PrintRange(RefNameRange, "RefName");
}
- PrintCursorComments(TU, Cursor, ValidationData);
+ PrintCursorComments(Cursor, ValidationData);
}
}
@@ -1935,6 +1955,31 @@ static int inspect_cursor_at(int argc, const char **argv) {
printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
if (clang_Cursor_isDynamicCall(Cursor))
printf(" Dynamic-call");
+ if (Cursor.kind == CXCursor_ObjCMessageExpr) {
+ CXType T = clang_Cursor_getReceiverType(Cursor);
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" Receiver-type=%s", clang_getCString(S));
+ clang_disposeString(S);
+ }
+
+ {
+ CXModule mod = clang_Cursor_getModule(Cursor);
+ CXString name;
+ unsigned i, numHeaders;
+ if (mod) {
+ name = clang_Module_getFullName(mod);
+ numHeaders = clang_Module_getNumTopLevelHeaders(mod);
+ printf(" ModuleName=%s Headers(%d):",
+ clang_getCString(name), numHeaders);
+ clang_disposeString(name);
+ for (i = 0; i < numHeaders; ++i) {
+ CXFile file = clang_Module_getTopLevelHeader(mod, i);
+ CXString filename = clang_getFileName(file);
+ printf("\n%s", clang_getCString(filename));
+ clang_disposeString(filename);
+ }
+ }
+ }
if (completionString != NULL) {
printf("\nCompletion string: ");
@@ -2062,12 +2107,49 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+#define MAX_IMPORTED_ASTFILES 200
+
+typedef struct {
+ char **filenames;
+ unsigned num_files;
+} ImportedASTFilesData;
+
+static ImportedASTFilesData *importedASTs_create() {
+ ImportedASTFilesData *p;
+ p = malloc(sizeof(ImportedASTFilesData));
+ p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
+ p->num_files = 0;
+ return p;
+}
+
+static void importedASTs_dispose(ImportedASTFilesData *p) {
+ unsigned i;
+ if (!p)
+ return;
+
+ for (i = 0; i < p->num_files; ++i)
+ free(p->filenames[i]);
+ free(p->filenames);
+ free(p);
+}
+
+static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
+ unsigned i;
+ assert(p && file);
+ for (i = 0; i < p->num_files; ++i)
+ if (strcmp(file, p->filenames[i]) == 0)
+ return;
+ assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
+ p->filenames[p->num_files++] = strdup(file);
+}
+
typedef struct {
const char *check_prefix;
int first_check_printed;
int fail_for_error;
int abort;
const char *main_filename;
+ ImportedASTFilesData *importedASTs;
} IndexData;
static void printCheck(IndexData *data) {
@@ -2098,7 +2180,7 @@ static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
index_data = (IndexData *)client_data;
clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
if (line == 0) {
- printf("<null loc>");
+ printf("<invalid>");
return;
}
if (!file) {
@@ -2186,6 +2268,7 @@ static const char *getEntityKindString(CXIdxEntityKind kind) {
case CXIdxEntity_CXXDestructor: return "destructor";
case CXIdxEntity_CXXConversionFunction: return "conversion-func";
case CXIdxEntity_CXXTypeAlias: return "type-alias";
+ case CXIdxEntity_CXXInterface: return "c++-__interface";
}
assert(0 && "Garbage entity kind");
return 0;
@@ -2323,7 +2406,37 @@ static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
printf(" | name: \"%s\"", info->filename);
printf(" | hash loc: ");
printCXIndexLoc(info->hashLoc, client_data);
- printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled);
+ printf(" | isImport: %d | isAngled: %d | isModule: %d\n",
+ info->isImport, info->isAngled, info->isModuleImport);
+
+ return (CXIdxClientFile)info->file;
+}
+
+static CXIdxClientFile index_importedASTFile(CXClientData client_data,
+ const CXIdxImportedASTFileInfo *info) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ if (index_data->importedASTs) {
+ CXString filename = clang_getFileName(info->file);
+ importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
+ clang_disposeString(filename);
+ }
+
+ printf("[importedASTFile]: ");
+ printCXIndexFile((CXIdxClientFile)info->file);
+ if (info->module) {
+ CXString name = clang_Module_getFullName(info->module);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printf(" | name: \"%s\"", clang_getCString(name));
+ printf(" | isImplicit: %d\n", info->isImplicit);
+ clang_disposeString(name);
+ } else {
+ /* PCH file, the rest are not relevant. */
+ printf("\n");
+ }
return (CXIdxClientFile)info->file;
}
@@ -2458,7 +2571,7 @@ static IndexerCallbacks IndexCB = {
index_diagnostic,
index_enteredMainFile,
index_ppIncludedFile,
- 0, /*importedASTFile*/
+ index_importedASTFile,
index_startedTranslationUnit,
index_indexDeclaration,
index_indexEntityReference
@@ -2475,7 +2588,7 @@ static unsigned getIndexOptions(void) {
return index_opts;
}
-static int index_file(int argc, const char **argv) {
+static int index_file(int argc, const char **argv, int full) {
const char *check_prefix;
CXIndex Idx;
CXIndexAction idxAction;
@@ -2508,15 +2621,40 @@ static int index_file(int argc, const char **argv) {
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = 0;
+
+ if (full)
+ index_data.importedASTs = importedASTs_create();
index_opts = getIndexOptions();
idxAction = clang_IndexAction_create(Idx);
result = clang_indexSourceFile(idxAction, &index_data,
&IndexCB,sizeof(IndexCB), index_opts,
- 0, argv, argc, 0, 0, 0, 0);
+ 0, argv, argc, 0, 0, 0,
+ getDefaultParsingOptions());
if (index_data.fail_for_error)
result = -1;
+
+ if (full) {
+ CXTranslationUnit TU;
+ unsigned i;
+
+ for (i = 0; i < index_data.importedASTs->num_files; ++i) {
+ if (!CreateTranslationUnit(Idx, index_data.importedASTs->filenames[i],
+ &TU)) {
+ result = -1;
+ goto finished;
+ }
+ result = clang_indexTranslationUnit(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB),
+ index_opts, TU);
+ clang_disposeTranslationUnit(TU);
+ }
+ }
+finished:
+ importedASTs_dispose(index_data.importedASTs);
clang_IndexAction_dispose(idxAction);
clang_disposeIndex(Idx);
return result;
@@ -2551,6 +2689,7 @@ static int index_tu(int argc, const char **argv) {
return 1;
}
idxAction = 0;
+ TU = 0;
result = 1;
if (!CreateTranslationUnit(Idx, argv[0], &TU))
@@ -2560,6 +2699,8 @@ static int index_tu(int argc, const char **argv) {
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = 0;
index_opts = getIndexOptions();
idxAction = clang_IndexAction_create(Idx);
@@ -2571,6 +2712,7 @@ static int index_tu(int argc, const char **argv) {
finished:
clang_IndexAction_dispose(idxAction);
+ clang_disposeTranslationUnit(TU);
clang_disposeIndex(Idx);
return result;
@@ -2994,7 +3136,8 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
argc - num_unsaved_files,
unsaved_files,
num_unsaved_files,
- CXTranslationUnit_Incomplete);
+ CXTranslationUnit_Incomplete |
+ CXTranslationUnit_ForSerialization);
if (!TU) {
fprintf(stderr, "Unable to load translation unit!\n");
free_remapped_files(unsaved_files, num_unsaved_files);
@@ -3212,8 +3355,10 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
- " c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n");
+ fprintf(stderr,
" c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
+ " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
" c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n");
@@ -3271,7 +3416,9 @@ int cindextest_main(int argc, const char **argv) {
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
- return index_file(argc - 2, argv + 2);
+ return index_file(argc - 2, argv + 2, /*full=*/0);
+ if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
+ return index_file(argc - 2, argv + 2, /*full=*/1);
if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
return index_tu(argc - 2, argv + 2);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index 85e229f..f5d7616 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_executable(clang-check
target_link_libraries(clang-check
clangTooling
clangBasic
+ clangRewriteFrontend
)
install(TARGETS clang-check
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index 9e58077..6c081ac 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -1,4 +1,4 @@
-//===- tools/clang-check/ClangCheck.cpp - Clang check tool ----------------===//
+//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements a clang-check tool that runs the
-// clang::SyntaxOnlyAction over a number of translation units.
+// This file implements a clang-check tool that runs clang based on the info
+// stored in a compilation database.
//
// This tool uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
@@ -16,20 +16,24 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/CommandLine.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Frontend/FrontendActions.h"
-#include "clang/Tooling/CommandLineClangTool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
-static const char *MoreHelpText =
+static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::extrahelp MoreHelp(
"\tFor example, to run clang-check on all files in a subtree of the\n"
"\tsource tree, use:\n"
"\n"
@@ -41,26 +45,90 @@ static const char *MoreHelpText =
"\n"
"\tNote, that path/in/subtree and current directory should follow the\n"
"\trules described above.\n"
- "\n";
+ "\n"
+);
+
+static OwningPtr<OptTable> Options(createDriverOptTable());
+static cl::opt<bool> ASTDump(
+ "ast-dump",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)));
+static cl::opt<bool> ASTList(
+ "ast-list",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_list)));
+static cl::opt<bool> ASTPrint(
+ "ast-print",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_print)));
+static cl::opt<std::string> ASTDumpFilter(
+ "ast-dump-filter",
+ cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)));
+
+static cl::opt<bool> Fixit(
+ "fixit",
+ cl::desc(Options->getOptionHelpText(options::OPT_fixit)));
+static cl::opt<bool> FixWhatYouCan(
+ "fix-what-you-can",
+ cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)));
namespace {
-class ActionFactory {
+
+// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
+// into a header file and reuse that.
+class FixItOptions : public clang::FixItOptions {
+public:
+ FixItOptions() {
+ FixWhatYouCan = ::FixWhatYouCan;
+ }
+
+ std::string RewriteFilename(const std::string& filename, int &fd) {
+ assert(llvm::sys::path::is_absolute(filename) &&
+ "clang-fixit expects absolute paths only.");
+
+ // We don't need to do permission checking here since clang will diagnose
+ // any I/O errors itself.
+
+ fd = -1; // No file descriptor for file.
+
+ return filename;
+ }
+};
+
+/// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
+/// in the final error counts.
+///
+/// This has the side-effect that clang-check -fixit exits with code 0 on
+/// successfully fixing all errors.
+class FixItRewriter : public clang::FixItRewriter {
+public:
+ FixItRewriter(clang::DiagnosticsEngine& Diags,
+ clang::SourceManager& SourceMgr,
+ const clang::LangOptions& LangOpts,
+ clang::FixItOptions* FixItOpts)
+ : clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
+ }
+
+ virtual bool IncludeInDiagnosticCounts() const { return false; }
+};
+
+/// \brief Subclasses \c clang::FixItAction so that we can install the custom
+/// \c FixItRewriter.
+class FixItAction : public clang::FixItAction {
public:
- ActionFactory()
- : Options(createDriverOptTable()),
- ASTDump(
- "ast-dump",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_dump))),
- ASTList(
- "ast-list",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_list))),
- ASTPrint(
- "ast-print",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_print))),
- ASTDumpFilter(
- "ast-dump-filter",
- cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter))) {}
+ virtual bool BeginSourceFileAction(clang::CompilerInstance& CI,
+ StringRef Filename) {
+ FixItOpts.reset(new FixItOptions);
+ Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts(), FixItOpts.get()));
+ return true;
+ }
+};
+
+} // namespace
+// Anonymous namespace here causes problems with gcc <= 4.4 on MacOS 10.6.
+// "Non-global symbol: ... can't be a weak_definition"
+namespace clang_check {
+class ClangCheckActionFactory {
+public:
clang::ASTConsumer *newASTConsumer() {
if (ASTList)
return clang::CreateASTDeclNodeLister();
@@ -70,19 +138,15 @@ public:
return clang::CreateASTPrinter(&llvm::outs(), ASTDumpFilter);
return new clang::ASTConsumer();
}
-private:
- OwningPtr<OptTable> Options;
- cl::opt<bool> ASTDump;
- cl::opt<bool> ASTList;
- cl::opt<bool> ASTPrint;
- cl::opt<std::string> ASTDumpFilter;
};
}
int main(int argc, const char **argv) {
- ActionFactory Factory;
- CommandLineClangTool Tool;
- cl::extrahelp MoreHelp(MoreHelpText);
- Tool.initialize(argc, argv);
+ CommonOptionsParser OptionsParser(argc, argv);
+ ClangTool Tool(OptionsParser.GetCompilations(),
+ OptionsParser.GetSourcePathList());
+ if (Fixit)
+ return Tool.run(newFrontendActionFactory<FixItAction>());
+ clang_check::ClangCheckActionFactory Factory;
return Tool.run(newFrontendActionFactory(&Factory));
}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
index 6775c65..28f94f6 100644
--- a/tools/clang-check/Makefile
+++ b/tools/clang-check/Makefile
@@ -18,7 +18,7 @@ include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
- clangEdit.a clangAST.a clangLex.a clangBasic.a
+ clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
+ clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
-
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index 7162451..abd69fd 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -60,7 +60,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
IntrusiveRefCntPtr<DiagnosticsEngine> InterimDiags(
- new DiagnosticsEngine(DiagIDs, DiagsBuffer));
+ new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer));
// Try to build a CompilerInvocation.
OwningPtr<CompilerInvocation> Invocation(
@@ -71,7 +71,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// Build the diagnostics parser
IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
- CompilerInstance::createDiagnostics(Invocation->getDiagnosticOpts(),
+ CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
argc, argv);
if (!FinalDiags)
return NULL;
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index 9db2c26..bf9f766 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -14,11 +14,13 @@
#include "DiagTool.h"
#include "DiagnosticNames.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/DenseSet.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
+#include "llvm/Support/Process.h"
DEF_DIAGTOOL("tree",
"Show warning flags in a tree view",
@@ -31,11 +33,39 @@ static void printUsage() {
llvm::errs() << "Usage: diagtool tree [--flags-only] [<diagnostic-group>]\n";
}
+static bool showColors(llvm::raw_ostream &out) {
+ if (&out != &llvm::errs() && &out != &llvm::outs())
+ return false;
+ return llvm::errs().is_displayed() && llvm::outs().is_displayed();
+}
+
+static void setColor(bool ShowColors, llvm::raw_ostream &out,
+ llvm::raw_ostream::Colors Color) {
+ if (ShowColors)
+ out << llvm::sys::Process::OutputColor(Color, false, false);
+}
+
+static void resetColor(bool ShowColors, llvm::raw_ostream &out) {
+ if (ShowColors)
+ out << llvm::sys::Process::ResetColor();
+}
+
+static clang::DiagnosticsEngine::Level getLevel(unsigned DiagID) {
+ // FIXME: This feels like a hack.
+ static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
+ new DiagnosticOptions);
+ return Diags.getDiagnosticLevel(DiagID, SourceLocation());
+}
+
static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group,
bool FlagsOnly, unsigned Indent = 0) {
out.indent(Indent * 2);
+
+ bool ShowColors = showColors(out);
+ setColor(ShowColors, out, llvm::raw_ostream::YELLOW);
out << "-W" << Group.getName() << "\n";
-
+ resetColor(ShowColors, out);
+
++Indent;
for (GroupRecord::subgroup_iterator I = Group.subgroup_begin(),
E = Group.subgroup_end();
@@ -47,8 +77,15 @@ static void printGroup(llvm::raw_ostream &out, const GroupRecord &Group,
for (GroupRecord::diagnostics_iterator I = Group.diagnostics_begin(),
E = Group.diagnostics_end();
I != E; ++I) {
+ if (ShowColors) {
+ if (getLevel(I->DiagID) != DiagnosticsEngine::Ignored) {
+ setColor(ShowColors, out, llvm::raw_ostream::GREEN);
+ }
+ }
out.indent(Indent * 2);
- out << I->getName() << "\n";
+ out << I->getName();
+ resetColor(ShowColors, out);
+ out << "\n";
}
}
}
@@ -106,7 +143,7 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
++argv;
}
}
-
+
bool ShowAll = false;
StringRef RootGroup;
@@ -127,6 +164,14 @@ int TreeView::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
return -1;
}
+ if (showColors(out)) {
+ out << '\n';
+ setColor(true, out, llvm::raw_ostream::GREEN);
+ out << "GREEN";
+ resetColor(true, out);
+ out << " = enabled by default\n\n";
+ }
+
if (ShowAll)
return showAll(out, FlagsOnly);
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 71d7766..2545610 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -29,7 +29,8 @@ target_link_libraries(clang
clangParse
clangEdit
clangARCMigrate
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangSema
clangSerialization
clangStaticAnalyzerFrontend
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 270d4fd..f07b0f2 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -35,7 +35,8 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
clangStaticAnalyzerCore.a \
- clangAnalysis.a clangARCMigrate.a clangRewrite.a \
+ clangAnalysis.a clangARCMigrate.a \
+ clangRewriteFrontend.a clangRewriteCore.a \
clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index f8e8a6b..f196856 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -47,86 +47,11 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) {
exit(1);
}
-// FIXME: Define the need for this testing away.
-static int cc1_test(DiagnosticsEngine &Diags,
- const char **ArgBegin, const char **ArgEnd) {
- 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 = createDriverOptTable();
- 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;
- if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags))
- return 1;
-
- // Convert the invocation back to argument strings.
- std::vector<std::string> InvocationArgs;
- Invocation.toArgs(InvocationArgs);
-
- // Dump the converted arguments.
- 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;
- if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
- Invocation2Args.end(), Diags))
- return 1;
-
- // 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 0;
-}
-
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
OwningPtr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- // Run clang -cc1 test.
- if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
- DiagnosticsEngine Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(),
- DiagnosticOptions()));
- return cc1_test(Diags, ArgBegin + 1, ArgEnd);
- }
-
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
@@ -135,8 +60,9 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
- DiagnosticsEngine Diags(DiagID, DiagsBuffer);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
bool Success;
Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
ArgBegin, ArgEnd, Diags);
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 7dd54bd..5587e40 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -19,9 +19,9 @@
#include "clang/Driver/CC1AsOptions.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
@@ -51,7 +51,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;
@@ -189,7 +189,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
ie = Args->filtered_end(); it != ie; ++it, First=false) {
const Arg *A = it;
if (First)
- Opts.InputFile = A->getValue(*Args);
+ Opts.InputFile = A->getValue();
else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
Success = false;
@@ -201,7 +201,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.LLVMArgs.push_back("-fatal-assembler-warnings");
Opts.OutputPath = Args->getLastArgValue(OPT_o);
if (Arg *A = Args->getLastArg(OPT_filetype)) {
- StringRef Name = A->getValue(*Args);
+ StringRef Name = A->getValue();
unsigned OutputType = StringSwitch<unsigned>(Name)
.Case("asm", FT_Asm)
.Case("null", FT_Null)
@@ -329,7 +329,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
- MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
@@ -343,7 +343,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
- MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple);
+ MCAsmBackend *MAB = TheTarget->createMCAsmBackend(Opts.Triple, Opts.CPU);
Str.reset(TheTarget->createMCObjectStreamer(Opts.Triple, Ctx, *MAB, *Out,
CE, Opts.RelaxAll,
Opts.NoExecStack));
@@ -394,11 +394,12 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
InitializeAllAsmParsers();
// Construct our diagnostic client.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(errs(), DiagnosticOptions());
+ = new TextDiagnosticPrinter(errs(), &*DiagOpts);
DiagClient->setPrefix("clang -cc1as");
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- DiagnosticsEngine Diags(DiagID, DiagClient);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 12a9329..81979ec 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Compilation.h"
@@ -19,7 +20,6 @@
#include "clang/Driver/Option.h"
#include "clang/Driver/OptTable.h"
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
@@ -375,7 +375,7 @@ int main(int argc_, const char **argv_) {
llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
- DiagnosticOptions DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
{
// Note that ParseDiagnosticArgs() uses the cc1 option table.
OwningPtr<OptTable> CC1Opts(createDriverOptTable());
@@ -385,17 +385,17 @@ int main(int argc_, const char **argv_) {
// We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
// Any errors that would be diagnosed here will also be diagnosed later,
// when the DiagnosticsEngine actually exists.
- (void) ParseDiagnosticArgs(DiagOpts, *Args);
+ (void) ParseDiagnosticArgs(*DiagOpts, *Args);
}
// Now we can create the DiagnosticsEngine with a properly-filled-out
// DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
+ = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- DiagnosticsEngine Diags(DiagID, DiagClient);
- ProcessWarningOptions(Diags, DiagOpts);
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+ ProcessWarningOptions(Diags, *DiagOpts);
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index bd27b4c..3a6c408 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -145,8 +145,8 @@ RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
///
/// \param Cursor the cursor to visit.
///
-/// \param CheckRegionOfInterest if true, then the caller already checked that
-/// this cursor is within the region of interest.
+/// \param CheckedRegionOfInterest if true, then the caller already checked
+/// that this cursor is within the region of interest.
///
/// \returns true if the visitation should be aborted, false if it
/// should continue.
@@ -182,8 +182,13 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
case CXChildVisit_Continue:
return false;
- case CXChildVisit_Recurse:
- return VisitChildren(Cursor);
+ case CXChildVisit_Recurse: {
+ bool ret = VisitChildren(Cursor);
+ if (PostChildrenVisitor)
+ if (PostChildrenVisitor(Cursor, ClientData))
+ return true;
+ return ret;
+ }
}
llvm_unreachable("Invalid CXChildVisitResult!");
@@ -566,6 +571,16 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
continue;
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
+ // Ignore synthesized ivars here, otherwise if we have something like:
+ // @synthesize prop = _prop;
+ // and '_prop' is not declared, we will encounter a '_prop' ivar before
+ // encountering the 'prop' synthesize declaration and we will think that
+ // we passed the region-of-interest.
+ if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) {
+ if (ivarD->getSynthesize())
+ continue;
+ }
+
// FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
// declarations is a mismatch with the compiler semantics.
if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
@@ -1006,12 +1021,12 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
// Visit synthesized methods since they will be skipped when visiting
// the @interface.
if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
- if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
- if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
+ if (MD->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl)
if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
@@ -1312,7 +1327,12 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
if (Expr *E = TAL.getSourceDeclExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
-
+
+ case TemplateArgument::NullPtr:
+ if (Expr *E = TAL.getSourceNullPtrExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
case TemplateArgument::Expression:
if (Expr *E = TAL.getSourceExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
@@ -1622,6 +1642,7 @@ DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
+DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
#undef DEF_JOB
class DeclVisit : public VisitorJob {
@@ -2198,6 +2219,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
case CXChildVisit_Break: return true;
case CXChildVisit_Continue: break;
case CXChildVisit_Recurse:
+ if (PostChildrenVisitor)
+ WL.push_back(PostChildrenVisit(0, Cursor));
EnqueueWorkList(WL, S);
break;
}
@@ -2314,6 +2337,11 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
}
break;
}
+
+ case VisitorJob::PostChildrenVisitKind:
+ if (PostChildrenVisitor(Parent, ClientData))
+ return true;
+ break;
}
}
return false;
@@ -2528,12 +2556,13 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
bool IncludeBriefCommentsInCodeCompletion
= options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+ bool ForSerialization = options & CXTranslationUnit_ForSerialization;
// Configure the diagnostics.
- DiagnosticOptions DiagOpts;
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
- command_line_args));
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ num_command_line_args,
+ command_line_args));
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -2615,6 +2644,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
/*AllowPCHWithCompilerErrors=*/true,
SkipFunctionBodies,
/*UserFilesAreVolatile=*/true,
+ ForSerialization,
&ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {
@@ -2689,7 +2719,8 @@ static void clang_saveTranslationUnit_Impl(void *UserData) {
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
setThreadBackgroundPriority();
- STUI->result = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ bool hadError = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None;
}
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
@@ -3018,6 +3049,10 @@ static CXString getDeclSpelling(Decl *D) {
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return createCXString(Property->getIdentifier()->getName());
+ if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D))
+ if (Module *Mod = ImportD->getImportedModule())
+ return createCXString(Mod->getFullModuleName());
+
return createCXString("");
}
@@ -3219,6 +3254,18 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc());
}
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) {
+ ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs();
+ if (!Locs.empty())
+ return cxloc::translateSourceRange(Ctx,
+ SourceRange(Locs.front(), Locs.back()));
+ }
+ return clang_getNullRange();
+ }
+
// FIXME: A CXCursor_InclusionDirective should give the location of the
// filename, but we don't keep track of this.
@@ -3510,8 +3557,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("BreakStmt");
case CXCursor_ReturnStmt:
return createCXString("ReturnStmt");
- case CXCursor_AsmStmt:
- return createCXString("AsmStmt");
+ case CXCursor_GCCAsmStmt:
+ return createCXString("GCCAsmStmt");
case CXCursor_MSAsmStmt:
return createCXString("MSAsmStmt");
case CXCursor_ObjCAtTryStmt:
@@ -3614,6 +3661,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("ObjCDynamicDecl");
case CXCursor_CXXAccessSpecifier:
return createCXString("CXXAccessSpecifier");
+ case CXCursor_ModuleImportDecl:
+ return createCXString("ModuleImport");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3810,7 +3859,8 @@ unsigned clang_isInvalid(enum CXCursorKind K) {
}
unsigned clang_isDeclaration(enum CXCursorKind K) {
- return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl;
+ return (K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl) ||
+ (K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl);
}
unsigned clang_isReference(enum CXCursorKind K) {
@@ -3957,7 +4007,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
- if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl)
+ if (!clang_isDeclaration(C.kind))
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
@@ -4092,7 +4142,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
return SourceRange(Start, End);
}
- if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4115,7 +4165,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
/// \brief Retrieves the "raw" cursor extent, which is then extended to include
/// the decl-specifier-seq for declarations.
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
- if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4809,6 +4859,9 @@ typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data);
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data);
+
namespace {
class AnnotateTokensWorker {
AnnotateTokensData &Annotated;
@@ -4820,6 +4873,13 @@ class AnnotateTokensWorker {
CursorVisitor AnnotateVis;
SourceManager &SrcMgr;
bool HasContextSensitiveKeywords;
+
+ struct PostChildrenInfo {
+ CXCursor Cursor;
+ SourceRange CursorRange;
+ unsigned BeforeChildrenTokenIdx;
+ };
+ llvm::SmallVector<PostChildrenInfo, 8> PostChildrenInfos;
bool MoreTokens() const { return TokIdx < NumTokens; }
unsigned NextToken() const { return TokIdx; }
@@ -4848,12 +4908,15 @@ public:
AnnotateTokensVisitor, this,
/*VisitPreprocessorLast=*/true,
/*VisitIncludedEntities=*/false,
- RegionOfInterest),
+ RegionOfInterest,
+ /*VisitDeclsOnly=*/false,
+ AnnotateTokensPostChildrenVisitor),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
+ bool postVisitChildren(CXCursor cursor);
void AnnotateTokens();
/// \brief Determine whether the annotator saw any cursors that have
@@ -4861,6 +4924,10 @@ public:
bool hasContextSensitiveKeywords() const {
return HasContextSensitiveKeywords;
}
+
+ ~AnnotateTokensWorker() {
+ assert(PostChildrenInfos.empty());
+ }
};
}
@@ -5062,7 +5129,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
// Adjust the annotated range based specific declarations.
const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
- if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) {
+ if (clang_isDeclaration(cursorK)) {
Decl *D = cxcursor::getCursorDecl(cursor);
SourceLocation StartLoc;
@@ -5121,25 +5188,47 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
}
}
- // Visit children to get their cursor information.
- const unsigned BeforeChildren = NextToken();
- VisitChildren(cursor);
+ // Before recursing into the children keep some state that we are going
+ // to use in the AnnotateTokensWorker::postVisitChildren callback to do some
+ // extra work after the child nodes are visited.
+ // Note that we don't call VisitChildren here to avoid traversing statements
+ // code-recursively which can blow the stack.
+
+ PostChildrenInfo Info;
+ Info.Cursor = cursor;
+ Info.CursorRange = cursorRange;
+ Info.BeforeChildrenTokenIdx = NextToken();
+ PostChildrenInfos.push_back(Info);
+
+ return CXChildVisit_Recurse;
+}
+
+bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) {
+ if (PostChildrenInfos.empty())
+ return false;
+ const PostChildrenInfo &Info = PostChildrenInfos.back();
+ if (!clang_equalCursors(Info.Cursor, cursor))
+ return false;
+
+ const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx;
const unsigned AfterChildren = NextToken();
+ SourceRange cursorRange = Info.CursorRange;
// Scan the tokens that are at the end of the cursor, but are not captured
// but the child cursors.
annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange);
-
+
// Scan the tokens that are at the beginning of the cursor, but are not
// capture by the child cursors.
for (unsigned I = BeforeChildren; I != AfterChildren; ++I) {
if (!clang_isInvalid(clang_getCursorKind(Cursors[I])))
break;
-
+
Cursors[I] = cursor;
}
- return CXChildVisit_Continue;
+ PostChildrenInfos.pop_back();
+ return false;
}
static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
@@ -5148,6 +5237,12 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent);
}
+static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
+ CXClientData client_data) {
+ return static_cast<AnnotateTokensWorker*>(client_data)->
+ postVisitChildren(cursor);
+}
+
namespace {
/// \brief Uses the macro expansions in the preprocessing record to find
@@ -5732,13 +5827,61 @@ CXString clang_Cursor_getBriefCommentText(CXCursor C) {
CXComment clang_Cursor_getParsedComment(CXCursor C) {
if (!clang_isDeclaration(C.kind))
- return cxcomment::createCXComment(NULL);
+ return cxcomment::createCXComment(NULL, NULL);
const Decl *D = getCursorDecl(C);
const ASTContext &Context = getCursorContext(C);
- const comments::FullComment *FC = Context.getCommentForDecl(D);
+ const comments::FullComment *FC = Context.getCommentForDecl(D, /*PP=*/ NULL);
+
+ return cxcomment::createCXComment(FC, getCursorTU(C));
+}
+
+CXModule clang_Cursor_getModule(CXCursor C) {
+ if (C.kind == CXCursor_ModuleImportDecl) {
+ if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C)))
+ return ImportD->getImportedModule();
+ }
+
+ return 0;
+}
+
+CXModule clang_Module_getParent(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->Parent;
+}
+
+CXString clang_Module_getName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->Name);
+}
- return cxcomment::createCXComment(FC);
+CXString clang_Module_getFullName(CXModule CXMod) {
+ if (!CXMod)
+ return createCXString("");
+ Module *Mod = static_cast<Module*>(CXMod);
+ return createCXString(Mod->getFullModuleName());
+}
+
+unsigned clang_Module_getNumTopLevelHeaders(CXModule CXMod) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+ return Mod->TopHeaders.size();
+}
+
+CXFile clang_Module_getTopLevelHeader(CXModule CXMod, unsigned Index) {
+ if (!CXMod)
+ return 0;
+ Module *Mod = static_cast<Module*>(CXMod);
+
+ if (Index < Mod->TopHeaders.size())
+ return const_cast<FileEntry *>(Mod->TopHeaders[Index]);
+
+ return 0;
}
} // end: extern "C"
@@ -5994,6 +6137,9 @@ void SetSafetyThreadStackSize(unsigned Value) {
}
void clang::setThreadBackgroundPriority() {
+ if (getenv("LIBCLANG_BGPRIO_DISABLE"))
+ return;
+
// FIXME: Move to llvm/Support and make it cross-platform.
#ifdef __APPLE__
setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index 240b0f6..9bc3efa 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -67,8 +67,9 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
= dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(
getCursorDecl(C))) {
switch (PartialSpec->getTagKind()) {
- case TTK_Class: return CXCursor_ClassDecl;
+ case TTK_Interface:
case TTK_Struct: return CXCursor_StructDecl;
+ case TTK_Class: return CXCursor_ClassDecl;
case TTK_Union: return CXCursor_UnionDecl;
case TTK_Enum: return CXCursor_NoDeclFound;
}
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 0073b50..46af661 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -223,8 +223,6 @@ clang_getCompletionParent(CXCompletionString completion_string,
if (!CCStr)
return createCXString((const char *)0);
- if (kind)
- *kind = CCStr->getParentContextKind();
return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
}
@@ -248,6 +246,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Diagnostics produced while performing code completion.
SmallVector<StoredDiagnostic, 8> Diagnostics;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+
/// \brief Diag object
IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
@@ -307,8 +307,10 @@ static llvm::sys::cas_flag CodeCompletionResultObjects;
AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
+ DiagOpts(new DiagnosticOptions),
Diag(new DiagnosticsEngine(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ &*DiagOpts)),
FileSystemOpts(FileSystemOpts),
FileMgr(new FileManager(FileSystemOpts)),
SourceMgr(new SourceManager(*Diag, *FileMgr)),
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 14722e0..3154480 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -19,7 +19,7 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/DiagnosticRenderer.h"
-#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -87,7 +87,7 @@ public:
class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
public:
CXDiagnosticRenderer(const LangOptions &LangOpts,
- const DiagnosticOptions &DiagOpts,
+ DiagnosticOptions *DiagOpts,
CXDiagnosticSetImpl *mainSet)
: DiagnosticNoteRenderer(LangOpts, DiagOpts),
CurrentSet(mainSet), MainSet(mainSet) {}
@@ -191,9 +191,9 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
if (!TU->Diagnostics) {
CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
TU->Diagnostics = Set;
- DiagnosticOptions DOpts;
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
- DOpts, Set);
+ &*DOpts, Set);
for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
ei = AU->stored_diag_end(); it != ei; ++it) {
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index c885dd5..6140032 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -402,6 +402,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
AlreadyStarted = true;
switch (D->getTagKind()) {
+ case TTK_Interface:
case TTK_Struct: Out << "@ST"; break;
case TTK_Class: Out << "@CT"; break;
case TTK_Union: Out << "@UT"; break;
@@ -413,6 +414,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
AlreadyStarted = true;
switch (D->getTagKind()) {
+ case TTK_Interface:
case TTK_Struct: Out << "@SP"; break;
case TTK_Class: Out << "@CP"; break;
case TTK_Union: Out << "@UP"; break;
@@ -424,6 +426,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
if (!AlreadyStarted) {
switch (D->getTagKind()) {
+ case TTK_Interface:
case TTK_Struct: Out << "@S"; break;
case TTK_Class: Out << "@C"; break;
case TTK_Union: Out << "@U"; break;
@@ -725,10 +728,12 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
break;
case TemplateArgument::Declaration:
- if (Decl *D = Arg.getAsDecl())
- Visit(D);
+ Visit(Arg.getAsDecl());
break;
-
+
+ case TemplateArgument::NullPtr:
+ break;
+
case TemplateArgument::TemplateExpansion:
Out << 'P'; // pack expansion of...
// Fall through
@@ -800,36 +805,11 @@ bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
if (!D || D->getLocStart().isInvalid())
return true;
- // Check if the cursor has 'NoLinkage'.
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
- switch (ND->getLinkage()) {
- case ExternalLinkage:
- // Generate USRs for all entities with external linkage.
- break;
- case NoLinkage:
- case UniqueExternalLinkage:
- // We allow enums, typedefs, and structs that have no linkage to
- // have USRs that are anchored to the file they were defined in
- // (e.g., the header). This is a little gross, but in principal
- // enums/anonymous structs/etc. defined in a common header file
- // are referred to across multiple translation units.
- if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) ||
- isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) ||
- isa<VarDecl>(ND) || isa<NamespaceDecl>(ND))
- break;
- // Fall-through.
- case InternalLinkage:
- if (isa<FunctionDecl>(ND))
- break;
- }
+ USRGenerator UG(&D->getASTContext(), &Buf);
+ UG->Visit(const_cast<Decl*>(D));
- {
- USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(const_cast<Decl*>(D));
-
- if (UG->ignoreResults())
- return true;
- }
+ if (UG->ignoreResults())
+ return true;
return false;
}
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 283276f..1426c42 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -43,7 +43,8 @@ set(SOURCES
set(LIBRARIES
clangARCMigrate
- clangRewrite
+ clangRewriteCore
+ clangRewriteFrontend
clangFrontend
clangDriver
clangSerialization
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index c5c9ca8..fa149a0 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -15,12 +15,11 @@
#include "CXString.h"
#include "CXComment.h"
#include "CXCursor.h"
-#include "CXTranslationUnit.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h"
-#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -94,9 +93,9 @@ unsigned clang_Comment_getNumChildren(CXComment CXC) {
CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) {
const Comment *C = getASTNode(CXC);
if (!C || ChildIdx >= C->child_count())
- return createCXComment(NULL);
+ return createCXComment(NULL, NULL);
- return createCXComment(*(C->child_begin() + ChildIdx));
+ return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit);
}
unsigned clang_Comment_isWhitespace(CXComment CXC) {
@@ -134,7 +133,8 @@ CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
if (!ICC)
return createCXString((const char *) 0);
- return createCXString(ICC->getCommandName(), /*DupString=*/ false);
+ const CommandTraits &Traits = getCommandTraits(CXC);
+ return createCXString(ICC->getCommandName(Traits), /*DupString=*/ false);
}
enum CXCommentInlineCommandRenderKind
@@ -221,7 +221,8 @@ CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
if (!BCC)
return createCXString((const char *) 0);
- return createCXString(BCC->getCommandName(), /*DupString=*/ false);
+ const CommandTraits &Traits = getCommandTraits(CXC);
+ return createCXString(BCC->getCommandName(Traits), /*DupString=*/ false);
}
unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
@@ -244,9 +245,9 @@ CXString clang_BlockCommandComment_getArgText(CXComment CXC,
CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
if (!BCC)
- return createCXComment(NULL);
+ return createCXComment(NULL, NULL);
- return createCXComment(BCC->getParagraph());
+ return createCXComment(BCC->getParagraph(), CXC.TranslationUnit);
}
CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
@@ -254,7 +255,7 @@ CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
if (!PCC || !PCC->hasParamName())
return createCXString((const char *) 0);
- return createCXString(PCC->getParamName(), /*DupString=*/ false);
+ return createCXString(PCC->getParamNameAsWritten(), /*DupString=*/ false);
}
unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
@@ -305,7 +306,7 @@ CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
if (!TPCC || !TPCC->hasParamName())
return createCXString((const char *) 0);
- return createCXString(TPCC->getParamName(), /*DupString=*/ false);
+ return createCXString(TPCC->getParamNameAsWritten(), /*DupString=*/ false);
}
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
@@ -405,7 +406,8 @@ public:
/// Separate parts of a FullComment.
struct FullCommentParts {
/// Take a full comment apart and initialize members accordingly.
- FullCommentParts(const FullComment *C);
+ FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits);
const BlockContentComment *Brief;
const ParagraphComment *FirstParagraph;
@@ -415,9 +417,9 @@ struct FullCommentParts {
SmallVector<const BlockContentComment *, 8> MiscBlocks;
};
-FullCommentParts::FullCommentParts(const FullComment *C) :
+FullCommentParts::FullCommentParts(const FullComment *C,
+ const CommandTraits &Traits) :
Brief(NULL), FirstParagraph(NULL), Returns(NULL) {
- const CommandTraits Traits;
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
const Comment *Child = *I;
@@ -440,12 +442,12 @@ FullCommentParts::FullCommentParts(const FullComment *C) :
case Comment::BlockCommandCommentKind: {
const BlockCommandComment *BCC = cast<BlockCommandComment>(Child);
- StringRef CommandName = BCC->getCommandName();
- if (!Brief && Traits.isBriefCommand(CommandName)) {
+ const CommandInfo *Info = Traits.getCommandInfo(BCC->getCommandID());
+ if (!Brief && Info->IsBriefCommand) {
Brief = BCC;
break;
}
- if (!Returns && Traits.isReturnsCommand(CommandName)) {
+ if (!Returns && Info->IsReturnsCommand) {
Returns = BCC;
break;
}
@@ -483,7 +485,8 @@ FullCommentParts::FullCommentParts(const FullComment *C) :
case Comment::VerbatimLineCommentKind: {
const VerbatimLineComment *VLC = cast<VerbatimLineComment>(Child);
- if (!Traits.isDeclarationCommand(VLC->getCommandName()))
+ const CommandInfo *Info = Traits.getCommandInfo(VLC->getCommandID());
+ if (!Info->IsDeclarationCommand)
MiscBlocks.push_back(VLC);
break;
}
@@ -533,7 +536,11 @@ class CommentASTToHTMLConverter :
public ConstCommentVisitor<CommentASTToHTMLConverter> {
public:
/// \param Str accumulator for HTML.
- CommentASTToHTMLConverter(SmallVectorImpl<char> &Str) : Result(Str) { }
+ CommentASTToHTMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits) :
+ FC(FC), Result(Str), Traits(Traits)
+ { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -561,10 +568,11 @@ public:
void appendToResultWithHTMLEscaping(StringRef S);
private:
- const CommandTraits Traits;
-
+ const FullComment *FC;
/// Output stream for HTML.
llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
};
} // end unnamed namespace
@@ -637,14 +645,14 @@ void CommentASTToHTMLConverter::visitParagraphComment(
void CommentASTToHTMLConverter::visitBlockCommandComment(
const BlockCommandComment *C) {
- StringRef CommandName = C->getCommandName();
- if (Traits.isBriefCommand(CommandName)) {
+ const CommandInfo *Info = Traits.getCommandInfo(C->getCommandID());
+ if (Info->IsBriefCommand) {
Result << "<p class=\"para-brief\">";
visitNonStandaloneParagraphComment(C->getParagraph());
Result << "</p>";
return;
}
- if (Traits.isReturnsCommand(CommandName)) {
+ if (Info->IsReturnsCommand) {
Result << "<p class=\"para-returns\">"
"<span class=\"word-returns\">Returns</span> ";
visitNonStandaloneParagraphComment(C->getParagraph());
@@ -661,10 +669,11 @@ void CommentASTToHTMLConverter::visitParamCommandComment(
Result << "<dt class=\"param-name-index-"
<< C->getParamIndex()
<< "\">";
- } else
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ } else {
Result << "<dt class=\"param-name-index-invalid\">";
-
- appendToResultWithHTMLEscaping(C->getParamName());
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
Result << "</dt>";
if (C->isParamIndexValid()) {
@@ -687,10 +696,12 @@ void CommentASTToHTMLConverter::visitTParamCommandComment(
<< "\">";
else
Result << "<dt class=\"tparam-name-index-other\">";
- } else
+ appendToResultWithHTMLEscaping(C->getParamName(FC));
+ } else {
Result << "<dt class=\"tparam-name-index-invalid\">";
-
- appendToResultWithHTMLEscaping(C->getParamName());
+ appendToResultWithHTMLEscaping(C->getParamNameAsWritten());
+ }
+
Result << "</dt>";
if (C->isPositionValid()) {
@@ -735,7 +746,7 @@ void CommentASTToHTMLConverter::visitVerbatimLineComment(
}
void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C);
+ FullCommentParts Parts(C, Traits);
bool FirstParagraphIsBrief = false;
if (Parts.Brief)
@@ -822,7 +833,7 @@ CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
return createCXString((const char *) 0);
SmallString<128> HTML;
- CommentASTToHTMLConverter Converter(HTML);
+ CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
Converter.visit(HTC);
return createCXString(HTML.str(), /* DupString = */ true);
}
@@ -833,7 +844,7 @@ CXString clang_FullComment_getAsHTML(CXComment CXC) {
return createCXString((const char *) 0);
SmallString<1024> HTML;
- CommentASTToHTMLConverter Converter(HTML);
+ CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
Converter.visit(FC);
return createCXString(HTML.str(), /* DupString = */ true);
}
@@ -845,9 +856,11 @@ class CommentASTToXMLConverter :
public ConstCommentVisitor<CommentASTToXMLConverter> {
public:
/// \param Str accumulator for XML.
- CommentASTToXMLConverter(const SourceManager &SM,
- SmallVectorImpl<char> &Str) :
- SM(SM), Result(Str) { }
+ CommentASTToXMLConverter(const FullComment *FC,
+ SmallVectorImpl<char> &Str,
+ const CommandTraits &Traits,
+ const SourceManager &SM) :
+ FC(FC), Result(Str), Traits(Traits), SM(SM) { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -870,11 +883,27 @@ public:
void appendToResultWithXMLEscaping(StringRef S);
private:
- const SourceManager &SM;
+ const FullComment *FC;
/// Output stream for XML.
llvm::raw_svector_ostream Result;
+
+ const CommandTraits &Traits;
+ const SourceManager &SM;
};
+
+void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
+ SmallVectorImpl<char> &Str) {
+ ASTContext &Context = ThisDecl->CurrentDecl->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ llvm::raw_svector_ostream OS(Str);
+ PrintingPolicy PPolicy(LangOpts);
+ PPolicy.SuppressAttributes = true;
+ PPolicy.TerseOutput = true;
+ ThisDecl->CurrentDecl->print(OS, PPolicy,
+ /*Indentation*/0, /*PrintInstantiation*/true);
+}
+
} // end unnamed namespace
void CommentASTToXMLConverter::visitTextComment(const TextComment *C) {
@@ -947,7 +976,8 @@ void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandCommen
void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->getParamName());
+ appendToResultWithXMLEscaping(C->isParamIndexValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
Result << "</Name>";
if (C->isParamIndexValid())
@@ -973,7 +1003,8 @@ void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandCommen
void CommentASTToXMLConverter::visitTParamCommandComment(
const TParamCommandComment *C) {
Result << "<Parameter><Name>";
- appendToResultWithXMLEscaping(C->getParamName());
+ appendToResultWithXMLEscaping(C->isPositionValid() ? C->getParamName(FC)
+ : C->getParamNameAsWritten());
Result << "</Name>";
if (C->isPositionValid() && C->getDepth() == 1) {
@@ -991,7 +1022,7 @@ void CommentASTToXMLConverter::visitVerbatimBlockComment(
if (NumLines == 0)
return;
- Result << llvm::StringSwitch<const char *>(C->getCommandName())
+ Result << llvm::StringSwitch<const char *>(C->getCommandName(Traits))
.Case("code", "<Verbatim xml:space=\"preserve\" kind=\"code\">")
.Default("<Verbatim xml:space=\"preserve\" kind=\"verbatim\">");
for (unsigned i = 0; i != NumLines; ++i) {
@@ -1015,7 +1046,7 @@ void CommentASTToXMLConverter::visitVerbatimLineComment(
}
void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
- FullCommentParts Parts(C);
+ FullCommentParts Parts(C, Traits);
const DeclInfo *DI = C->getDeclInfo();
StringRef RootEndTag;
@@ -1083,7 +1114,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
{
// Print line and column number.
- SourceLocation Loc = DI->ThisDecl->getLocation();
+ SourceLocation Loc = DI->CurrentDecl->getLocation();
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
FileID FID = LocInfo.first;
unsigned FileOffset = LocInfo.second;
@@ -1104,7 +1135,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << ">";
bool FoundName = false;
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->ThisDecl)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DI->CommentDecl)) {
if (DeclarationName DeclName = ND->getDeclName()) {
Result << "<Name>";
std::string Name = DeclName.getAsString();
@@ -1119,7 +1150,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
{
// Print USR.
SmallString<128> USR;
- cxcursor::getDeclCursorUSR(DI->ThisDecl, USR);
+ cxcursor::getDeclCursorUSR(DI->CommentDecl, USR);
if (!USR.empty()) {
Result << "<USR>";
appendToResultWithXMLEscaping(USR);
@@ -1132,6 +1163,15 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << "<Other><Name>unknown</Name>";
}
+ {
+ // Pretty-print the declaration.
+ Result << "<Declaration>";
+ SmallString<128> Declaration;
+ getSourceTextOfDeclaration(DI, Declaration);
+ appendToResultWithXMLEscaping(Declaration);
+ Result << "</Declaration>";
+ }
+
bool FirstParagraphIsBrief = false;
if (Parts.Brief) {
Result << "<Abstract>";
@@ -1163,6 +1203,72 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
visit(Parts.Returns);
Result << "</ResultDiscussion>";
}
+
+ if (DI->CommentDecl->hasAttrs()) {
+ const AttrVec &Attrs = DI->CommentDecl->getAttrs();
+ for (unsigned i = 0, e = Attrs.size(); i != e; i++) {
+ const AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attrs[i]);
+ if (!AA) {
+ if (const DeprecatedAttr *DA = dyn_cast<DeprecatedAttr>(Attrs[i])) {
+ if (DA->getMessage().empty())
+ Result << "<Deprecated/>";
+ else {
+ Result << "<Deprecated>";
+ appendToResultWithXMLEscaping(DA->getMessage());
+ Result << "</Deprecated>";
+ }
+ }
+ else if (const UnavailableAttr *UA = dyn_cast<UnavailableAttr>(Attrs[i])) {
+ if (UA->getMessage().empty())
+ Result << "<Unavailable/>";
+ else {
+ Result << "<Unavailable>";
+ appendToResultWithXMLEscaping(UA->getMessage());
+ Result << "</Unavailable>";
+ }
+ }
+ continue;
+ }
+
+ // 'availability' attribute.
+ Result << "<Availability";
+ StringRef Distribution;
+ if (AA->getPlatform()) {
+ Distribution = AvailabilityAttr::getPrettyPlatformName(
+ AA->getPlatform()->getName());
+ if (Distribution.empty())
+ Distribution = AA->getPlatform()->getName();
+ }
+ Result << " distribution=\"" << Distribution << "\">";
+ VersionTuple IntroducedInVersion = AA->getIntroduced();
+ if (!IntroducedInVersion.empty()) {
+ Result << "<IntroducedInVersion>"
+ << IntroducedInVersion.getAsString()
+ << "</IntroducedInVersion>";
+ }
+ VersionTuple DeprecatedInVersion = AA->getDeprecated();
+ if (!DeprecatedInVersion.empty()) {
+ Result << "<DeprecatedInVersion>"
+ << DeprecatedInVersion.getAsString()
+ << "</DeprecatedInVersion>";
+ }
+ VersionTuple RemovedAfterVersion = AA->getObsoleted();
+ if (!RemovedAfterVersion.empty()) {
+ Result << "<RemovedAfterVersion>"
+ << RemovedAfterVersion.getAsString()
+ << "</RemovedAfterVersion>";
+ }
+ StringRef DeprecationSummary = AA->getMessage();
+ if (!DeprecationSummary.empty()) {
+ Result << "<DeprecationSummary>";
+ appendToResultWithXMLEscaping(DeprecationSummary);
+ Result << "</DeprecationSummary>";
+ }
+ if (AA->getUnavailable())
+ Result << "<Unavailable/>";
+ Result << "</Availability>";
+ }
+ }
{
bool StartTagEmitted = false;
@@ -1213,15 +1319,16 @@ void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
extern "C" {
-CXString clang_FullComment_getAsXML(CXTranslationUnit TU, CXComment CXC) {
+CXString clang_FullComment_getAsXML(CXComment CXC) {
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
if (!FC)
return createCXString((const char *) 0);
+ CXTranslationUnit TU = CXC.TranslationUnit;
SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
SmallString<1024> XML;
- CommentASTToXMLConverter Converter(SM, XML);
+ CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM);
Converter.visit(FC);
return createCXString(XML.str(), /* DupString = */ true);
}
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index 753877e..5134317 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -15,20 +15,29 @@
#define LLVM_CLANG_CXCOMMENT_H
#include "clang-c/Index.h"
+#include "CXTranslationUnit.h"
#include "clang/AST/Comment.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Frontend/ASTUnit.h"
namespace clang {
+namespace comments {
+ class CommandTraits;
+}
+
namespace cxcomment {
-inline CXComment createCXComment(const comments::Comment *C) {
+inline CXComment createCXComment(const comments::Comment *C,
+ CXTranslationUnit TU) {
CXComment Result;
- Result.Data = C;
+ Result.ASTNode = C;
+ Result.TranslationUnit = TU;
return Result;
}
inline const comments::Comment *getASTNode(CXComment CXC) {
- return static_cast<const comments::Comment *>(CXC.Data);
+ return static_cast<const comments::Comment *>(CXC.ASTNode);
}
template<typename T>
@@ -40,6 +49,14 @@ inline const T *getASTNodeAs(CXComment CXC) {
return dyn_cast<T>(C);
}
+inline ASTContext &getASTContext(CXComment CXC) {
+ return static_cast<ASTUnit *>(CXC.TranslationUnit->TUData)->getASTContext();
+}
+
+inline comments::CommandTraits &getCommandTraits(CXComment CXC) {
+ return getASTContext(CXC).getCommentCommandTraits();
+}
+
} // end namespace cxcomment
} // end namespace clang
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 2757af4..8d3e169 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -15,6 +15,7 @@
#include "CXTranslationUnit.h"
#include "CXCursor.h"
+#include "CXType.h"
#include "CXString.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/AST/Decl.h"
@@ -145,8 +146,8 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
K = CXCursor_ReturnStmt;
break;
- case Stmt::AsmStmtClass:
- K = CXCursor_AsmStmt;
+ case Stmt::GCCAsmStmtClass:
+ K = CXCursor_GCCAsmStmt;
break;
case Stmt::MSAsmStmtClass:
@@ -432,6 +433,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ case Stmt::FunctionParmPackExprClass:
case Stmt::UnresolvedLookupExprClass:
K = CXCursor_DeclRefExpr;
break;
@@ -794,194 +796,20 @@ CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
-static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU,
- ObjCContainerDecl *Container,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods,
- bool MovedToSuper) {
- if (!Container)
- return;
-
- // In categories look for overriden methods from protocols. A method from
- // category is not "overriden" since it is considered as the "same" method
- // (same USR) as the one from the interface.
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
- // Check whether we have a matching method at this category but only if we
- // are at the super class level.
- if (MovedToSuper)
- if (ObjCMethodDecl *
- Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- if (Method != Overridden) {
- // We found an override at this category; there is no need to look
- // into its protocols.
- Methods.push_back(MakeCXCursor(Overridden, TU));
- return;
- }
-
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
- return;
- }
-
- // Check whether we have a matching method at this level.
- if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- if (Method != Overridden) {
- // We found an override at this level; there is no need to look
- // into other protocols or categories.
- Methods.push_back(MakeCXCursor(Overridden, TU));
- return;
- }
-
- if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) {
- for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
- PEnd = Protocol->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
- }
-
- if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
- for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
- PEnd = Interface->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
-
- for (ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethodsRecurse(TU, Category, Method, Methods,
- MovedToSuper);
-
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
- return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods,
- /*MovedToSuper=*/true);
- }
-}
-
-static inline void CollectOverriddenMethods(CXTranslationUnit TU,
- ObjCContainerDecl *Container,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- CollectOverriddenMethodsRecurse(TU, Container, Method, Methods,
- /*MovedToSuper=*/false);
-}
-
-static void collectOverriddenMethodsSlow(CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &overridden) {
- assert(Method->isOverriding());
-
- if (ObjCProtocolDecl *
- ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
- CollectOverriddenMethods(TU, ProtD, Method, overridden);
-
- } else if (ObjCImplDecl *
- IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
- ObjCInterfaceDecl *ID = IMD->getClassInterface();
- if (!ID)
- return;
- // Start searching for overridden methods using the method from the
- // interface as starting point.
- if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- Method = IFaceMeth;
- CollectOverriddenMethods(TU, ID, Method, overridden);
-
- } else if (ObjCCategoryDecl *
- CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
- ObjCInterfaceDecl *ID = CatD->getClassInterface();
- if (!ID)
- return;
- // Start searching for overridden methods using the method from the
- // interface as starting point.
- if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
- Method = IFaceMeth;
- CollectOverriddenMethods(TU, ID, Method, overridden);
-
- } else {
- CollectOverriddenMethods(TU,
- dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
- Method, overridden);
- }
-}
-
-static void collectOnCategoriesAfterLocation(SourceLocation Loc,
- ObjCInterfaceDecl *Class,
- CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- if (!Class)
- return;
-
- SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
- for (ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
- CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, true);
-
- collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), TU,
- Method, Methods);
-}
-
-/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding()
-/// returns false.
-/// You'd think that in that case there are no overrides but categories can
-/// "introduce" new overridden methods that are missed by Sema because the
-/// overrides lookup that it does for methods, inside implementations, will
-/// stop at the interface level (if there is a method there) and not look
-/// further in super classes.
-static void collectOverriddenMethodsFast(CXTranslationUnit TU,
- ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- assert(!Method->isOverriding());
-
- ObjCContainerDecl *ContD = cast<ObjCContainerDecl>(Method->getDeclContext());
- if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD))
- return;
- ObjCInterfaceDecl *Class = Method->getClassInterface();
- if (!Class)
- return;
-
- collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(),
- TU, Method, Methods);
-}
-
void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden) {
assert(clang_isDeclaration(cursor.kind));
- Decl *D = getCursorDecl(cursor);
+ const NamedDecl *D = dyn_cast_or_null<NamedDecl>(getCursorDecl(cursor));
if (!D)
return;
- // Handle C++ member functions.
CXTranslationUnit TU = getCursorTU(cursor);
- if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
- for (CXXMethodDecl::method_iterator
- M = CXXMethod->begin_overridden_methods(),
- MEnd = CXXMethod->end_overridden_methods();
- M != MEnd; ++M)
- overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU));
- return;
- }
-
- ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D);
- if (!Method)
- return;
+ SmallVector<const NamedDecl *, 8> OverDecls;
+ D->getASTContext().getOverriddenMethods(D, OverDecls);
- if (Method->isRedeclaration()) {
- Method = cast<ObjCContainerDecl>(Method->getDeclContext())->
- getMethod(Method->getSelector(), Method->isInstanceMethod());
- }
-
- if (!Method->isOverriding()) {
- collectOverriddenMethodsFast(TU, Method, overridden);
- } else {
- collectOverriddenMethodsSlow(TU, Method, overridden);
- assert(!overridden.empty() &&
- "ObjCMethodDecl's overriding bit is not as expected");
+ for (SmallVector<const NamedDecl *, 8>::iterator
+ I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) {
+ overridden.push_back(MakeCXCursor(const_cast<NamedDecl*>(*I), TU));
}
}
@@ -1345,4 +1173,16 @@ int clang_Cursor_isDynamicCall(CXCursor C) {
return 0;
}
+CXType clang_Cursor_getReceiverType(CXCursor C) {
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+ const Expr *E = 0;
+ if (clang_isExpression(C.kind))
+ E = getCursorExpr(C);
+
+ if (const ObjCMessageExpr *MsgE = dyn_cast_or_null<ObjCMessageExpr>(E))
+ return cxtype::MakeCXType(MsgE->getReceiverType(), TU);
+
+ return cxtype::MakeCXType(QualType(), TU);
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 15f818a..4e031d2 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -464,6 +464,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86Pascal);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
+ TCALLINGCONV(PnaclCall);
}
#undef TCALLINGCONV
}
@@ -615,7 +616,7 @@ long long clang_getArraySize(CXType CT) {
}
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
- if ((C.kind < CXCursor_FirstDecl) || (C.kind > CXCursor_LastDecl))
+ if (!clang_isDeclaration(C.kind))
return cxstring::createCXString("");
Decl *D = static_cast<Decl*>(C.data[0]);
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 88b70a4..7cf7508 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -1,4 +1,4 @@
-//===- CursorVisitor.h - CursorVisitor interface --------------------------===//
+//===- CursorVisitor.h - CursorVisitor interface ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -32,7 +32,7 @@ public:
NestedNameSpecifierLocVisitKind,
DeclarationNameInfoVisitKind,
MemberRefVisitKind, SizeOfPackExprPartsKind,
- LambdaExprPartsKind };
+ LambdaExprPartsKind, PostChildrenVisitKind };
protected:
void *data[3];
CXCursor parent;
@@ -46,7 +46,6 @@ protected:
public:
Kind getKind() const { return K; }
const CXCursor &getParent() const { return parent; }
- static bool classof(VisitorJob *VJ) { return true; }
};
typedef SmallVector<VisitorJob, 10> VisitorWorkList;
@@ -55,6 +54,13 @@ typedef SmallVector<VisitorJob, 10> VisitorWorkList;
class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
public TypeLocVisitor<CursorVisitor, bool>
{
+public:
+ /// \brief Callback called after child nodes of a cursor have been visited.
+ /// Return true to break visitation or false to continue.
+ typedef bool (*PostChildrenVisitorTy)(CXCursor cursor,
+ CXClientData client_data);
+
+private:
/// \brief The translation unit we are traversing.
CXTranslationUnit TU;
ASTUnit *AU;
@@ -69,6 +75,8 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
/// \brief The visitor function.
CXCursorVisitor Visitor;
+ PostChildrenVisitorTy PostChildrenVisitor;
+
/// \brief The opaque client data, to be passed along to the visitor.
CXClientData ClientData;
@@ -137,9 +145,11 @@ public:
bool VisitPreprocessorLast,
bool VisitIncludedPreprocessingEntries = false,
SourceRange RegionOfInterest = SourceRange(),
- bool VisitDeclsOnly = false)
+ bool VisitDeclsOnly = false,
+ PostChildrenVisitorTy PostChildrenVisitor = 0)
: TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
- Visitor(Visitor), ClientData(ClientData),
+ Visitor(Visitor), PostChildrenVisitor(PostChildrenVisitor),
+ ClientData(ClientData),
VisitPreprocessorLast(VisitPreprocessorLast),
VisitIncludedEntities(VisitIncludedPreprocessingEntries),
RegionOfInterest(RegionOfInterest),
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index acf8838..3614206 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -130,8 +130,20 @@ public:
}
bool VisitDeclStmt(DeclStmt *S) {
- if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ if (IndexCtx.shouldIndexFunctionLocalSymbols()) {
IndexCtx.indexDeclGroupRef(S->getDeclGroup());
+ return true;
+ }
+
+ DeclGroupRef DG = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
+ const Decl *D = *I;
+ if (!D)
+ continue;
+ if (!IndexCtx.isFunctionLocalDecl(D))
+ IndexCtx.indexTopLevelDecl(D);
+ }
+
return true;
}
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
index 7560398..4b6706f 100644
--- a/tools/libclang/IndexDecl.cpp
+++ b/tools/libclang/IndexDecl.cpp
@@ -110,7 +110,7 @@ public:
return true;
}
- bool VisitTypedefDecl(TypedefNameDecl *D) {
+ bool VisitTypedefNameDecl(TypedefNameDecl *D) {
IndexCtx.handleTypedefName(D);
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
return true;
@@ -194,7 +194,7 @@ public:
bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
// Methods associated with a property, even user-declared ones, are
// handled when we handle the property.
- if (D->isSynthesized())
+ if (D->isPropertyAccessor())
return true;
handleObjCMethod(D);
@@ -228,12 +228,12 @@ public:
}
if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
- if (MD->isSynthesized())
+ if (MD->isPropertyAccessor())
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
- if (MD->isSynthesized())
+ if (MD->isPropertyAccessor())
IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
D->getLexicalDeclContext());
}
@@ -305,6 +305,11 @@ public:
IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
return true;
}
+
+ bool VisitImportDecl(ImportDecl *D) {
+ IndexCtx.importedModule(D);
+ return true;
+ }
};
} // anonymous namespace
@@ -325,7 +330,7 @@ void IndexingContext::indexDeclContext(const DeclContext *DC) {
}
}
-void IndexingContext::indexTopLevelDecl(Decl *D) {
+void IndexingContext::indexTopLevelDecl(const Decl *D) {
if (isNotFromSourceFile(D->getLocation()))
return;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 8fe9c36..714a36e 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -68,13 +68,15 @@ public:
const Token &IncludeTok,
StringRef FileName,
bool IsAngled,
+ CharSourceRange FilenameRange,
const FileEntry *File,
- SourceLocation EndLoc,
StringRef SearchPath,
- StringRef RelativePath) {
+ StringRef RelativePath,
+ const Module *Imported) {
bool isImport = (IncludeTok.is(tok::identifier) &&
IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
- IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled);
+ IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled,
+ Imported);
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
@@ -189,6 +191,13 @@ public:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+
+ if (!PPOpts.ImplicitPCHInclude.empty()) {
+ IndexCtx.importedPCH(
+ CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude));
+ }
+
IndexCtx.setASTContext(CI.getASTContext());
Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
@@ -281,13 +290,13 @@ static void clang_indexSourceFile_Impl(void *UserData) {
CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
// Configure the diagnostics.
- DiagnosticOptions DiagOpts;
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
- command_line_args,
- CaptureDiag,
- /*ShouldOwnClient=*/true,
- /*ShouldCloneClient=*/false));
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ num_command_line_args,
+ command_line_args,
+ CaptureDiag,
+ /*ShouldOwnClient=*/true,
+ /*ShouldCloneClient=*/false));
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -346,9 +355,6 @@ static void clang_indexSourceFile_Impl(void *UserData) {
// precompiled headers are involved), we disable it.
CInvok->getLangOpts()->SpellChecking = false;
- if (!requestedToGetTU)
- CInvok->getPreprocessorOpts().DetailedRecord = false;
-
if (index_options & CXIndexOpt_SuppressWarnings)
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
@@ -374,7 +380,6 @@ static void clang_indexSourceFile_Impl(void *UserData) {
bool PrecompilePreamble = false;
bool CacheCodeCompletionResults = false;
PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
- PPOpts.DetailedRecord = false;
PPOpts.AllowPCHWithCompilerErrors = true;
if (requestedToGetTU) {
@@ -383,11 +388,15 @@ static void clang_indexSourceFile_Impl(void *UserData) {
// FIXME: Add a flag for modules.
CacheCodeCompletionResults
= TU_options & CXTranslationUnit_CacheCompletionResults;
- if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
- PPOpts.DetailedRecord = true;
- }
}
+ if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
+ PPOpts.DetailedRecord = true;
+ }
+
+ if (!requestedToGetTU && !CInvok->getLangOpts()->Modules)
+ PPOpts.DetailedRecord = false;
+
DiagnosticErrorTrap DiagTrap(*Diags);
bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags,
IndexAction.get(),
@@ -435,57 +444,39 @@ static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) {
if (!PP.getPreprocessingRecord())
return;
- PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
-
// FIXME: Only deserialize inclusion directives.
- // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
- // that it depends on.
- bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
PreprocessingRecord::iterator I, E;
- if (OnlyLocal) {
- I = PPRec.local_begin();
- E = PPRec.local_end();
- } else {
- I = PPRec.begin();
- E = PPRec.end();
- }
+ llvm::tie(I, E) = Unit.getLocalPreprocessingEntities();
+ bool isModuleFile = Unit.isModuleFile();
for (; I != E; ++I) {
PreprocessedEntity *PPE = *I;
if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
- IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(),
- ID->getFile(), ID->getKind() == InclusionDirective::Import,
- !ID->wasInQuotes());
+ SourceLocation Loc = ID->getSourceRange().getBegin();
+ // Modules have synthetic main files as input, give an invalid location
+ // if the location points to such a file.
+ if (isModuleFile && Unit.isInMainFileID(Loc))
+ Loc = SourceLocation();
+ IdxCtx.ppIncludedFile(Loc, ID->getFileName(),
+ ID->getFile(),
+ ID->getKind() == InclusionDirective::Import,
+ !ID->wasInQuotes(), ID->importedModule());
}
}
}
-static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
- // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
- // that it depends on.
-
- bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
-
- if (OnlyLocal) {
- for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(),
- TLEnd = Unit.top_level_end();
- TL != TLEnd; ++TL) {
- IdxCtx.indexTopLevelDecl(*TL);
- if (IdxCtx.shouldAbort())
- return;
- }
+static bool topLevelDeclVisitor(void *context, const Decl *D) {
+ IndexingContext &IdxCtx = *static_cast<IndexingContext*>(context);
+ IdxCtx.indexTopLevelDecl(D);
+ if (IdxCtx.shouldAbort())
+ return false;
+ return true;
+}
- } else {
- TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl();
- for (TranslationUnitDecl::decl_iterator
- I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) {
- IdxCtx.indexTopLevelDecl(*I);
- if (IdxCtx.shouldAbort())
- return;
- }
- }
+static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ Unit.visitLocalTopLevelDecls(&IdxCtx, topLevelDeclVisitor);
}
static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) {
@@ -539,6 +530,11 @@ static void clang_indexTranslationUnit_Impl(void *UserData) {
if (!Unit)
return;
+ ASTUnit::ConcurrencyCheck Check(*Unit);
+
+ if (const FileEntry *PCHFile = Unit->getPCHFile())
+ IndexCtx->importedPCH(PCHFile);
+
FileManager &FileMgr = Unit->getFileManager();
if (Unit->getOriginalSourceFileName().empty())
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index ace5c75..d4daa49 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -1,4 +1,4 @@
-//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//===- IndexingContext.cpp - Higher level API functions -------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -204,6 +204,26 @@ void IndexingContext::setPreprocessor(Preprocessor &PP) {
static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP);
}
+bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
+ assert(D);
+
+ if (!D->getParentFunctionOrMethod())
+ return false;
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ switch (ND->getLinkage()) {
+ case NoLinkage:
+ case InternalLinkage:
+ return true;
+ case UniqueExternalLinkage:
+ case ExternalLinkage:
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool IndexingContext::shouldAbort() {
if (!CB.abortQuery)
return false;
@@ -220,7 +240,8 @@ void IndexingContext::enteredMainFile(const FileEntry *File) {
void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
StringRef filename,
const FileEntry *File,
- bool isImport, bool isAngled) {
+ bool isImport, bool isAngled,
+ bool isModuleImport) {
if (!CB.ppIncludedFile)
return;
@@ -228,11 +249,44 @@ void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
SA.toCStr(filename),
(CXFile)File,
- isImport, isAngled };
+ isImport, isAngled, isModuleImport };
CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
FileMap[File] = idxFile;
}
+void IndexingContext::importedModule(const ImportDecl *ImportD) {
+ if (!CB.importedASTFile)
+ return;
+
+ Module *Mod = ImportD->getImportedModule();
+ if (!Mod)
+ return;
+ std::string ModuleName = Mod->getFullModuleName();
+
+ CXIdxImportedASTFileInfo Info = {
+ (CXFile)Mod->getASTFile(),
+ Mod,
+ getIndexLoc(ImportD->getLocation()),
+ ImportD->isImplicit()
+ };
+ CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info);
+ (void)astFile;
+}
+
+void IndexingContext::importedPCH(const FileEntry *File) {
+ if (!CB.importedASTFile)
+ return;
+
+ CXIdxImportedASTFileInfo Info = {
+ (CXFile)File,
+ /*module=*/NULL,
+ getIndexLoc(SourceLocation()),
+ /*isImplicit=*/false
+ };
+ CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info);
+ (void)astFile;
+}
+
void IndexingContext::startedTranslationUnit() {
CXIdxClientContainer idxCont = 0;
if (CB.startedTranslationUnit)
@@ -590,7 +644,7 @@ bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
return false;
if (Loc.isInvalid())
return false;
- if (!shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod())
+ if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D))
return false;
if (isNotFromSourceFile(D->getLocation()))
return false;
@@ -855,6 +909,10 @@ void IndexingContext::getEntityInfo(const NamedDecl *D,
EntityInfo.kind = CXIdxEntity_CXXClass;
EntityInfo.lang = CXIdxEntityLang_CXX;
break;
+ case TTK_Interface:
+ EntityInfo.kind = CXIdxEntity_CXXInterface;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
case TTK_Enum:
EntityInfo.kind = CXIdxEntity_Enum; break;
}
@@ -1065,6 +1123,8 @@ bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
return false;
if (isa<ObjCMethodDecl>(D))
return false;
+ if (isa<ImportDecl>(D))
+ return false;
return true;
}
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index 00e1096..0fc7238 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -1,4 +1,4 @@
-//===- IndexingContext.h - Higher level API functions ------------------------===//
+//===- IndexingContext.h - Higher level API functions -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -100,8 +100,6 @@ struct DeclInfo : public CXIdxDeclInfo {
numAttributes = 0;
declAsContainer = semanticContainer = lexicalContainer = 0;
}
-
- static bool classof(const DeclInfo *) { return true; }
};
struct ObjCContainerDeclInfo : public DeclInfo {
@@ -126,7 +124,6 @@ struct ObjCContainerDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
}
- static bool classof(const ObjCContainerDeclInfo *D) { return true; }
private:
void init(bool isForwardRef, bool isImplementation) {
@@ -152,7 +149,6 @@ struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCInterface;
}
- static bool classof(const ObjCInterfaceDeclInfo *D) { return true; }
};
struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
@@ -167,7 +163,6 @@ struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCProtocol;
}
- static bool classof(const ObjCProtocolDeclInfo *D) { return true; }
};
struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
@@ -183,7 +178,6 @@ struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCCategory;
}
- static bool classof(const ObjCCategoryDeclInfo *D) { return true; }
};
struct ObjCPropertyDeclInfo : public DeclInfo {
@@ -197,7 +191,6 @@ struct ObjCPropertyDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_ObjCProperty;
}
- static bool classof(const ObjCPropertyDeclInfo *D) { return true; }
};
struct CXXClassDeclInfo : public DeclInfo {
@@ -209,7 +202,6 @@ struct CXXClassDeclInfo : public DeclInfo {
static bool classof(const DeclInfo *D) {
return D->Kind == Info_CXXClass;
}
- static bool classof(const CXXClassDeclInfo *D) { return true; }
};
struct AttrInfo : public CXIdxAttrInfo {
@@ -221,8 +213,6 @@ struct AttrInfo : public CXIdxAttrInfo {
loc = Loc;
this->A = A;
}
-
- static bool classof(const AttrInfo *) { return true; }
};
struct IBOutletCollectionInfo : public AttrInfo {
@@ -240,7 +230,6 @@ struct IBOutletCollectionInfo : public AttrInfo {
static bool classof(const AttrInfo *A) {
return A->kind == CXIdxAttr_IBOutletCollection;
}
- static bool classof(const IBOutletCollectionInfo *D) { return true; }
};
class AttrListInfo {
@@ -251,8 +240,8 @@ class AttrListInfo {
SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
unsigned ref_cnt;
- AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT
- void operator=(const AttrListInfo&); // DO NOT IMPLEMENT
+ AttrListInfo(const AttrListInfo &) LLVM_DELETED_FUNCTION;
+ void operator=(const AttrListInfo &) LLVM_DELETED_FUNCTION;
public:
AttrListInfo(const Decl *D, IndexingContext &IdxCtx);
@@ -370,6 +359,8 @@ public:
return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
}
+ static bool isFunctionLocalDecl(const Decl *D);
+
bool shouldAbort();
bool hasDiagnosticCallback() const { return CB.diagnostic; }
@@ -378,7 +369,10 @@ public:
void ppIncludedFile(SourceLocation hashLoc,
StringRef filename, const FileEntry *File,
- bool isImport, bool isAngled);
+ bool isImport, bool isAngled, bool isModuleImport);
+
+ void importedModule(const ImportDecl *ImportD);
+ void importedPCH(const FileEntry *File);
void startedTranslationUnit();
@@ -451,7 +445,7 @@ public:
bool isNotFromSourceFile(SourceLocation Loc) const;
- void indexTopLevelDecl(Decl *D);
+ void indexTopLevelDecl(const Decl *D);
void indexTUDeclsInObjCContainer();
void indexDeclGroupRef(DeclGroupRef DG);
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 975d381..93f63cf 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -17,10 +17,11 @@ SHARED_LIBRARY = 1
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
- clangSerialization.a \
- clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
- clangAST.a clangLex.a clangTooling.a clangBasic.a
+USEDLIBS = clangARCMigrate.a clangRewriteCore.a clangRewriteFrontend.a \
+ clangFrontend.a clangDriver.a \
+ clangSerialization.a \
+ clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+ clangAST.a clangLex.a clangTooling.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
@@ -51,4 +52,10 @@ ifeq ($(HOST_OS),Darwin)
LLVMLibsOptions += -Wl,-install_name \
-Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)"
endif
+
+ # If we're doing an Apple-style build, add the LTO object path.
+ ifeq ($(RC_BUILDIT),YES)
+ TempFile := $(shell mkdir -p ${OBJROOT}/dSYMs ; mktemp ${OBJROOT}/dSYMs/clang-lto.XXXXXX)
+ LLVMLibsOptions += -Wl,-object_path_lto -Wl,$(TempFile)
+ endif
endif
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 7131025..4844204 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -657,6 +657,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type:
@@ -689,6 +690,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Null:
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::NullPtr:
return true;
case TemplateArgument::Type: {
@@ -1753,7 +1755,7 @@ bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \
return true; \
}
-DEF_TRAVERSE_STMT(AsmStmt, {
+DEF_TRAVERSE_STMT(GCCAsmStmt, {
StmtQueue.queue(S->getAsmString());
for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) {
StmtQueue.queue(S->getInputConstraintLiteral(I));
@@ -1762,7 +1764,7 @@ DEF_TRAVERSE_STMT(AsmStmt, {
StmtQueue.queue(S->getOutputConstraintLiteral(I));
}
for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) {
- StmtQueue.queue(S->getClobber(I));
+ StmtQueue.queue(S->getClobberStringLiteral(I));
}
// children() iterates over inputExpr and outputExpr.
})
@@ -2141,6 +2143,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { })
DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { })
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { })
+DEF_TRAVERSE_STMT(FunctionParmPackExpr, { })
DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { })
DEF_TRAVERSE_STMT(AtomicExpr, { })
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 610bd91..4495b66 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -13,8 +13,15 @@ clang_Cursor_getNumArguments
clang_Cursor_getObjCSelectorIndex
clang_Cursor_getSpellingNameRange
clang_Cursor_getTranslationUnit
+clang_Cursor_getReceiverType
clang_Cursor_isDynamicCall
clang_Cursor_isNull
+clang_Cursor_getModule
+clang_Module_getParent
+clang_Module_getName
+clang_Module_getFullName
+clang_Module_getNumTopLevelHeaders
+clang_Module_getTopLevelHeader
clang_IndexAction_create
clang_IndexAction_dispose
clang_Range_isNull
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index c7636f9..8717225 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -346,6 +346,7 @@ my %LinkerOptionMap = (
my %CompilerLinkerOptionMap = (
'-fobjc-arc' => 0,
+ '-fno-objc-arc' => 0,
'-fobjc-abi-version' => 0, # This is really a 1 argument, but always has '='
'-fobjc-legacy-dispatch' => 0,
'-mios-simulator-version-min' => 0, # This really has 1 argument, but always has '='
@@ -353,6 +354,7 @@ my %CompilerLinkerOptionMap = (
'-arch' => 1,
'-m32' => 0,
'-m64' => 0,
+ '-stdlib' => 0, # This is really a 1 argument, but always has '='
'-v' => 0,
'-fpascal-strings' => 0,
'-mmacosx-version-min' => 0, # This is really a 1 argument, but always has '='
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 65c4893..a13b235 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -93,30 +93,13 @@ if (grep /^--help-checkers$/, @ARGV) {
}
##----------------------------------------------------------------------------##
-# Some initial preprocessing of Clang options.
+# Declaration of Clang options. Populated later.
##----------------------------------------------------------------------------##
-# Find 'clang'
-my $ClangSB = Cwd::realpath("$RealBin/bin/clang");
-if (!defined $ClangSB || ! -x $ClangSB) {
- $ClangSB = Cwd::realpath("$RealBin/clang");
-}
my $Clang;
-if (!defined $ClangSB || ! -x $ClangSB) {
- # Default to looking for 'clang' in the path.
- $Clang = `which clang`;
- chomp $Clang;
- if ($Clang eq "") {
- DieDiag("No 'clang' executable found in path.\n");
- }
-}
-else {
- $Clang = $ClangSB;
-}
-my $ClangCXX = $Clang;
-$ClangCXX =~ s/\-\d+\.\d+$//;
-$ClangCXX .= "++";
-my $ClangVersion = HtmlEscape(`$Clang --version`);
+my $ClangSB;
+my $ClangCXX;
+my $ClangVersion;
##----------------------------------------------------------------------------##
# GetHTMLRunDir - Construct an HTML directory name for the current sub-run.
@@ -1003,74 +986,107 @@ ENDTEXT
print <<ENDTEXT;
OPTIONS:
- -analyze-headers - Also analyze functions in #included files.
+ -analyze-headers
+
+ Also analyze functions in #included files. By default, such functions
+ are skipped unless they are called by functions within the main source file.
- -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.
+ -o <output location>
+
+ Specifies the output directory for analyzer reports. 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
--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.
+ Display this message.
- --html-title [title] - Specify the title used on generated HTML pages.
- --html-title=[title] If not specified, a default title will be used.
+ -k
+ --keep-going
+
+ Add a "keep on going" option to the specified build command. This option
+ currently supports make and xcodebuild. This is a convenience option; one
+ can specify this behavior directly using build options.
- -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.
-
- -plist-html - By default the output of scan-build is a set of HTML files.
- This option outputs the results as a set of HTML
- and .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.
+ --html-title [title]
+ --html-title=[title]
- --use-cc [compiler path] - $Prog attempts to guess the default compiler for
- --use-cc=[compiler path] your C and Objective-C code. Use this option
- to specify an alternate compiler.
+ Specify the title used on generated HTML pages. If not specified, a default
+ title will be used.
- --use-c++ [compiler path] - $Prog attempts to guess the default compiler for
- --use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
- to specify an alternate compiler.
+ -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.
+
+ -plist-html
+
+ By default the output of scan-build is a set of HTML files. This option
+ outputs the results as a set of HTML and .plist files.
+
+ --status-bugs
+
+ By default, the exit status of scan-build is the same as the executed build
+ command. Specifying this option causes the exit status of scan-build to be 1
+ if it found potential bugs and 0 otherwise.
+
+ --use-cc [compiler path]
+ --use-cc=[compiler path]
+
+ scan-build analyzes a project by interposing a "fake compiler", which
+ executes a real compiler for compilation and the static analyzer for analysis.
+ Because of the current implementation of interposition, scan-build does not
+ know what compiler your project normally uses. Instead, it simply overrides
+ the CC environment variable, and guesses your default compiler.
+
+ In the future, this interposition mechanism to be improved, but if you need
+ scan-build to use a specific compiler for *compilation* then you can use
+ this option to specify a path to that compiler.
+
+ --use-c++ [compiler path]
+ --use-c++=[compiler path]
+
+ This is the same as "-use-cc" but for C++ code.
+
+ -v
+
+ Enable verbose output from scan-build. A second and third '-v' increases
+ verbosity.
- -v - Verbose output from $Prog and the analyzer.
- A second and third '-v' increases verbosity.
+ -V
+ --view
- -V - View analysis results in a web browser when the build
- --view completes.
+ View analysis results in a web browser when the build 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.
+ -no-failure-reports
+
+ Do not create a 'failures' subdirectory that includes analyzer crash reports
+ and preprocessed source files.
- -stats - Generates visitation statistics for the project being analyzed.
+ -stats
+
+ Generates visitation statistics for the project being analyzed.
- -maxloop N - specifiy the number of times a block can be visited before giving
- up. Default is 4. Increase for more comprehensive coverage at a
- cost of speed.
- -internal-stats - Generate internal analyzer statistics.
+ -maxloop <loop count>
+
+ Specifiy the number of times a block can be visited before giving up.
+ Default is 4. Increase for more comprehensive coverage at a cost of speed.
+
+ -internal-stats
+
+ Generate internal analyzer statistics.
+
+ --use-analyzer [Xcode|path to clang]
+ --use-analyzer=[Xcode|path to clang]
+ scan-build uses the 'clang' executable relative to itself for static
+ analysis. One can override this behavior with this option by using the
+ 'clang' packaged with Xcode (on OS X) or from the PATH.
+
CONTROLLING CHECKERS:
A default group of checkers are always run unless explicitly disabled.
@@ -1119,85 +1135,86 @@ foreach my $lang ("c", "objective-c", "objective-c++", "c++") {
}
# Query clang for complete list of checkers.
-pipe(FROM_CHILD, TO_PARENT);
-my $pid = fork();
-if ($pid == 0) {
- close FROM_CHILD;
- open(STDOUT,">&", \*TO_PARENT);
- open(STDERR,">&", \*TO_PARENT);
- exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
-}
-close(TO_PARENT);
-my $foundCheckers = 0;
-while(<FROM_CHILD>) {
- if (/CHECKERS:/) {
- $foundCheckers = 1;
- last;
+if (defined $Clang && -x $Clang) {
+ pipe(FROM_CHILD, TO_PARENT);
+ my $pid = fork();
+ if ($pid == 0) {
+ close FROM_CHILD;
+ open(STDOUT,">&", \*TO_PARENT);
+ open(STDERR,">&", \*TO_PARENT);
+ exec $Clang, ('-cc1', @PluginsToLoad , '-analyzer-checker-help');
}
-}
-if (!$foundCheckers) {
- print " *** Could not query Clang for the list of available checkers.";
-}
-else {
- print("\nAVAILABLE CHECKERS:\n\n");
- my $skip = 0;
+ close(TO_PARENT);
+ my $foundCheckers = 0;
while(<FROM_CHILD>) {
- if (/experimental/) {
- $skip = 1;
- next;
- }
- if ($skip) {
- next if (!/^\s\s[^\s]/);
- $skip = 0;
+ if (/CHECKERS:/) {
+ $foundCheckers = 1;
+ last;
}
- s/^\s\s//;
- if (/^([^\s]+)/) {
- # Is the checker enabled?
- my $checker = $1;
- my $enabled = 0;
- my $aggregate = "";
- foreach my $domain (split /\./, $checker) {
- $aggregate .= $domain;
- if ($EnabledCheckers{$aggregate}) {
- $enabled =1;
- last;
- }
- # append a dot, if an additional domain is added in the next iteration
- $aggregate .= ".";
+ }
+ if (!$foundCheckers) {
+ print " *** Could not query Clang for the list of available checkers.";
+ }
+ else {
+ print("\nAVAILABLE CHECKERS:\n\n");
+ my $skip = 0;
+ while(<FROM_CHILD>) {
+ if (/experimental/) {
+ $skip = 1;
+ next;
+ }
+ if ($skip) {
+ next if (!/^\s\s[^\s]/);
+ $skip = 0;
}
+ s/^\s\s//;
+ if (/^([^\s]+)/) {
+ # Is the checker enabled?
+ my $checker = $1;
+ my $enabled = 0;
+ my $aggregate = "";
+ foreach my $domain (split /\./, $checker) {
+ $aggregate .= $domain;
+ if ($EnabledCheckers{$aggregate}) {
+ $enabled =1;
+ last;
+ }
+ # append a dot, if an additional domain is added in the next iteration
+ $aggregate .= ".";
+ }
- if ($enabled) {
- print " + ";
+ if ($enabled) {
+ print " + ";
+ }
+ else {
+ print " ";
+ }
}
else {
print " ";
}
+ print $_;
}
- else {
- print " ";
- }
- print $_;
- }
+ print "\nNOTE: \"+\" indicates that an analysis is enabled by default.\n"
+ }
+ waitpid($pid,0);
+ close(FROM_CHILD);
}
-waitpid($pid,0);
-close(FROM_CHILD);
print <<ENDTEXT
- NOTE: "+" indicates that an analysis is enabled by default.
-
BUILD OPTIONS
You can specify any build option acceptable to the build command.
EXAMPLE
- $Prog -o /tmp/myhtmldir make -j4
+ scan-build -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.
+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 scan-build analyzes a project. The analyzer
+should support most parallel builds, but not distributed builds.
ENDTEXT
}
@@ -1251,6 +1268,7 @@ if (!@ARGV) {
my $displayHelp = 0;
+my $AnalyzerDiscoveryMethod;
while (@ARGV) {
@@ -1418,6 +1436,16 @@ while (@ARGV) {
push @PluginsToLoad, "-load", shift @ARGV;
next;
}
+ if ($arg eq "--use-analyzer") {
+ shift @ARGV;
+ $AnalyzerDiscoveryMethod = shift @ARGV;
+ next;
+ }
+ if ($arg =~ /^--use-analyzer=(.+)$/) {
+ shift @ARGV;
+ $AnalyzerDiscoveryMethod = $1;
+ next;
+ }
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
@@ -1429,11 +1457,50 @@ if (!@ARGV and $displayHelp == 0) {
$displayHelp = 1;
}
+# Find 'clang'
+if (!defined $AnalyzerDiscoveryMethod) {
+ $Clang = Cwd::realpath("$RealBin/bin/clang");
+ if (!defined $Clang || ! -x $Clang) {
+ $Clang = Cwd::realpath("$RealBin/clang");
+ }
+ if (!defined $Clang || ! -x $Clang) {
+ if (!$displayHelp) {
+ DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
+ " Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
+ }
+ }
+}
+else {
+ if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) {
+ my $xcrun = `which xcrun`;
+ chomp $xcrun;
+ if ($xcrun eq "") {
+ DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n");
+ }
+ $Clang = `$xcrun -toolchain XcodeDefault -find clang`;
+ chomp $Clang;
+ if ($Clang eq "") {
+ DieDiag("No 'clang' executable found by 'xcrun'\n");
+ }
+ }
+ else {
+ $Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
+ if (! -x $Clang) {
+ DieDiag("Cannot find an executable clang at '$Clang'\n");
+ }
+ }
+}
+
if ($displayHelp) {
DisplayHelp();
exit 1;
}
+$ClangCXX = $Clang;
+$ClangCXX =~ s/\-\d+\.\d+$//;
+$ClangCXX .= "++";
+$ClangVersion = HtmlEscape(`$Clang --version`);
+
# Determine where results go.
$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
$HtmlTitle = "${CurrentDirSuffix} - scan-build results"
@@ -1457,15 +1524,12 @@ if (!defined $CmdCXX || ! -x $CmdCXX) {
DieDiag("Executable 'c++-analyzer' does not exist at '$CmdCXX'\n") if(! -x $CmdCXX);
}
-if (!defined $ClangSB || ! -x $ClangSB) {
- Diag("'clang' executable not found in '$RealBin/bin'.\n");
- Diag("Using 'clang' from path: $Clang\n");
-}
+Diag("Using '$Clang' for static analysis\n");
SetHtmlEnv(\@ARGV, $HtmlDir);
if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; }
if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; }
-if ($MaxLoop > 0) { push @AnalysesToRun, '-analyzer-max-loop=$MaxLoop'; }
+if ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; }
# Delay setting up other environment variables in case we can do true
# interposition.
diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/scan-build.1
index 0f43196..0c7ef1d 100644
--- a/tools/scan-build/scan-build.1
+++ b/tools/scan-build/scan-build.1
@@ -1,9 +1,9 @@
.\" This file is distributed under the University of Illinois Open Source
.\" License. See LICENSE.TXT for details.
-.\" $Id: scan-build.1 157412 2012-05-24 20:16:00Z kremenek $
+.\" $Id: scan-build.1 167537 2012-11-07 17:12:37Z jrose $
.Dd May 25, 2012
+.Dt SCAN-BUILD 1
.Os "clang" "3.1"
-.Dt SCAN-BUILD \&1 CLANG
.Sh NAME
.Nm scan-build
.Nd Clang static analyzer
@@ -139,7 +139,7 @@ which is far less precise but can more quickly analyze code.
was the default store model for checker-0.221 and earlier.
.\"
.El
-.Sh RETURN VALUES
+.Sh EXIT STATUS
.Nm
returns the value returned by
.Ar build_command
@@ -188,10 +188,10 @@ Check for undefined results of binary operators.
.It core.VLASize
Check for declarations of VLA of undefined or zero size.
.It core.builtin.BuiltinFunctions
-Evaluate compiler builtin functions, e.g.
+Evaluate compiler builtin functions, e.g.
.Fn alloca .
.It core.builtin.NoReturnFunctions
-Evaluate
+Evaluate
.Ql panic
functions that are known to not return to the caller.
.It core.uninitialized.ArraySubscript
@@ -270,9 +270,10 @@ Check for proper uses of
.Fn CFNumberCreate .
.It osx.coreFoundation.CFRetainRelease
Check for null arguments to
-.Fn CFRetain
+.Fn CFRetain ,
+.Fn CFRelease ,
and
-.Fn CFRelease .
+.Fn CFMakeCollectable .
.It osx.coreFoundation.containers.OutOfBounds
Checks for index out-of-bounds when using the
.Vt CFArray
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index c280bb4..93824af 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -20,10 +20,19 @@ def FindClangSpecs(path):
if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
yield os.path.join(root, f)
-def ModifySpec(path, pathToChecker):
+def ModifySpec(path, isBuiltinAnalyzer, pathToChecker):
t = tempfile.NamedTemporaryFile(delete=False)
foundAnalyzer = False
with open(path) as f:
+ if isBuiltinAnalyzer:
+ # First search for CLANG_ANALYZER_EXEC. Newer
+ # versions of Xcode set EXEC_PATH to be CLANG_ANALYZER_EXEC.
+ with open(path) as f2:
+ for line in f2:
+ if line.find("CLANG_ANALYZER_EXEC") >= 0:
+ pathToChecker = "$(CLANG_ANALYZER_EXEC)"
+ break
+ # Now create a new file.
for line in f:
if not foundAnalyzer:
if line.find("Static Analyzer") >= 0:
@@ -63,6 +72,7 @@ def main():
print "(-) You must quit Xcode first before modifying its configuration files."
return
+ isBuiltinAnalyzer = False
if options.path:
# Expand tildes.
path = os.path.expanduser(options.path)
@@ -74,19 +84,25 @@ def main():
else:
print "(+) Using the Clang bundled with Xcode"
path = options.default
+ isBuiltinAnalyzer = True
try:
xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
except AttributeError:
# Fall back to the default install location when using Python < 2.7.0
xcode_path = "/Developer"
- if (re.search("Xcode.app", xcode_path)):
+ if (xcode_path.find(".app/") != -1):
# Cut off the 'Developer' dir, as the xcspec lies in another part
# of the Xcode.app subtree.
xcode_path = os.path.dirname(xcode_path)
+ foundSpec = False
for x in FindClangSpecs(xcode_path):
- ModifySpec(x, path)
+ foundSpec = True
+ ModifySpec(x, isBuiltinAnalyzer, path)
+
+ if foundSpec == False:
+ print "(-) No compiler configuration file was found. Xcode's analyzer has not been updated."
if __name__ == '__main__':
main()
diff --git a/tools/scan-view/ScanView.py b/tools/scan-view/ScanView.py
index c6dddba..32570b9 100644
--- a/tools/scan-view/ScanView.py
+++ b/tools/scan-view/ScanView.py
@@ -707,6 +707,11 @@ File Bug</h3>
return None
def send_path(self, path):
+ # If the requested path is outside the root directory, do not open it
+ rel = os.path.abspath(os.path.join(self.server.root, path))
+ if not rel.startswith(os.path.abspath(self.server.root) ):
+ return self.send_404()
+
ctype = self.guess_type(path)
if ctype.startswith('text/'):
# Patch file instead
OpenPOWER on IntegriCloud