diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-27 15:17:06 +0000 |
commit | 53992adde3eda3ccf9da63bc7e45673f043de18f (patch) | |
tree | 3558f327a6f9ab59c5d7a06528d84e1560445247 /tools | |
parent | 7e411337c0ed226dace6e07f1420486768161308 (diff) | |
download | FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.zip FreeBSD-src-53992adde3eda3ccf9da63bc7e45673f043de18f.tar.gz |
Update clang to r104832.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/c-index-test/c-index-test.c | 32 | ||||
-rw-r--r-- | tools/driver/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/driver/cc1_main.cpp | 6 | ||||
-rw-r--r-- | tools/driver/cc1as_main.cpp | 373 | ||||
-rw-r--r-- | tools/driver/driver.cpp | 21 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 525 | ||||
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 51 | ||||
-rw-r--r-- | tools/libclang/CIndexUSRs.cpp | 429 | ||||
-rw-r--r-- | tools/libclang/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 10 | ||||
-rw-r--r-- | tools/libclang/CXTypes.cpp | 249 | ||||
-rw-r--r-- | tools/libclang/Makefile | 2 | ||||
-rw-r--r-- | tools/libclang/libclang.darwin.exports | 9 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 10 |
14 files changed, 1448 insertions, 271 deletions
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 4941816..4268cec 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -447,6 +447,31 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Typekind testing. */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, + CXClientData d) { + + if (!clang_isInvalid(clang_getCursorKind(cursor))) { + CXType T = clang_getCursorType(cursor); + CXType CT = clang_getCanonicalType(T); + CXString S = clang_getTypeKindSpelling(T.kind); + PrintCursor(cursor); + printf(" typekind=%s", clang_getCString(S)); + if (!clang_equalTypes(T, CT)) { + CXString CS = clang_getTypeKindSpelling(CT.kind); + printf(" [canonical=%s]", clang_getCString(CS)); + clang_disposeString(CS); + } + clang_disposeString(S); + printf("\n"); + } + return CXChildVisit_Recurse; +} + + +/******************************************************************************/ /* Loading ASTs/source. */ /******************************************************************************/ @@ -757,7 +782,8 @@ void print_completion_result(CXCompletionResult *completion_result, clang_disposeString(ks); print_completion_string(completion_result->CompletionString, file); - fprintf(file, "\n"); + fprintf(file, " (%u)\n", + clang_getCompletionPriority(completion_result->CompletionString)); } int perform_code_completion(int argc, const char **argv) { @@ -1179,6 +1205,7 @@ static void print_usage(void) { " c-index-test -test-inclusion-stack-source {<args>}*\n" " c-index-test -test-inclusion-stack-tu <AST file>\n" " c-index-test -test-print-linkage-source {<args>}*\n" + " c-index-test -test-print-typekind {<args>}*\n" " c-index-test -print-usr [<CursorKind> {<args>}]*\n" " c-index-test -print-usr-file <file>\n\n" " <symbol filter> values:\n%s", @@ -1223,6 +1250,9 @@ int main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, NULL); + else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0) + return perform_test_load_source(argc - 2, argv + 2, "all", + PrintTypeKind, 0); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { if (argc > 2) return print_usrs(argv + 2, argv + argc); diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index ca2f408..706f050 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -26,6 +26,7 @@ set( LLVM_LINK_COMPONENTS add_clang_executable(clang driver.cpp cc1_main.cpp + cc1as_main.cpp ) if(UNIX) diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 144a734..ac19e93 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -1,4 +1,4 @@ -//===-- cc1_main.cpp - Clang CC1 Driver -----------------------------------===// +//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===// // // The LLVM Compiler Infrastructure // @@ -43,7 +43,7 @@ using namespace clang; // Main driver //===----------------------------------------------------------------------===// -void LLVMErrorHandler(void *UserData, const std::string &Message) { +static void LLVMErrorHandler(void *UserData, const std::string &Message) { Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); Diags.Report(diag::err_fe_error_backend) << Message; @@ -63,6 +63,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case ASTPrint: return new ASTPrintAction(); case ASTPrintXML: return new ASTPrintXMLAction(); case ASTView: return new ASTViewAction(); + case BoostCon: return new BoostConAction(); case DumpRawTokens: return new DumpRawTokensAction(); case DumpTokens: return new DumpTokensAction(); case EmitAssembly: return new EmitAssemblyAction(); @@ -70,6 +71,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case EmitHTML: return new HTMLPrintAction(); case EmitLLVM: return new EmitLLVMAction(); case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); case EmitObj: return new EmitObjAction(); case FixIt: return new FixItAction(); case GeneratePCH: return new GeneratePCHAction(); diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp new file mode 100644 index 0000000..5f1ee09 --- /dev/null +++ b/tools/driver/cc1as_main.cpp @@ -0,0 +1,373 @@ +//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is the entry point to the clang -cc1as functionality, which implements +// the direct interface to the LLVM MC based assembler. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/DriverDiagnostic.h" +#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 "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCParser/AsmParser.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Host.h" +#include "llvm/System/Path.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmParser.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" +using namespace clang; +using namespace clang::driver; +using namespace llvm; + +namespace { + +/// \brief Helper class for representing a single invocation of the assembler. +struct AssemblerInvocation { + /// @name Target Options + /// @{ + + std::string Triple; + + /// @} + /// @name Language Options + /// @{ + + std::vector<std::string> IncludePaths; + unsigned NoInitialTextSection : 1; + + /// @} + /// @name Frontend Options + /// @{ + + std::string InputFile; + std::vector<std::string> LLVMArgs; + std::string OutputPath; + enum FileType { + FT_Asm, ///< Assembly (.s) output, transliterate mode. + FT_Null, ///< No output, for timing purposes. + FT_Obj ///< Object file output. + }; + FileType OutputType; + unsigned ShowHelp : 1; + unsigned ShowVersion : 1; + + /// @} + /// @name Transliterate Options + /// @{ + + unsigned OutputAsmVariant; + unsigned ShowEncoding : 1; + unsigned ShowInst : 1; + + /// @} + /// @name Assembler Options + /// @{ + + unsigned RelaxAll : 1; + + /// @} + +public: + AssemblerInvocation() { + Triple = ""; + NoInitialTextSection = 0; + InputFile = "-"; + OutputPath = "-"; + OutputType = FT_Asm; + OutputAsmVariant = 0; + ShowInst = 0; + ShowEncoding = 0; + RelaxAll = 0; + } + + static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin, + const char **ArgEnd, Diagnostic &Diags); +}; + +} + +void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, + const char **ArgBegin, + const char **ArgEnd, + Diagnostic &Diags) { + using namespace clang::driver::cc1asoptions; + // Parse the arguments. + OwningPtr<OptTable> OptTbl(createCC1AsOptTable()); + unsigned MissingArgIndex, MissingArgCount; + OwningPtr<InputArgList> Args( + OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); + + // Check for missing argument error. + if (MissingArgCount) + Diags.Report(diag::err_drv_missing_argument) + << Args->getArgString(MissingArgIndex) << MissingArgCount; + + // Issue errors on unknown arguments. + for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN), + ie = Args->filtered_end(); it != ie; ++it) + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + + // Construct the invocation. + + // Target Options + Opts.Triple = Args->getLastArgValue(OPT_triple); + if (Opts.Triple.empty()) // Use the host triple if unspecified. + Opts.Triple = sys::getHostTriple(); + + // Language Options + Opts.IncludePaths = Args->getAllArgValues(OPT_I); + Opts.NoInitialTextSection = Args->hasArg(OPT_n); + + // Frontend Options + if (Args->hasArg(OPT_INPUT)) { + bool First = true; + for (arg_iterator it = Args->filtered_begin(OPT_INPUT), + ie = Args->filtered_end(); it != ie; ++it, First=false) { + if (First) + Opts.InputFile = it->getValue(*Args); + else + Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); + } + } + Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm); + Opts.OutputPath = Args->getLastArgValue(OPT_o); + if (Arg *A = Args->getLastArg(OPT_filetype)) { + StringRef Name = A->getValue(*Args); + unsigned OutputType = StringSwitch<unsigned>(Name) + .Case("asm", FT_Asm) + .Case("null", FT_Null) + .Case("obj", FT_Obj) + .Default(~0U); + if (OutputType == ~0U) + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(*Args) << Name; + else + Opts.OutputType = FileType(OutputType); + } + Opts.ShowHelp = Args->hasArg(OPT_help); + Opts.ShowVersion = Args->hasArg(OPT_version); + + // Transliterate Options + Opts.OutputAsmVariant = Args->getLastArgIntValue(OPT_output_asm_variant, + 0, Diags); + Opts.ShowEncoding = Args->hasArg(OPT_show_encoding); + Opts.ShowInst = Args->hasArg(OPT_show_inst); + + // Assemble Options + Opts.RelaxAll = Args->hasArg(OPT_relax_all); +} + +static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts, + Diagnostic &Diags, + bool Binary) { + if (Opts.OutputPath.empty()) + Opts.OutputPath = "-"; + + // Make sure that the Out file gets unlinked from the disk if we get a + // SIGINT. + if (Opts.OutputPath != "-") + sys::RemoveFileOnSignal(sys::Path(Opts.OutputPath)); + + std::string Error; + raw_fd_ostream *Out = + new raw_fd_ostream(Opts.OutputPath.c_str(), Error, + (Binary ? raw_fd_ostream::F_Binary : 0)); + if (!Error.empty()) { + Diags.Report(diag::err_fe_unable_to_open_output) + << Opts.OutputPath << Error; + return 0; + } + + return new formatted_raw_ostream(*Out, formatted_raw_ostream::DELETE_STREAM); +} + +static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { + // Get the target specific parser. + std::string Error; + const Target *TheTarget(TargetRegistry::lookupTarget(Opts.Triple, Error)); + if (!TheTarget) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + MemoryBuffer *Buffer = MemoryBuffer::getFileOrSTDIN(Opts.InputFile, &Error); + if (Buffer == 0) { + Diags.Report(diag::err_fe_error_reading) << Opts.InputFile; + return false; + } + + SourceMgr SrcMgr; + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); + + // Record the location of the include directories so that the lexer can find + // it later. + SrcMgr.setIncludeDirs(Opts.IncludePaths); + + OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple)); + assert(MAI && "Unable to create target asm info!"); + + MCContext Ctx(*MAI); + bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; + formatted_raw_ostream *Out = GetOutputStream(Opts, Diags, IsBinary); + if (!Out) + return false; + + // FIXME: We shouldn't need to do this (and link in codegen). + OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, "")); + if (!TM) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + OwningPtr<MCCodeEmitter> CE; + OwningPtr<MCStreamer> Str; + OwningPtr<TargetAsmBackend> TAB; + + if (Opts.OutputType == AssemblerInvocation::FT_Asm) { + MCInstPrinter *IP = + TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI); + if (Opts.ShowEncoding) + CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); + Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(), + /*asmverbose*/true, IP, CE.get(), + Opts.ShowInst)); + } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { + Str.reset(createNullStreamer(Ctx)); + } else { + assert(Opts.OutputType == AssemblerInvocation::FT_Obj && + "Invalid file type!"); + CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); + TAB.reset(TheTarget->createAsmBackend(Opts.Triple)); + Str.reset(createMachOStreamer(Ctx, *TAB, *Out, CE.get(), Opts.RelaxAll)); + } + + AsmParser Parser(SrcMgr, Ctx, *Str.get(), *MAI); + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + if (!TAP) { + Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; + return false; + } + + Parser.setTargetParser(*TAP.get()); + + bool Success = !Parser.Run(Opts.NoInitialTextSection); + + // Close the output. + delete Out; + + // Delete output on errors. + if (!Success && Opts.OutputPath != "-") + sys::Path(Opts.OutputPath).eraseFromDisk(); + + return Success; +} + +static void LLVMErrorHandler(void *UserData, const std::string &Message) { + Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); + + Diags.Report(diag::err_fe_error_backend) << Message; + + // We cannot recover from llvm errors. + exit(1); +} + +int cc1as_main(const char **ArgBegin, const char **ArgEnd, + const char *Argv0, void *MainAddr) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Initialize targets and assembly printers/parsers. + InitializeAllTargetInfos(); + // FIXME: We shouldn't need to initialize the Target(Machine)s. + InitializeAllTargets(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // Construct our diagnostic client. + TextDiagnosticPrinter DiagClient(errs(), DiagnosticOptions()); + DiagClient.setPrefix("clang -cc1as"); + Diagnostic Diags(&DiagClient); + + // Set an error handler, so that any LLVM backend diagnostics go through our + // error handler. + install_fatal_error_handler(LLVMErrorHandler, + static_cast<void*>(&Diags)); + + // Parse the arguments. + AssemblerInvocation Asm; + AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags); + + // Honor -help. + if (Asm.ShowHelp) { + llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable()); + Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler"); + return 0; + } + + // Honor -version. + // + // FIXME: Use a better -version message? + if (Asm.ShowVersion) { + llvm::cl::PrintVersionMessage(); + return 0; + } + + // Honor -mllvm. + // + // FIXME: Remove this, one day. + if (!Asm.LLVMArgs.empty()) { + unsigned NumArgs = Asm.LLVMArgs.size(); + const char **Args = new const char*[NumArgs + 2]; + Args[0] = "clang (LLVM option parsing)"; + for (unsigned i = 0; i != NumArgs; ++i) + Args[i + 1] = Asm.LLVMArgs[i].c_str(); + Args[NumArgs + 1] = 0; + llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args)); + } + + // Execute the invocation, unless there were parsing errors. + bool Success = false; + if (!Diags.getNumErrors()) + Success = ExecuteAssembler(Asm, Diags); + + // If any timers were active but haven't been destroyed yet, print their + // results now. + TimerGroup::printAll(errs()); + + return !Success; +} diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 3f1cca1..c4b12cb 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -170,15 +170,28 @@ static void ApplyQAOverride(std::vector<const char*> &Args, extern int cc1_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr); +extern int cc1as_main(const char **ArgBegin, const char **ArgEnd, + const char *Argv0, void *MainAddr); int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc, argv); - // Dispatch to cc1_main if appropriate. - if (argc > 1 && llvm::StringRef(argv[1]) == "-cc1") - return cc1_main(argv+2, argv+argc, argv[0], - (void*) (intptr_t) GetExecutablePath); + // Handle -cc1 integrated tools. + if (argc > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { + llvm::StringRef Tool = argv[1] + 4; + + if (Tool == "") + return cc1_main(argv+2, argv+argc, argv[0], + (void*) (intptr_t) GetExecutablePath); + if (Tool == "as") + return cc1as_main(argv+2, argv+argc, argv[0], + (void*) (intptr_t) GetExecutablePath); + + // Reject unknown tools. + llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; + return 1; + } bool CanonicalPrefixes = true; for (int i = 1; i < argc; ++i) { diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index f9f7351..a077589 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -44,11 +44,11 @@ using namespace clang::cxstring; // Crash Reporting. //===----------------------------------------------------------------------===// -#ifdef __APPLE__ -#define USE_CRASHTRACER +#ifdef USE_CRASHTRACER #include "clang/Analysis/Support/SaveAndRestore.h" // Integrate with crash reporter. -extern "C" const char *__crashreporter_info__; +static const char *__crashreporter_info__ = 0; +asm(".desc ___crashreporter_info__, 0x10"); #define NUM_CRASH_STRINGS 32 static unsigned crashtracer_counter = 0; static unsigned crashtracer_counter_id[NUM_CRASH_STRINGS] = { 0 }; @@ -152,6 +152,23 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, return RangeOverlap; } +/// \brief Determine if a source location falls within, before, or after a +/// a given source range. +static RangeComparisonResult LocationCompare(SourceManager &SM, + SourceLocation L, SourceRange R) { + assert(R.isValid() && "First range is invalid?"); + assert(L.isValid() && "Second range is invalid?"); + if (L == R.getBegin()) + return RangeOverlap; + if (L == R.getEnd()) + return RangeAfter; + if (SM.isBeforeInTranslationUnit(L, R.getBegin())) + return RangeBefore; + if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) + return RangeAfter; + return RangeOverlap; +} + /// \brief Translate a Clang source range into a CIndex source range. /// /// Clang internally represents ranges where the end location points to the @@ -222,6 +239,27 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, /// \param R a half-open source range retrieved from the abstract syntax tree. RangeComparisonResult CompareRegionOfInterest(SourceRange R); + class SetParentRAII { + CXCursor &Parent; + Decl *&StmtParent; + CXCursor OldParent; + + public: + SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) + : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) + { + Parent = NewParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + + ~SetParentRAII() { + Parent = OldParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + }; + public: CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, unsigned MaxPCHLevel, @@ -259,6 +297,7 @@ public: bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); @@ -268,6 +307,8 @@ public: // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); bool VisitObjCClassDecl(ObjCClassDecl *D); + bool VisitLinkageSpecDecl(LinkageSpecDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); // Type visitors // FIXME: QualifiedTypeLoc doesn't provide any location information @@ -277,6 +318,7 @@ public: bool VisitTagTypeLoc(TagTypeLoc TL); // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); bool VisitPointerTypeLoc(PointerTypeLoc TL); bool VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL); @@ -297,8 +339,10 @@ public: // FIXME: LabelStmt label? bool VisitIfStmt(IfStmt *S); bool VisitSwitchStmt(SwitchStmt *S); + bool VisitCaseStmt(CaseStmt *S); bool VisitWhileStmt(WhileStmt *S); bool VisitForStmt(ForStmt *S); +// bool VisitSwitchCase(SwitchCase *S); // Expression visitors bool VisitBlockExpr(BlockExpr *B); @@ -417,26 +461,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { // Set the Parent field to Cursor, then back to its old value once we're // done. - class SetParentRAII { - CXCursor &Parent; - Decl *&StmtParent; - CXCursor OldParent; - - public: - SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent) - : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) - { - Parent = NewParent; - if (clang_isDeclaration(Parent.kind)) - StmtParent = getCursorDecl(Parent); - } - - ~SetParentRAII() { - Parent = OldParent; - if (clang_isDeclaration(Parent.kind)) - StmtParent = getCursorDecl(Parent); - } - } SetParent(Parent, StmtParent, Cursor); + SetParentRAII SetParent(Parent, StmtParent, Cursor); if (clang_isDeclaration(Cursor.kind)) { Decl *D = getCursorDecl(Cursor); @@ -504,7 +529,11 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU); + Decl *D = *I; + if (D->getLexicalDeclContext() != DC) + continue; + + CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { SourceRange Range = @@ -642,6 +671,40 @@ bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { return VisitObjCContainerDecl(PID); } +bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { + // FIXME: This implements a workaround with @property declarations also being + // installed in the DeclContext for the @interface. Eventually this code + // should be removed. + ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(PD->getDeclContext()); + if (!CDecl || !CDecl->IsClassExtension()) + return false; + + ObjCInterfaceDecl *ID = CDecl->getClassInterface(); + if (!ID) + return false; + + IdentifierInfo *PropertyId = PD->getIdentifier(); + ObjCPropertyDecl *prevDecl = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(ID), PropertyId); + + if (!prevDecl) + return false; + + // Visit synthesized methods since they will be skipped when visiting + // the @interface. + if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) + if (MD->isSynthesized()) + if (Visit(MakeCXCursor(MD, TU))) + return true; + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Issue callbacks for super class. if (D->getSuperClass() && @@ -705,6 +768,14 @@ bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) { return false; } +bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + return VisitDeclContext(D); +} + bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { ASTContext &Context = TU->getASTContext(); @@ -780,6 +851,13 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; + return false; +} + +bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) + return true; + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) @@ -790,19 +868,7 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseTypeLoc())) - return true; - - if (TL.hasProtocolsAsWritten()) { - for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { - if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), - TL.getProtocolLoc(I), - TU))) - return true; - } - } - - return false; + return Visit(TL.getPointeeLoc()); } bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { @@ -861,13 +927,60 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { bool CursorVisitor::VisitStmt(Stmt *S) { for (Stmt::child_iterator Child = S->child_begin(), ChildEnd = S->child_end(); Child != ChildEnd; ++Child) { - if (*Child && Visit(MakeCXCursor(*Child, StmtParent, TU))) - return true; + if (Stmt *C = *Child) + if (Visit(MakeCXCursor(C, StmtParent, TU))) + return true; } return false; } +bool CursorVisitor::VisitCaseStmt(CaseStmt *S) { + // Specially handle CaseStmts because they can be nested, e.g.: + // + // case 1: + // case 2: + // + // In this case the second CaseStmt is the child of the first. Walking + // these recursively can blow out the stack. + CXCursor Cursor = MakeCXCursor(S, StmtParent, TU); + while (true) { + // Set the Parent field to Cursor, then back to its old value once we're + // done. + SetParentRAII SetParent(Parent, StmtParent, Cursor); + + if (Stmt *LHS = S->getLHS()) + if (Visit(MakeCXCursor(LHS, StmtParent, TU))) + return true; + if (Stmt *RHS = S->getRHS()) + if (Visit(MakeCXCursor(RHS, StmtParent, TU))) + return true; + if (Stmt *SubStmt = S->getSubStmt()) { + if (!isa<CaseStmt>(SubStmt)) + return Visit(MakeCXCursor(SubStmt, StmtParent, TU)); + + // Specially handle 'CaseStmt' so that we don't blow out the stack. + CaseStmt *CS = cast<CaseStmt>(SubStmt); + Cursor = MakeCXCursor(CS, StmtParent, TU); + if (RegionOfInterest.isValid()) { + SourceRange Range = CS->getSourceRange(); + if (Range.isInvalid() || CompareRegionOfInterest(Range)) + return false; + } + + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: return true; + case CXChildVisit_Continue: return false; + case CXChildVisit_Recurse: + // Perform tail-recursion manually. + S = CS; + continue; + } + } + return false; + } +} + bool CursorVisitor::VisitDeclStmt(DeclStmt *S) { for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { @@ -1089,8 +1202,6 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, RemappedFiles.size(), /*CaptureDiagnostics=*/true)); - // FIXME: Until we have broader testing, just drop the entire AST if we - // encountered an error. if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. if (CXXIdx->getDisplayDiagnostics() && Unit.get()) { @@ -1368,6 +1479,16 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) { return Result; } +unsigned clang_isFromMainFile(CXSourceLocation loc) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(loc.int_data); + if (!loc.ptr_data[0] || Loc.isInvalid()) + return 0; + + const SourceManager &SM = + *static_cast<const SourceManager*>(loc.ptr_data[0]); + return SM.isFromMainFile(Loc) ? 1 : 0; +} + } // end: extern "C" //===----------------------------------------------------------------------===// @@ -1474,10 +1595,11 @@ static CXString getDeclSpelling(Decl *D) { // ObjCCategoryImplDecl returns the category name. return createCXString(CIMP->getIdentifier()->getNameStart()); - if (ND->getIdentifier()) - return createCXString(ND->getIdentifier()->getNameStart()); - - return createCXString(""); + llvm::SmallString<1024> S; + llvm::raw_svector_ostream os(S); + ND->printName(os); + + return createCXString(os.str()); } CXString clang_getCursorSpelling(CXCursor C) { @@ -1615,12 +1737,18 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("attribute(ibaction)"); case CXCursor_IBOutletAttr: return createCXString("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return createCXString("attribute(iboutletcollection)"); case CXCursor_PreprocessingDirective: return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: return createCXString("macro definition"); case CXCursor_MacroInstantiation: return createCXString("macro instantiation"); + case CXCursor_Namespace: + return createCXString("Namespace"); + case CXCursor_LinkageSpec: + return createCXString("LinkageSpec"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -1763,7 +1891,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), L); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullLocation(); Decl *D = getCursorDecl(C); @@ -1829,7 +1957,7 @@ CXSourceRange clang_getCursorExtent(CXCursor C) { return cxloc::translateSourceRange(getCursorContext(C), R); } - if (!getCursorDecl(C)) + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) return clang_getNullRange(); Decl *D = getCursorDecl(C); @@ -2286,9 +2414,15 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, const char *StartPos = Buf.data() + LocInfo.second; IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos); - CXTok.int_data[0] = II->getTokenID() == tok::identifier? - CXToken_Identifier - : CXToken_Keyword; + + if (II->getObjCKeywordID() != tok::objc_not_keyword) { + CXTok.int_data[0] = CXToken_Keyword; + } + else { + CXTok.int_data[0] = II->getTokenID() == tok::identifier? + CXToken_Identifier + : CXToken_Keyword; + } CXTok.ptr_data = II; } else if (Tok.is(tok::comment)) { CXTok.int_data[0] = CXToken_Comment; @@ -2308,62 +2442,214 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, *NumTokens = CXTokens.size(); } +void clang_disposeTokens(CXTranslationUnit TU, + CXToken *Tokens, unsigned NumTokens) { + free(Tokens); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Token annotation APIs. +//===----------------------------------------------------------------------===// + typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData; +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data); +namespace { +class AnnotateTokensWorker { + AnnotateTokensData &Annotated; + CXToken *Tokens; + CXCursor *Cursors; + unsigned NumTokens; + unsigned TokIdx; + CursorVisitor AnnotateVis; + SourceManager &SrcMgr; + + bool MoreTokens() const { return TokIdx < NumTokens; } + unsigned NextToken() const { return TokIdx; } + void AdvanceToken() { ++TokIdx; } + SourceLocation GetTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); + } -enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, - CXCursor parent, - CXClientData client_data) { - AnnotateTokensData *Data = static_cast<AnnotateTokensData *>(client_data); - - // We only annotate the locations of declarations, simple - // references, and expressions which directly reference something. - CXCursorKind Kind = clang_getCursorKind(cursor); - if (clang_isDeclaration(Kind) || clang_isReference(Kind)) { - // Okay: We can annotate the location of this declaration with the - // declaration or reference - } else if (clang_isExpression(cursor.kind)) { - if (Kind != CXCursor_DeclRefExpr && - Kind != CXCursor_MemberRefExpr && - Kind != CXCursor_ObjCMessageExpr) - return CXChildVisit_Recurse; - - CXCursor Referenced = clang_getCursorReferenced(cursor); - if (Referenced == cursor || Referenced == clang_getNullCursor()) - return CXChildVisit_Recurse; - - // Okay: we can annotate the location of this expression - } else if (clang_isPreprocessing(cursor.kind)) { - // We can always annotate a preprocessing directive/macro instantiation. - } else { - // Nothing to annotate - return CXChildVisit_Recurse; +public: + AnnotateTokensWorker(AnnotateTokensData &annotated, + CXToken *tokens, CXCursor *cursors, unsigned numTokens, + ASTUnit *CXXUnit, SourceRange RegionOfInterest) + : Annotated(annotated), Tokens(tokens), Cursors(cursors), + NumTokens(numTokens), TokIdx(0), + AnnotateVis(CXXUnit, AnnotateTokensVisitor, this, + Decl::MaxPCHLevel, RegionOfInterest), + SrcMgr(CXXUnit->getSourceManager()) {} + + void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } + enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + void AnnotateTokens(CXCursor parent); +}; +} + +void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) { + // Walk the AST within the region of interest, annotating tokens + // along the way. + VisitChildren(parent); + + for (unsigned I = 0 ; I < TokIdx ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + if (Pos != Annotated.end()) + Cursors[I] = Pos->second; } + // Finish up annotating any tokens left. + if (!MoreTokens()) + return; + + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = TokIdx ; I < NumTokens ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second; + } +} + +enum CXChildVisitResult +AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { CXSourceLocation Loc = clang_getCursorLocation(cursor); - (*Data)[Loc.int_data] = cursor; - return CXChildVisit_Recurse; + // We can always annotate a preprocessing directive/macro instantiation. + if (clang_isPreprocessing(cursor.kind)) { + Annotated[Loc.int_data] = cursor; + return CXChildVisit_Recurse; + } + + CXSourceRange cursorExtent = clang_getCursorExtent(cursor); + SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + + if (cursorRange.isInvalid()) + return CXChildVisit_Continue; + + SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data); + + // Adjust the annotated range based specific declarations. + const enum CXCursorKind cursorK = clang_getCursorKind(cursor); + if (cursorK >= CXCursor_FirstDecl && cursorK <= CXCursor_LastDecl) { + Decl *D = cxcursor::getCursorDecl(cursor); + // Don't visit synthesized ObjC methods, since they have no syntatic + // representation in the source. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->isSynthesized()) + return CXChildVisit_Continue; + } + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) { + TypeLoc TL = TI->getTypeLoc(); + SourceLocation TLoc = TL.getSourceRange().getBegin(); + if (TLoc.isValid() && + SrcMgr.isBeforeInTranslationUnit(TLoc, L)) + cursorRange.setBegin(TLoc); + } + } + } + + const enum CXCursorKind K = clang_getCursorKind(parent); + const CXCursor updateC = + (clang_isInvalid(K) || K == CXCursor_TranslationUnit || + L.isMacroID()) + ? clang_getNullCursor() : parent; + + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + Cursors[I] = updateC; + AdvanceToken(); + continue; + case RangeAfter: + return CXChildVisit_Continue; + case RangeOverlap: + break; + } + break; + } + + // Visit children to get their cursor information. + const unsigned BeforeChildren = NextToken(); + VisitChildren(cursor); + const unsigned AfterChildren = NextToken(); + + // Adjust 'Last' to the last token within the extent of the cursor. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + assert(0 && "Infeasible"); + case RangeAfter: + break; + case RangeOverlap: + Cursors[I] = updateC; + AdvanceToken(); + continue; + } + break; + } + const unsigned Last = NextToken(); + + // Scan the tokens that are at the beginning of the cursor, but are not + // capture by the child cursors. + + // For AST elements within macros, rely on a post-annotate pass to + // to correctly annotate the tokens with cursors. Otherwise we can + // get confusing results of having tokens that map to cursors that really + // are expanded by an instantiation. + if (L.isMacroID()) + cursor = clang_getNullCursor(); + + for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { + if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) + break; + Cursors[I] = cursor; + } + // Scan the tokens that are at the end of the cursor, but are not captured + // but the child cursors. + for (unsigned I = AfterChildren; I != Last; ++I) + Cursors[I] = cursor; + + TokIdx = Last; + return CXChildVisit_Continue; } +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent); +} + +extern "C" { + void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, unsigned NumTokens, CXCursor *Cursors) { - if (NumTokens == 0) - return; - // Any token we don't specifically annotate will have a NULL cursor. - for (unsigned I = 0; I != NumTokens; ++I) - Cursors[I] = clang_getNullCursor(); + if (NumTokens == 0 || !Tokens || !Cursors) + return; ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - if (!CXXUnit || !Tokens) + if (!CXXUnit) { + // Any token we don't specifically annotate will have a NULL cursor. + const CXCursor &C = clang_getNullCursor(); + for (unsigned I = 0; I != NumTokens; ++I) + Cursors[I] = C; return; + } ASTUnit::ConcurrencyCheck Check(*CXXUnit); // Determine the region of interest, which contains all of the tokens. SourceRange RegionOfInterest; - RegionOfInterest.setBegin( - cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); + RegionOfInterest.setBegin(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, Tokens[0]))); + SourceLocation End = cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[NumTokens - 1])); @@ -2373,14 +2659,14 @@ void clang_annotateTokens(CXTranslationUnit TU, // region of interest to the corresponding cursors. AnnotateTokensData Annotated; - // Relex the tokens within the source range to look for preprocessing + // Relex the tokens within the source range to look for preprocessing // directives. SourceManager &SourceMgr = CXXUnit->getSourceManager(); std::pair<FileID, unsigned> BeginLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); std::pair<FileID, unsigned> EndLocInfo = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); - + llvm::StringRef Buffer; bool Invalid = false; if (BeginLocInfo.first == EndLocInfo.first && @@ -2388,16 +2674,16 @@ void clang_annotateTokens(CXTranslationUnit TU, !Invalid) { Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), CXXUnit->getASTContext().getLangOptions(), - Buffer.begin(), Buffer.data() + BeginLocInfo.second, + 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 + + // 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 @@ -2410,51 +2696,35 @@ void clang_annotateTokens(CXTranslationUnit TU, std::vector<SourceLocation> Locations; do { Locations.push_back(Tok.getLocation()); - Lex.LexFromRawLexer(Tok); + Lex.LexFromRawLexer(Tok); } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof)); - + using namespace cxcursor; CXCursor Cursor = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(), Locations.back()), - CXXUnit); + CXXUnit); 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. - CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); - CursorVisitor AnnotateVis(CXXUnit, AnnotateTokensVisitor, &Annotated, - Decl::MaxPCHLevel, RegionOfInterest); - AnnotateVis.VisitChildren(Parent); - - for (unsigned I = 0; I != NumTokens; ++I) { - // Determine whether we saw a cursor at this token's location. - AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); - if (Pos == Annotated.end()) - continue; - - Cursors[I] = Pos->second; - } -} -void clang_disposeTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens) { - free(Tokens); + // Annotate all of the source locations in the region of interest that map to + // a specific cursor. + AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens, + CXXUnit, RegionOfInterest); + W.AnnotateTokens(clang_getTranslationUnitCursor(CXXUnit)); } - } // end: extern "C" //===----------------------------------------------------------------------===// @@ -2540,6 +2810,21 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { } } // end: extern "C" + +//===----------------------------------------------------------------------===// +// C++ AST instrospection. +//===----------------------------------------------------------------------===// + +extern "C" { +unsigned clang_CXXMethod_isStatic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C)); + return (D && D->isStatic()) ? 1 : 0; +} + +} // end: extern "C" + //===----------------------------------------------------------------------===// // CXString Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index a21614c..481a375 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -37,12 +37,27 @@ using namespace clang; using namespace clang::cxstring; +namespace { + /// \brief Stored representation of a completion string. + /// + /// This is the representation behind a CXCompletionString. + class CXStoredCodeCompletionString : public CodeCompletionString { + unsigned Priority; + + public: + CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } + + unsigned getPriority() const { return Priority; } + }; +} + extern "C" { enum CXCompletionChunkKind clang_getCompletionChunkKind(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return CXCompletionChunk_Text; @@ -97,7 +112,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, CXString clang_getCompletionChunkText(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return createCXString(0); @@ -121,9 +137,12 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_SemiColon: case CodeCompletionString::CK_Equal: case CodeCompletionString::CK_HorizontalSpace: - case CodeCompletionString::CK_VerticalSpace: return createCXString((*CCStr)[chunk_number].Text, false); + case CodeCompletionString::CK_VerticalSpace: + // FIXME: Temporary hack until we figure out how to handle vertical space. + return createCXString(" "); + case CodeCompletionString::CK_Optional: // Note: treated as an empty text block. return createCXString(""); @@ -137,7 +156,8 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string, CXCompletionString clang_getCompletionChunkCompletionString(CXCompletionString completion_string, unsigned chunk_number) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; if (!CCStr || chunk_number >= CCStr->size()) return 0; @@ -174,10 +194,17 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string, } unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { - CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; return CCStr? CCStr->size() : 0; } +unsigned clang_getCompletionPriority(CXCompletionString completion_string) { + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; + return CCStr? CCStr->getPriority() : CCP_Unlikely; +} + static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, unsigned &Value) { if (Memory + sizeof(unsigned) > MemoryEnd) @@ -223,7 +250,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) - delete (CodeCompletionString *)Results[I].CompletionString; + delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; delete Buffer; @@ -373,10 +400,16 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, if (ReadUnsigned(Str, StrEnd, KindValue)) break; - CodeCompletionString *CCStr - = CodeCompletionString::Deserialize(Str, StrEnd); - if (!CCStr) + unsigned Priority; + if (ReadUnsigned(Str, StrEnd, Priority)) + break; + + CXStoredCodeCompletionString *CCStr + = new CXStoredCodeCompletionString(Priority); + if (!CCStr->Deserialize(Str, StrEnd)) { + delete CCStr; continue; + } if (!CCStr->empty()) { // Vend the code-completion result to the caller. diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index f3c74e8..e98fd26 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -28,12 +28,33 @@ using namespace clang::cxstring; namespace { class USRGenerator : public DeclVisitor<USRGenerator> { - llvm::raw_ostream &Out; + llvm::SmallString<1024> Buf; + llvm::raw_svector_ostream Out; bool IgnoreResults; ASTUnit *AU; + bool generatedLoc; public: - USRGenerator(ASTUnit *au, llvm::raw_ostream &out) - : Out(out), IgnoreResults(false), AU(au) {} + USRGenerator(const CXCursor *C = 0) + : Out(Buf), + IgnoreResults(false), + AU(C ? cxcursor::getCursorASTUnit(*C) : 0), + generatedLoc(false) + { + // Add the USR space prefix. + Out << "c:"; + } + + llvm::StringRef str() { + return Out.str(); + } + + USRGenerator* operator->() { return this; } + + template <typename T> + llvm::raw_svector_ostream &operator<<(const T &x) { + Out << x; + return Out; + } bool ignoreResults() const { return IgnoreResults; } @@ -52,10 +73,14 @@ public: void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); void VisitVarDecl(VarDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D) { + IgnoreResults = true; + return; + } /// Generate the string component containing the location of the /// declaration. - void GenLoc(const Decl *D); + bool GenLoc(const Decl *D); /// String generation methods used both by the visitation methods /// and from other clients that want to directly generate USRs. These @@ -63,10 +88,6 @@ public: /// of an AST element), but only the fragments concerning the AST element /// itself. - /// Generate a USR fragment for a named declaration. This does - /// not include the USR component for the parent. - void GenNamedDecl(llvm::StringRef name); - /// Generate a USR for an Objective-C class. void GenObjCClass(llvm::StringRef cls); /// Generate a USR for an Objective-C class category. @@ -81,31 +102,12 @@ public: void GenObjCProperty(llvm::StringRef prop); /// Generate a USR for an Objective-C protocol. void GenObjCProtocol(llvm::StringRef prot); -}; -class StringUSRGenerator { -private: - llvm::SmallString<1024> StrBuf; - llvm::raw_svector_ostream Out; - USRGenerator UG; -public: - StringUSRGenerator(const CXCursor *C = 0) - : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) { - // Add the USR space prefix. - Out << "c:"; - } - - llvm::StringRef str() { - return Out.str(); - } + void VisitType(QualType T); - USRGenerator* operator->() { return &UG; } - - template <typename T> - llvm::raw_svector_ostream &operator<<(const T &x) { - Out << x; - return Out; - } + /// Emit a Decl's name using NamedDecl::printName() and return true if + /// the decl had no name. + bool EmitDeclName(const NamedDecl *D); }; } // end anonymous namespace @@ -114,56 +116,91 @@ public: // Generating USRs from ASTS. //===----------------------------------------------------------------------===// +bool USRGenerator::EmitDeclName(const NamedDecl *D) { + Out.flush(); + const unsigned startSize = Buf.size(); + D->printName(Out); + Out.flush(); + const unsigned endSize = Buf.size(); + return startSize == endSize; +} + +static bool InAnonymousNamespace(const Decl *D) { + if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext())) + return ND->isAnonymousNamespace(); + return false; +} + +static inline bool ShouldGenerateLocation(const NamedDecl *D) { + return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D); +} + void USRGenerator::VisitDeclContext(DeclContext *DC) { if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) Visit(D); } void USRGenerator::VisitFieldDecl(FieldDecl *D) { - const std::string &s = D->getNameAsString(); - if (s.empty()) { + VisitDeclContext(D->getDeclContext()); + Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { // Bit fields can be anonymous. IgnoreResults = true; return; } - VisitDeclContext(D->getDeclContext()); - Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@") << s; } void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } - else - VisitDeclContext(D->getDeclContext()); + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + Out << "@F@"; + D->printName(Out); + + ASTContext &Ctx = AU->getASTContext(); + if (!Ctx.getLangOptions().CPlusPlus || D->isExternC()) + return; - Out << "@F@" << D; + // Mangle in type information for the arguments. + for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end(); + I != E; ++I) { + Out << '#'; + if (ParmVarDecl *PD = *I) + VisitType(PD->getType()); + } + if (D->isVariadic()) + Out << '.'; + Out << '#'; + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->isStatic()) + Out << 'S'; + if (unsigned quals = MD->getTypeQualifiers()) + Out << (char)('0' + quals); + } } void USRGenerator::VisitNamedDecl(NamedDecl *D) { VisitDeclContext(D->getDeclContext()); - const std::string &s = D->getNameAsString(); - // The string can be empty if the declaration has no name; e.g., it is - // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); - // In this case, don't generate a USR. - if (s.empty()) + Out << "@"; + + if (EmitDeclName(D)) { + // The string can be empty if the declaration has no name; e.g., it is + // the ParmDecl with no name for declaration of a function pointer type, + // e.g.: void (*f)(void *); + // In this case, don't generate a USR. IgnoreResults = true; - else - GenNamedDecl(s); + } } void USRGenerator::VisitVarDecl(VarDecl *D) { // VarDecls can be declared 'extern' within a function or method body, // but their enclosing DeclContext is the function, not the TU. We need // to check the storage class to correctly generate the USR. - if (D->getLinkage() != ExternalLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - } + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); // Variables always have simple names. llvm::StringRef s = D->getName(); @@ -175,18 +212,28 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { if (s.empty()) IgnoreResults = true; else - GenNamedDecl(s); + Out << '@' << s; } void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + VisitDeclContext(D->getDeclContext()); - Out << "@N@" << D; + if (!IgnoreResults) + Out << "@N@" << D->getName(); } void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Visit(cast<Decl>(D->getDeclContext())); - GenObjCMethod(DeclarationName(D->getSelector()).getAsString(), - D->isInstanceMethod()); + // Ideally we would use 'GenObjCMethod', but this is such a hot path + // for Objective-C code that we don't want to use + // DeclarationName::getAsString(). + Out << (D->isInstanceMethod() ? "(im)" : "(cm)"); + DeclarationName N(D->getSelector()); + N.printName(Out); } void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) { @@ -258,59 +305,56 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { } void USRGenerator::VisitTagDecl(TagDecl *D) { + // Add the location of the tag decl to handle resolution across + // translation units. + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + D = D->getCanonicalDecl(); VisitDeclContext(D->getDeclContext()); - switch (D->getTagKind()) { - case TagDecl::TK_struct: Out << "@S"; break; - case TagDecl::TK_class: Out << "@C"; break; - case TagDecl::TK_union: Out << "@U"; break; - case TagDecl::TK_enum: Out << "@E"; break; - } - const std::string &s = D->getNameAsString(); - const TypedefDecl *TD = 0; - if (s.empty()) { - TD = D->getTypedefForAnonDecl(); - Out << (TD ? 'A' : 'a'); + switch (D->getTagKind()) { + case TTK_Struct: Out << "@S"; break; + case TTK_Class: Out << "@C"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; } - // Add the location of the tag decl to handle resolution across - // translation units. - if (D->getLinkage() == NoLinkage) { - Out << '@'; - GenLoc(D); - if (IgnoreResults) - return; - } + Out << '@'; + Out.flush(); + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; - if (s.empty()) { - if (TD) + if (EmitDeclName(D)) { + if (const TypedefDecl *TD = D->getTypedefForAnonDecl()) { + Buf[off] = 'A'; Out << '@' << TD; + } + else + Buf[off] = 'a'; } - else - Out << '@' << s; } void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; DeclContext *DC = D->getDeclContext(); if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC)) Visit(DCN); Out << "@T@"; - if (D->getLinkage() == NoLinkage) { - GenLoc(D); - if (IgnoreResults) - return; - Out << '@'; - } Out << D->getName(); } -void USRGenerator::GenLoc(const Decl *D) { +bool USRGenerator::GenLoc(const Decl *D) { + if (generatedLoc) + return IgnoreResults; + generatedLoc = true; + const SourceManager &SM = AU->getSourceManager(); SourceLocation L = D->getLocStart(); if (L.isInvalid()) { IgnoreResults = true; - return; + return true; } L = SM.getInstantiationLoc(L); const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L); @@ -322,21 +366,145 @@ void USRGenerator::GenLoc(const Decl *D) { else { // This case really isn't interesting. IgnoreResults = true; - return; + return true; } Out << '@' << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':' << SM.getColumnNumber(Decomposed.first, Decomposed.second); + + return IgnoreResults; +} + +void USRGenerator::VisitType(QualType T) { + // This method mangles in USR information for types. It can possibly + // just reuse the naming-mangling logic used by codegen, although the + // requirements for USRs might not be the same. + ASTContext &Ctx = AU->getASTContext(); + + do { + T = Ctx.getCanonicalType(T); + Qualifiers Q = T.getQualifiers(); + unsigned qVal = 0; + if (Q.hasConst()) + qVal |= 0x1; + if (Q.hasVolatile()) + qVal |= 0x2; + if (Q.hasRestrict()) + qVal |= 0x4; + if(qVal) + Out << ((char) ('0' + qVal)); + + // Mangle in ObjC GC qualifiers? + + if (const PointerType *PT = T->getAs<PointerType>()) { + Out << '*'; + T = PT->getPointeeType(); + continue; + } + if (const ReferenceType *RT = T->getAs<ReferenceType>()) { + Out << '&'; + T = RT->getPointeeType(); + continue; + } + if (const FunctionProtoType *FT = T->getAs<FunctionProtoType>()) { + Out << 'F'; + VisitType(FT->getResultType()); + for (FunctionProtoType::arg_type_iterator + I = FT->arg_type_begin(), E = FT->arg_type_end(); I!=E; ++I) { + VisitType(*I); + } + if (FT->isVariadic()) + Out << '.'; + return; + } + if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) { + Out << 'B'; + T = BT->getPointeeType(); + continue; + } + if (const BuiltinType *BT = T->getAs<BuiltinType>()) { + unsigned char c = '\0'; + switch (BT->getKind()) { + case BuiltinType::Void: + c = 'v'; break; + case BuiltinType::Bool: + c = 'b'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: + c = 'c'; break; + case BuiltinType::Char16: + c = 'q'; break; + case BuiltinType::Char32: + c = 'w'; break; + case BuiltinType::UShort: + c = 's'; break; + case BuiltinType::UInt: + c = 'i'; break; + case BuiltinType::ULong: + c = 'l'; break; + case BuiltinType::ULongLong: + c = 'k'; break; + case BuiltinType::UInt128: + c = 'j'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + c = 'C'; break; + case BuiltinType::WChar: + c = 'W'; break; + case BuiltinType::Short: + c = 'S'; break; + case BuiltinType::Int: + c = 'I'; break; + case BuiltinType::Long: + c = 'L'; break; + case BuiltinType::LongLong: + c = 'K'; break; + case BuiltinType::Int128: + c = 'J'; break; + case BuiltinType::Float: + c = 'f'; break; + case BuiltinType::Double: + c = 'd'; break; + case BuiltinType::LongDouble: + c = 'D'; break; + case BuiltinType::NullPtr: + c = 'n'; break; + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UndeducedAuto: + IgnoreResults = true; + return; + case BuiltinType::ObjCId: + c = 'o'; break; + case BuiltinType::ObjCClass: + c = 'O'; break; + case BuiltinType::ObjCSel: + c = 'e'; break; + } + Out << c; + return; + } + if (const ComplexType *CT = T->getAs<ComplexType>()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs<TagType>()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); } //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// -void USRGenerator::GenNamedDecl(llvm::StringRef name) { - Out << "@" << name; -} - void USRGenerator::GenObjCClass(llvm::StringRef cls) { Out << "objc(cs)" << cls; } @@ -346,7 +514,7 @@ void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) { } void USRGenerator::GenObjCIvar(llvm::StringRef ivar) { - GenNamedDecl(ivar); + Out << '@' << ivar; } void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) { @@ -383,6 +551,7 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // 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 @@ -390,27 +559,27 @@ static CXString getDeclCursorUSR(const CXCursor &C) { // are referred to across multiple translation units. if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) || isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) || - isa<VarDecl>(ND)) + isa<VarDecl>(ND) || isa<NamespaceDecl>(ND)) break; // Fall-through. case InternalLinkage: if (isa<FunctionDecl>(ND)) break; - case UniqueExternalLinkage: - return createCXString(""); } - StringUSRGenerator SUG(&C); - SUG->Visit(D); + USRGenerator UG(&C); + UG->Visit(D); - if (SUG->ignoreResults()) + if (UG->ignoreResults()) return createCXString(""); +#if 0 // For development testing. - // assert(SUG.str().size() > 2); + assert(UG.str().size() > 2); +#endif // Return a copy of the string that must be disposed by the caller. - return createCXString(SUG.str(), true); + return createCXString(UG.str(), true); } extern "C" { @@ -422,56 +591,56 @@ CXString clang_getCursorUSR(CXCursor C) { return getDeclCursorUSR(C); if (K == CXCursor_MacroDefinition) { - StringUSRGenerator SUG(&C); - SUG << "macro@" - << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); - return createCXString(SUG.str(), true); + USRGenerator UG(&C); + UG << "macro@" + << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); + return createCXString(UG.str(), true); } return createCXString(""); } CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCIvar(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCIvar(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCMethod(const char *name, unsigned isInstanceMethod, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCMethod(name, isInstanceMethod); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCMethod(name, isInstanceMethod); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCClass(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCClass(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCClass(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProtocol(const char *name) { - StringUSRGenerator SUG; - SUG->GenObjCProtocol(name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCProtocol(name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCCategory(const char *class_name, const char *category_name) { - StringUSRGenerator SUG; - SUG->GenObjCCategory(class_name, category_name); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG->GenObjCCategory(class_name, category_name); + return createCXString(UG.str(), true); } CXString clang_constructUSR_ObjCProperty(const char *property, CXString classUSR) { - StringUSRGenerator SUG; - SUG << extractUSRSuffix(clang_getCString(classUSR)); - SUG->GenObjCProperty(property); - return createCXString(SUG.str(), true); + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCProperty(property); + return createCXString(UG.str(), true); } } // end extern "C" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index d3de94a..62c9738 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(libclang CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp + CXTypes.cpp ../../include/clang-c/Index.h ) set_target_properties(libclang PROPERTIES OUTPUT_NAME clang) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index c8eb482..f7192dd 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -56,13 +56,14 @@ static CXCursorKind GetCursorKind(Decl *D) { case Decl::ParmVar: return CXCursor_ParmDecl; case Decl::Typedef: return CXCursor_TypedefDecl; case Decl::Var: return CXCursor_VarDecl; + case Decl::Namespace: return CXCursor_Namespace; default: if (TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { - case TagDecl::TK_struct: return CXCursor_StructDecl; - case TagDecl::TK_class: return CXCursor_ClassDecl; - case TagDecl::TK_union: return CXCursor_UnionDecl; - case TagDecl::TK_enum: return CXCursor_EnumDecl; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_EnumDecl; } } @@ -79,6 +80,7 @@ static CXCursorKind GetCursorKind(const Attr *A) { default: break; case Attr::IBActionKind: return CXCursor_IBActionAttr; case Attr::IBOutletKind: return CXCursor_IBOutletAttr; + case Attr::IBOutletCollectionKind: return CXCursor_IBOutletCollectionAttr; } return CXCursor_UnexposedAttr; diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp new file mode 100644 index 0000000..137370a --- /dev/null +++ b/tools/libclang/CXTypes.cpp @@ -0,0 +1,249 @@ +//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------------===// +// +// This file implements the 'CXTypes' API hooks in the Clang-C library. +// +//===--------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; + +static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { +#define BTCASE(K) case BuiltinType::K: return CXType_##K + switch (BT->getKind()) { + BTCASE(Void); + BTCASE(Bool); + BTCASE(Char_U); + BTCASE(UChar); + BTCASE(Char16); + BTCASE(Char32); + BTCASE(UShort); + BTCASE(UInt); + BTCASE(ULong); + BTCASE(ULongLong); + BTCASE(UInt128); + BTCASE(Char_S); + BTCASE(SChar); + BTCASE(WChar); + BTCASE(Short); + BTCASE(Int); + BTCASE(Long); + BTCASE(LongLong); + BTCASE(Int128); + BTCASE(Float); + BTCASE(Double); + BTCASE(LongDouble); + BTCASE(NullPtr); + BTCASE(Overload); + BTCASE(Dependent); + BTCASE(ObjCId); + BTCASE(ObjCClass); + BTCASE(ObjCSel); + default: + return CXType_Unexposed; + } +#undef BTCASE +} + +static CXTypeKind GetTypeKind(QualType T) { + Type *TP = T.getTypePtr(); + if (!TP) + return CXType_Invalid; + +#define TKCASE(K) case Type::K: return CXType_##K + switch (TP->getTypeClass()) { + case Type::Builtin: + return GetBuiltinTypeKind(cast<BuiltinType>(TP)); + TKCASE(Complex); + TKCASE(Pointer); + TKCASE(BlockPointer); + TKCASE(LValueReference); + TKCASE(RValueReference); + TKCASE(Record); + TKCASE(Enum); + TKCASE(Typedef); + TKCASE(ObjCInterface); + TKCASE(ObjCObjectPointer); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + +static CXType MakeCXType(QualType T, ASTUnit *TU) { + CXTypeKind TK = GetTypeKind(T); + CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; + return CT; +} + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline ASTUnit* GetASTU(CXType CT) { + return static_cast<ASTUnit*>(CT.data[1]); +} + +extern "C" { + +CXType clang_getCursorType(CXCursor C) { + ASTUnit *AU = cxcursor::getCursorASTUnit(C); + + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, AU); + } + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU); + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + return MakeCXType(VD->getType(), AU); + + return MakeCXType(QualType(), AU); + } + + return MakeCXType(QualType(), AU); +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetASTU(CT)); + + ASTUnit *AU = GetASTU(CT); + return MakeCXType(AU->getASTContext().getCanonicalType(T), AU); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + + if (!TP) + return MakeCXType(QualType(), GetASTU(CT)); + + switch (TP->getTypeClass()) { + case Type::Pointer: + T = cast<PointerType>(TP)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast<BlockPointerType>(TP)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast<ReferenceType>(TP)->getPointeeType(); + break; + case Type::ObjCObjectPointer: + T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); + break; + default: + T = QualType(); + break; + } + return MakeCXType(T, GetASTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + Decl *D = 0; + + switch (TP->getTypeClass()) { + case Type::Typedef: + D = cast<TypedefType>(TP)->getDecl(); + break; + case Type::ObjCObject: + D = cast<ObjCObjectType>(TP)->getInterface(); + break; + case Type::ObjCInterface: + D = cast<ObjCInterfaceType>(TP)->getDecl(); + break; + case Type::Record: + case Type::Enum: + D = cast<TagType>(TP)->getDecl(); + break; + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetASTU(CT)); +} + +CXString clang_getTypeKindSpelling(enum CXTypeKind K) { + const char *s = 0; +#define TKIND(X) case CXType_##X: s = "" #X ""; break + switch (K) { + TKIND(Invalid); + TKIND(Unexposed); + TKIND(Void); + TKIND(Bool); + TKIND(Char_U); + TKIND(UChar); + TKIND(Char16); + TKIND(Char32); + TKIND(UShort); + TKIND(UInt); + TKIND(ULong); + TKIND(ULongLong); + TKIND(UInt128); + TKIND(Char_S); + TKIND(SChar); + TKIND(WChar); + TKIND(Short); + TKIND(Int); + TKIND(Long); + TKIND(LongLong); + TKIND(Int128); + TKIND(Float); + TKIND(Double); + TKIND(LongDouble); + TKIND(NullPtr); + TKIND(Overload); + TKIND(Dependent); + TKIND(ObjCId); + TKIND(ObjCClass); + TKIND(ObjCSel); + TKIND(Complex); + TKIND(Pointer); + TKIND(BlockPointer); + TKIND(LValueReference); + TKIND(RValueReference); + TKIND(Record); + TKIND(Enum); + TKIND(Typedef); + TKIND(ObjCInterface); + TKIND(ObjCObjectPointer); + } +#undef TKIND + return cxstring::createCXString(s); +} + +unsigned clang_equalTypes(CXType A, CXType B) { + return A.data[0] == B.data[0] && A.data[1] == B.data[1];; +} + +} // end: extern "C" diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index a7877bf..ff0fa33 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -50,6 +50,6 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -no-undefined -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index b361168..a9f4f07 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -1,3 +1,4 @@ +_clang_CXXMethod_isStatic _clang_annotateTokens _clang_codeComplete _clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ _clang_disposeTranslationUnit _clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_equalTypes _clang_formatDiagnostic _clang_getCString +_clang_getCanonicalType _clang_getClangVersion _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText +_clang_getCompletionPriority _clang_getCursor _clang_getCursorDefinition _clang_getCursorExtent @@ -37,6 +41,7 @@ _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced _clang_getCursorSpelling +_clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent _clang_getDiagnostic @@ -58,6 +63,7 @@ _clang_getNullLocation _clang_getNullRange _clang_getNumCompletionChunks _clang_getNumDiagnostics +_clang_getPointeeType _clang_getRange _clang_getRangeEnd _clang_getRangeStart @@ -67,9 +73,12 @@ _clang_getTokenLocation _clang_getTokenSpelling _clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_getTypeDeclaration +_clang_getTypeKindSpelling _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression +_clang_isFromMainFile _clang_isInvalid _clang_isPreprocessing _clang_isReference diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 991bb06..b09e6ac 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -1,3 +1,4 @@ +clang_CXXMethod_isStatic clang_annotateTokens clang_codeComplete clang_codeCompleteGetDiagnostic @@ -21,12 +22,15 @@ clang_disposeTranslationUnit clang_enableStackTraces clang_equalCursors clang_equalLocations +clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCanonicalType clang_getClangVersion clang_getCompletionChunkCompletionString clang_getCompletionChunkKind clang_getCompletionChunkText +clang_getCompletionPriority clang_getCursor clang_getCursorDefinition clang_getCursorExtent @@ -37,6 +41,7 @@ clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced clang_getCursorSpelling +clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent clang_getDiagnostic @@ -58,6 +63,7 @@ clang_getNullLocation clang_getNullRange clang_getNumCompletionChunks clang_getNumDiagnostics +clang_getPointeeType clang_getRange clang_getRangeEnd clang_getRangeStart @@ -67,9 +73,12 @@ clang_getTokenLocation clang_getTokenSpelling clang_getTranslationUnitCursor clang_getTranslationUnitSpelling +clang_getTypeDeclaration +clang_getTypeKindSpelling clang_isCursorDefinition clang_isDeclaration clang_isExpression +clang_isFromMainFile clang_isInvalid clang_isPreprocessing clang_isReference @@ -79,3 +88,4 @@ clang_isUnexposed clang_setUseExternalASTGeneration clang_tokenize clang_visitChildren + |