diff options
Diffstat (limited to 'tools')
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 |