From 01af97d3b23bded2b2b21af19bbc6e4cce49e5b3 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Mon, 2 May 2011 19:39:53 +0000 Subject: Vendor import of clang trunk r130700: http://llvm.org/svn/llvm-project/cfe/trunk@130700 --- tools/c-index-test/Makefile | 3 + tools/c-index-test/c-index-test.c | 39 +- tools/driver/CMakeLists.txt | 1 + tools/driver/Makefile | 2 +- tools/driver/cc1_main.cpp | 2 +- tools/driver/cc1as_main.cpp | 9 +- tools/driver/driver.cpp | 105 ++++- tools/libclang/CIndex.cpp | 807 +++++++++++++++++++++++++------- tools/libclang/CIndexCodeCompletion.cpp | 21 +- tools/libclang/CIndexInclusionStack.cpp | 10 +- tools/libclang/CIndexUSRs.cpp | 10 +- tools/libclang/CIndexer.cpp | 5 + tools/libclang/CMakeLists.txt | 64 +-- tools/libclang/CXCursor.cpp | 9 +- tools/libclang/libclang.darwin.exports | 6 +- tools/libclang/libclang.exports | 4 + tools/scan-build/ccc-analyzer | 66 ++- tools/scan-build/scan-build | 30 +- 18 files changed, 903 insertions(+), 290 deletions(-) (limited to 'tools') diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index 3d9849a3a401..68064041f435 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -13,6 +13,9 @@ TOOLNAME = c-index-test # No plugins, optimize startup time. TOOL_NO_EXPORTS = 1 +# Don't install this. It is used for tests. +NO_INSTALL = 1 + LINK_COMPONENTS := support mc USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \ clangSerialization.a clangParse.a clangSema.a clangAnalysis.a \ diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index d4e567d9e26a..f7b7a367cfd6 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -370,6 +370,23 @@ void PrintDiagnostics(CXTranslationUnit TU) { } } +void PrintMemoryUsage(CXTranslationUnit TU) { + unsigned long total = 0.0; + unsigned i = 0; + CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU); + fprintf(stderr, "Memory usage:\n"); + for (i = 0 ; i != usage.numEntries; ++i) { + const char *name = clang_getTUResourceUsageName(usage.entries[i].kind); + unsigned long amount = usage.entries[i].amount; + total += amount; + fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount, + ((double) amount)/(1024*1024)); + } + fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total, + ((double) total)/(1024*1024)); + clang_disposeCXTUResourceUsage(usage); +} + /******************************************************************************/ /* Logic for testing traversal. */ /******************************************************************************/ @@ -990,7 +1007,7 @@ void print_completion_result(CXCompletionResult *completion_result, int my_stricmp(const char *s1, const char *s2) { while (*s1 && *s2) { - int c1 = tolower(*s1), c2 = tolower(*s2); + int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2); if (c1 < c2) return -1; else if (c1 > c2) @@ -1503,6 +1520,8 @@ static CXCursorVisitor GetVisitor(const char *s) { return FilteredPrintingVisitor; if (strcmp(s, "-usrs") == 0) return USRVisitor; + if (strncmp(s, "-memory-usage", 13) == 0) + return GetVisitor(s + 13); return NULL; } @@ -1519,16 +1538,20 @@ static void print_usage(void) { "[FileCheck prefix]\n" " c-index-test -test-load-source {}*\n"); fprintf(stderr, + " c-index-test -test-load-source-memory-usage " + " {}*\n" " c-index-test -test-load-source-reparse " " {}*\n" " c-index-test -test-load-source-usrs {}*\n" + " c-index-test -test-load-source-usrs-memory-usage " + " {}*\n" " c-index-test -test-annotate-tokens= {}*\n" " c-index-test -test-inclusion-stack-source {}*\n" - " c-index-test -test-inclusion-stack-tu \n" + " c-index-test -test-inclusion-stack-tu \n"); + fprintf(stderr, " c-index-test -test-print-linkage-source {}*\n" " c-index-test -test-print-typekind {}*\n" - " c-index-test -print-usr [ {}]*\n"); - fprintf(stderr, + " c-index-test -print-usr [ {}]*\n" " c-index-test -print-usr-file \n" " c-index-test -write-pch \n\n"); fprintf(stderr, @@ -1569,8 +1592,14 @@ int cindextest_main(int argc, const char **argv) { } else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { CXCursorVisitor I = GetVisitor(argv[1] + 17); + + PostVisitTU postVisit = 0; + if (strstr(argv[1], "-memory-usage")) + postVisit = PrintMemoryUsage; + if (I) - return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL); + return perform_test_load_source(argc - 3, argv + 3, argv[2], I, + postVisit); } else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) return perform_file_scan(argv[2], argv[3], diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 552e7a534427..0c41490175e9 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -23,6 +23,7 @@ set( LLVM_LINK_COMPONENTS bitreader bitwriter codegen + instrumentation ipo selectiondag ) diff --git a/tools/driver/Makefile b/tools/driver/Makefile index d96f9505ffe5..abe70983df42 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -36,7 +36,7 @@ TOOL_INFO_PLIST := Info.plist include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \ - ipo selectiondag + instrumentation ipo selectiondag USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \ diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 7fb394fa5b01..535eaa9c96f8 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -168,7 +168,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // When running with -disable-free, don't do any destruction or shutdown. if (Clang->getFrontendOpts().DisableFree) { - if (Clang->getFrontendOpts().ShowStats) + if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats) llvm::PrintStatistics(); Clang.take(); return !Success; diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 1d544f3d3c9d..ec6ce65a9b8b 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -71,6 +71,7 @@ struct AssemblerInvocation { std::vector IncludePaths; unsigned NoInitialTextSection : 1; + unsigned SaveTemporaryLabels : 1; /// @} /// @name Frontend Options @@ -156,6 +157,7 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, // Language Options Opts.IncludePaths = Args->getAllArgValues(OPT_I); Opts.NoInitialTextSection = Args->hasArg(OPT_n); + Opts.SaveTemporaryLabels = Args->hasArg(OPT_L); // Frontend Options if (Args->hasArg(OPT_INPUT)) { @@ -265,6 +267,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { const TargetAsmInfo *tai = new TargetAsmInfo(*TM); MCContext Ctx(*MAI, tai); + if (Opts.SaveTemporaryLabels) + Ctx.setAllowTemporaryLabels(false); OwningPtr Str; @@ -275,7 +279,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { // FIXME: There is a bit of code duplication with addPassesToEmitFile. if (Opts.OutputType == AssemblerInvocation::FT_Asm) { MCInstPrinter *IP = - TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI); + TheTarget->createMCInstPrinter(*TM, Opts.OutputAsmVariant, *MAI); MCCodeEmitter *CE = 0; TargetAsmBackend *TAB = 0; if (Opts.ShowEncoding) { @@ -283,7 +287,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { TAB = TheTarget->createAsmBackend(Opts.Triple); } Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true, - /*useLoc*/ true, IP, CE, TAB, + /*useLoc*/ true, + /*useCFI*/ true, IP, CE, TAB, Opts.ShowInst)); } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { Str.reset(createNullStreamer(Ctx)); diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 0b5d2c97a4e7..db72da42ea34 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -18,6 +18,7 @@ #include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/OwningPtr.h" @@ -35,6 +36,8 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" #include using namespace clang; using namespace clang::driver; @@ -252,6 +255,85 @@ static void ExpandArgv(int argc, const char **argv, } } +static void ParseProgName(llvm::SmallVectorImpl &ArgVector, + std::set &SavedStrings, + Driver &TheDriver) +{ + // Try to infer frontend type and default target from the program name. + + // suffixes[] contains the list of known driver suffixes. + // Suffixes are compared against the program name in order. + // If there is a match, the frontend type is updated as necessary (CPP/C++). + // If there is no match, a second round is done after stripping the last + // hyphen and everything following it. This allows using something like + // "clang++-2.9". + + // If there is a match in either the first or second round, + // the function tries to identify a target as prefix. E.g. + // "x86_64-linux-clang" as interpreted as suffix "clang" with + // target prefix "x86_64-linux". If such a target prefix is found, + // is gets added via -ccc-host-triple as implicit first argument. + static const struct { + const char *Suffix; + bool IsCXX; + bool IsCPP; + } suffixes [] = { + { "clang", false, false }, + { "clang++", true, false }, + { "clang-c++", true, false }, + { "clang-cc", false, false }, + { "clang-cpp", false, true }, + { "clang-g++", true, false }, + { "clang-gcc", false, false }, + { "cc", false, false }, + { "cpp", false, true }, + { "++", true, false }, + }; + std::string ProgName(llvm::sys::path::stem(ArgVector[0])); + llvm::StringRef ProgNameRef(ProgName); + llvm::StringRef Prefix; + + for (int Components = 2; Components; --Components) { + bool FoundMatch = false; + size_t i; + + for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) { + if (ProgNameRef.endswith(suffixes[i].Suffix)) { + FoundMatch = true; + if (suffixes[i].IsCXX) + TheDriver.CCCIsCXX = true; + if (suffixes[i].IsCPP) + TheDriver.CCCIsCPP = true; + break; + } + } + + if (FoundMatch) { + llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-', + ProgNameRef.size() - strlen(suffixes[i].Suffix)); + if (LastComponent != llvm::StringRef::npos) + Prefix = ProgNameRef.slice(0, LastComponent); + break; + } + + llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-'); + if (LastComponent == llvm::StringRef::npos) + break; + ProgNameRef = ProgNameRef.slice(0, LastComponent); + } + + if (Prefix.empty()) + return; + + std::string IgnoredError; + if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + ArgVector.insert(&ArgVector[1], + SaveStringInSet(SavedStrings, Prefix)); + ArgVector.insert(&ArgVector[1], + SaveStringInSet(SavedStrings, std::string("-ccc-host-triple"))); + } +} + int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); @@ -328,19 +410,8 @@ int main(int argc_, const char **argv_) { TheDriver.setInstalledDir(InstalledPath); } - // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++ - // compiler. This matches things like "c++", "clang++", and "clang++-1.1". - // - // Note that we intentionally want to use argv[0] here, to support "clang++" - // being a symlink. - // - // We use *argv instead of argv[0] to work around a bogus g++ warning. - const char *progname = argv_[0]; - std::string ProgName(llvm::sys::path::stem(progname)); - if (llvm::StringRef(ProgName).endswith("++") || - llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) { - TheDriver.CCCIsCXX = true; - } + llvm::InitializeAllTargets(); + ParseProgName(argv, SavedStrings, TheDriver); // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); @@ -352,6 +423,11 @@ int main(int argc_, const char **argv_) { if (TheDriver.CCPrintHeaders) TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE"); + // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE. + TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS"); + if (TheDriver.CCLogDiagnostics) + TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE"); + // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a // command line behind the scenes. if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) { @@ -378,8 +454,7 @@ int main(int argc_, const char **argv_) { argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end()); } - llvm::OwningPtr C(TheDriver.BuildCompilation(argv.size(), - &argv[0])); + llvm::OwningPtr C(TheDriver.BuildCompilation(argv)); int Res = 0; if (C.get()) Res = TheDriver.ExecuteCompilation(*C); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index cd1b8d66673a..28f1506988e1 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -34,6 +34,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" #include "clang/Analysis/Support/SaveAndRestore.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/PrettyStackTrace.h" @@ -115,7 +116,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, // location accordingly. SourceLocation EndLoc = R.getEnd(); if (EndLoc.isValid() && EndLoc.isMacroID()) - EndLoc = SM.getSpellingLoc(EndLoc); + EndLoc = SM.getInstantiationRange(EndLoc).second; if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) { unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts); EndLoc = EndLoc.getFileLocWithOffset(Length); @@ -187,6 +188,10 @@ class CursorVisitor : public DeclVisitor, // be suppressed. unsigned MaxPCHLevel; + /// \brief Whether we should visit the preprocessing record entries last, + /// after visiting other declarations. + bool VisitPreprocessorLast; + /// \brief When valid, a source range to which the cursor should restrict /// its search. SourceRange RegionOfInterest; @@ -234,11 +239,12 @@ public: CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor, CXClientData ClientData, unsigned MaxPCHLevel, + bool VisitPreprocessorLast, SourceRange RegionOfInterest = SourceRange()) : TU(TU), AU(static_cast(TU->TUData)), Visitor(Visitor), ClientData(ClientData), - MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest), - DI_current(0) + MaxPCHLevel(MaxPCHLevel), VisitPreprocessorLast(VisitPreprocessorLast), + RegionOfInterest(RegionOfInterest), DI_current(0) { Parent.kind = CXCursor_NoDeclFound; Parent.data[0] = 0; @@ -266,6 +272,7 @@ public: bool VisitChildren(CXCursor Parent); // Declaration visitors + bool VisitTypeAliasDecl(TypeAliasDecl *D); bool VisitAttributes(Decl *D); bool VisitBlockDecl(BlockDecl *B); bool VisitCXXRecordDecl(CXXRecordDecl *D); @@ -342,7 +349,11 @@ public: bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL); bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); - + bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL); + bool VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL); + bool VisitElaboratedTypeLoc(ElaboratedTypeLoc TL); + // Data-recursive visitor functions. bool IsInRegionOfInterest(CXCursor C); bool RunVisitorWorkList(VisitorWorkList &WL); @@ -472,7 +483,8 @@ CursorVisitor::getPreprocessedEntities() { /// \returns true if the visitation should be aborted, false if it /// should continue. bool CursorVisitor::VisitChildren(CXCursor Cursor) { - if (clang_isReference(Cursor.kind)) { + if (clang_isReference(Cursor.kind) && + Cursor.kind != CXCursor_CXXBaseSpecifier) { // By definition, references have no children. return false; } @@ -483,68 +495,96 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); - assert(D && "Invalid declaration cursor"); + if (!D) + return false; + return VisitAttributes(D) || Visit(D); } - if (clang_isStatement(Cursor.kind)) - return Visit(getCursorStmt(Cursor)); - if (clang_isExpression(Cursor.kind)) - return Visit(getCursorExpr(Cursor)); + if (clang_isStatement(Cursor.kind)) { + if (Stmt *S = getCursorStmt(Cursor)) + return Visit(S); + + return false; + } + + if (clang_isExpression(Cursor.kind)) { + if (Expr *E = getCursorExpr(Cursor)) + return Visit(E); + + return false; + } if (clang_isTranslationUnit(Cursor.kind)) { CXTranslationUnit tu = getCursorTU(Cursor); ASTUnit *CXXUnit = static_cast(tu->TUData); - if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && - RegionOfInterest.isInvalid()) { - for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), - TLEnd = CXXUnit->top_level_end(); - TL != TLEnd; ++TL) { - if (Visit(MakeCXCursor(*TL, tu), true)) + + int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast }; + for (unsigned I = 0; I != 2; ++I) { + if (VisitOrder[I]) { + if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && + RegionOfInterest.isInvalid()) { + for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), + TLEnd = CXXUnit->top_level_end(); + TL != TLEnd; ++TL) { + if (Visit(MakeCXCursor(*TL, tu), true)) + return true; + } + } else if (VisitDeclContext( + CXXUnit->getASTContext().getTranslationUnitDecl())) return true; + continue; } - } else if (VisitDeclContext( - CXXUnit->getASTContext().getTranslationUnitDecl())) - return true; - // Walk the preprocessing record. - if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { - // FIXME: Once we have the ability to deserialize a preprocessing record, - // do so. - PreprocessingRecord::iterator E, EEnd; - for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) { - if (MacroInstantiation *MI = dyn_cast(*E)) { - if (Visit(MakeMacroInstantiationCursor(MI, tu))) - return true; - - continue; - } - - if (MacroDefinition *MD = dyn_cast(*E)) { - if (Visit(MakeMacroDefinitionCursor(MD, tu))) - return true; + // Walk the preprocessing record. + if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { + // FIXME: Once we have the ability to deserialize a preprocessing record, + // do so. + PreprocessingRecord::iterator E, EEnd; + for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) { + if (MacroInstantiation *MI = dyn_cast(*E)) { + if (Visit(MakeMacroInstantiationCursor(MI, tu))) + return true; + + continue; + } - continue; - } - - if (InclusionDirective *ID = dyn_cast(*E)) { - if (Visit(MakeInclusionDirectiveCursor(ID, tu))) - return true; + if (MacroDefinition *MD = dyn_cast(*E)) { + if (Visit(MakeMacroDefinitionCursor(MD, tu))) + return true; + + continue; + } - continue; + if (InclusionDirective *ID = dyn_cast(*E)) { + if (Visit(MakeInclusionDirectiveCursor(ID, tu))) + return true; + + continue; + } } } } + return false; } + if (Cursor.kind == CXCursor_CXXBaseSpecifier) { + if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) { + if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) { + return Visit(BaseTSInfo->getTypeLoc()); + } + } + } + // Nothing to visit at the moment. return false; } bool CursorVisitor::VisitBlockDecl(BlockDecl *B) { - if (Visit(B->getSignatureAsWritten()->getTypeLoc())) - return true; + if (TypeSourceInfo *TSInfo = B->getSignatureAsWritten()) + if (Visit(TSInfo->getTypeLoc())) + return true; if (Stmt *Body = B->getBody()) return Visit(MakeCXCursor(Body, StmtParent, TU)); @@ -604,6 +644,13 @@ bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { return false; } +bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) { + if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) { if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) return Visit(TSInfo->getTypeLoc()); @@ -742,7 +789,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { // FIXME: Attributes? } - if (ND->isThisDeclarationADefinition()) { + if (ND->isThisDeclarationADefinition() && !ND->isLateTemplateParsed()) { if (CXXConstructorDecl *Constructor = dyn_cast(ND)) { // Find the initializers that were written in the source. llvm::SmallVector WrittenInits; @@ -1315,6 +1362,9 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: + if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc())) + return true; + return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(), TAL.getTemplateNameLoc()); } @@ -1362,7 +1412,9 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { case BuiltinType::LongDouble: case BuiltinType::NullPtr: case BuiltinType::Overload: + case BuiltinType::BoundMember: case BuiltinType::Dependent: + case BuiltinType::UnknownAny: break; case BuiltinType::ObjCId: @@ -1388,7 +1440,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { } bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getTypedefDecl(), TL.getNameLoc(), TU)); + return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU)); } bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { @@ -1400,10 +1452,7 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { } bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - // FIXME: We can't visit the template type parameter, because there's - // no context information with which we can match up the depth/index in the - // type to the appropriate - return false; + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { @@ -1503,6 +1552,35 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { return false; } +bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { + if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) + return true; + + return false; +} + +bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc TL) { + // Visit the nested-name-specifier, if there is one. + if (TL.getQualifierLoc() && + VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) + return true; + + // Visit the template arguments. + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) + return true; + + return false; +} + +bool CursorVisitor::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { + if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) + return true; + + return Visit(TL.getNamedTypeLoc()); +} + bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { return Visit(TL.getPatternLoc()); } @@ -1703,12 +1781,14 @@ public: void VisitObjCEncodeExpr(ObjCEncodeExpr *E); void VisitObjCMessageExpr(ObjCMessageExpr *M); void VisitOverloadExpr(OverloadExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S); void VisitSwitchStmt(SwitchStmt *S); void VisitWhileStmt(WhileStmt *W); void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E); + void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); + void VisitExpressionTraitExpr(ExpressionTraitExpr *E); void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U); void VisitVAArgExpr(VAArgExpr *E); void VisitSizeOfPackExpr(SizeOfPackExpr *E); @@ -1797,8 +1877,8 @@ void EnqueueVisitor:: VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); AddDeclarationNameInfo(E); - if (NestedNameSpecifier *Qualifier = E->getQualifier()) - AddNestedNameSpecifier(Qualifier, E->getQualifierRange()); + if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) + AddNestedNameSpecifierLoc(QualifierLoc); if (!E->isImplicitAccess()) AddStmt(E->getBase()); } @@ -1934,12 +2014,8 @@ void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) { // visit it. // FIXME: If we ever want to show these implicit accesses, this will be // unfortunate. However, clang_getCursor() relies on this behavior. - if (CXXThisExpr *This - = llvm::dyn_cast(M->getBase()->IgnoreParenImpCasts())) - if (This->isImplicit()) - return; - - AddStmt(M->getBase()); + if (!M->isImplicitAccess()) + AddStmt(M->getBase()); } void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { AddTypeLoc(E->getEncodedTypeSourceInfo()); @@ -1958,7 +2034,7 @@ void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) { AddStmt(E->getIndexExpr(Node.getArrayExprIndex())); break; case OffsetOfNode::Field: - AddMemberRef(Node.getField(), Node.getRange().getEnd()); + AddMemberRef(Node.getField(), Node.getSourceRange().getEnd()); break; case OffsetOfNode::Identifier: case OffsetOfNode::Base: @@ -1972,7 +2048,8 @@ void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) { AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); WL.push_back(OverloadExprParts(E, Parent)); } -void EnqueueVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { EnqueueChildren(E); if (E->isArgumentType()) AddTypeLoc(E->getArgumentTypeInfo()); @@ -1991,6 +2068,7 @@ void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) { AddStmt(W->getCond()); AddDecl(W->getConditionVariable()); } + void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { AddTypeLoc(E->getQueriedTypeSourceInfo()); } @@ -2000,6 +2078,14 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { AddTypeLoc(E->getLhsTypeSourceInfo()); } +void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + AddTypeLoc(E->getQueriedTypeSourceInfo()); +} + +void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + EnqueueChildren(E); +} + void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) { VisitOverloadExpr(U); if (!U->isImplicitAccess()) @@ -2124,8 +2210,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { MemberExpr *M = cast(&LI)->get(); // Visit the nested-name-specifier - if (NestedNameSpecifier *Qualifier = M->getQualifier()) - if (VisitNestedNameSpecifier(Qualifier, M->getQualifierRange())) + if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) return true; // Visit the declaration name. @@ -2146,8 +2232,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { case VisitorJob::DeclRefExprPartsKind: { DeclRefExpr *DR = cast(&LI)->get(); // Visit nested-name-specifier, if present. - if (NestedNameSpecifier *Qualifier = DR->getQualifier()) - if (VisitNestedNameSpecifier(Qualifier, DR->getQualifierRange())) + if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) return true; // Visit declaration name. if (VisitDeclarationNameInfo(DR->getNameInfo())) @@ -2157,8 +2243,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { case VisitorJob::OverloadExprPartsKind: { OverloadExpr *O = cast(&LI)->get(); // Visit the nested-name-specifier. - if (NestedNameSpecifier *Qualifier = O->getQualifier()) - if (VisitNestedNameSpecifier(Qualifier, O->getQualifierRange())) + if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) return true; // Visit the declaration name. if (VisitDeclarationNameInfo(O->getNameInfo())) @@ -2253,6 +2339,13 @@ void clang_disposeIndex(CXIndex CIdx) { delete static_cast(CIdx); } +void clang_toggleCrashRecovery(unsigned isEnabled) { + if (isEnabled) + llvm::CrashRecoveryContext::Enable(); + else + llvm::CrashRecoveryContext::Disable(); +} + CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, const char *ast_filename) { if (!CIdx) @@ -2327,27 +2420,37 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { // Configure the diagnostics. DiagnosticOptions DiagOpts; - llvm::IntrusiveRefCntPtr Diags; - Diags = CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, - command_line_args); + llvm::IntrusiveRefCntPtr + Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, + command_line_args)); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar > + DiagCleanup(Diags.getPtr()); + + llvm::OwningPtr > + RemappedFiles(new std::vector()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + std::vector > RemappedCleanup(RemappedFiles.get()); - llvm::SmallVector RemappedFiles; for (unsigned I = 0; I != num_unsaved_files; ++I) { llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); - RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, - Buffer)); + RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); } - llvm::SmallVector Args; + llvm::OwningPtr > + Args(new std::vector()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar > + ArgsCleanup(Args.get()); - // The 'source_filename' argument is optional. If the caller does not - // specify it then it is assumed that the source file is specified - // in the actual argument list. - if (source_filename) - Args.push_back(source_filename); - // Since the Clang C library is primarily used by batch tools dealing with // (often very broken) source code, where spell-checking can have a // significant negative impact on performance (particularly when @@ -2362,26 +2465,37 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { } } if (!FoundSpellCheckingArgument) - Args.push_back("-fno-spell-checking"); + Args->push_back("-fno-spell-checking"); - Args.insert(Args.end(), command_line_args, - command_line_args + num_command_line_args); + Args->insert(Args->end(), command_line_args, + command_line_args + num_command_line_args); + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + // Put the source file after command_line_args otherwise if '-x' flag is + // present it will be unused. + if (source_filename) + Args->push_back(source_filename); // Do we need the detailed preprocessing record? if (options & CXTranslationUnit_DetailedPreprocessingRecord) { - Args.push_back("-Xclang"); - Args.push_back("-detailed-preprocessing-record"); + Args->push_back("-Xclang"); + Args->push_back("-detailed-preprocessing-record"); } unsigned NumErrors = Diags->getClient()->getNumErrors(); llvm::OwningPtr Unit( - ASTUnit::LoadFromCommandLine(Args.data(), Args.data() + Args.size(), + ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0 + /* vector::data() not portable */, + Args->size() ? (&(*Args)[0] + Args->size()) :0, Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), /*CaptureDiagnostics=*/true, - RemappedFiles.data(), - RemappedFiles.size(), + RemappedFiles->size() ? &(*RemappedFiles)[0]:0, + RemappedFiles->size(), + /*RemappedFilesKeepOriginalName=*/true, PrecompilePreamble, CompleteTranslationUnit, CacheCodeCompetionResults, @@ -2503,16 +2617,23 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { ASTUnit *CXXUnit = static_cast(TU->TUData); ASTUnit::ConcurrencyCheck Check(*CXXUnit); - llvm::SmallVector RemappedFiles; + llvm::OwningPtr > + RemappedFiles(new std::vector()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + std::vector > RemappedCleanup(RemappedFiles.get()); + for (unsigned I = 0; I != num_unsaved_files; ++I) { llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); const llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); - RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, - Buffer)); + RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); } - if (!CXXUnit->Reparse(RemappedFiles.data(), RemappedFiles.size())) + if (!CXXUnit->Reparse(RemappedFiles->size() ? &(*RemappedFiles)[0] : 0, + RemappedFiles->size())) RTUI->result = 0; } @@ -2627,7 +2748,22 @@ CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { begin.int_data, end.int_data }; return Result; } +} // end: extern "C" + +static void createNullLocation(CXFile *file, unsigned *line, + unsigned *column, unsigned *offset) { + if (file) + *file = 0; + if (line) + *line = 0; + if (column) + *column = 0; + if (offset) + *offset = 0; + return; +} +extern "C" { void clang_getInstantiationLocation(CXSourceLocation location, CXFile *file, unsigned *line, @@ -2636,14 +2772,7 @@ void clang_getInstantiationLocation(CXSourceLocation location, SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); if (!location.ptr_data[0] || Loc.isInvalid()) { - if (file) - *file = 0; - if (line) - *line = 0; - if (column) - *column = 0; - if (offset) - *offset = 0; + createNullLocation(file, line, column, offset); return; } @@ -2651,8 +2780,18 @@ void clang_getInstantiationLocation(CXSourceLocation location, *static_cast(location.ptr_data[0]); SourceLocation InstLoc = SM.getInstantiationLoc(Loc); + // Check that the FileID is invalid on the instantiation location. + // This can manifest in invalid code. + FileID fileID = SM.getFileID(InstLoc); + bool Invalid = false; + const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); + if (!sloc.isFile() || Invalid) { + createNullLocation(file, line, column, offset); + return; + } + if (file) - *file = (void *)SM.getFileEntryForID(SM.getFileID(InstLoc)); + *file = (void *)SM.getFileEntryForSLocEntry(sloc); if (line) *line = SM.getInstantiationLineNumber(InstLoc); if (column) @@ -2816,7 +2955,8 @@ unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, CXClientData client_data) { CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data, - getCursorASTUnit(parent)->getMaxPCHLevel()); + getCursorASTUnit(parent)->getMaxPCHLevel(), + false); return CursorVis.VisitChildren(parent); } @@ -3216,6 +3356,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("UsingDirective"); case CXCursor_UsingDeclaration: return createCXString("UsingDeclaration"); + case CXCursor_TypeAliasDecl: + return createCXString("TypeAliasDecl"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -3272,7 +3414,7 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { // the region of interest, rather than starting from the translation unit. CXCursor Parent = clang_getTranslationUnitCursor(TU); CursorVisitor CursorVis(TU, GetCursorVisitor, &Result, - Decl::MaxPCHLevel, SourceLocation(SLoc)); + Decl::MaxPCHLevel, true, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); } @@ -3587,25 +3729,30 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) { if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) { Decl *D = cxcursor::getCursorDecl(C); SourceRange R = D->getSourceRange(); - + + // Adjust the start of the location for declarations preceded by + // declaration specifiers. + SourceLocation StartLoc; if (const DeclaratorDecl *DD = dyn_cast(D)) { - if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { - TypeLoc TL = TI->getTypeLoc(); - SourceLocation TLoc = TL.getSourceRange().getBegin(); - if (TLoc.isValid() && R.getBegin().isValid() && - SrcMgr.isBeforeInTranslationUnit(TLoc, R.getBegin())) - R.setBegin(TLoc); - } + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); + } else if (TypedefDecl *Typedef = dyn_cast(D)) { + if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); + } - // FIXME: Multiple variables declared in a single declaration - // currently lack the information needed to correctly determine their - // ranges when accounting for the type-specifier. We use context - // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, - // and if so, whether it is the first decl. - if (VarDecl *VD = dyn_cast(D)) { - if (!cxcursor::isFirstInDeclGroup(C)) - R.setBegin(VD->getLocation()); - } + if (StartLoc.isValid() && R.getBegin().isValid() && + SrcMgr.isBeforeInTranslationUnit(StartLoc, R.getBegin())) + R.setBegin(StartLoc); + + // FIXME: Multiple variables declared in a single declaration + // currently lack the information needed to correctly determine their + // ranges when accounting for the type-specifier. We use context + // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, + // and if so, whether it is the first decl. + if (VarDecl *VD = dyn_cast(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + R.setBegin(VD->getLocation()); } return R; @@ -3660,7 +3807,9 @@ CXCursor clang_getCursorReferenced(CXCursor C) { if (clang_isStatement(C.kind)) { Stmt *S = getCursorStmt(C); if (GotoStmt *Goto = dyn_cast_or_null(S)) - return MakeCXCursor(Goto->getLabel()->getStmt(), getCursorDecl(C), tu); + if (LabelDecl *label = Goto->getLabel()) + if (LabelStmt *labelS = label->getStmt()) + return MakeCXCursor(labelS, getCursorDecl(C), tu); return clang_getNullCursor(); } @@ -3749,6 +3898,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { // declaration and definition. case Decl::Namespace: case Decl::Typedef: + case Decl::TypeAlias: case Decl::TemplateTypeParm: case Decl::EnumConstant: case Decl::Field: @@ -4215,7 +4365,8 @@ class AnnotateTokensWorker { unsigned PreprocessingTokIdx; CursorVisitor AnnotateVis; SourceManager &SrcMgr; - + bool HasContextSensitiveKeywords; + bool MoreTokens() const { return TokIdx < NumTokens; } unsigned NextToken() const { return TokIdx; } void AdvanceToken() { ++TokIdx; } @@ -4231,8 +4382,9 @@ public: NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0), AnnotateVis(tu, AnnotateTokensVisitor, this, - Decl::MaxPCHLevel, RegionOfInterest), - SrcMgr(static_cast(tu->TUData)->getSourceManager()) {} + Decl::MaxPCHLevel, true, RegionOfInterest), + SrcMgr(static_cast(tu->TUData)->getSourceManager()), + HasContextSensitiveKeywords(false) { } void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); @@ -4240,6 +4392,12 @@ public: void AnnotateTokens() { AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU())); } + + /// \brief Determine whether the annotator saw any cursors that have + /// context-sensitive keywords. + bool hasContextSensitiveKeywords() const { + return HasContextSensitiveKeywords; + } }; } @@ -4273,7 +4431,52 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Recurse; - + + if (!HasContextSensitiveKeywords) { + // Objective-C properties can have context-sensitive keywords. + if (cursor.kind == CXCursor_ObjCPropertyDecl) { + if (ObjCPropertyDecl *Property + = dyn_cast_or_null(getCursorDecl(cursor))) + HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0; + } + // Objective-C methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl || + cursor.kind == CXCursor_ObjCClassMethodDecl) { + if (ObjCMethodDecl *Method + = dyn_cast_or_null(getCursorDecl(cursor))) { + if (Method->getObjCDeclQualifier()) + HasContextSensitiveKeywords = true; + else { + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; ++P) { + if ((*P)->getObjCDeclQualifier()) { + HasContextSensitiveKeywords = true; + break; + } + } + } + } + } + // C++ methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_CXXMethod) { + if (CXXMethodDecl *Method + = dyn_cast_or_null(getCursorDecl(cursor))) { + if (Method->hasAttr() || Method->hasAttr()) + HasContextSensitiveKeywords = true; + } + } + // C++ classes can have context-sensitive keywords. + else if (cursor.kind == CXCursor_StructDecl || + cursor.kind == CXCursor_ClassDecl || + cursor.kind == CXCursor_ClassTemplate || + cursor.kind == CXCursor_ClassTemplatePartialSpecialization) { + if (Decl *D = getCursorDecl(cursor)) + if (D->hasAttr()) + HasContextSensitiveKeywords = true; + } + } + if (clang_isPreprocessing(cursor.kind)) { // For macro instantiations, just note where the beginning of the macro // instantiation occurs. @@ -4342,15 +4545,19 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { if (MD->isSynthesized()) return CXChildVisit_Continue; } + + SourceLocation StartLoc; if (const DeclaratorDecl *DD = dyn_cast(D)) { - if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { - TypeLoc TL = TI->getTypeLoc(); - SourceLocation TLoc = TL.getSourceRange().getBegin(); - if (TLoc.isValid() && L.isValid() && - SrcMgr.isBeforeInTranslationUnit(TLoc, L)) - cursorRange.setBegin(TLoc); - } + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); + } else if (TypedefDecl *Typedef = dyn_cast(D)) { + if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); } + + if (StartLoc.isValid() && L.isValid() && + SrcMgr.isBeforeInTranslationUnit(StartLoc, L)) + cursorRange.setBegin(StartLoc); } // If the location of the cursor occurs within a macro instantiation, record @@ -4444,43 +4651,36 @@ static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, return static_cast(client_data)->Visit(cursor, parent); } -// This gets run a separate thread to avoid stack blowout. -static void runAnnotateTokensWorker(void *UserData) { - ((AnnotateTokensWorker*)UserData)->AnnotateTokens(); +namespace { + struct clang_annotateTokens_Data { + CXTranslationUnit TU; + ASTUnit *CXXUnit; + CXToken *Tokens; + unsigned NumTokens; + CXCursor *Cursors; + }; } -extern "C" { - -void clang_annotateTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens, - CXCursor *Cursors) { - - if (NumTokens == 0 || !Tokens || !Cursors) - return; - - // Any token we don't specifically annotate will have a NULL cursor. - CXCursor C = clang_getNullCursor(); - for (unsigned I = 0; I != NumTokens; ++I) - Cursors[I] = C; - - ASTUnit *CXXUnit = static_cast(TU->TUData); - if (!CXXUnit) - return; - - ASTUnit::ConcurrencyCheck Check(*CXXUnit); +// This gets run a separate thread to avoid stack blowout. +static void clang_annotateTokensImpl(void *UserData) { + CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU; + ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit; + CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens; + const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens; + CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors; // Determine the region of interest, which contains all of the tokens. SourceRange RegionOfInterest; - RegionOfInterest.setBegin(cxloc::translateSourceLocation( - clang_getTokenLocation(TU, Tokens[0]))); - RegionOfInterest.setEnd(cxloc::translateSourceLocation( - clang_getTokenLocation(TU, - Tokens[NumTokens - 1]))); + RegionOfInterest.setBegin( + cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); + RegionOfInterest.setEnd( + cxloc::translateSourceLocation(clang_getTokenLocation(TU, + Tokens[NumTokens-1]))); // A mapping from the source locations found when re-lexing or traversing the // region of interest to the corresponding cursors. AnnotateTokensData Annotated; - + // Relex the tokens within the source range to look for preprocessing // directives. SourceManager &SourceMgr = CXXUnit->getSourceManager(); @@ -4488,7 +4688,7 @@ void clang_annotateTokens(CXTranslationUnit TU, = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); std::pair EndLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); - + llvm::StringRef Buffer; bool Invalid = false; if (BeginLocInfo.first == EndLocInfo.first && @@ -4499,13 +4699,13 @@ void clang_annotateTokens(CXTranslationUnit TU, Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); Lex.SetCommentRetentionState(true); - + // Lex tokens in raw mode until we hit the end of the range, to avoid // entering #includes or expanding macros. while (true) { Token Tok; Lex.LexFromRawLexer(Tok); - + reprocess: if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { // We have found a preprocessing directive. Gobble it up so that we @@ -4515,49 +4715,158 @@ void clang_annotateTokens(CXTranslationUnit TU, // // FIXME: Some simple tests here could identify macro definitions and // #undefs, to provide specific cursor kinds for those. - std::vector Locations; + llvm::SmallVector Locations; do { Locations.push_back(Tok.getLocation()); Lex.LexFromRawLexer(Tok); } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); - + using namespace cxcursor; CXCursor Cursor - = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), - Locations.back()), + = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), + Locations.back()), TU); for (unsigned I = 0, N = Locations.size(); I != N; ++I) { Annotated[Locations[I].getRawEncoding()] = Cursor; } - + if (Tok.isAtStartOfLine()) goto reprocess; - + continue; } - + if (Tok.is(tok::eof)) break; } } - + // Annotate all of the source locations in the region of interest that map to // a specific cursor. AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens, TU, RegionOfInterest); - - // Run the worker within a CrashRecoveryContext. + // FIXME: We use a ridiculous stack size here because the data-recursion // algorithm uses a large stack frame than the non-data recursive version, // and AnnotationTokensWorker currently transforms the data-recursion // algorithm back into a traditional recursion by explicitly calling // VisitChildren(). We will need to remove this explicit recursive call. + W.AnnotateTokens(); + + // If we ran into any entities that involve context-sensitive keywords, + // take another pass through the tokens to mark them as such. + if (W.hasContextSensitiveKeywords()) { + for (unsigned I = 0; I != NumTokens; ++I) { + if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier) + continue; + + if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) { + IdentifierInfo *II = static_cast(Tokens[I].ptr_data); + if (ObjCPropertyDecl *Property + = dyn_cast_or_null(getCursorDecl(Cursors[I]))) { + if (Property->getPropertyAttributesAsWritten() != 0 && + llvm::StringSwitch(II->getName()) + .Case("readonly", true) + .Case("assign", true) + .Case("readwrite", true) + .Case("retain", true) + .Case("copy", true) + .Case("nonatomic", true) + .Case("atomic", true) + .Case("getter", true) + .Case("setter", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + } + continue; + } + + if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl || + Cursors[I].kind == CXCursor_ObjCClassMethodDecl) { + IdentifierInfo *II = static_cast(Tokens[I].ptr_data); + if (llvm::StringSwitch(II->getName()) + .Case("in", true) + .Case("out", true) + .Case("inout", true) + .Case("oneway", true) + .Case("bycopy", true) + .Case("byref", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + continue; + } + + if (Cursors[I].kind == CXCursor_CXXMethod) { + IdentifierInfo *II = static_cast(Tokens[I].ptr_data); + if (CXXMethodDecl *Method + = dyn_cast_or_null(getCursorDecl(Cursors[I]))) { + if ((Method->hasAttr() || + Method->hasAttr()) && + Method->getLocation().getRawEncoding() != Tokens[I].int_data[1] && + llvm::StringSwitch(II->getName()) + .Case("final", true) + .Case("override", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + } + continue; + } + + if (Cursors[I].kind == CXCursor_ClassDecl || + Cursors[I].kind == CXCursor_StructDecl || + Cursors[I].kind == CXCursor_ClassTemplate) { + IdentifierInfo *II = static_cast(Tokens[I].ptr_data); + if (II->getName() == "final") { + // We have to be careful with 'final', since it could be the name + // of a member class rather than the context-sensitive keyword. + // So, check whether the cursor associated with this + Decl *D = getCursorDecl(Cursors[I]); + if (CXXRecordDecl *Record = dyn_cast_or_null(D)) { + if ((Record->hasAttr()) && + Record->getIdentifier() != II) + Tokens[I].int_data[0] = CXToken_Keyword; + } else if (ClassTemplateDecl *ClassTemplate + = dyn_cast_or_null(D)) { + CXXRecordDecl *Record = ClassTemplate->getTemplatedDecl(); + if ((Record->hasAttr()) && + Record->getIdentifier() != II) + Tokens[I].int_data[0] = CXToken_Keyword; + } + } + continue; + } + } + } +} + +extern "C" { + +void clang_annotateTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens, + CXCursor *Cursors) { + + if (NumTokens == 0 || !Tokens || !Cursors) + return; + + // Any token we don't specifically annotate will have a NULL cursor. + CXCursor C = clang_getNullCursor(); + for (unsigned I = 0; I != NumTokens; ++I) + Cursors[I] = C; + + ASTUnit *CXXUnit = static_cast(TU->TUData); + if (!CXXUnit) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors }; llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, runAnnotateTokensWorker, &W, + if (!RunSafely(CRC, clang_annotateTokensImpl, &data, GetSafetyThreadStackSize() * 2)) { fprintf(stderr, "libclang: crash detected while annotating tokens\n"); } } + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -4639,14 +4948,22 @@ extern "C" { enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { if (clang_isDeclaration(cursor.kind)) if (Decl *D = cxcursor::getCursorDecl(cursor)) { - if (D->hasAttr() || - (isa(D) && cast(D)->isDeleted())) + if (isa(D) && cast(D)->isDeleted()) return CXAvailability_Available; - if (D->hasAttr()) + switch (D->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + return CXAvailability_Available; + + case AR_Deprecated: return CXAvailability_Deprecated; + + case AR_Unavailable: + return CXAvailability_NotAvailable; + } } - + return CXAvailability_Available; } @@ -4866,10 +5183,141 @@ CXType clang_getIBOutletCollectionType(CXCursor C) { IBOutletCollectionAttr *A = cast(cxcursor::getCursorAttr(C)); - return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C)); + return cxtype::MakeCXType(A->getInterFace(), cxcursor::getCursorTU(C)); } } // end: extern "C" +//===----------------------------------------------------------------------===// +// Inspecting memory usage. +//===----------------------------------------------------------------------===// + +typedef std::vector MemUsageEntries; + +static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries, + enum CXTUResourceUsageKind k, + unsigned long amount) { + CXTUResourceUsageEntry entry = { k, amount }; + entries.push_back(entry); +} + +extern "C" { + +const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) { + const char *str = ""; + switch (kind) { + case CXTUResourceUsage_AST: + str = "ASTContext: expressions, declarations, and types"; + break; + case CXTUResourceUsage_Identifiers: + str = "ASTContext: identifiers"; + break; + case CXTUResourceUsage_Selectors: + str = "ASTContext: selectors"; + break; + case CXTUResourceUsage_GlobalCompletionResults: + str = "Code completion: cached global results"; + break; + case CXTUResourceUsage_SourceManagerContentCache: + str = "SourceManager: content cache allocator"; + break; + case CXTUResourceUsage_AST_SideTables: + str = "ASTContext: side tables"; + break; + case CXTUResourceUsage_SourceManager_Membuffer_Malloc: + str = "SourceManager: malloc'ed memory buffers"; + break; + case CXTUResourceUsage_SourceManager_Membuffer_MMap: + str = "SourceManager: mmap'ed memory buffers"; + break; + case CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc: + str = "ExternalASTSource: malloc'ed memory buffers"; + break; + case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap: + str = "ExternalASTSource: mmap'ed memory buffers"; + break; + } + return str; +} + +CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) { + if (!TU) { + CXTUResourceUsage usage = { (void*) 0, 0, 0 }; + return usage; + } + + ASTUnit *astUnit = static_cast(TU->TUData); + llvm::OwningPtr entries(new MemUsageEntries()); + ASTContext &astContext = astUnit->getASTContext(); + + // How much memory is used by AST nodes and types? + createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST, + (unsigned long) astContext.getASTAllocatedMemory()); + + // How much memory is used by identifiers? + createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Identifiers, + (unsigned long) astContext.Idents.getAllocator().getTotalMemory()); + + // How much memory is used for selectors? + createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Selectors, + (unsigned long) astContext.Selectors.getTotalMemory()); + + // How much memory is used by ASTContext's side tables? + createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_AST_SideTables, + (unsigned long) astContext.getSideTableAllocatedMemory()); + + // How much memory is used for caching global code completion results? + unsigned long completionBytes = 0; + if (GlobalCodeCompletionAllocator *completionAllocator = + astUnit->getCachedCompletionAllocator().getPtr()) { + completionBytes = completionAllocator-> getTotalMemory(); + } + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_GlobalCompletionResults, + completionBytes); + + // How much memory is being used by SourceManager's content cache? + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManagerContentCache, + (unsigned long) astContext.getSourceManager().getContentCacheSize()); + + // How much memory is being used by the MemoryBuffer's in SourceManager? + const SourceManager::MemoryBufferSizes &srcBufs = + astUnit->getSourceManager().getMemoryBufferSizes(); + + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManager_Membuffer_Malloc, + (unsigned long) srcBufs.malloc_bytes); + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManager_Membuffer_MMap, + (unsigned long) srcBufs.mmap_bytes); + + // How much memory is being used by the ExternalASTSource? + if (ExternalASTSource *esrc = astContext.getExternalSource()) { + const ExternalASTSource::MemoryBufferSizes &sizes = + esrc->getMemoryBufferSizes(); + + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc, + (unsigned long) sizes.malloc_bytes); + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_ExternalASTSource_Membuffer_MMap, + (unsigned long) sizes.mmap_bytes); + } + + CXTUResourceUsage usage = { (void*) entries.get(), + (unsigned) entries->size(), + entries->size() ? &(*entries)[0] : 0 }; + entries.take(); + return usage; +} + +void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) { + if (usage.data) + delete (MemUsageEntries*) usage.data; +} + +} // end extern "C" + //===----------------------------------------------------------------------===// // Misc. utility functions. //===----------------------------------------------------------------------===// @@ -4906,3 +5354,4 @@ CXString clang_getClangVersion() { } } // end: extern "C" + diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 292719bebdae..e85e80246f9e 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -201,7 +201,7 @@ clang_getCompletionAvailability(CXCompletionString completion_string) { /// \brief The CXCodeCompleteResults structure we allocate internally; /// the client only sees the initial CXCodeCompleteResults structure. struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { - AllocatedCXCodeCompleteResults(); + AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts); ~AllocatedCXCodeCompleteResults(); /// \brief Diagnostics produced while performing code completion. @@ -216,10 +216,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { FileSystemOptions FileSystemOpts; /// \brief File manager, used for diagnostics. - FileManager FileMgr; + llvm::IntrusiveRefCntPtr FileMgr; /// \brief Source manager, used for diagnostics. - SourceManager SourceMgr; + llvm::IntrusiveRefCntPtr SourceMgr; /// \brief Temporary files that should be removed once we have finished /// with the code-completion results. @@ -243,12 +243,14 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// Used for debugging purposes only. static llvm::sys::cas_flag CodeCompletionResultObjects; -AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() +AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( + const FileSystemOptions& FileSystemOpts) : CXCodeCompleteResults(), Diag(new Diagnostic( llvm::IntrusiveRefCntPtr(new DiagnosticIDs))), - FileMgr(FileSystemOpts), - SourceMgr(*Diag, FileMgr) { + FileSystemOpts(FileSystemOpts), + FileMgr(new FileManager(FileSystemOpts)), + SourceMgr(new SourceManager(*Diag, *FileMgr)) { if (getenv("LIBCLANG_OBJTRACKING")) { llvm::sys::AtomicIncrement(&CodeCompletionResultObjects); fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects); @@ -380,7 +382,8 @@ void clang_codeCompleteAt_Impl(void *UserData) { } // Parse the resulting source file to find code-completion results. - AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; + AllocatedCXCodeCompleteResults *Results = + new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts()); Results->Results = 0; Results->NumResults = 0; @@ -393,8 +396,8 @@ void clang_codeCompleteAt_Impl(void *UserData) { (options & CXCodeComplete_IncludeMacros), (options & CXCodeComplete_IncludeCodePatterns), Capture, - *Results->Diag, Results->LangOpts, Results->SourceMgr, - Results->FileMgr, Results->Diagnostics, + *Results->Diag, Results->LangOpts, *Results->SourceMgr, + *Results->FileMgr, Results->Diagnostics, Results->TemporaryBuffers); // Keep a reference to the allocator used for cached global completions, so diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp index e0f4d42defdb..6bc4f2e776a3 100644 --- a/tools/libclang/CIndexInclusionStack.cpp +++ b/tools/libclang/CIndexInclusionStack.cpp @@ -40,14 +40,14 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, i = 0; for ( ; i < n ; ++i) { - - const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i); + bool Invalid = false; + const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i, &Invalid); - if (!SL.isFile()) + if (!SL.isFile() || Invalid) continue; const SrcMgr::FileInfo &FI = SL.getFile(); - if (!FI.getContentCache()->Entry) + if (!FI.getContentCache()->OrigEntry) continue; // Build the inclusion stack. @@ -61,7 +61,7 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, // Callback to the client. // FIXME: We should have a function to construct CXFiles. - CB((CXFile) FI.getContentCache()->Entry, + CB((CXFile) FI.getContentCache()->OrigEntry, InclusionStack.data(), InclusionStack.size(), clientData); } } diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index e74d1d4deb3f..9917d2ad2104 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -431,7 +431,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { const unsigned off = Buf.size() - 1; if (EmitDeclName(D)) { - if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) { + if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { Buf[off] = 'A'; Out << '@' << TD; } @@ -470,6 +470,12 @@ bool USRGenerator::GenLoc(const Decl *D) { if (generatedLoc) return IgnoreResults; generatedLoc = true; + + // Guard against null declarations in invalid code. + if (!D) { + IgnoreResults = true; + return true; + } const SourceManager &SM = AU->getSourceManager(); SourceLocation L = D->getLocStart(); @@ -570,7 +576,9 @@ void USRGenerator::VisitType(QualType T) { case BuiltinType::NullPtr: c = 'n'; break; case BuiltinType::Overload: + case BuiltinType::BoundMember: case BuiltinType::Dependent: + case BuiltinType::UnknownAny: IgnoreResults = true; return; case BuiltinType::ObjCId: diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp index 992d76a2efe9..56974b9e999b 100644 --- a/tools/libclang/CIndexer.cpp +++ b/tools/libclang/CIndexer.cpp @@ -32,6 +32,7 @@ #include #ifdef __CYGWIN__ +#include #include #define LLVM_ON_WIN32 1 #endif @@ -60,7 +61,11 @@ std::string CIndexer::getClangResourcesPath() { #ifdef __CYGWIN__ char w32path[MAX_PATH]; strcpy(w32path, path); +#if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181 + cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH); +#else cygwin_conv_to_full_posix_path(w32path, path); +#endif #endif llvm::sys::Path LibClangPath(path); diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 11759eefb6d3..7a6270d17647 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -1,5 +1,3 @@ -set(SHARED_LIBRARY TRUE) - set(LLVM_USED_LIBS clangFrontend clangDriver @@ -15,7 +13,7 @@ set( LLVM_LINK_COMPONENTS mc ) -add_clang_library(libclang +set(SOURCES CIndex.cpp CIndexCXX.cpp CIndexCodeCompletion.cpp @@ -27,34 +25,44 @@ add_clang_library(libclang CXString.cpp CXType.cpp ../../include/clang-c/Index.h -) - -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # Darwin-specific linker flags + ) - set(LIBCLANG_LINK_FLAGS "-Wl,-compatibility_version -Wl,1") - - set(LIBCLANG_LINK_FLAGS - "${LIBCLANG_LINK_FLAGS} -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000") +if( LLVM_ENABLE_PIC ) + set(SHARED_LIBRARY TRUE) + add_clang_library(libclang ${SOURCES}) set_target_properties(libclang PROPERTIES - LINK_FLAGS "${LIBCLANG_LINK_FLAGS}" - INSTALL_NAME_DIR "@executable_path/../lib") + OUTPUT_NAME "libclang" + VERSION ${LIBCLANG_LIBRARY_VERSION} + DEFINE_SYMBOL _CINDEX_LIB_) + + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(LIBCLANG_LINK_FLAGS + "-Wl,-compatibility_version -Wl,1 -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000") + set_target_properties(libclang + PROPERTIES + LINK_FLAGS "${LIBCLANG_LINK_FLAGS}" + INSTALL_NAME_DIR "@executable_path/../lib") + endif() + + if(MSVC) + # windows.h doesn't compile with /Za + get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS) + string(REPLACE "/Za" "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) + set_target_properties(libclang PROPERTIES + COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) + endif() + + set(LIBCLANG_STATIC_TARGET_NAME libclang_static) +else() + set(LIBCLANG_STATIC_TARGET_NAME libclang) endif() -# Versioning information -set_target_properties(libclang PROPERTIES VERSION ${LIBCLANG_LIBRARY_VERSION}) - -if(MSVC) - # windows.h doesn't compile with /Za - get_target_property(NON_ANSI_COMPILE_FLAGS libclang COMPILE_FLAGS) - string(REPLACE /Za "" NON_ANSI_COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) - set_target_properties(libclang PROPERTIES COMPILE_FLAGS ${NON_ANSI_COMPILE_FLAGS}) -endif(MSVC) - -set_target_properties(libclang - PROPERTIES - PREFIX "" # Otherwise we get liblibclang.so - LINKER_LANGUAGE CXX - DEFINE_SYMBOL _CINDEX_LIB_) +if( NOT BUILD_SHARED_LIBS AND NOT WIN32 ) + add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES}) + + set_target_properties(${LIBCLANG_STATIC_TARGET_NAME} + PROPERTIES + OUTPUT_NAME "libclang") +endif() diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index dd22a97ab19b..2a78012d8917 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -95,6 +95,10 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::ObjCForCollectionStmtClass: case Stmt::CXXCatchStmtClass: case Stmt::CXXTryStmtClass: + case Stmt::CXXForRangeStmtClass: + case Stmt::SEHTryStmtClass: + case Stmt::SEHExceptStmtClass: + case Stmt::SEHFinallyStmtClass: K = CXCursor_UnexposedStmt; break; @@ -111,7 +115,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::ParenExprClass: case Stmt::UnaryOperatorClass: case Stmt::OffsetOfExprClass: - case Stmt::SizeOfAlignOfExprClass: + case Stmt::UnaryExprOrTypeTraitExprClass: case Stmt::ArraySubscriptExprClass: case Stmt::BinaryOperatorClass: case Stmt::CompoundAssignOperatorClass: @@ -129,6 +133,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::AddrLabelExprClass: case Stmt::StmtExprClass: case Stmt::ChooseExprClass: + case Stmt::GenericSelectionExprClass: case Stmt::GNUNullExprClass: case Stmt::CXXStaticCastExprClass: case Stmt::CXXDynamicCastExprClass: @@ -149,6 +154,8 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::UnresolvedLookupExprClass: case Stmt::UnaryTypeTraitExprClass: case Stmt::BinaryTypeTraitExprClass: + case Stmt::ArrayTypeTraitExprClass: + case Stmt::ExpressionTraitExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::ExprWithCleanupsClass: diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index 7614544ca3bc..30c3fd1ac30a 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -21,6 +21,7 @@ _clang_defaultEditingTranslationUnitOptions _clang_defaultReparseOptions _clang_defaultSaveOptions _clang_disposeCXCursorSet +_clang_disposeCXTUResourceUsage _clang_disposeCodeCompleteResults _clang_disposeDiagnostic _clang_disposeIndex @@ -35,6 +36,7 @@ _clang_equalTypes _clang_executeOnThread _clang_formatDiagnostic _clang_getCString +_clang_getCXTUResourceUsage _clang_getCXXAccessSpecifier _clang_getCanonicalCursor _clang_getCanonicalType @@ -98,6 +100,7 @@ _clang_getRangeStart _clang_getResultType _clang_getSpecializedCursorTemplate _clang_getSpellingLocation +_clang_getTUResourceUsageName _clang_getTemplateCursorKind _clang_getTokenExtent _clang_getTokenKind @@ -108,8 +111,8 @@ _clang_getTranslationUnitSpelling _clang_getTypeDeclaration _clang_getTypeKindSpelling _clang_hashCursor -_clang_isCursorDefinition _clang_isConstQualifiedType +_clang_isCursorDefinition _clang_isDeclaration _clang_isExpression _clang_isInvalid @@ -126,6 +129,7 @@ _clang_parseTranslationUnit _clang_reparseTranslationUnit _clang_saveTranslationUnit _clang_sortCodeCompletionResults +_clang_toggleCrashRecovery _clang_tokenize _clang_visitChildren _clang_visitChildrenWithBlock diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index c2f0587b9ae8..4e96e8a0d6d7 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -21,6 +21,7 @@ clang_defaultEditingTranslationUnitOptions clang_defaultReparseOptions clang_defaultSaveOptions clang_disposeCXCursorSet +clang_disposeCXTUResourceUsage clang_disposeCodeCompleteResults clang_disposeDiagnostic clang_disposeIndex @@ -35,6 +36,7 @@ clang_equalTypes clang_executeOnThread clang_formatDiagnostic clang_getCString +clang_getCXTUResourceUsage clang_getCXXAccessSpecifier clang_getCanonicalCursor clang_getCanonicalType @@ -98,6 +100,7 @@ clang_getRangeStart clang_getResultType clang_getSpecializedCursorTemplate clang_getSpellingLocation +clang_getTUResourceUsageName clang_getTemplateCursorKind clang_getTokenExtent clang_getTokenKind @@ -126,6 +129,7 @@ clang_parseTranslationUnit clang_reparseTranslationUnit clang_saveTranslationUnit clang_sortCodeCompletionResults +clang_toggleCrashRecovery clang_tokenize clang_visitChildren clang_visitChildrenWithBlock diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 5601387d794c..7793a8db49b1 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/ccc-analyzer @@ -147,9 +147,10 @@ sub GetCCArgs { } sub Analyze { - my ($Clang, $Args, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir, + my ($Clang, $OriginalArgs, $AnalyzeArgs, $Lang, $Output, $Verbose, $HtmlDir, $file) = @_; + my @Args = @$OriginalArgs; my $Cmd; my @CmdArgs; my @CmdArgsSansAnalyses; @@ -166,41 +167,37 @@ sub Analyze { else { $Cmd = $Clang; if ($Lang eq "objective-c" || $Lang eq "objective-c++") { - push @$Args,'-DIBOutlet=__attribute__((iboutlet))'; - push @$Args,'-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection)))'; - push @$Args,'-DIBAction=void)__attribute__((ibaction)'; + push @Args,'-DIBOutlet=__attribute__((iboutlet))'; + push @Args,'-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection)))'; + push @Args,'-DIBAction=void)__attribute__((ibaction)'; } # Create arguments for doing regular parsing. - my $SyntaxArgs = GetCCArgs("-fsyntax-only", $Args); - @CmdArgsSansAnalyses = @CmdArgs; - push @CmdArgsSansAnalyses, @$SyntaxArgs; - + my $SyntaxArgs = GetCCArgs("-fsyntax-only", \@Args); + @CmdArgsSansAnalyses = @$SyntaxArgs; + # Create arguments for doing static analysis. if (defined $ResultFile) { - push @$Args,'-o'; - push @$Args, $ResultFile; + push @Args, '-o', $ResultFile; } elsif (defined $HtmlDir) { - push @$Args,'-o'; - push @$Args, $HtmlDir; + push @Args, '-o', $HtmlDir; + } + if ($Verbose) { + push @Args, "-Xclang", "-analyzer-display-progress"; } - push @$Args,"-Xclang"; - push @$Args,"-analyzer-display-progress"; foreach my $arg (@$AnalyzeArgs) { - push @$Args, "-Xclang"; - push @$Args, $arg; + push @Args, "-Xclang", $arg; } - + # Display Ubiviz graph? if (defined $ENV{'CCC_UBI'}) { - push @$Args, "-Xclang"; - push @$Args,"-analyzer-viz-egraph-ubigraph"; + push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph"; } - my $AnalysisArgs = GetCCArgs("--analyze", $Args); - push @CmdArgs, @$AnalysisArgs; + my $AnalysisArgs = GetCCArgs("--analyze", \@Args); + @CmdArgs = @$AnalysisArgs; } my @PrintArgs; @@ -217,7 +214,7 @@ sub Analyze { if ($Verbose == 1) { # We MUST print to stderr. Some clients use the stdout output of # gcc for various purposes. - print STDERR join(' ',@PrintArgs); + print STDERR join(' ', @PrintArgs); print STDERR "\n"; } elsif ($Verbose == 2) { @@ -368,9 +365,11 @@ my %LangMap = ( 'cp' => 'c++', 'cpp' => 'c++', 'cc' => 'c++', + 'ii' => 'c++', 'i' => 'c-cpp-output', 'm' => 'objective-c', - 'mi' => 'objective-c-cpp-output' + 'mi' => 'objective-c-cpp-output', + 'mm' => 'objective-c++' ); my %UniqueOptions = ( @@ -383,14 +382,11 @@ my %UniqueOptions = ( my %LangsAccepted = ( "objective-c" => 1, - "c" => 1 + "c" => 1, + "c++" => 1, + "objective-c++" => 1 ); -if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) { - $LangsAccepted{"c++"} = 1; - $LangsAccepted{"objective-c++"} = 1; -} - ##----------------------------------------------------------------------------## # Main Logic. ##----------------------------------------------------------------------------## @@ -613,8 +609,7 @@ if ($Action eq 'compile' or $Action eq 'link') { my @AnalyzeArgs; if ($FileLang ne 'unknown') { - push @CmdArgs,'-x'; - push @CmdArgs,$FileLang; + push @CmdArgs, '-x', $FileLang; } if (defined $StoreModel) { @@ -625,9 +620,9 @@ if ($Action eq 'compile' or $Action eq 'link') { push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel"; } -# if (defined $Analyses) { -# push @AnalyzeArgs, split '\s+', $Analyses; -# } + if (defined $Analyses) { + push @AnalyzeArgs, split '\s+', $Analyses; + } if (defined $OutputFormat) { push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat; @@ -646,8 +641,7 @@ if ($Action eq 'compile' or $Action eq 'link') { if (scalar @Archs) { foreach my $arch (@Archs) { my @NewArgs; - push @NewArgs, '-arch'; - push @NewArgs, $arch; + push @NewArgs, '-arch', $arch; push @NewArgs, @CmdArgs; Analyze($Clang, \@NewArgs, \@AnalyzeArgs, $FileLang, $Output, $Verbose, $HtmlDir, $file); diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build index f7e521f49ecb..f835ca3520c4 100755 --- a/tools/scan-build/scan-build +++ b/tools/scan-build/scan-build @@ -201,8 +201,8 @@ sub SetHtmlEnv { die "No build command." if (scalar(@$Args) == 0); my $Cmd = $$Args[0]; - - if ($Cmd =~ /configure/) { + + if ($Cmd =~ /configure/ || $Cmd =~ /autogen/) { return; } @@ -290,7 +290,7 @@ sub AddStatLine { print $Line . "\n"; my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable - \ CFGBlocks:\ (\d+)\ \|\ Aborted\ Block:\ (yes|no)\ \|\ Empty\ WorkList: + \ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList: \ (yes|no)/x; if ($Line !~ $Regex) { @@ -1001,8 +1001,16 @@ ADVANCED OPTIONS: -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 3. Increase for more comprehensive coverage at a + up. Default is 4. Increase for more comprehensive coverage at a cost of speed. + +CONTROLLING CHECKERS: + + A default group of checkers are always run unless explicitly disabled. + Checkers may be enabled/disabled using the following options: + + -enable-checker [checker name] + -disable-checker [checker name] ENDTEXT # Query clang for list of checkers that are enabled. @@ -1053,7 +1061,7 @@ else { print("\nAVAILABLE CHECKERS:\n\n"); my $skip = 0; while() { - if (/core\.experimental/ or /debug\./ or /unix.experimental/ or /cocoa.experimental/) { + if (/experimental/) { $skip = 1; next; } @@ -1305,6 +1313,16 @@ while (@ARGV) { $MaxLoop = shift @ARGV; next; } + if ($arg eq "-enable-checker") { + shift @ARGV; + push @AnalysesToRun, "-analyzer-checker", shift @ARGV; + next; + } + if ($arg eq "-disable-checker") { + shift @ARGV; + push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV; + next; + } DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/); @@ -1365,7 +1383,7 @@ if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; } if ($AnalyzerStats) { - push @AnalysesToRun, '-analyzer-stats'; + push @AnalysesToRun, '-analyzer-checker', 'debug.Stats'; } if ($MaxLoop > 0) { push @AnalysesToRun, '-analyzer-max-loop ' . $MaxLoop; -- cgit v1.2.3