diff options
author | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 |
---|---|---|
committer | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 |
commit | be1de4be954c80875ad4108e0a33e8e131b2f2c0 (patch) | |
tree | 1fbbecf276bf7c7bdcbb4dd446099d6d90eaa516 /clang/tools/libclang | |
parent | c4626a62754862d20b41e8a46a3574264ea80e6d (diff) | |
parent | f1bd2e48c5324d3f7cda4090c87f8a5b6f463ce2 (diff) |
Merge branch 'master' of ssh://bitbucket.org/czan/honours
Diffstat (limited to 'clang/tools/libclang')
34 files changed, 16781 insertions, 0 deletions
diff --git a/clang/tools/libclang/ARCMigrate.cpp b/clang/tools/libclang/ARCMigrate.cpp new file mode 100644 index 0000000..5ee5cf6 --- /dev/null +++ b/clang/tools/libclang/ARCMigrate.cpp @@ -0,0 +1,139 @@ +//===- ARCMigrate.cpp - Clang-C ARC Migration Library ---------------------===// +// +// 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 main API hooks in the Clang-C ARC Migration library. +// +//===----------------------------------------------------------------------===// + +#include "clang-c/Index.h" + +#include "CXString.h" +#include "clang/ARCMigrate/ARCMT.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "llvm/Support/FileSystem.h" + +using namespace clang; +using namespace arcmt; + +namespace { + +struct Remap { + std::vector<std::pair<std::string, std::string> > Vec; +}; + +} // anonymous namespace. + +//===----------------------------------------------------------------------===// +// libClang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +CXRemapping clang_getRemappings(const char *migrate_dir_path) { + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + if (!migrate_dir_path) { + if (Logging) + llvm::errs() << "clang_getRemappings was called with NULL parameter\n"; + return 0; + } + + bool exists = false; + llvm::sys::fs::exists(migrate_dir_path, exists); + if (!exists) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + llvm::errs() << "\"" << migrate_dir_path << "\" does not exist\n"; + } + return 0; + } + + TextDiagnosticBuffer diagBuffer; + OwningPtr<Remap> remap(new Remap()); + + bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return 0; + } + + return remap.take(); +} + +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles) { + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + OwningPtr<Remap> remap(new Remap()); + + if (numFiles == 0) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "numFiles=0\n"; + return remap.take(); + } + + if (!filePaths) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "NULL filePaths\n"; + return 0; + } + + TextDiagnosticBuffer diagBuffer; + SmallVector<StringRef, 32> Files; + for (unsigned i = 0; i != numFiles; ++i) + Files.push_back(filePaths[i]); + + bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files, + &diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappingsFromFileList\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return remap.take(); + } + + return remap.take(); +} + +unsigned clang_remap_getNumFiles(CXRemapping map) { + return static_cast<Remap *>(map)->Vec.size(); + +} + +void clang_remap_getFilenames(CXRemapping map, unsigned index, + CXString *original, CXString *transformed) { + if (original) + *original = cxstring::createCXString( + static_cast<Remap *>(map)->Vec[index].first, + /*DupString =*/ true); + if (transformed) + *transformed = cxstring::createCXString( + static_cast<Remap *>(map)->Vec[index].second, + /*DupString =*/ true); +} + +void clang_remap_dispose(CXRemapping map) { + delete static_cast<Remap *>(map); +} + +} // end: extern "C" diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp new file mode 100644 index 0000000..605cc8b --- /dev/null +++ b/clang/tools/libclang/CIndex.cpp @@ -0,0 +1,5876 @@ +//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// +// +// 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 main API hooks in the Clang-C Source Indexing +// library. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXTranslationUnit.h" +#include "CXString.h" +#include "CXType.h" +#include "CXSourceLocation.h" +#include "CIndexDiagnostic.h" +#include "CursorVisitor.h" + +#include "clang/Basic/Version.h" + +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; +using namespace clang::cxcursor; +using namespace clang::cxstring; +using namespace clang::cxtu; +using namespace clang::cxindex; + +CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) { + if (!TU) + return 0; + CXTranslationUnit D = new CXTranslationUnitImpl(); + D->CIdx = CIdx; + D->TUData = TU; + D->StringPool = createCXStringPool(); + D->Diagnostics = 0; + return D; +} + +cxtu::CXTUOwner::~CXTUOwner() { + if (TU) + clang_disposeTranslationUnit(TU); +} + +/// \brief Compare two source ranges to determine their relative position in +/// the translation unit. +static RangeComparisonResult RangeCompare(SourceManager &SM, + SourceRange R1, + SourceRange R2) { + assert(R1.isValid() && "First range is invalid?"); + assert(R2.isValid() && "Second range is invalid?"); + if (R1.getEnd() != R2.getBegin() && + SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) + return RangeBefore; + if (R2.getEnd() != R1.getBegin() && + SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) + return RangeAfter; + 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() || L == R.getEnd()) + return RangeOverlap; + 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 +/// start of the token at the end. However, for external clients it is more +/// useful to have a CXSourceRange be a proper half-open interval. This routine +/// does the appropriate translation. +CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, + const LangOptions &LangOpts, + const CharSourceRange &R) { + // We want the last character in this location, so we will adjust the + // location accordingly. + SourceLocation EndLoc = R.getEnd(); + if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) + EndLoc = SM.getExpansionRange(EndLoc).second; + if (R.isTokenRange() && !EndLoc.isInvalid()) { + unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc), + SM, LangOpts); + EndLoc = EndLoc.getLocWithOffset(Length); + } + + CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts }, + R.getBegin().getRawEncoding(), + EndLoc.getRawEncoding() }; + return Result; +} + +//===----------------------------------------------------------------------===// +// Cursor visitor. +//===----------------------------------------------------------------------===// + +static SourceRange getRawCursorExtent(CXCursor C); +static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr); + + +RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { + return RangeCompare(AU->getSourceManager(), R, RegionOfInterest); +} + +/// \brief Visit the given cursor and, if requested by the visitor, +/// its children. +/// +/// \param Cursor the cursor to visit. +/// +/// \param CheckRegionOfInterest if true, then the caller already checked that +/// this cursor is within the region of interest. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { + if (clang_isInvalid(Cursor.kind)) + return false; + + if (clang_isDeclaration(Cursor.kind)) { + Decl *D = getCursorDecl(Cursor); + if (!D) { + assert(0 && "Invalid declaration cursor"); + return true; // abort. + } + + // Ignore implicit declarations, unless it's an objc method because + // currently we should report implicit methods for properties when indexing. + if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) + return false; + } + + // If we have a range of interest, and this cursor doesn't intersect with it, + // we're done. + if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { + SourceRange Range = getRawCursorExtent(Cursor); + 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: + return VisitChildren(Cursor); + } + + llvm_unreachable("Invalid CXChildVisitResult!"); +} + +static bool visitPreprocessedEntitiesInRange(SourceRange R, + PreprocessingRecord &PPRec, + CursorVisitor &Visitor) { + SourceManager &SM = Visitor.getASTUnit()->getSourceManager(); + FileID FID; + + if (!Visitor.shouldVisitIncludedEntities()) { + // If the begin/end of the range lie in the same FileID, do the optimization + // where we skip preprocessed entities that do not come from the same FileID. + FID = SM.getFileID(SM.getFileLoc(R.getBegin())); + if (FID != SM.getFileID(SM.getFileLoc(R.getEnd()))) + FID = FileID(); + } + + std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> + Entities = PPRec.getPreprocessedEntitiesInRange(R); + return Visitor.visitPreprocessedEntities(Entities.first, Entities.second, + PPRec, FID); +} + +void CursorVisitor::visitFileRegion() { + if (RegionOfInterest.isInvalid()) + return; + + ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + + std::pair<FileID, unsigned> + Begin = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getBegin())), + End = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getEnd())); + + if (End.first != Begin.first) { + // If the end does not reside in the same file, try to recover by + // picking the end of the file of begin location. + End.first = Begin.first; + End.second = SM.getFileIDSize(Begin.first); + } + + assert(Begin.first == End.first); + if (Begin.second > End.second) + return; + + FileID File = Begin.first; + unsigned Offset = Begin.second; + unsigned Length = End.second - Begin.second; + + if (!VisitDeclsOnly && !VisitPreprocessorLast) + if (visitPreprocessedEntitiesInRegion()) + return; // visitation break. + + visitDeclsFromFileRegion(File, Offset, Length); + + if (!VisitDeclsOnly && VisitPreprocessorLast) + visitPreprocessedEntitiesInRegion(); +} + +static bool isInLexicalContext(Decl *D, DeclContext *DC) { + if (!DC) + return false; + + for (DeclContext *DeclDC = D->getLexicalDeclContext(); + DeclDC; DeclDC = DeclDC->getLexicalParent()) { + if (DeclDC == DC) + return true; + } + return false; +} + +void CursorVisitor::visitDeclsFromFileRegion(FileID File, + unsigned Offset, unsigned Length) { + ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + SourceRange Range = RegionOfInterest; + + SmallVector<Decl *, 16> Decls; + Unit->findFileRegionDecls(File, Offset, Length, Decls); + + // If we didn't find any file level decls for the file, try looking at the + // file that it was included from. + while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) { + bool Invalid = false; + const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid); + if (Invalid) + return; + + SourceLocation Outer; + if (SLEntry.isFile()) + Outer = SLEntry.getFile().getIncludeLoc(); + else + Outer = SLEntry.getExpansion().getExpansionLocStart(); + if (Outer.isInvalid()) + return; + + llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer); + Length = 0; + Unit->findFileRegionDecls(File, Offset, Length, Decls); + } + + assert(!Decls.empty()); + + bool VisitedAtLeastOnce = false; + DeclContext *CurDC = 0; + SmallVector<Decl *, 16>::iterator DIt = Decls.begin(); + for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) { + Decl *D = *DIt; + if (D->getSourceRange().isInvalid()) + continue; + + if (isInLexicalContext(D, CurDC)) + continue; + + CurDC = dyn_cast<DeclContext>(D); + + if (TagDecl *TD = dyn_cast<TagDecl>(D)) + if (!TD->isFreeStanding()) + continue; + + RangeComparisonResult CompRes = RangeCompare(SM, D->getSourceRange(),Range); + if (CompRes == RangeBefore) + continue; + if (CompRes == RangeAfter) + break; + + assert(CompRes == RangeOverlap); + VisitedAtLeastOnce = true; + + if (isa<ObjCContainerDecl>(D)) { + FileDI_current = &DIt; + FileDE_current = DE; + } else { + FileDI_current = 0; + } + + if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true)) + break; + } + + if (VisitedAtLeastOnce) + return; + + // No Decls overlapped with the range. Move up the lexical context until there + // is a context that contains the range or we reach the translation unit + // level. + DeclContext *DC = DIt == Decls.begin() ? (*DIt)->getLexicalDeclContext() + : (*(DIt-1))->getLexicalDeclContext(); + + while (DC && !DC->isTranslationUnit()) { + Decl *D = cast<Decl>(DC); + SourceRange CurDeclRange = D->getSourceRange(); + if (CurDeclRange.isInvalid()) + break; + + if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) { + Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true); + break; + } + + DC = D->getLexicalDeclContext(); + } +} + +bool CursorVisitor::visitPreprocessedEntitiesInRegion() { + if (!AU->getPreprocessor().getPreprocessingRecord()) + return false; + + PreprocessingRecord &PPRec + = *AU->getPreprocessor().getPreprocessingRecord(); + SourceManager &SM = AU->getSourceManager(); + + if (RegionOfInterest.isValid()) { + SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest); + SourceLocation B = MappedRange.getBegin(); + SourceLocation E = MappedRange.getEnd(); + + if (AU->isInPreambleFileID(B)) { + if (SM.isLoadedSourceLocation(E)) + return visitPreprocessedEntitiesInRange(SourceRange(B, E), + PPRec, *this); + + // Beginning of range lies in the preamble but it also extends beyond + // it into the main file. Split the range into 2 parts, one covering + // the preamble and another covering the main file. This allows subsequent + // calls to visitPreprocessedEntitiesInRange to accept a source range that + // lies in the same FileID, allowing it to skip preprocessed entities that + // do not come from the same FileID. + bool breaked = + visitPreprocessedEntitiesInRange( + SourceRange(B, AU->getEndOfPreambleFileID()), + PPRec, *this); + if (breaked) return true; + return visitPreprocessedEntitiesInRange( + SourceRange(AU->getStartOfMainFileID(), E), + PPRec, *this); + } + + return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this); + } + + bool OnlyLocalDecls + = !AU->isMainFileAST() && AU->getOnlyLocalDecls(); + + if (OnlyLocalDecls) + return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(), + PPRec); + + return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec); +} + +template<typename InputIterator> +bool CursorVisitor::visitPreprocessedEntities(InputIterator First, + InputIterator Last, + PreprocessingRecord &PPRec, + FileID FID) { + for (; First != Last; ++First) { + if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID)) + continue; + + PreprocessedEntity *PPE = *First; + if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) { + if (Visit(MakeMacroExpansionCursor(ME, TU))) + return true; + + continue; + } + + if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) { + if (Visit(MakeMacroDefinitionCursor(MD, TU))) + return true; + + continue; + } + + if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { + if (Visit(MakeInclusionDirectiveCursor(ID, TU))) + return true; + + continue; + } + } + + return false; +} + +/// \brief Visit the children of the given cursor. +/// +/// \returns true if the visitation should be aborted, false if it +/// should continue. +bool CursorVisitor::VisitChildren(CXCursor Cursor) { + if (clang_isReference(Cursor.kind) && + Cursor.kind != CXCursor_CXXBaseSpecifier) { + // By definition, references have no children. + return false; + } + + // Set the Parent field to Cursor, then back to its old value once we're + // done. + SetParentRAII SetParent(Parent, StmtParent, Cursor); + + if (clang_isDeclaration(Cursor.kind)) { + Decl *D = getCursorDecl(Cursor); + if (!D) + return false; + + return VisitAttributes(D) || Visit(D); + } + + 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<ASTUnit*>(tu->TUData); + + 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, RegionOfInterest), true)) + return true; + } + } else if (VisitDeclContext( + CXXUnit->getASTContext().getTranslationUnitDecl())) + return true; + continue; + } + + // Walk the preprocessing record. + if (CXXUnit->getPreprocessor().getPreprocessingRecord()) + visitPreprocessedEntitiesInRegion(); + } + + return false; + } + + if (Cursor.kind == CXCursor_CXXBaseSpecifier) { + if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) { + if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) { + return Visit(BaseTSInfo->getTypeLoc()); + } + } + } + + if (Cursor.kind == CXCursor_IBOutletCollectionAttr) { + IBOutletCollectionAttr *A = + cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor)); + if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>()) + return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(), + A->getInterfaceLoc(), TU)); + } + + // Nothing to visit at the moment. + return false; +} + +bool CursorVisitor::VisitBlockDecl(BlockDecl *B) { + if (TypeSourceInfo *TSInfo = B->getSignatureAsWritten()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + if (Stmt *Body = B->getBody()) + return Visit(MakeCXCursor(Body, StmtParent, TU, RegionOfInterest)); + + return false; +} + +llvm::Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) { + if (RegionOfInterest.isValid()) { + SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager()); + if (Range.isInvalid()) + return llvm::Optional<bool>(); + + switch (CompareRegionOfInterest(Range)) { + case RangeBefore: + // This declaration comes before the region of interest; skip it. + return llvm::Optional<bool>(); + + case RangeAfter: + // This declaration comes after the region of interest; we're done. + return false; + + case RangeOverlap: + // This declaration overlaps the region of interest; visit it. + break; + } + } + return true; +} + +bool CursorVisitor::VisitDeclContext(DeclContext *DC) { + DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + + // FIXME: Eventually remove. This part of a hack to support proper + // iteration over all Decls contained lexically within an ObjC container. + SaveAndRestore<DeclContext::decl_iterator*> DI_saved(DI_current, &I); + SaveAndRestore<DeclContext::decl_iterator> DE_saved(DE_current, E); + + for ( ; I != E; ++I) { + Decl *D = *I; + if (D->getLexicalDeclContext() != DC) + continue; + CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest); + + // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol + // declarations is a mismatch with the compiler semantics. + if (Cursor.kind == CXCursor_ObjCInterfaceDecl) { + ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D); + if (!ID->isThisDeclarationADefinition()) + Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU); + + } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) { + ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D); + if (!PD->isThisDeclarationADefinition()) + Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU); + } + + const llvm::Optional<bool> &V = shouldVisitCursor(Cursor); + if (!V.hasValue()) + continue; + if (!V.getValue()) + return false; + if (Visit(Cursor, true)) + return true; + } + return false; +} + +bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + llvm_unreachable("Translation units are visited directly by Visit()"); +} + +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()); + + return false; +} + +bool CursorVisitor::VisitTagDecl(TagDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + bool ShouldVisitBody = false; + switch (D->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // Nothing to visit + return false; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + break; + + case TSK_ExplicitSpecialization: + ShouldVisitBody = true; + break; + } + + // Visit the template arguments used in the specialization. + if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) { + TypeLoc TL = SpecType->getTypeLoc(); + if (TemplateSpecializationTypeLoc *TSTLoc + = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) { + for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I))) + return true; + } + } + + if (ShouldVisitBody && VisitCXXRecordDecl(D)) + return true; + + return false; +} + +bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + // Visit the partial specialization arguments. + const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten(); + for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I) + if (VisitTemplateArgumentLoc(TemplateArgs[I])) + return true; + + return VisitCXXRecordDecl(D); +} + +bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // Visit the default argument. + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo()) + if (Visit(DefArg->getTypeLoc())) + return true; + + return false; +} + +bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { + if (Expr *Init = D->getInitExpr()) + return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest)); + return false; +} + +bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { + if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + // Visit the nested-name-specifier, if present. + if (NestedNameSpecifierLoc QualifierLoc = DD->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + return false; +} + +/// \brief Compare two base or member initializers based on their source order. +static int CompareCXXCtorInitializers(const void* Xp, const void *Yp) { + CXXCtorInitializer const * const *X + = static_cast<CXXCtorInitializer const * const *>(Xp); + CXXCtorInitializer const * const *Y + = static_cast<CXXCtorInitializer const * const *>(Yp); + + if ((*X)->getSourceOrder() < (*Y)->getSourceOrder()) + return -1; + else if ((*X)->getSourceOrder() > (*Y)->getSourceOrder()) + return 1; + else + return 0; +} + +bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { + if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) { + // Visit the function declaration's syntactic components in the order + // written. This requires a bit of work. + TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); + FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL); + + // If we have a function declared directly (without the use of a typedef), + // visit just the return type. Otherwise, just visit the function's type + // now. + if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) || + (!FTL && Visit(TL))) + return true; + + // Visit the nested-name-specifier, if present. + if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(ND->getNameInfo())) + return true; + + // FIXME: Visit explicitly-specified template arguments! + + // Visit the function parameters, if we have a function type. + if (FTL && VisitFunctionTypeLoc(*FTL, true)) + return true; + + // FIXME: Attributes? + } + + if (ND->doesThisDeclarationHaveABody() && !ND->isLateTemplateParsed()) { + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(ND)) { + // Find the initializers that were written in the source. + SmallVector<CXXCtorInitializer *, 4> WrittenInits; + for (CXXConstructorDecl::init_iterator I = Constructor->init_begin(), + IEnd = Constructor->init_end(); + I != IEnd; ++I) { + if (!(*I)->isWritten()) + continue; + + WrittenInits.push_back(*I); + } + + // Sort the initializers in source order + llvm::array_pod_sort(WrittenInits.begin(), WrittenInits.end(), + &CompareCXXCtorInitializers); + + // Visit the initializers in source order + for (unsigned I = 0, N = WrittenInits.size(); I != N; ++I) { + CXXCtorInitializer *Init = WrittenInits[I]; + if (Init->isAnyMemberInitializer()) { + if (Visit(MakeCursorMemberRef(Init->getAnyMember(), + Init->getMemberLocation(), TU))) + return true; + } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) { + if (Visit(TInfo->getTypeLoc())) + return true; + } + + // Visit the initializer value. + if (Expr *Initializer = Init->getInit()) + if (Visit(MakeCXCursor(Initializer, ND, TU, RegionOfInterest))) + return true; + } + } + + if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitFieldDecl(FieldDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (Expr *BitWidth = D->getBitWidth()) + return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest)); + + return false; +} + +bool CursorVisitor::VisitVarDecl(VarDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (Expr *Init = D->getInit()) + return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest)); + + return false; +} + +bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (Expr *DefArg = D->getDefaultArgument()) + return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest)); + + return false; +} + +bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the FunctionDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitFunctionDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitCXXRecordDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() && + VisitTemplateArgumentLoc(D->getDefaultArgument())) + return true; + + return false; +} + +bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { + if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + for (ObjCMethodDecl::param_iterator P = ND->param_begin(), + PEnd = ND->param_end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU, RegionOfInterest))) + return true; + } + + if (ND->isThisDeclarationADefinition() && + Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest))) + return true; + + return false; +} + +template <typename DeclIt> +static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current, + SourceManager &SM, SourceLocation EndLoc, + SmallVectorImpl<Decl *> &Decls) { + DeclIt next = *DI_current; + while (++next != DE_current) { + Decl *D_next = *next; + if (!D_next) + break; + SourceLocation L = D_next->getLocStart(); + if (!L.isValid()) + break; + if (SM.isBeforeInTranslationUnit(L, EndLoc)) { + *DI_current = next; + Decls.push_back(D_next); + continue; + } + break; + } +} + +namespace { + struct ContainerDeclsSort { + SourceManager &SM; + ContainerDeclsSort(SourceManager &sm) : SM(sm) {} + bool operator()(Decl *A, Decl *B) { + SourceLocation L_A = A->getLocStart(); + SourceLocation L_B = B->getLocStart(); + assert(L_A.isValid() && L_B.isValid()); + return SM.isBeforeInTranslationUnit(L_A, L_B); + } + }; +} + +bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) { + // FIXME: Eventually convert back to just 'VisitDeclContext()'. Essentially + // an @implementation can lexically contain Decls that are not properly + // nested in the AST. When we identify such cases, we need to retrofit + // this nesting here. + if (!DI_current && !FileDI_current) + return VisitDeclContext(D); + + // Scan the Decls that immediately come after the container + // in the current DeclContext. If any fall within the + // container's lexical region, stash them into a vector + // for later processing. + SmallVector<Decl *, 24> DeclsInContainer; + SourceLocation EndLoc = D->getSourceRange().getEnd(); + SourceManager &SM = AU->getSourceManager(); + if (EndLoc.isValid()) { + if (DI_current) { + addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc, + DeclsInContainer); + } else { + addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc, + DeclsInContainer); + } + } + + // The common case. + if (DeclsInContainer.empty()) + return VisitDeclContext(D); + + // Get all the Decls in the DeclContext, and sort them with the + // additional ones we've collected. Then visit them. + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I!=E; ++I) { + Decl *subDecl = *I; + if (!subDecl || subDecl->getLexicalDeclContext() != D || + subDecl->getLocStart().isInvalid()) + continue; + DeclsInContainer.push_back(subDecl); + } + + // Now sort the Decls so that they appear in lexical order. + std::sort(DeclsInContainer.begin(), DeclsInContainer.end(), + ContainerDeclsSort(SM)); + + // Now visit the decls. + for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(), + E = DeclsInContainer.end(); I != E; ++I) { + CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest); + const llvm::Optional<bool> &V = shouldVisitCursor(Cursor); + if (!V.hasValue()) + continue; + if (!V.getValue()) + return false; + if (Visit(Cursor, true)) + return true; + } + return false; +} + +bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { + if (Visit(MakeCursorObjCClassRef(ND->getClassInterface(), ND->getLocation(), + TU))) + return true; + + ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); + for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), + E = ND->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return VisitObjCContainerDecl(ND); +} + +bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + if (!PID->isThisDeclarationADefinition()) + return Visit(MakeCursorObjCProtocolRef(PID, PID->getLocation(), TU)); + + ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin(); + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return VisitObjCContainerDecl(PID); +} + +bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { + if (PD->getTypeSourceInfo() && Visit(PD->getTypeSourceInfo()->getTypeLoc())) + return true; + + // 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() && MD->getLexicalDeclContext() == CDecl) + if (Visit(MakeCXCursor(MD, TU, RegionOfInterest))) + return true; + + if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) + if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl) + if (Visit(MakeCXCursor(MD, TU, RegionOfInterest))) + return true; + + return false; +} + +bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + if (!D->isThisDeclarationADefinition()) { + // Forward declaration is treated like a reference. + return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU)); + } + + // Issue callbacks for super class. + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + D->getSuperClassLoc(), + TU))) + return true; + + ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); I != E; ++I, ++PL) + if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU))) + return true; + + return VisitObjCContainerDecl(D); +} + +bool CursorVisitor::VisitObjCImplDecl(ObjCImplDecl *D) { + return VisitObjCContainerDecl(D); +} + +bool CursorVisitor::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + // 'ID' could be null when dealing with invalid code. + if (ObjCInterfaceDecl *ID = D->getClassInterface()) + if (Visit(MakeCursorObjCClassRef(ID, D->getLocation(), TU))) + return true; + + return VisitObjCImplDecl(D); +} + +bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { +#if 0 + // Issue callbacks for super class. + // FIXME: No source location information! + if (D->getSuperClass() && + Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), + D->getSuperClassLoc(), + TU))) + return true; +#endif + + return VisitObjCImplDecl(D); +} + +bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) { + if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl()) + return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU)); + + return false; +} + +bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + return Visit(MakeCursorNamespaceRef(D->getAliasedNamespace(), + D->getTargetNameLoc(), TU)); +} + +bool CursorVisitor::VisitUsingDecl(UsingDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) { + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + } + + if (Visit(MakeCursorOverloadedDeclRef(D, D->getLocation(), TU))) + return true; + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(), + D->getIdentLocation(), TU)); +} + +bool CursorVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) { + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + } + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + return false; +} + +bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { + switch (Name.getName().getNameKind()) { + case clang::DeclarationName::Identifier: + case clang::DeclarationName::CXXLiteralOperatorName: + case clang::DeclarationName::CXXOperatorName: + case clang::DeclarationName::CXXUsingDirective: + return false; + + case clang::DeclarationName::CXXConstructorName: + case clang::DeclarationName::CXXDestructorName: + case clang::DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case clang::DeclarationName::ObjCZeroArgSelector: + case clang::DeclarationName::ObjCOneArgSelector: + case clang::DeclarationName::ObjCMultiArgSelector: + // FIXME: Per-identifier location info? + return false; + } + + llvm_unreachable("Invalid DeclarationName::Kind!"); +} + +bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range) { + // FIXME: This whole routine is a hack to work around the lack of proper + // source information in nested-name-specifiers (PR5791). Since we do have + // a beginning source location, we can visit the first component of the + // nested-name-specifier, if it's a single-token component. + if (!NNS) + return false; + + // Get the first component in the nested-name-specifier. + while (NestedNameSpecifier *Prefix = NNS->getPrefix()) + NNS = Prefix; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Namespace: + return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(), + TU)); + + case NestedNameSpecifier::NamespaceAlias: + return Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(), + Range.getBegin(), TU)); + + case NestedNameSpecifier::TypeSpec: { + // If the type has a form where we know that the beginning of the source + // range matches up with a reference cursor. Visit the appropriate reference + // cursor. + const Type *T = NNS->getAsType(); + if (const TypedefType *Typedef = dyn_cast<TypedefType>(T)) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU)); + if (const TagType *Tag = dyn_cast<TagType>(T)) + return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU)); + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(T)) + return VisitTemplateName(TST->getTemplateName(), Range.getBegin()); + break; + } + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Identifier: + break; + } + + return false; +} + +bool +CursorVisitor::VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) { + SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; + for (; Qualifier; Qualifier = Qualifier.getPrefix()) + Qualifiers.push_back(Qualifier); + + while (!Qualifiers.empty()) { + NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); + NestedNameSpecifier *NNS = Q.getNestedNameSpecifier(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Namespace: + if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), + Q.getLocalBeginLoc(), + TU))) + return true; + + break; + + case NestedNameSpecifier::NamespaceAlias: + if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(), + Q.getLocalBeginLoc(), + TU))) + return true; + + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + if (Visit(Q.getTypeLoc())) + return true; + + break; + + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Identifier: + break; + } + } + + return false; +} + +bool CursorVisitor::VisitTemplateParameters( + const TemplateParameterList *Params) { + if (!Params) + return false; + + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU, RegionOfInterest))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { + switch (Name.getKind()) { + case TemplateName::Template: + return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU)); + + case TemplateName::OverloadedTemplate: + // Visit the overloaded template set. + if (Visit(MakeCursorOverloadedDeclRef(Name, Loc, TU))) + return true; + + return false; + + case TemplateName::DependentTemplate: + // FIXME: Visit nested-name-specifier. + return false; + + case TemplateName::QualifiedTemplate: + // FIXME: Visit nested-name-specifier. + return Visit(MakeCursorTemplateRef( + Name.getAsQualifiedTemplateName()->getDecl(), + Loc, TU)); + + case TemplateName::SubstTemplateTemplateParm: + return Visit(MakeCursorTemplateRef( + Name.getAsSubstTemplateTemplateParm()->getParameter(), + Loc, TU)); + + case TemplateName::SubstTemplateTemplateParmPack: + return Visit(MakeCursorTemplateRef( + Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), + Loc, TU)); + } + + llvm_unreachable("Invalid TemplateName::Kind!"); +} + +bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { + switch (TAL.getArgument().getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + return false; + + case TemplateArgument::Type: + if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case TemplateArgument::Declaration: + if (Expr *E = TAL.getSourceDeclExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); + return false; + + case TemplateArgument::Expression: + if (Expr *E = TAL.getSourceExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); + return false; + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc())) + return true; + + return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(), + TAL.getTemplateNameLoc()); + } + + llvm_unreachable("Invalid TemplateArgument::Kind!"); +} + +bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + return VisitDeclContext(D); +} + +bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + return Visit(TL.getUnqualifiedLoc()); +} + +bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + ASTContext &Context = AU->getASTContext(); + + // Some builtin types (such as Objective-C's "id", "sel", and + // "Class") have associated declarations. Create cursors for those. + QualType VisitType; + switch (TL.getTypePtr()->getKind()) { + + case BuiltinType::Void: + case BuiltinType::NullPtr: + case BuiltinType::Dependent: +#define BUILTIN_TYPE(Id, SingletonId) +#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: +#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: +#define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id: +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + break; + + case BuiltinType::ObjCId: + VisitType = Context.getObjCIdType(); + break; + + case BuiltinType::ObjCClass: + VisitType = Context.getObjCClassType(); + break; + + case BuiltinType::ObjCSel: + VisitType = Context.getObjCSelType(); + break; + } + + if (!VisitType.isNull()) { + if (const TypedefType *Typedef = VisitType->getAs<TypedefType>()) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), TL.getBuiltinLoc(), + TU)); + } + + return false; +} + +bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { + if (TL.isDefinition()) + return Visit(MakeCXCursor(TL.getDecl(), TU, RegionOfInterest)); + + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +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))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitParenTypeLoc(ParenTypeLoc TL) { + return Visit(TL.getInnerLoc()); +} + +bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { + return Visit(TL.getPointeeLoc()); +} + +bool CursorVisitor::VisitAttributedTypeLoc(AttributedTypeLoc TL) { + return Visit(TL.getModifiedLoc()); +} + +bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, + bool SkipResultType) { + if (!SkipResultType && Visit(TL.getResultLoc())) + return true; + + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (Decl *D = TL.getArg(I)) + if (Visit(MakeCXCursor(D, TU, RegionOfInterest))) + return true; + + return false; +} + +bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { + if (Visit(TL.getElementLoc())) + return true; + + if (Expr *Size = TL.getSizeExpr()) + return Visit(MakeCXCursor(Size, StmtParent, TU, RegionOfInterest)); + + return false; +} + +bool CursorVisitor::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + // Visit the template name. + if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), + TL.getTemplateNameLoc())) + 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::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { + return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); +} + +bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { + if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; +} + +bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { + if (TypeSourceInfo *TSInfo = TL.getUnderlyingTInfo()) + return Visit(TSInfo->getTypeLoc()); + + 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()); +} + +bool CursorVisitor::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { + if (Expr *E = TL.getUnderlyingExpr()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); +} + +bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) { + return Visit(TL.getValueLoc()); +} + +#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \ +bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + return Visit##PARENT##Loc(TL); \ +} + +DEFAULT_TYPELOC_IMPL(Complex, Type) +DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType) +DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType) +DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType) +DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType) +DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type) +DEFAULT_TYPELOC_IMPL(Vector, Type) +DEFAULT_TYPELOC_IMPL(ExtVector, VectorType) +DEFAULT_TYPELOC_IMPL(FunctionProto, FunctionType) +DEFAULT_TYPELOC_IMPL(FunctionNoProto, FunctionType) +DEFAULT_TYPELOC_IMPL(Record, TagType) +DEFAULT_TYPELOC_IMPL(Enum, TagType) +DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type) +DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type) +DEFAULT_TYPELOC_IMPL(Auto, Type) + +bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { + // Visit the nested-name-specifier, if present. + if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + if (D->isCompleteDefinition()) { + for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), + E = D->bases_end(); I != E; ++I) { + if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU))) + return true; + } + } + + return VisitTagDecl(D); +} + +bool CursorVisitor::VisitAttributes(Decl *D) { + for (AttrVec::const_iterator i = D->attr_begin(), e = D->attr_end(); + i != e; ++i) + if (Visit(MakeCXCursor(*i, D, TU))) + return true; + + return false; +} + +//===----------------------------------------------------------------------===// +// Data-recursive visitor methods. +//===----------------------------------------------------------------------===// + +namespace { +#define DEF_JOB(NAME, DATA, KIND)\ +class NAME : public VisitorJob {\ +public:\ + NAME(DATA *d, CXCursor parent) : VisitorJob(parent, VisitorJob::KIND, d) {} \ + static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\ + DATA *get() const { return static_cast<DATA*>(data[0]); }\ +}; + +DEF_JOB(StmtVisit, Stmt, StmtVisitKind) +DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind) +DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind) +DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind) +DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo, + ExplicitTemplateArgsVisitKind) +DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind) +DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind) +#undef DEF_JOB + +class DeclVisit : public VisitorJob { +public: + DeclVisit(Decl *d, CXCursor parent, bool isFirst) : + VisitorJob(parent, VisitorJob::DeclVisitKind, + d, isFirst ? (void*) 1 : (void*) 0) {} + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == DeclVisitKind; + } + Decl *get() const { return static_cast<Decl*>(data[0]); } + bool isFirst() const { return data[1] ? true : false; } +}; +class TypeLocVisit : public VisitorJob { +public: + TypeLocVisit(TypeLoc tl, CXCursor parent) : + VisitorJob(parent, VisitorJob::TypeLocVisitKind, + tl.getType().getAsOpaquePtr(), tl.getOpaqueData()) {} + + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == TypeLocVisitKind; + } + + TypeLoc get() const { + QualType T = QualType::getFromOpaquePtr(data[0]); + return TypeLoc(T, data[1]); + } +}; + +class LabelRefVisit : public VisitorJob { +public: + LabelRefVisit(LabelDecl *LD, SourceLocation labelLoc, CXCursor parent) + : VisitorJob(parent, VisitorJob::LabelRefVisitKind, LD, + labelLoc.getPtrEncoding()) {} + + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == VisitorJob::LabelRefVisitKind; + } + LabelDecl *get() const { return static_cast<LabelDecl*>(data[0]); } + SourceLocation getLoc() const { + return SourceLocation::getFromPtrEncoding(data[1]); } +}; + +class NestedNameSpecifierLocVisit : public VisitorJob { +public: + NestedNameSpecifierLocVisit(NestedNameSpecifierLoc Qualifier, CXCursor parent) + : VisitorJob(parent, VisitorJob::NestedNameSpecifierLocVisitKind, + Qualifier.getNestedNameSpecifier(), + Qualifier.getOpaqueData()) { } + + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == VisitorJob::NestedNameSpecifierLocVisitKind; + } + + NestedNameSpecifierLoc get() const { + return NestedNameSpecifierLoc(static_cast<NestedNameSpecifier*>(data[0]), + data[1]); + } +}; + +class DeclarationNameInfoVisit : public VisitorJob { +public: + DeclarationNameInfoVisit(Stmt *S, CXCursor parent) + : VisitorJob(parent, VisitorJob::DeclarationNameInfoVisitKind, S) {} + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == VisitorJob::DeclarationNameInfoVisitKind; + } + DeclarationNameInfo get() const { + Stmt *S = static_cast<Stmt*>(data[0]); + switch (S->getStmtClass()) { + default: + llvm_unreachable("Unhandled Stmt"); + case clang::Stmt::MSDependentExistsStmtClass: + return cast<MSDependentExistsStmt>(S)->getNameInfo(); + case Stmt::CXXDependentScopeMemberExprClass: + return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo(); + case Stmt::DependentScopeDeclRefExprClass: + return cast<DependentScopeDeclRefExpr>(S)->getNameInfo(); + } + } +}; +class MemberRefVisit : public VisitorJob { +public: + MemberRefVisit(FieldDecl *D, SourceLocation L, CXCursor parent) + : VisitorJob(parent, VisitorJob::MemberRefVisitKind, D, + L.getPtrEncoding()) {} + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == VisitorJob::MemberRefVisitKind; + } + FieldDecl *get() const { + return static_cast<FieldDecl*>(data[0]); + } + SourceLocation getLoc() const { + return SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]); + } +}; +class EnqueueVisitor : public StmtVisitor<EnqueueVisitor, void> { + VisitorWorkList &WL; + CXCursor Parent; +public: + EnqueueVisitor(VisitorWorkList &wl, CXCursor parent) + : WL(wl), Parent(parent) {} + + void VisitAddrLabelExpr(AddrLabelExpr *E); + void VisitBlockExpr(BlockExpr *B); + void VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + void VisitCompoundStmt(CompoundStmt *S); + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ } + void VisitMSDependentExistsStmt(MSDependentExistsStmt *S); + void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); + void VisitCXXNewExpr(CXXNewExpr *E); + void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); + void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); + void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); + void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); + void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); + void VisitCXXUuidofExpr(CXXUuidofExpr *E); + void VisitCXXCatchStmt(CXXCatchStmt *S); + void VisitDeclRefExpr(DeclRefExpr *D); + void VisitDeclStmt(DeclStmt *S); + void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); + void VisitDesignatedInitExpr(DesignatedInitExpr *E); + void VisitExplicitCastExpr(ExplicitCastExpr *E); + void VisitForStmt(ForStmt *FS); + void VisitGotoStmt(GotoStmt *GS); + void VisitIfStmt(IfStmt *If); + void VisitInitListExpr(InitListExpr *IE); + void VisitMemberExpr(MemberExpr *M); + void VisitOffsetOfExpr(OffsetOfExpr *E); + void VisitObjCEncodeExpr(ObjCEncodeExpr *E); + void VisitObjCMessageExpr(ObjCMessageExpr *M); + void VisitOverloadExpr(OverloadExpr *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 VisitTypeTraitExpr(TypeTraitExpr *E); + void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); + void VisitExpressionTraitExpr(ExpressionTraitExpr *E); + void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U); + void VisitVAArgExpr(VAArgExpr *E); + void VisitSizeOfPackExpr(SizeOfPackExpr *E); + void VisitPseudoObjectExpr(PseudoObjectExpr *E); + void VisitOpaqueValueExpr(OpaqueValueExpr *E); + void VisitLambdaExpr(LambdaExpr *E); + +private: + void AddDeclarationNameInfo(Stmt *S); + void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); + void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A); + void AddMemberRef(FieldDecl *D, SourceLocation L); + void AddStmt(Stmt *S); + void AddDecl(Decl *D, bool isFirst = true); + void AddTypeLoc(TypeSourceInfo *TI); + void EnqueueChildren(Stmt *S); +}; +} // end anonyous namespace + +void EnqueueVisitor::AddDeclarationNameInfo(Stmt *S) { + // 'S' should always be non-null, since it comes from the + // statement we are visiting. + WL.push_back(DeclarationNameInfoVisit(S, Parent)); +} + +void +EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) { + if (Qualifier) + WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent)); +} + +void EnqueueVisitor::AddStmt(Stmt *S) { + if (S) + WL.push_back(StmtVisit(S, Parent)); +} +void EnqueueVisitor::AddDecl(Decl *D, bool isFirst) { + if (D) + WL.push_back(DeclVisit(D, Parent, isFirst)); +} +void EnqueueVisitor:: + AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) { + if (A) + WL.push_back(ExplicitTemplateArgsVisit( + const_cast<ASTTemplateArgumentListInfo*>(A), Parent)); +} +void EnqueueVisitor::AddMemberRef(FieldDecl *D, SourceLocation L) { + if (D) + WL.push_back(MemberRefVisit(D, L, Parent)); +} +void EnqueueVisitor::AddTypeLoc(TypeSourceInfo *TI) { + if (TI) + WL.push_back(TypeLocVisit(TI->getTypeLoc(), Parent)); + } +void EnqueueVisitor::EnqueueChildren(Stmt *S) { + unsigned size = WL.size(); + for (Stmt::child_range Child = S->children(); Child; ++Child) { + AddStmt(*Child); + } + if (size == WL.size()) + return; + // Now reverse the entries we just added. This will match the DFS + // ordering performed by the worklist. + VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); + std::reverse(I, E); +} +void EnqueueVisitor::VisitAddrLabelExpr(AddrLabelExpr *E) { + WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent)); +} +void EnqueueVisitor::VisitBlockExpr(BlockExpr *B) { + AddDecl(B->getBlockDecl()); +} +void EnqueueVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + EnqueueChildren(E); + AddTypeLoc(E->getTypeSourceInfo()); +} +void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) { + for (CompoundStmt::reverse_body_iterator I = S->body_rbegin(), + E = S->body_rend(); I != E; ++I) { + AddStmt(*I); + } +} +void EnqueueVisitor:: +VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { + AddStmt(S->getSubStmt()); + AddDeclarationNameInfo(S); + if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc()) + AddNestedNameSpecifierLoc(QualifierLoc); +} + +void EnqueueVisitor:: +VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { + AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + AddDeclarationNameInfo(E); + if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) + AddNestedNameSpecifierLoc(QualifierLoc); + if (!E->isImplicitAccess()) + AddStmt(E->getBase()); +} +void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) { + // Enqueue the initializer , if any. + AddStmt(E->getInitializer()); + // Enqueue the array size, if any. + AddStmt(E->getArraySize()); + // Enqueue the allocated type. + AddTypeLoc(E->getAllocatedTypeSourceInfo()); + // Enqueue the placement arguments. + for (unsigned I = E->getNumPlacementArgs(); I > 0; --I) + AddStmt(E->getPlacementArg(I-1)); +} +void EnqueueVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *CE) { + for (unsigned I = CE->getNumArgs(); I > 1 /* Yes, this is 1 */; --I) + AddStmt(CE->getArg(I-1)); + AddStmt(CE->getCallee()); + AddStmt(CE->getArg(0)); +} +void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + // Visit the name of the type being destroyed. + AddTypeLoc(E->getDestroyedTypeInfo()); + // Visit the scope type that looks disturbingly like the nested-name-specifier + // but isn't. + AddTypeLoc(E->getScopeTypeInfo()); + // Visit the nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) + AddNestedNameSpecifierLoc(QualifierLoc); + // Visit base expression. + AddStmt(E->getBase()); +} +void EnqueueVisitor::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { + AddTypeLoc(E->getTypeSourceInfo()); +} +void EnqueueVisitor::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { + EnqueueChildren(E); + AddTypeLoc(E->getTypeSourceInfo()); +} +void EnqueueVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + EnqueueChildren(E); + if (E->isTypeOperand()) + AddTypeLoc(E->getTypeOperandSourceInfo()); +} + +void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr + *E) { + EnqueueChildren(E); + AddTypeLoc(E->getTypeSourceInfo()); +} +void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) { + EnqueueChildren(E); + if (E->isTypeOperand()) + AddTypeLoc(E->getTypeOperandSourceInfo()); +} + +void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) { + EnqueueChildren(S); + AddDecl(S->getExceptionDecl()); +} + +void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) { + if (DR->hasExplicitTemplateArgs()) { + AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs()); + } + WL.push_back(DeclRefExprParts(DR, Parent)); +} +void EnqueueVisitor::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + AddDeclarationNameInfo(E); + AddNestedNameSpecifierLoc(E->getQualifierLoc()); +} +void EnqueueVisitor::VisitDeclStmt(DeclStmt *S) { + unsigned size = WL.size(); + bool isFirst = true; + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + AddDecl(*D, isFirst); + isFirst = false; + } + if (size == WL.size()) + return; + // Now reverse the entries we just added. This will match the DFS + // ordering performed by the worklist. + VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); + std::reverse(I, E); +} +void EnqueueVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *E) { + AddStmt(E->getInit()); + typedef DesignatedInitExpr::Designator Designator; + for (DesignatedInitExpr::reverse_designators_iterator + D = E->designators_rbegin(), DEnd = E->designators_rend(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + if (FieldDecl *Field = D->getField()) + AddMemberRef(Field, D->getFieldLoc()); + continue; + } + if (D->isArrayDesignator()) { + AddStmt(E->getArrayIndex(*D)); + continue; + } + assert(D->isArrayRangeDesignator() && "Unknown designator kind"); + AddStmt(E->getArrayRangeEnd(*D)); + AddStmt(E->getArrayRangeStart(*D)); + } +} +void EnqueueVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { + EnqueueChildren(E); + AddTypeLoc(E->getTypeInfoAsWritten()); +} +void EnqueueVisitor::VisitForStmt(ForStmt *FS) { + AddStmt(FS->getBody()); + AddStmt(FS->getInc()); + AddStmt(FS->getCond()); + AddDecl(FS->getConditionVariable()); + AddStmt(FS->getInit()); +} +void EnqueueVisitor::VisitGotoStmt(GotoStmt *GS) { + WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent)); +} +void EnqueueVisitor::VisitIfStmt(IfStmt *If) { + AddStmt(If->getElse()); + AddStmt(If->getThen()); + AddStmt(If->getCond()); + AddDecl(If->getConditionVariable()); +} +void EnqueueVisitor::VisitInitListExpr(InitListExpr *IE) { + // We care about the syntactic form of the initializer list, only. + if (InitListExpr *Syntactic = IE->getSyntacticForm()) + IE = Syntactic; + EnqueueChildren(IE); +} +void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) { + WL.push_back(MemberExprParts(M, Parent)); + + // If the base of the member access expression is an implicit 'this', don't + // visit it. + // FIXME: If we ever want to show these implicit accesses, this will be + // unfortunate. However, clang_getCursor() relies on this behavior. + if (!M->isImplicitAccess()) + AddStmt(M->getBase()); +} +void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { + AddTypeLoc(E->getEncodedTypeSourceInfo()); +} +void EnqueueVisitor::VisitObjCMessageExpr(ObjCMessageExpr *M) { + EnqueueChildren(M); + AddTypeLoc(M->getClassReceiverTypeInfo()); +} +void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) { + // Visit the components of the offsetof expression. + for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) { + typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; + const OffsetOfNode &Node = E->getComponent(I-1); + switch (Node.getKind()) { + case OffsetOfNode::Array: + AddStmt(E->getIndexExpr(Node.getArrayExprIndex())); + break; + case OffsetOfNode::Field: + AddMemberRef(Node.getField(), Node.getSourceRange().getEnd()); + break; + case OffsetOfNode::Identifier: + case OffsetOfNode::Base: + continue; + } + } + // Visit the type into which we're computing the offset. + AddTypeLoc(E->getTypeSourceInfo()); +} +void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) { + AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + WL.push_back(OverloadExprParts(E, Parent)); +} +void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { + EnqueueChildren(E); + if (E->isArgumentType()) + AddTypeLoc(E->getArgumentTypeInfo()); +} +void EnqueueVisitor::VisitStmt(Stmt *S) { + EnqueueChildren(S); +} +void EnqueueVisitor::VisitSwitchStmt(SwitchStmt *S) { + AddStmt(S->getBody()); + AddStmt(S->getCond()); + AddDecl(S->getConditionVariable()); +} + +void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) { + AddStmt(W->getBody()); + AddStmt(W->getCond()); + AddDecl(W->getConditionVariable()); +} + +void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { + AddTypeLoc(E->getQueriedTypeSourceInfo()); +} + +void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { + AddTypeLoc(E->getRhsTypeSourceInfo()); + AddTypeLoc(E->getLhsTypeSourceInfo()); +} + +void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) { + for (unsigned I = E->getNumArgs(); I > 0; --I) + AddTypeLoc(E->getArg(I-1)); +} + +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()) + AddStmt(U->getBase()); +} +void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) { + AddStmt(E->getSubExpr()); + AddTypeLoc(E->getWrittenTypeInfo()); +} +void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + WL.push_back(SizeOfPackExprParts(E, Parent)); +} +void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) { + // If the opaque value has a source expression, just transparently + // visit that. This is useful for (e.g.) pseudo-object expressions. + if (Expr *SourceExpr = E->getSourceExpr()) + return Visit(SourceExpr); +} +void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) { + AddStmt(E->getBody()); + WL.push_back(LambdaExprParts(E, Parent)); +} +void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) { + // Treat the expression like its syntactic form. + Visit(E->getSyntacticForm()); +} + +void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) { + EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); +} + +bool CursorVisitor::IsInRegionOfInterest(CXCursor C) { + if (RegionOfInterest.isValid()) { + SourceRange Range = getRawCursorExtent(C); + if (Range.isInvalid() || CompareRegionOfInterest(Range)) + return false; + } + return true; +} + +bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { + while (!WL.empty()) { + // Dequeue the worklist item. + VisitorJob LI = WL.back(); + WL.pop_back(); + + // Set the Parent field, then back to its old value once we're done. + SetParentRAII SetParent(Parent, StmtParent, LI.getParent()); + + switch (LI.getKind()) { + case VisitorJob::DeclVisitKind: { + Decl *D = cast<DeclVisit>(&LI)->get(); + if (!D) + continue; + + // For now, perform default visitation for Decls. + if (Visit(MakeCXCursor(D, TU, RegionOfInterest, + cast<DeclVisit>(&LI)->isFirst()))) + return true; + + continue; + } + case VisitorJob::ExplicitTemplateArgsVisitKind: { + const ASTTemplateArgumentListInfo *ArgList = + cast<ExplicitTemplateArgsVisit>(&LI)->get(); + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + continue; + } + case VisitorJob::TypeLocVisitKind: { + // Perform default visitation for TypeLocs. + if (Visit(cast<TypeLocVisit>(&LI)->get())) + return true; + continue; + } + case VisitorJob::LabelRefVisitKind: { + LabelDecl *LS = cast<LabelRefVisit>(&LI)->get(); + if (LabelStmt *stmt = LS->getStmt()) { + if (Visit(MakeCursorLabelRef(stmt, cast<LabelRefVisit>(&LI)->getLoc(), + TU))) { + return true; + } + } + continue; + } + + case VisitorJob::NestedNameSpecifierLocVisitKind: { + NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI); + if (VisitNestedNameSpecifierLoc(V->get())) + return true; + continue; + } + + case VisitorJob::DeclarationNameInfoVisitKind: { + if (VisitDeclarationNameInfo(cast<DeclarationNameInfoVisit>(&LI) + ->get())) + return true; + continue; + } + case VisitorJob::MemberRefVisitKind: { + MemberRefVisit *V = cast<MemberRefVisit>(&LI); + if (Visit(MakeCursorMemberRef(V->get(), V->getLoc(), TU))) + return true; + continue; + } + case VisitorJob::StmtVisitKind: { + Stmt *S = cast<StmtVisit>(&LI)->get(); + if (!S) + continue; + + // Update the current cursor. + CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest); + if (!IsInRegionOfInterest(Cursor)) + continue; + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: return true; + case CXChildVisit_Continue: break; + case CXChildVisit_Recurse: + EnqueueWorkList(WL, S); + break; + } + continue; + } + case VisitorJob::MemberExprPartsKind: { + // Handle the other pieces in the MemberExpr besides the base. + MemberExpr *M = cast<MemberExprParts>(&LI)->get(); + + // Visit the nested-name-specifier + if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(M->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments, if any. + if (M->hasExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = M->getTemplateArgs(), + *ArgEnd = Arg + M->getNumTemplateArgs(); + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + continue; + } + case VisitorJob::DeclRefExprPartsKind: { + DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get(); + // Visit nested-name-specifier, if present. + if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + // Visit declaration name. + if (VisitDeclarationNameInfo(DR->getNameInfo())) + return true; + continue; + } + case VisitorJob::OverloadExprPartsKind: { + OverloadExpr *O = cast<OverloadExprParts>(&LI)->get(); + // Visit the nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + // Visit the declaration name. + if (VisitDeclarationNameInfo(O->getNameInfo())) + return true; + // Visit the overloaded declaration reference. + if (Visit(MakeCursorOverloadedDeclRef(O, TU))) + return true; + continue; + } + case VisitorJob::SizeOfPackExprPartsKind: { + SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get(); + NamedDecl *Pack = E->getPack(); + if (isa<TemplateTypeParmDecl>(Pack)) { + if (Visit(MakeCursorTypeRef(cast<TemplateTypeParmDecl>(Pack), + E->getPackLoc(), TU))) + return true; + + continue; + } + + if (isa<TemplateTemplateParmDecl>(Pack)) { + if (Visit(MakeCursorTemplateRef(cast<TemplateTemplateParmDecl>(Pack), + E->getPackLoc(), TU))) + return true; + + continue; + } + + // Non-type template parameter packs and function parameter packs are + // treated like DeclRefExpr cursors. + continue; + } + + case VisitorJob::LambdaExprPartsKind: { + // Visit captures. + LambdaExpr *E = cast<LambdaExprParts>(&LI)->get(); + for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(), + CEnd = E->explicit_capture_end(); + C != CEnd; ++C) { + if (C->capturesThis()) + continue; + + if (Visit(MakeCursorVariableRef(C->getCapturedVar(), + C->getLocation(), + TU))) + return true; + } + + // Visit parameters and return type, if present. + if (E->hasExplicitParameters() || E->hasExplicitResultType()) { + TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + if (E->hasExplicitParameters() && E->hasExplicitResultType()) { + // Visit the whole type. + if (Visit(TL)) + return true; + } else if (isa<FunctionProtoTypeLoc>(TL)) { + FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); + if (E->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) + if (Visit(MakeCXCursor(Proto.getArg(I), TU))) + return true; + } else { + // Visit result type. + if (Visit(Proto.getResultLoc())) + return true; + } + } + } + break; + } + } + } + return false; +} + +bool CursorVisitor::Visit(Stmt *S) { + VisitorWorkList *WL = 0; + if (!WorkListFreeList.empty()) { + WL = WorkListFreeList.back(); + WL->clear(); + WorkListFreeList.pop_back(); + } + else { + WL = new VisitorWorkList(); + WorkListCache.push_back(WL); + } + EnqueueWorkList(*WL, S); + bool result = RunVisitorWorkList(*WL); + WorkListFreeList.push_back(WL); + return result; +} + +namespace { +typedef llvm::SmallVector<SourceRange, 4> RefNamePieces; +RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, + const DeclarationNameInfo &NI, + const SourceRange &QLoc, + const ASTTemplateArgumentListInfo *TemplateArgs = 0){ + const bool WantQualifier = NameFlags & CXNameRange_WantQualifier; + const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs; + const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece; + + const DeclarationName::NameKind Kind = NI.getName().getNameKind(); + + RefNamePieces Pieces; + + if (WantQualifier && QLoc.isValid()) + Pieces.push_back(QLoc); + + if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr) + Pieces.push_back(NI.getLoc()); + + if (WantTemplateArgs && TemplateArgs) + Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc, + TemplateArgs->RAngleLoc)); + + if (Kind == DeclarationName::CXXOperatorName) { + Pieces.push_back(SourceLocation::getFromRawEncoding( + NI.getInfo().CXXOperatorName.BeginOpNameLoc)); + Pieces.push_back(SourceLocation::getFromRawEncoding( + NI.getInfo().CXXOperatorName.EndOpNameLoc)); + } + + if (WantSinglePiece) { + SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd()); + Pieces.clear(); + Pieces.push_back(R); + } + + return Pieces; +} +} + +//===----------------------------------------------------------------------===// +// Misc. API hooks. +//===----------------------------------------------------------------------===// + +static llvm::sys::Mutex EnableMultithreadingMutex; +static bool EnabledMultithreading; + +static void fatal_error_handler(void *user_data, const std::string& reason) { + // Write the result out to stderr avoiding errs() because raw_ostreams can + // call report_fatal_error. + fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str()); + ::abort(); +} + +extern "C" { +CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics) { + // Disable pretty stack trace functionality, which will otherwise be a very + // poor citizen of the world and set up all sorts of signal handlers. + llvm::DisablePrettyStackTrace = true; + + // We use crash recovery to make some of our APIs more reliable, implicitly + // enable it. + llvm::CrashRecoveryContext::Enable(); + + // Enable support for multithreading in LLVM. + { + llvm::sys::ScopedLock L(EnableMultithreadingMutex); + if (!EnabledMultithreading) { + llvm::install_fatal_error_handler(fatal_error_handler, 0); + llvm::llvm_start_multithreaded(); + EnabledMultithreading = true; + } + } + + CIndexer *CIdxr = new CIndexer(); + if (excludeDeclarationsFromPCH) + CIdxr->setOnlyLocalDecls(); + if (displayDiagnostics) + CIdxr->setDisplayDiagnostics(); + + if (getenv("LIBCLANG_BGPRIO_INDEX")) + CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | + CXGlobalOpt_ThreadBackgroundPriorityForIndexing); + if (getenv("LIBCLANG_BGPRIO_EDIT")) + CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | + CXGlobalOpt_ThreadBackgroundPriorityForEditing); + + return CIdxr; +} + +void clang_disposeIndex(CXIndex CIdx) { + if (CIdx) + delete static_cast<CIndexer *>(CIdx); +} + +void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) { + if (CIdx) + static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options); +} + +unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) { + if (CIdx) + return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags(); + return 0; +} + +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) + return 0; + + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + FileSystemOptions FileSystemOpts; + FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory(); + + IntrusiveRefCntPtr<DiagnosticsEngine> Diags; + ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts, + CXXIdx->getOnlyLocalDecls(), + 0, 0, + /*CaptureDiagnostics=*/true, + /*AllowPCHWithCompilerErrors=*/true); + return MakeCXTranslationUnit(CXXIdx, TU); +} + +unsigned clang_defaultEditingTranslationUnitOptions() { + return CXTranslationUnit_PrecompiledPreamble | + CXTranslationUnit_CacheCompletionResults; +} + +CXTranslationUnit +clang_createTranslationUnitFromSourceFile(CXIndex CIdx, + const char *source_filename, + int num_command_line_args, + const char * const *command_line_args, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files) { + unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord; + return clang_parseTranslationUnit(CIdx, source_filename, + command_line_args, num_command_line_args, + unsaved_files, num_unsaved_files, + Options); +} + +struct ParseTranslationUnitInfo { + CXIndex CIdx; + const char *source_filename; + const char *const *command_line_args; + int num_command_line_args; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXTranslationUnit result; +}; +static void clang_parseTranslationUnit_Impl(void *UserData) { + ParseTranslationUnitInfo *PTUI = + static_cast<ParseTranslationUnitInfo*>(UserData); + CXIndex CIdx = PTUI->CIdx; + const char *source_filename = PTUI->source_filename; + const char * const *command_line_args = PTUI->command_line_args; + int num_command_line_args = PTUI->num_command_line_args; + struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files; + unsigned num_unsaved_files = PTUI->num_unsaved_files; + unsigned options = PTUI->options; + PTUI->result = 0; + + if (!CIdx) + return; + + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + // FIXME: Add a flag for modules. + TranslationUnitKind TUKind + = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete; + bool CacheCodeCompetionResults + = options & CXTranslationUnit_CacheCompletionResults; + bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies; + + // Configure the diagnostics. + DiagnosticOptions DiagOpts; + IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, + command_line_args)); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > + DiagCleanup(Diags.getPtr()); + + OwningPtr<std::vector<ASTUnit::RemappedFile> > + RemappedFiles(new std::vector<ASTUnit::RemappedFile>()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); + + for (unsigned I = 0; I != num_unsaved_files; ++I) { + 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)); + } + + OwningPtr<std::vector<const char *> > + Args(new std::vector<const char*>()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > + ArgsCleanup(Args.get()); + + // 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 + // precompiled headers are involved), we disable it by default. + // Only do this if we haven't found a spell-checking-related argument. + bool FoundSpellCheckingArgument = false; + for (int I = 0; I != num_command_line_args; ++I) { + if (strcmp(command_line_args[I], "-fno-spell-checking") == 0 || + strcmp(command_line_args[I], "-fspell-checking") == 0) { + FoundSpellCheckingArgument = true; + break; + } + } + if (!FoundSpellCheckingArgument) + Args->push_back("-fno-spell-checking"); + + 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"); + } + + unsigned NumErrors = Diags->getClient()->getNumErrors(); + OwningPtr<ASTUnit> ErrUnit; + OwningPtr<ASTUnit> Unit( + 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->size() ? &(*RemappedFiles)[0]:0, + RemappedFiles->size(), + /*RemappedFilesKeepOriginalName=*/true, + PrecompilePreamble, + TUKind, + CacheCodeCompetionResults, + /*AllowPCHWithCompilerErrors=*/true, + SkipFunctionBodies, + &ErrUnit)); + + if (NumErrors != Diags->getClient()->getNumErrors()) { + // Make sure to check that 'Unit' is non-NULL. + if (CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); + } + + PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take()); +} +CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args, + num_command_line_args, unsaved_files, + num_unsaved_files, options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_parseTranslationUnit_Impl, &PTUI)) { + fprintf(stderr, "libclang: crash detected during parsing: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return 0; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + PrintLibclangResourceUsage(PTUI.result); + } + + return PTUI.result; +} + +unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { + return CXSaveTranslationUnit_None; +} + +namespace { + +struct SaveTranslationUnitInfo { + CXTranslationUnit TU; + const char *FileName; + unsigned options; + CXSaveError result; +}; + +} + +static void clang_saveTranslationUnit_Impl(void *UserData) { + SaveTranslationUnitInfo *STUI = + static_cast<SaveTranslationUnitInfo*>(UserData); + + CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + STUI->result = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName); +} + +int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, + unsigned options) { + if (!TU) + return CXSaveError_InvalidTU; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None }; + + if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() || + getenv("LIBCLANG_NOTHREADS")) { + clang_saveTranslationUnit_Impl(&STUI); + + if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return STUI.result; + } + + // We have an AST that has invalid nodes due to compiler errors. + // Use a crash recovery thread for protection. + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) { + fprintf(stderr, "libclang: crash detected during AST saving: {\n"); + fprintf(stderr, " 'filename' : '%s'\n", FileName); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return CXSaveError_Unknown; + + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + PrintLibclangResourceUsage(TU); + } + + return STUI.result; +} + +void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { + if (CTUnit) { + // If the translation unit has been marked as unsafe to free, just discard + // it. + if (static_cast<ASTUnit *>(CTUnit->TUData)->isUnsafeToFree()) + return; + + delete static_cast<ASTUnit *>(CTUnit->TUData); + disposeCXStringPool(CTUnit->StringPool); + delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics); + delete CTUnit; + } +} + +unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { + return CXReparse_None; +} + +struct ReparseTranslationUnitInfo { + CXTranslationUnit TU; + unsigned num_unsaved_files; + struct CXUnsavedFile *unsaved_files; + unsigned options; + int result; +}; + +static void clang_reparseTranslationUnit_Impl(void *UserData) { + ReparseTranslationUnitInfo *RTUI = + static_cast<ReparseTranslationUnitInfo*>(UserData); + CXTranslationUnit TU = RTUI->TU; + + // Reset the associated diagnostics. + delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); + TU->Diagnostics = 0; + + unsigned num_unsaved_files = RTUI->num_unsaved_files; + struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; + unsigned options = RTUI->options; + (void) options; + RTUI->result = 1; + + if (!TU) + return; + + CIndexer *CXXIdx = (CIndexer*)TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + OwningPtr<std::vector<ASTUnit::RemappedFile> > + RemappedFiles(new std::vector<ASTUnit::RemappedFile>()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); + + for (unsigned I = 0; I != num_unsaved_files; ++I) { + 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)); + } + + if (!CXXUnit->Reparse(RemappedFiles->size() ? &(*RemappedFiles)[0] : 0, + RemappedFiles->size())) + RTUI->result = 0; +} + +int clang_reparseTranslationUnit(CXTranslationUnit TU, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options) { + ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files, + options, 0 }; + + if (getenv("LIBCLANG_NOTHREADS")) { + clang_reparseTranslationUnit_Impl(&RTUI); + return RTUI.result; + } + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) { + fprintf(stderr, "libclang: crash detected during reparsing\n"); + static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true); + return 1; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return RTUI.result; +} + + +CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { + if (!CTUnit) + return createCXString(""); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit->TUData); + return createCXString(CXXUnit->getOriginalSourceFileName(), true); +} + +CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { + CXCursor Result = { CXCursor_TranslationUnit, 0, { 0, 0, TU } }; + return Result; +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// CXFile Operations. +//===----------------------------------------------------------------------===// + +extern "C" { +CXString clang_getFileName(CXFile SFile) { + if (!SFile) + return createCXString((const char*)NULL); + + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return createCXString(FEnt->getName()); +} + +time_t clang_getFileTime(CXFile SFile) { + if (!SFile) + return 0; + + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return FEnt->getModificationTime(); +} + +CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) { + if (!tu) + return 0; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); + + FileManager &FMgr = CXXUnit->getFileManager(); + return const_cast<FileEntry *>(FMgr.getFile(file_name)); +} + +unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) { + if (!tu || !file) + return 0; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); + FileEntry *FEnt = static_cast<FileEntry *>(file); + return CXXUnit->getPreprocessor().getHeaderSearchInfo() + .isFileMultipleIncludeGuarded(FEnt); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// CXCursor Operations. +//===----------------------------------------------------------------------===// + +static Decl *getDeclFromExpr(Stmt *E) { + if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + return getDeclFromExpr(CE->getSubExpr()); + + if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) + return RefExpr->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) + return RE->getDecl(); + if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (PRE->isExplicitProperty()) + return PRE->getExplicitProperty(); + // It could be messaging both getter and setter as in: + // ++myobj.myprop; + // in which case prefer to associate the setter since it is less obvious + // from inspecting the source that the setter is going to get called. + if (PRE->isMessagingSetter()) + return PRE->getImplicitPropertySetter(); + return PRE->getImplicitPropertyGetter(); + } + if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) + return getDeclFromExpr(POE->getSyntacticForm()); + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) + if (Expr *Src = OVE->getSourceExpr()) + return getDeclFromExpr(Src); + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) + return getDeclFromExpr(CE->getCallee()); + if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) + if (!CE->isElidable()) + return CE->getConstructor(); + if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) + return OME->getMethodDecl(); + + if (ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E)) + return PE->getProtocol(); + if (SubstNonTypeTemplateParmPackExpr *NTTP + = dyn_cast<SubstNonTypeTemplateParmPackExpr>(E)) + return NTTP->getParameterPack(); + if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) + if (isa<NonTypeTemplateParmDecl>(SizeOfPack->getPack()) || + isa<ParmVarDecl>(SizeOfPack->getPack())) + return SizeOfPack->getPack(); + + return 0; +} + +static SourceLocation getLocationFromExpr(Expr *E) { + if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + return getLocationFromExpr(CE->getSubExpr()); + + if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) + return /*FIXME:*/Msg->getLeftLoc(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return DRE->getLocation(); + if (MemberExpr *Member = dyn_cast<MemberExpr>(E)) + return Member->getMemberLoc(); + if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) + return Ivar->getLocation(); + if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) + return SizeOfPack->getPackLoc(); + if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) + return PropRef->getLocation(); + + return E->getLocStart(); +} + +extern "C" { + +unsigned clang_visitChildren(CXCursor parent, + CXCursorVisitor visitor, + CXClientData client_data) { + CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data, + /*VisitPreprocessorLast=*/false); + return CursorVis.VisitChildren(parent); +} + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif +#if __has_feature(blocks) +typedef enum CXChildVisitResult + (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent); + +static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; + return block(cursor, parent); +} +#else +// If we are compiled with a compiler that doesn't have native blocks support, +// define and call the block manually, so the +typedef struct _CXChildVisitResult +{ + void *isa; + int flags; + int reserved; + enum CXChildVisitResult(*invoke)(struct _CXChildVisitResult*, CXCursor, + CXCursor); +} *CXCursorVisitorBlock; + +static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; + return block->invoke(block, cursor, parent); +} +#endif + + +unsigned clang_visitChildrenWithBlock(CXCursor parent, + CXCursorVisitorBlock block) { + return clang_visitChildren(parent, visitWithBlock, block); +} + +static CXString getDeclSpelling(Decl *D) { + if (!D) + return createCXString(""); + + NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND) { + if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D)) + if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) + return createCXString(Property->getIdentifier()->getName()); + + return createCXString(""); + } + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) + return createCXString(OMD->getSelector().getAsString()); + + if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) + // No, this isn't the same as the code below. getIdentifier() is non-virtual + // and returns different names. NamedDecl returns the class name and + // ObjCCategoryImplDecl returns the category name. + return createCXString(CIMP->getIdentifier()->getNameStart()); + + if (isa<UsingDirectiveDecl>(D)) + return createCXString(""); + + SmallString<1024> S; + llvm::raw_svector_ostream os(S); + ND->printName(os); + + return createCXString(os.str()); +} + +CXString clang_getCursorSpelling(CXCursor C) { + if (clang_isTranslationUnit(C.kind)) + return clang_getTranslationUnitSpelling( + static_cast<CXTranslationUnit>(C.data[2])); + + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; + return createCXString(Super->getIdentifier()->getNameStart()); + } + case CXCursor_ObjCClassRef: { + ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + return createCXString(Class->getIdentifier()->getNameStart()); + } + case CXCursor_ObjCProtocolRef: { + ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; + assert(OID && "getCursorSpelling(): Missing protocol decl"); + return createCXString(OID->getIdentifier()->getNameStart()); + } + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return createCXString(B->getType().getAsString()); + } + case CXCursor_TypeRef: { + TypeDecl *Type = getCursorTypeRef(C).first; + assert(Type && "Missing type decl"); + + return createCXString(getCursorContext(C).getTypeDeclType(Type). + getAsString()); + } + case CXCursor_TemplateRef: { + TemplateDecl *Template = getCursorTemplateRef(C).first; + assert(Template && "Missing template decl"); + + return createCXString(Template->getNameAsString()); + } + + case CXCursor_NamespaceRef: { + NamedDecl *NS = getCursorNamespaceRef(C).first; + assert(NS && "Missing namespace decl"); + + return createCXString(NS->getNameAsString()); + } + + case CXCursor_MemberRef: { + FieldDecl *Field = getCursorMemberRef(C).first; + assert(Field && "Missing member decl"); + + return createCXString(Field->getNameAsString()); + } + + case CXCursor_LabelRef: { + LabelStmt *Label = getCursorLabelRef(C).first; + assert(Label && "Missing label"); + + return createCXString(Label->getName()); + } + + case CXCursor_OverloadedDeclRef: { + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; + if (Decl *D = Storage.dyn_cast<Decl *>()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + return createCXString(ND->getNameAsString()); + return createCXString(""); + } + if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) + return createCXString(E->getName().getAsString()); + OverloadedTemplateStorage *Ovl + = Storage.get<OverloadedTemplateStorage*>(); + if (Ovl->size() == 0) + return createCXString(""); + return createCXString((*Ovl->begin())->getNameAsString()); + } + + case CXCursor_VariableRef: { + VarDecl *Var = getCursorVariableRef(C).first; + assert(Var && "Missing variable decl"); + + return createCXString(Var->getNameAsString()); + } + + default: + return createCXString("<not implemented>"); + } + } + + if (clang_isExpression(C.kind)) { + Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return getDeclSpelling(D); + return createCXString(""); + } + + if (clang_isStatement(C.kind)) { + Stmt *S = getCursorStmt(C); + if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) + return createCXString(Label->getName()); + + return createCXString(""); + } + + if (C.kind == CXCursor_MacroExpansion) + return createCXString(getCursorMacroExpansion(C)->getName() + ->getNameStart()); + + if (C.kind == CXCursor_MacroDefinition) + return createCXString(getCursorMacroDefinition(C)->getName() + ->getNameStart()); + + if (C.kind == CXCursor_InclusionDirective) + return createCXString(getCursorInclusionDirective(C)->getFileName()); + + if (clang_isDeclaration(C.kind)) + return getDeclSpelling(getCursorDecl(C)); + + if (C.kind == CXCursor_AnnotateAttr) { + AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C)); + return createCXString(AA->getAnnotation()); + } + + if (C.kind == CXCursor_AsmLabelAttr) { + AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C)); + return createCXString(AA->getLabel()); + } + + return createCXString(""); +} + +CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C, + unsigned pieceIndex, + unsigned options) { + if (clang_Cursor_isNull(C)) + return clang_getNullRange(); + + ASTContext &Ctx = getCursorContext(C); + + if (clang_isStatement(C.kind)) { + Stmt *S = getCursorStmt(C); + if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) { + if (pieceIndex > 0) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, Label->getIdentLoc()); + } + + return clang_getNullRange(); + } + + if (C.kind == CXCursor_ObjCMessageExpr) { + if (ObjCMessageExpr * + ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) { + if (pieceIndex >= ME->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex)); + } + } + + if (C.kind == CXCursor_ObjCInstanceMethodDecl || + C.kind == CXCursor_ObjCClassMethodDecl) { + if (ObjCMethodDecl * + MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) { + if (pieceIndex >= MD->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex)); + } + } + + if (C.kind == CXCursor_ObjCCategoryDecl || + C.kind == CXCursor_ObjCCategoryImplDecl) { + if (pieceIndex > 0) + return clang_getNullRange(); + if (ObjCCategoryDecl * + CD = dyn_cast_or_null<ObjCCategoryDecl>(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc()); + if (ObjCCategoryImplDecl * + CID = dyn_cast_or_null<ObjCCategoryImplDecl>(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc()); + } + + // FIXME: A CXCursor_InclusionDirective should give the location of the + // filename, but we don't keep track of this. + + // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation + // but we don't keep track of this. + + // FIXME: A CXCursor_AsmLabelAttr should give the location of the label + // but we don't keep track of this. + + // Default handling, give the location of the cursor. + + if (pieceIndex > 0) + return clang_getNullRange(); + + CXSourceLocation CXLoc = clang_getCursorLocation(C); + SourceLocation Loc = cxloc::translateSourceLocation(CXLoc); + return cxloc::translateSourceRange(Ctx, Loc); +} + +CXString clang_getCursorDisplayName(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getCursorSpelling(C); + + Decl *D = getCursorDecl(C); + if (!D) + return createCXString(""); + + PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy(); + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) + D = FunTmpl->getTemplatedDecl(); + + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << *Function; + if (Function->getPrimaryTemplate()) + OS << "<>"; + OS << "("; + for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) { + if (I) + OS << ", "; + OS << Function->getParamDecl(I)->getType().getAsString(Policy); + } + + if (Function->isVariadic()) { + if (Function->getNumParams()) + OS << ", "; + OS << "..."; + } + OS << ")"; + return createCXString(OS.str()); + } + + if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) { + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << *ClassTemplate; + OS << "<"; + TemplateParameterList *Params = ClassTemplate->getTemplateParameters(); + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + if (I) + OS << ", "; + + NamedDecl *Param = Params->getParam(I); + if (Param->getIdentifier()) { + OS << Param->getIdentifier()->getName(); + continue; + } + + // There is no parameter name, which makes this tricky. Try to come up + // with something useful that isn't too long. + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + OS << (TTP->wasDeclaredWithTypename()? "typename" : "class"); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) + OS << NTTP->getType().getAsString(Policy); + else + OS << "template<...> class"; + } + + OS << ">"; + return createCXString(OS.str()); + } + + if (ClassTemplateSpecializationDecl *ClassSpec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + // If the type was explicitly written, use that. + if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten()) + return createCXString(TSInfo->getType().getAsString(Policy)); + + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << *ClassSpec; + OS << TemplateSpecializationType::PrintTemplateArgumentList( + ClassSpec->getTemplateArgs().data(), + ClassSpec->getTemplateArgs().size(), + Policy); + return createCXString(OS.str()); + } + + return clang_getCursorSpelling(C); +} + +CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { + switch (Kind) { + case CXCursor_FunctionDecl: + return createCXString("FunctionDecl"); + case CXCursor_TypedefDecl: + return createCXString("TypedefDecl"); + case CXCursor_EnumDecl: + return createCXString("EnumDecl"); + case CXCursor_EnumConstantDecl: + return createCXString("EnumConstantDecl"); + case CXCursor_StructDecl: + return createCXString("StructDecl"); + case CXCursor_UnionDecl: + return createCXString("UnionDecl"); + case CXCursor_ClassDecl: + return createCXString("ClassDecl"); + case CXCursor_FieldDecl: + return createCXString("FieldDecl"); + case CXCursor_VarDecl: + return createCXString("VarDecl"); + case CXCursor_ParmDecl: + return createCXString("ParmDecl"); + case CXCursor_ObjCInterfaceDecl: + return createCXString("ObjCInterfaceDecl"); + case CXCursor_ObjCCategoryDecl: + return createCXString("ObjCCategoryDecl"); + case CXCursor_ObjCProtocolDecl: + return createCXString("ObjCProtocolDecl"); + case CXCursor_ObjCPropertyDecl: + return createCXString("ObjCPropertyDecl"); + case CXCursor_ObjCIvarDecl: + return createCXString("ObjCIvarDecl"); + case CXCursor_ObjCInstanceMethodDecl: + return createCXString("ObjCInstanceMethodDecl"); + case CXCursor_ObjCClassMethodDecl: + return createCXString("ObjCClassMethodDecl"); + case CXCursor_ObjCImplementationDecl: + return createCXString("ObjCImplementationDecl"); + case CXCursor_ObjCCategoryImplDecl: + return createCXString("ObjCCategoryImplDecl"); + case CXCursor_CXXMethod: + return createCXString("CXXMethod"); + case CXCursor_UnexposedDecl: + return createCXString("UnexposedDecl"); + case CXCursor_ObjCSuperClassRef: + return createCXString("ObjCSuperClassRef"); + case CXCursor_ObjCProtocolRef: + return createCXString("ObjCProtocolRef"); + case CXCursor_ObjCClassRef: + return createCXString("ObjCClassRef"); + case CXCursor_TypeRef: + return createCXString("TypeRef"); + case CXCursor_TemplateRef: + return createCXString("TemplateRef"); + case CXCursor_NamespaceRef: + return createCXString("NamespaceRef"); + case CXCursor_MemberRef: + return createCXString("MemberRef"); + case CXCursor_LabelRef: + return createCXString("LabelRef"); + case CXCursor_OverloadedDeclRef: + return createCXString("OverloadedDeclRef"); + case CXCursor_VariableRef: + return createCXString("VariableRef"); + case CXCursor_IntegerLiteral: + return createCXString("IntegerLiteral"); + case CXCursor_FloatingLiteral: + return createCXString("FloatingLiteral"); + case CXCursor_ImaginaryLiteral: + return createCXString("ImaginaryLiteral"); + case CXCursor_StringLiteral: + return createCXString("StringLiteral"); + case CXCursor_CharacterLiteral: + return createCXString("CharacterLiteral"); + case CXCursor_ParenExpr: + return createCXString("ParenExpr"); + case CXCursor_UnaryOperator: + return createCXString("UnaryOperator"); + case CXCursor_ArraySubscriptExpr: + return createCXString("ArraySubscriptExpr"); + case CXCursor_BinaryOperator: + return createCXString("BinaryOperator"); + case CXCursor_CompoundAssignOperator: + return createCXString("CompoundAssignOperator"); + case CXCursor_ConditionalOperator: + return createCXString("ConditionalOperator"); + case CXCursor_CStyleCastExpr: + return createCXString("CStyleCastExpr"); + case CXCursor_CompoundLiteralExpr: + return createCXString("CompoundLiteralExpr"); + case CXCursor_InitListExpr: + return createCXString("InitListExpr"); + case CXCursor_AddrLabelExpr: + return createCXString("AddrLabelExpr"); + case CXCursor_StmtExpr: + return createCXString("StmtExpr"); + case CXCursor_GenericSelectionExpr: + return createCXString("GenericSelectionExpr"); + case CXCursor_GNUNullExpr: + return createCXString("GNUNullExpr"); + case CXCursor_CXXStaticCastExpr: + return createCXString("CXXStaticCastExpr"); + case CXCursor_CXXDynamicCastExpr: + return createCXString("CXXDynamicCastExpr"); + case CXCursor_CXXReinterpretCastExpr: + return createCXString("CXXReinterpretCastExpr"); + case CXCursor_CXXConstCastExpr: + return createCXString("CXXConstCastExpr"); + case CXCursor_CXXFunctionalCastExpr: + return createCXString("CXXFunctionalCastExpr"); + case CXCursor_CXXTypeidExpr: + return createCXString("CXXTypeidExpr"); + case CXCursor_CXXBoolLiteralExpr: + return createCXString("CXXBoolLiteralExpr"); + case CXCursor_CXXNullPtrLiteralExpr: + return createCXString("CXXNullPtrLiteralExpr"); + case CXCursor_CXXThisExpr: + return createCXString("CXXThisExpr"); + case CXCursor_CXXThrowExpr: + return createCXString("CXXThrowExpr"); + case CXCursor_CXXNewExpr: + return createCXString("CXXNewExpr"); + case CXCursor_CXXDeleteExpr: + return createCXString("CXXDeleteExpr"); + case CXCursor_UnaryExpr: + return createCXString("UnaryExpr"); + case CXCursor_ObjCStringLiteral: + return createCXString("ObjCStringLiteral"); + case CXCursor_ObjCBoolLiteralExpr: + return createCXString("ObjCBoolLiteralExpr"); + case CXCursor_ObjCEncodeExpr: + return createCXString("ObjCEncodeExpr"); + case CXCursor_ObjCSelectorExpr: + return createCXString("ObjCSelectorExpr"); + case CXCursor_ObjCProtocolExpr: + return createCXString("ObjCProtocolExpr"); + case CXCursor_ObjCBridgedCastExpr: + return createCXString("ObjCBridgedCastExpr"); + case CXCursor_BlockExpr: + return createCXString("BlockExpr"); + case CXCursor_PackExpansionExpr: + return createCXString("PackExpansionExpr"); + case CXCursor_SizeOfPackExpr: + return createCXString("SizeOfPackExpr"); + case CXCursor_LambdaExpr: + return createCXString("LambdaExpr"); + case CXCursor_UnexposedExpr: + return createCXString("UnexposedExpr"); + case CXCursor_DeclRefExpr: + return createCXString("DeclRefExpr"); + case CXCursor_MemberRefExpr: + return createCXString("MemberRefExpr"); + case CXCursor_CallExpr: + return createCXString("CallExpr"); + case CXCursor_ObjCMessageExpr: + return createCXString("ObjCMessageExpr"); + case CXCursor_UnexposedStmt: + return createCXString("UnexposedStmt"); + case CXCursor_DeclStmt: + return createCXString("DeclStmt"); + case CXCursor_LabelStmt: + return createCXString("LabelStmt"); + case CXCursor_CompoundStmt: + return createCXString("CompoundStmt"); + case CXCursor_CaseStmt: + return createCXString("CaseStmt"); + case CXCursor_DefaultStmt: + return createCXString("DefaultStmt"); + case CXCursor_IfStmt: + return createCXString("IfStmt"); + case CXCursor_SwitchStmt: + return createCXString("SwitchStmt"); + case CXCursor_WhileStmt: + return createCXString("WhileStmt"); + case CXCursor_DoStmt: + return createCXString("DoStmt"); + case CXCursor_ForStmt: + return createCXString("ForStmt"); + case CXCursor_GotoStmt: + return createCXString("GotoStmt"); + case CXCursor_IndirectGotoStmt: + return createCXString("IndirectGotoStmt"); + case CXCursor_ContinueStmt: + return createCXString("ContinueStmt"); + case CXCursor_BreakStmt: + return createCXString("BreakStmt"); + case CXCursor_ReturnStmt: + return createCXString("ReturnStmt"); + case CXCursor_AsmStmt: + return createCXString("AsmStmt"); + case CXCursor_ObjCAtTryStmt: + return createCXString("ObjCAtTryStmt"); + case CXCursor_ObjCAtCatchStmt: + return createCXString("ObjCAtCatchStmt"); + case CXCursor_ObjCAtFinallyStmt: + return createCXString("ObjCAtFinallyStmt"); + case CXCursor_ObjCAtThrowStmt: + return createCXString("ObjCAtThrowStmt"); + case CXCursor_ObjCAtSynchronizedStmt: + return createCXString("ObjCAtSynchronizedStmt"); + case CXCursor_ObjCAutoreleasePoolStmt: + return createCXString("ObjCAutoreleasePoolStmt"); + case CXCursor_ObjCForCollectionStmt: + return createCXString("ObjCForCollectionStmt"); + case CXCursor_CXXCatchStmt: + return createCXString("CXXCatchStmt"); + case CXCursor_CXXTryStmt: + return createCXString("CXXTryStmt"); + case CXCursor_CXXForRangeStmt: + return createCXString("CXXForRangeStmt"); + case CXCursor_SEHTryStmt: + return createCXString("SEHTryStmt"); + case CXCursor_SEHExceptStmt: + return createCXString("SEHExceptStmt"); + case CXCursor_SEHFinallyStmt: + return createCXString("SEHFinallyStmt"); + case CXCursor_NullStmt: + return createCXString("NullStmt"); + case CXCursor_InvalidFile: + return createCXString("InvalidFile"); + case CXCursor_InvalidCode: + return createCXString("InvalidCode"); + case CXCursor_NoDeclFound: + return createCXString("NoDeclFound"); + case CXCursor_NotImplemented: + return createCXString("NotImplemented"); + case CXCursor_TranslationUnit: + return createCXString("TranslationUnit"); + case CXCursor_UnexposedAttr: + return createCXString("UnexposedAttr"); + case CXCursor_IBActionAttr: + return createCXString("attribute(ibaction)"); + case CXCursor_IBOutletAttr: + return createCXString("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return createCXString("attribute(iboutletcollection)"); + case CXCursor_CXXFinalAttr: + return createCXString("attribute(final)"); + case CXCursor_CXXOverrideAttr: + return createCXString("attribute(override)"); + case CXCursor_AnnotateAttr: + return createCXString("attribute(annotate)"); + case CXCursor_AsmLabelAttr: + return createCXString("asm label"); + case CXCursor_PreprocessingDirective: + return createCXString("preprocessing directive"); + case CXCursor_MacroDefinition: + return createCXString("macro definition"); + case CXCursor_MacroExpansion: + return createCXString("macro expansion"); + case CXCursor_InclusionDirective: + return createCXString("inclusion directive"); + case CXCursor_Namespace: + return createCXString("Namespace"); + case CXCursor_LinkageSpec: + return createCXString("LinkageSpec"); + case CXCursor_CXXBaseSpecifier: + return createCXString("C++ base class specifier"); + case CXCursor_Constructor: + return createCXString("CXXConstructor"); + case CXCursor_Destructor: + return createCXString("CXXDestructor"); + case CXCursor_ConversionFunction: + return createCXString("CXXConversion"); + case CXCursor_TemplateTypeParameter: + return createCXString("TemplateTypeParameter"); + case CXCursor_NonTypeTemplateParameter: + return createCXString("NonTypeTemplateParameter"); + case CXCursor_TemplateTemplateParameter: + return createCXString("TemplateTemplateParameter"); + case CXCursor_FunctionTemplate: + return createCXString("FunctionTemplate"); + case CXCursor_ClassTemplate: + return createCXString("ClassTemplate"); + case CXCursor_ClassTemplatePartialSpecialization: + return createCXString("ClassTemplatePartialSpecialization"); + case CXCursor_NamespaceAlias: + return createCXString("NamespaceAlias"); + case CXCursor_UsingDirective: + return createCXString("UsingDirective"); + case CXCursor_UsingDeclaration: + return createCXString("UsingDeclaration"); + case CXCursor_TypeAliasDecl: + return createCXString("TypeAliasDecl"); + case CXCursor_ObjCSynthesizeDecl: + return createCXString("ObjCSynthesizeDecl"); + case CXCursor_ObjCDynamicDecl: + return createCXString("ObjCDynamicDecl"); + case CXCursor_CXXAccessSpecifier: + return createCXString("CXXAccessSpecifier"); + } + + llvm_unreachable("Unhandled CXCursorKind"); +} + +struct GetCursorData { + SourceLocation TokenBeginLoc; + bool PointsAtMacroArgExpansion; + CXCursor &BestCursor; + + GetCursorData(SourceManager &SM, + SourceLocation tokenBegin, CXCursor &outputCursor) + : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { + PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin); + } +}; + +static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + GetCursorData *Data = static_cast<GetCursorData *>(client_data); + CXCursor *BestCursor = &Data->BestCursor; + + // If we point inside a macro argument we should provide info of what the + // token is so use the actual cursor, don't replace it with a macro expansion + // cursor. + if (cursor.kind == CXCursor_MacroExpansion && Data->PointsAtMacroArgExpansion) + return CXChildVisit_Recurse; + + if (clang_isDeclaration(cursor.kind)) { + // Avoid having the implicit methods override the property decls. + if (ObjCMethodDecl *MD + = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { + if (MD->isImplicit()) + return CXChildVisit_Break; + + } else if (ObjCInterfaceDecl *ID + = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(cursor))) { + // Check that when we have multiple @class references in the same line, + // that later ones do not override the previous ones. + // If we have: + // @class Foo, Bar; + // source ranges for both start at '@', so 'Bar' will end up overriding + // 'Foo' even though the cursor location was at 'Foo'. + if (BestCursor->kind == CXCursor_ObjCInterfaceDecl || + BestCursor->kind == CXCursor_ObjCClassRef) + if (ObjCInterfaceDecl *PrevID + = dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(*BestCursor))){ + if (PrevID != ID && + !PrevID->isThisDeclarationADefinition() && + !ID->isThisDeclarationADefinition()) + return CXChildVisit_Break; + } + } + } + + if (clang_isExpression(cursor.kind) && + clang_isDeclaration(BestCursor->kind)) { + if (Decl *D = getCursorDecl(*BestCursor)) { + // Avoid having the cursor of an expression replace the declaration cursor + // when the expression source range overlaps the declaration range. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor. + if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() && + D->getLocation() == Data->TokenBeginLoc) + return CXChildVisit_Break; + } + } + + // If our current best cursor is the construction of a temporary object, + // don't replace that cursor with a type reference, because we want + // clang_getCursor() to point at the constructor. + if (clang_isExpression(BestCursor->kind) && + isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) && + cursor.kind == CXCursor_TypeRef) { + // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it + // as having the actual point on the type reference. + *BestCursor = getTypeRefedCallExprCursor(*BestCursor); + return CXChildVisit_Recurse; + } + + *BestCursor = cursor; + return CXChildVisit_Recurse; +} + +CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { + if (!TU) + return clang_getNullCursor(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + SourceLocation SLoc = cxloc::translateSourceLocation(Loc); + CXCursor Result = cxcursor::getCursor(TU, SLoc); + + bool Logging = getenv("LIBCLANG_LOGGING"); + if (Logging) { + CXFile SearchFile; + unsigned SearchLine, SearchColumn; + CXFile ResultFile; + unsigned ResultLine, ResultColumn; + CXString SearchFileName, ResultFileName, KindSpelling, USR; + const char *IsDef = clang_isCursorDefinition(Result)? " (Definition)" : ""; + CXSourceLocation ResultLoc = clang_getCursorLocation(Result); + + clang_getExpansionLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0); + clang_getExpansionLocation(ResultLoc, &ResultFile, &ResultLine, + &ResultColumn, 0); + SearchFileName = clang_getFileName(SearchFile); + ResultFileName = clang_getFileName(ResultFile); + KindSpelling = clang_getCursorKindSpelling(Result.kind); + USR = clang_getCursorUSR(Result); + fprintf(stderr, "clang_getCursor(%s:%d:%d) = %s(%s:%d:%d):%s%s\n", + clang_getCString(SearchFileName), SearchLine, SearchColumn, + clang_getCString(KindSpelling), + clang_getCString(ResultFileName), ResultLine, ResultColumn, + clang_getCString(USR), IsDef); + clang_disposeString(SearchFileName); + clang_disposeString(ResultFileName); + clang_disposeString(KindSpelling); + clang_disposeString(USR); + + CXCursor Definition = clang_getCursorDefinition(Result); + if (!clang_equalCursors(Definition, clang_getNullCursor())) { + CXSourceLocation DefinitionLoc = clang_getCursorLocation(Definition); + CXString DefinitionKindSpelling + = clang_getCursorKindSpelling(Definition.kind); + CXFile DefinitionFile; + unsigned DefinitionLine, DefinitionColumn; + clang_getExpansionLocation(DefinitionLoc, &DefinitionFile, + &DefinitionLine, &DefinitionColumn, 0); + CXString DefinitionFileName = clang_getFileName(DefinitionFile); + fprintf(stderr, " -> %s(%s:%d:%d)\n", + clang_getCString(DefinitionKindSpelling), + clang_getCString(DefinitionFileName), + DefinitionLine, DefinitionColumn); + clang_disposeString(DefinitionFileName); + clang_disposeString(DefinitionKindSpelling); + } + } + + return Result; +} + +CXCursor clang_getNullCursor(void) { + return MakeCXCursorInvalid(CXCursor_InvalidFile); +} + +unsigned clang_equalCursors(CXCursor X, CXCursor Y) { + return X == Y; +} + +unsigned clang_hashCursor(CXCursor C) { + unsigned Index = 0; + if (clang_isExpression(C.kind) || clang_isStatement(C.kind)) + Index = 1; + + return llvm::DenseMapInfo<std::pair<unsigned, void*> >::getHashValue( + std::make_pair(C.kind, C.data[Index])); +} + +unsigned clang_isInvalid(enum CXCursorKind K) { + return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid; +} + +unsigned clang_isDeclaration(enum CXCursorKind K) { + return K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl; +} + +unsigned clang_isReference(enum CXCursorKind K) { + return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; +} + +unsigned clang_isExpression(enum CXCursorKind K) { + return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr; +} + +unsigned clang_isStatement(enum CXCursorKind K) { + return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; +} + +unsigned clang_isAttribute(enum CXCursorKind K) { + return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr; +} + +unsigned clang_isTranslationUnit(enum CXCursorKind K) { + return K == CXCursor_TranslationUnit; +} + +unsigned clang_isPreprocessing(enum CXCursorKind K) { + return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing; +} + +unsigned clang_isUnexposed(enum CXCursorKind K) { + switch (K) { + case CXCursor_UnexposedDecl: + case CXCursor_UnexposedExpr: + case CXCursor_UnexposedStmt: + case CXCursor_UnexposedAttr: + return true; + default: + return false; + } +} + +CXCursorKind clang_getCursorKind(CXCursor C) { + return C.kind; +} + +CXSourceLocation clang_getCursorLocation(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCSuperClassRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<ObjCProtocolDecl *, SourceLocation> P + = getCursorObjCProtocolRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<ObjCInterfaceDecl *, SourceLocation> P + = getCursorObjCClassRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TemplateRef: { + std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_NamespaceRef: { + std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_MemberRef: { + std::pair<FieldDecl *, SourceLocation> P = getCursorMemberRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_VariableRef: { + std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C); + if (!BaseSpec) + return clang_getNullLocation(); + + if (TypeSourceInfo *TSInfo = BaseSpec->getTypeSourceInfo()) + return cxloc::translateSourceLocation(getCursorContext(C), + TSInfo->getTypeLoc().getBeginLoc()); + + return cxloc::translateSourceLocation(getCursorContext(C), + BaseSpec->getLocStart()); + } + + case CXCursor_LabelRef: { + std::pair<LabelStmt *, SourceLocation> P = getCursorLabelRef(C); + return cxloc::translateSourceLocation(getCursorContext(C), P.second); + } + + case CXCursor_OverloadedDeclRef: + return cxloc::translateSourceLocation(getCursorContext(C), + getCursorOverloadedDeclRef(C).second); + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return cxloc::translateSourceLocation(getCursorContext(C), + getLocationFromExpr(getCursorExpr(C))); + + if (clang_isStatement(C.kind)) + return cxloc::translateSourceLocation(getCursorContext(C), + getCursorStmt(C)->getLocStart()); + + if (C.kind == CXCursor_PreprocessingDirective) { + SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_MacroExpansion) { + SourceLocation L + = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_MacroDefinition) { + SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_InclusionDirective) { + SourceLocation L + = cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) + return clang_getNullLocation(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullLocation(); + + SourceLocation Loc = D->getLocation(); + // 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<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + Loc = VD->getLocation(); + } + + // For ObjC methods, give the start location of the method name. + if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + Loc = MD->getSelectorStartLoc(); + + return cxloc::translateSourceLocation(getCursorContext(C), Loc); +} + +} // end extern "C" + +CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) { + assert(TU); + + // Guard against an invalid SourceLocation, or we may assert in one + // of the following calls. + if (SLoc.isInvalid()) + return clang_getNullCursor(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + + // Translate the given source location to make it point at the beginning of + // the token under the cursor. + SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), + CXXUnit->getASTContext().getLangOpts()); + + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); + if (SLoc.isValid()) { + GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result); + CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + SourceLocation(SLoc)); + CursorVis.visitFileRegion(); + } + + return Result; +} + +static SourceRange getRawCursorExtent(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return getCursorObjCSuperClassRef(C).second; + + case CXCursor_ObjCProtocolRef: + return getCursorObjCProtocolRef(C).second; + + case CXCursor_ObjCClassRef: + return getCursorObjCClassRef(C).second; + + case CXCursor_TypeRef: + return getCursorTypeRef(C).second; + + case CXCursor_TemplateRef: + return getCursorTemplateRef(C).second; + + case CXCursor_NamespaceRef: + return getCursorNamespaceRef(C).second; + + case CXCursor_MemberRef: + return getCursorMemberRef(C).second; + + case CXCursor_CXXBaseSpecifier: + return getCursorCXXBaseSpecifier(C)->getSourceRange(); + + case CXCursor_LabelRef: + return getCursorLabelRef(C).second; + + case CXCursor_OverloadedDeclRef: + return getCursorOverloadedDeclRef(C).second; + + case CXCursor_VariableRef: + return getCursorVariableRef(C).second; + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return getCursorExpr(C)->getSourceRange(); + + if (clang_isStatement(C.kind)) + return getCursorStmt(C)->getSourceRange(); + + if (clang_isAttribute(C.kind)) + return getCursorAttr(C)->getRange(); + + if (C.kind == CXCursor_PreprocessingDirective) + return cxcursor::getCursorPreprocessingDirective(C); + + if (C.kind == CXCursor_MacroExpansion) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_MacroDefinition) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_InclusionDirective) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = cxcursor::getCursorInclusionDirective(C)->getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_TranslationUnit) { + ASTUnit *TU = getCursorASTUnit(C); + FileID MainID = TU->getSourceManager().getMainFileID(); + SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID); + SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID); + return SourceRange(Start, End); + } + + if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) { + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return SourceRange(); + + SourceRange R = D->getSourceRange(); + // 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<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + R.setBegin(VD->getLocation()); + } + return R; + } + return SourceRange(); +} + +/// \brief Retrieves the "raw" cursor extent, which is then extended to include +/// the decl-specifier-seq for declarations. +static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) { + if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) { + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return SourceRange(); + + SourceRange R = D->getSourceRange(); + + // Adjust the start of the location for declarations preceded by + // declaration specifiers. + SourceLocation StartLoc; + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getLocStart(); + } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) { + if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getLocStart(); + } + + 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<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + R.setBegin(VD->getLocation()); + } + + return R; + } + + return getRawCursorExtent(C); +} + +extern "C" { + +CXSourceRange clang_getCursorExtent(CXCursor C) { + SourceRange R = getRawCursorExtent(C); + if (R.isInvalid()) + return clang_getNullRange(); + + return cxloc::translateSourceRange(getCursorContext(C), R); +} + +CXCursor clang_getCursorReferenced(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); + + CXTranslationUnit tu = getCursorTU(C); + if (clang_isDeclaration(C.kind)) { + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) + return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu); + if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D)) + if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) + return MakeCXCursor(Property, tu); + + return C; + } + + if (clang_isExpression(C.kind)) { + Expr *E = getCursorExpr(C); + Decl *D = getDeclFromExpr(E); + if (D) { + CXCursor declCursor = MakeCXCursor(D, tu); + declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C), + declCursor); + return declCursor; + } + + if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E)) + return MakeCursorOverloadedDeclRef(Ovl, tu); + + return clang_getNullCursor(); + } + + if (clang_isStatement(C.kind)) { + Stmt *S = getCursorStmt(C); + if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S)) + if (LabelDecl *label = Goto->getLabel()) + if (LabelStmt *labelS = label->getStmt()) + return MakeCXCursor(labelS, getCursorDecl(C), tu); + + return clang_getNullCursor(); + } + + if (C.kind == CXCursor_MacroExpansion) { + if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition()) + return MakeMacroDefinitionCursor(Def, tu); + } + + if (!clang_isReference(C.kind)) + return clang_getNullCursor(); + + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu); + + case CXCursor_ObjCProtocolRef: { + ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first; + if (ObjCProtocolDecl *Def = Prot->getDefinition()) + return MakeCXCursor(Def, tu); + + return MakeCXCursor(Prot, tu); + } + + case CXCursor_ObjCClassRef: { + ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + if (ObjCInterfaceDecl *Def = Class->getDefinition()) + return MakeCXCursor(Def, tu); + + return MakeCXCursor(Class, tu); + } + + case CXCursor_TypeRef: + return MakeCXCursor(getCursorTypeRef(C).first, tu ); + + case CXCursor_TemplateRef: + return MakeCXCursor(getCursorTemplateRef(C).first, tu ); + + case CXCursor_NamespaceRef: + return MakeCXCursor(getCursorNamespaceRef(C).first, tu ); + + case CXCursor_MemberRef: + return MakeCXCursor(getCursorMemberRef(C).first, tu ); + + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); + return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), + tu )); + } + + case CXCursor_LabelRef: + // FIXME: We end up faking the "parent" declaration here because we + // don't want to make CXCursor larger. + return MakeCXCursor(getCursorLabelRef(C).first, + static_cast<ASTUnit*>(tu->TUData)->getASTContext() + .getTranslationUnitDecl(), + tu); + + case CXCursor_OverloadedDeclRef: + return C; + + case CXCursor_VariableRef: + return MakeCXCursor(getCursorVariableRef(C).first, tu); + + default: + // We would prefer to enumerate all non-reference cursor kinds here. + llvm_unreachable("Unhandled reference cursor kind"); + } +} + +CXCursor clang_getCursorDefinition(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); + + CXTranslationUnit TU = getCursorTU(C); + + bool WasReference = false; + if (clang_isReference(C.kind) || clang_isExpression(C.kind)) { + C = clang_getCursorReferenced(C); + WasReference = true; + } + + if (C.kind == CXCursor_MacroExpansion) + return clang_getCursorReferenced(C); + + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + switch (D->getKind()) { + // Declaration kinds that don't really separate the notions of + // declaration and definition. + case Decl::Namespace: + case Decl::Typedef: + case Decl::TypeAlias: + case Decl::TypeAliasTemplate: + case Decl::TemplateTypeParm: + case Decl::EnumConstant: + case Decl::Field: + case Decl::IndirectField: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::NonTypeTemplateParm: + case Decl::TemplateTemplateParm: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::AccessSpec: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::FileScopeAsm: + case Decl::StaticAssert: + case Decl::Block: + case Decl::Label: // FIXME: Is this right?? + case Decl::ClassScopeFunctionSpecialization: + case Decl::Import: + return C; + + // Declaration kinds that don't make any sense here, but are + // nonetheless harmless. + case Decl::TranslationUnit: + break; + + // Declaration kinds for which the definition is not resolvable. + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + break; + + case Decl::UsingDirective: + return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(), + TU); + + case Decl::NamespaceAlias: + return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), TU); + + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + if (TagDecl *Def = cast<TagDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: { + const FunctionDecl *Def = 0; + if (cast<FunctionDecl>(D)->getBody(Def)) + return MakeCXCursor(const_cast<FunctionDecl *>(Def), TU); + return clang_getNullCursor(); + } + + case Decl::Var: { + // Ask the variable if it has a definition. + if (VarDecl *Def = cast<VarDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + } + + case Decl::FunctionTemplate: { + const FunctionDecl *Def = 0; + if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def)) + return MakeCXCursor(Def->getDescribedFunctionTemplate(), TU); + return clang_getNullCursor(); + } + + case Decl::ClassTemplate: { + if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() + ->getDefinition()) + return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + TU); + return clang_getNullCursor(); + } + + case Decl::Using: + return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D), + D->getLocation(), TU); + + case Decl::UsingShadow: + return clang_getCursorDefinition( + MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), + TU)); + + case Decl::ObjCMethod: { + ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D); + if (Method->isThisDeclarationADefinition()) + return C; + + // Dig out the method definition in the associated + // @implementation, if we have it. + // FIXME: The ASTs should make finding the definition easier. + if (ObjCInterfaceDecl *Class + = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) + if (ObjCImplementationDecl *ClassImpl = Class->getImplementation()) + if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Def->isThisDeclarationADefinition()) + return MakeCXCursor(Def, TU); + + return clang_getNullCursor(); + } + + case Decl::ObjCCategory: + if (ObjCCategoryImplDecl *Impl + = cast<ObjCCategoryDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, TU); + return clang_getNullCursor(); + + case Decl::ObjCProtocol: + if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + + case Decl::ObjCInterface: { + // There are two notions of a "definition" for an Objective-C + // class: the interface and its implementation. When we resolved a + // reference to an Objective-C class, produce the @interface as + // the definition; when we were provided with the interface, + // produce the @implementation as the definition. + ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D); + if (WasReference) { + if (ObjCInterfaceDecl *Def = IFace->getDefinition()) + return MakeCXCursor(Def, TU); + } else if (ObjCImplementationDecl *Impl = IFace->getImplementation()) + return MakeCXCursor(Impl, TU); + return clang_getNullCursor(); + } + + case Decl::ObjCProperty: + // FIXME: We don't really know where to find the + // ObjCPropertyImplDecls that implement this property. + return clang_getNullCursor(); + + case Decl::ObjCCompatibleAlias: + if (ObjCInterfaceDecl *Class + = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) + if (ObjCInterfaceDecl *Def = Class->getDefinition()) + return MakeCXCursor(Def, TU); + + return clang_getNullCursor(); + + case Decl::Friend: + if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); + return clang_getNullCursor(); + + case Decl::FriendTemplate: + if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); + return clang_getNullCursor(); + } + + return clang_getNullCursor(); +} + +unsigned clang_isCursorDefinition(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + return clang_getCursorDefinition(C) == C; +} + +CXCursor clang_getCanonicalCursor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return C; + + if (Decl *D = getCursorDecl(C)) { + if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) + if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl()) + return MakeCXCursor(CatD, getCursorTU(C)); + + if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + return MakeCXCursor(IFD, getCursorTU(C)); + + return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C)); + } + + return C; +} + +int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) { + return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first; +} + +unsigned clang_getNumOverloadedDecls(CXCursor C) { + if (C.kind != CXCursor_OverloadedDeclRef) + return 0; + + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; + if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) + return E->getNumDecls(); + + if (OverloadedTemplateStorage *S + = Storage.dyn_cast<OverloadedTemplateStorage*>()) + return S->size(); + + Decl *D = Storage.get<Decl*>(); + if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) + return Using->shadow_size(); + + return 0; +} + +CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) { + if (cursor.kind != CXCursor_OverloadedDeclRef) + return clang_getNullCursor(); + + if (index >= clang_getNumOverloadedDecls(cursor)) + return clang_getNullCursor(); + + CXTranslationUnit TU = getCursorTU(cursor); + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(cursor).first; + if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>()) + return MakeCXCursor(E->decls_begin()[index], TU); + + if (OverloadedTemplateStorage *S + = Storage.dyn_cast<OverloadedTemplateStorage*>()) + return MakeCXCursor(S->begin()[index], TU); + + Decl *D = Storage.get<Decl*>(); + if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) { + // FIXME: This is, unfortunately, linear time. + UsingDecl::shadow_iterator Pos = Using->shadow_begin(); + std::advance(Pos, index); + return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU); + } + + return clang_getNullCursor(); +} + +void clang_getDefinitionSpellingAndExtent(CXCursor C, + const char **startBuf, + const char **endBuf, + unsigned *startLine, + unsigned *startColumn, + unsigned *endLine, + unsigned *endColumn) { + assert(getCursorDecl(C) && "CXCursor has null decl"); + NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C)); + FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); + CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); + + SourceManager &SM = FD->getASTContext().getSourceManager(); + *startBuf = SM.getCharacterData(Body->getLBracLoc()); + *endBuf = SM.getCharacterData(Body->getRBracLoc()); + *startLine = SM.getSpellingLineNumber(Body->getLBracLoc()); + *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc()); + *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); + *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); +} + + +CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags, + unsigned PieceIndex) { + RefNamePieces Pieces; + + switch (C.kind) { + case CXCursor_MemberRefExpr: + if (MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C))) + Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(), + E->getQualifierLoc().getSourceRange()); + break; + + case CXCursor_DeclRefExpr: + if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) + Pieces = buildPieces(NameFlags, false, E->getNameInfo(), + E->getQualifierLoc().getSourceRange(), + E->getOptionalExplicitTemplateArgs()); + break; + + case CXCursor_CallExpr: + if (CXXOperatorCallExpr *OCE = + dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) { + Expr *Callee = OCE->getCallee(); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) + Callee = ICE->getSubExpr(); + + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) + Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(), + DRE->getQualifierLoc().getSourceRange()); + } + break; + + default: + break; + } + + if (Pieces.empty()) { + if (PieceIndex == 0) + return clang_getCursorExtent(C); + } else if (PieceIndex < Pieces.size()) { + SourceRange R = Pieces[PieceIndex]; + if (R.isValid()) + return cxloc::translateSourceRange(getCursorContext(C), R); + } + + return clang_getNullRange(); +} + +void clang_enableStackTraces(void) { + llvm::sys::PrintStackTraceOnErrorSignal(); +} + +void clang_executeOnThread(void (*fn)(void*), void *user_data, + unsigned stack_size) { + llvm::llvm_execute_on_thread(fn, user_data, stack_size); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Token-based Operations. +//===----------------------------------------------------------------------===// + +/* CXToken layout: + * int_data[0]: a CXTokenKind + * int_data[1]: starting token location + * int_data[2]: token length + * int_data[3]: reserved + * ptr_data: for identifiers and keywords, an IdentifierInfo*. + * otherwise unused. + */ +extern "C" { + +CXTokenKind clang_getTokenKind(CXToken CXTok) { + return static_cast<CXTokenKind>(CXTok.int_data[0]); +} + +CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) { + switch (clang_getTokenKind(CXTok)) { + case CXToken_Identifier: + case CXToken_Keyword: + // We know we have an IdentifierInfo*, so use that. + return createCXString(static_cast<IdentifierInfo *>(CXTok.ptr_data) + ->getNameStart()); + + case CXToken_Literal: { + // We have stashed the starting pointer in the ptr_data field. Use it. + const char *Text = static_cast<const char *>(CXTok.ptr_data); + return createCXString(StringRef(Text, CXTok.int_data[2])); + } + + case CXToken_Punctuation: + case CXToken_Comment: + break; + } + + // We have to find the starting buffer pointer the hard way, by + // deconstructing the source location. + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + if (!CXXUnit) + return createCXString(""); + + SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]); + std::pair<FileID, unsigned> LocInfo + = CXXUnit->getSourceManager().getDecomposedSpellingLoc(Loc); + bool Invalid = false; + StringRef Buffer + = CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return createCXString(""); + + return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2])); +} + +CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) { + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + if (!CXXUnit) + return clang_getNullLocation(); + + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), + SourceLocation::getFromRawEncoding(CXTok.int_data[1])); +} + +CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) { + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + if (!CXXUnit) + return clang_getNullRange(); + + return cxloc::translateSourceRange(CXXUnit->getASTContext(), + SourceLocation::getFromRawEncoding(CXTok.int_data[1])); +} + +static void getTokens(ASTUnit *CXXUnit, SourceRange Range, + SmallVectorImpl<CXToken> &CXTokens) { + SourceManager &SourceMgr = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> BeginLocInfo + = SourceMgr.getDecomposedLoc(Range.getBegin()); + std::pair<FileID, unsigned> EndLocInfo + = SourceMgr.getDecomposedLoc(Range.getEnd()); + + // Cannot tokenize across files. + if (BeginLocInfo.first != EndLocInfo.first) + return; + + // Create a lexer + bool Invalid = false; + StringRef Buffer + = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); + if (Invalid) + return; + + Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), + CXXUnit->getASTContext().getLangOpts(), + Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end()); + Lex.SetCommentRetentionState(true); + + // Lex tokens until we hit the end of the range. + const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second; + Token Tok; + bool previousWasAt = false; + do { + // Lex the next token + Lex.LexFromRawLexer(Tok); + if (Tok.is(tok::eof)) + break; + + // Initialize the CXToken. + CXToken CXTok; + + // - Common fields + CXTok.int_data[1] = Tok.getLocation().getRawEncoding(); + CXTok.int_data[2] = Tok.getLength(); + CXTok.int_data[3] = 0; + + // - Kind-specific fields + if (Tok.isLiteral()) { + CXTok.int_data[0] = CXToken_Literal; + CXTok.ptr_data = (void *)Tok.getLiteralData(); + } else if (Tok.is(tok::raw_identifier)) { + // Lookup the identifier to determine whether we have a keyword. + IdentifierInfo *II + = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok); + + if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) { + CXTok.int_data[0] = CXToken_Keyword; + } + else { + CXTok.int_data[0] = Tok.is(tok::identifier) + ? CXToken_Identifier + : CXToken_Keyword; + } + CXTok.ptr_data = II; + } else if (Tok.is(tok::comment)) { + CXTok.int_data[0] = CXToken_Comment; + CXTok.ptr_data = 0; + } else { + CXTok.int_data[0] = CXToken_Punctuation; + CXTok.ptr_data = 0; + } + CXTokens.push_back(CXTok); + previousWasAt = Tok.is(tok::at); + } while (Lex.getBufferLocation() <= EffectiveBufferEnd); +} + +void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, + CXToken **Tokens, unsigned *NumTokens) { + if (Tokens) + *Tokens = 0; + if (NumTokens) + *NumTokens = 0; + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + if (!CXXUnit || !Tokens || !NumTokens) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + SourceRange R = cxloc::translateCXSourceRange(Range); + if (R.isInvalid()) + return; + + SmallVector<CXToken, 32> CXTokens; + getTokens(CXXUnit, R, CXTokens); + + if (CXTokens.empty()) + return; + + *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size()); + memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size()); + *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; + unsigned PreprocessingTokIdx; + CursorVisitor AnnotateVis; + SourceManager &SrcMgr; + bool HasContextSensitiveKeywords; + + 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]); + } + bool isFunctionMacroToken(unsigned tokI) const { + return Tokens[tokI].int_data[3] != 0; + } + SourceLocation getFunctionMacroTokenLoc(unsigned tokI) const { + return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[3]); + } + + void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange); + void annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult, + SourceRange); + +public: + AnnotateTokensWorker(AnnotateTokensData &annotated, + CXToken *tokens, CXCursor *cursors, unsigned numTokens, + CXTranslationUnit tu, SourceRange RegionOfInterest) + : Annotated(annotated), Tokens(tokens), Cursors(cursors), + NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0), + AnnotateVis(tu, + AnnotateTokensVisitor, this, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + RegionOfInterest), + SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()), + HasContextSensitiveKeywords(false) { } + + void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } + enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + void AnnotateTokens(); + + /// \brief Determine whether the annotator saw any cursors that have + /// context-sensitive keywords. + bool hasContextSensitiveKeywords() const { + return HasContextSensitiveKeywords; + } +}; +} + +void AnnotateTokensWorker::AnnotateTokens() { + // Walk the AST within the region of interest, annotating tokens + // along the way. + AnnotateVis.visitFileRegion(); + + for (unsigned I = 0 ; I < TokIdx ; ++I) { + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + if (Pos != Annotated.end() && + (clang_isInvalid(Cursors[I].kind) || + Pos->second.kind != CXCursor_PreprocessingDirective)) + 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) { + if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind)) + continue; + + AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]); + Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second; + } +} + +/// \brief It annotates and advances tokens with a cursor until the comparison +//// between the cursor location and the source range is the same as +/// \arg compResult. +/// +/// Pass RangeBefore to annotate tokens with a cursor until a range is reached. +/// Pass RangeOverlap to annotate tokens inside a range. +void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC, + RangeComparisonResult compResult, + SourceRange range) { + while (MoreTokens()) { + const unsigned I = NextToken(); + if (isFunctionMacroToken(I)) + return annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range); + + SourceLocation TokLoc = GetTokenLoc(I); + if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { + Cursors[I] = updateC; + AdvanceToken(); + continue; + } + break; + } +} + +/// \brief Special annotation handling for macro argument tokens. +void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens( + CXCursor updateC, + RangeComparisonResult compResult, + SourceRange range) { + assert(MoreTokens()); + assert(isFunctionMacroToken(NextToken()) && + "Should be called only for macro arg tokens"); + + // This works differently than annotateAndAdvanceTokens; because expanded + // macro arguments can have arbitrary translation-unit source order, we do not + // advance the token index one by one until a token fails the range test. + // We only advance once past all of the macro arg tokens if all of them + // pass the range test. If one of them fails we keep the token index pointing + // at the start of the macro arg tokens so that the failing token will be + // annotated by a subsequent annotation try. + + bool atLeastOneCompFail = false; + + unsigned I = NextToken(); + for (; I < NumTokens && isFunctionMacroToken(I); ++I) { + SourceLocation TokLoc = getFunctionMacroTokenLoc(I); + if (TokLoc.isFileID()) + continue; // not macro arg token, it's parens or comma. + if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { + if (clang_isInvalid(clang_getCursorKind(Cursors[I]))) + Cursors[I] = updateC; + } else + atLeastOneCompFail = true; + } + + if (!atLeastOneCompFail) + TokIdx = I; // All of the tokens were handled, advance beyond all of them. +} + +enum CXChildVisitResult +AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { + CXSourceLocation Loc = clang_getCursorLocation(cursor); + 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<ObjCPropertyDecl>(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<ObjCMethodDecl>(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<CXXMethodDecl>(getCursorDecl(cursor))) { + if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>()) + 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<FinalAttr>()) + HasContextSensitiveKeywords = true; + } + } + + if (clang_isPreprocessing(cursor.kind)) { + // For macro expansions, just note where the beginning of the macro + // expansion occurs. + if (cursor.kind == CXCursor_MacroExpansion) { + Annotated[Loc.int_data] = cursor; + return CXChildVisit_Recurse; + } + + // Items in the preprocessing record are kept separate from items in + // declarations, so we keep a separate token index. + unsigned SavedTokIdx = TokIdx; + TokIdx = PreprocessingTokIdx; + + // Skip tokens up until we catch up to the beginning of the preprocessing + // entry. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + AdvanceToken(); + continue; + case RangeAfter: + case RangeOverlap: + break; + } + break; + } + + // Look at all of the tokens within this range. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + llvm_unreachable("Infeasible"); + case RangeAfter: + break; + case RangeOverlap: + Cursors[I] = cursor; + AdvanceToken(); + continue; + } + break; + } + + // Save the preprocessing token index; restore the non-preprocessing + // token index. + PreprocessingTokIdx = TokIdx; + TokIdx = SavedTokIdx; + return CXChildVisit_Recurse; + } + + 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); + + SourceLocation StartLoc; + if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getLocStart(); + } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) { + if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getLocStart(); + } + + if (StartLoc.isValid() && L.isValid() && + SrcMgr.isBeforeInTranslationUnit(StartLoc, L)) + cursorRange.setBegin(StartLoc); + } + + // If the location of the cursor occurs within a macro instantiation, record + // the spelling location of the cursor in our annotation map. We can then + // paper over the token labelings during a post-processing step to try and + // get cursor mappings for tokens that are the *arguments* of a macro + // instantiation. + if (L.isMacroID()) { + unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding(); + // Only invalidate the old annotation if it isn't part of a preprocessing + // directive. Here we assume that the default construction of CXCursor + // results in CXCursor.kind being an initialized value (i.e., 0). If + // this isn't the case, we can fix by doing lookup + insertion. + + CXCursor &oldC = Annotated[rawEncoding]; + if (!clang_isPreprocessing(oldC.kind)) + oldC = cursor; + } + + const enum CXCursorKind K = clang_getCursorKind(parent); + const CXCursor updateC = + (clang_isInvalid(K) || K == CXCursor_TranslationUnit) + ? clang_getNullCursor() : parent; + + annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange); + + // Avoid having the cursor of an expression "overwrite" the annotation of the + // variable declaration that it belongs to. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor. + if (clang_isExpression(cursorK)) { + Expr *E = getCursorExpr(cursor); + if (Decl *D = getCursorParentDecl(cursor)) { + const unsigned I = NextToken(); + if (E->getLocStart().isValid() && D->getLocation().isValid() && + E->getLocStart() == D->getLocation() && + E->getLocStart() == GetTokenLoc(I)) { + Cursors[I] = updateC; + AdvanceToken(); + } + } + } + + // Visit children to get their cursor information. + const unsigned BeforeChildren = NextToken(); + VisitChildren(cursor); + const unsigned AfterChildren = NextToken(); + + // Scan the tokens that are at the end of the cursor, but are not captured + // but the child cursors. + annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange); + + // Scan the tokens that are at the beginning of the cursor, but are not + // capture by the child cursors. + for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { + if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) + break; + + Cursors[I] = cursor; + } + + return CXChildVisit_Continue; +} + +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + return static_cast<AnnotateTokensWorker*>(client_data)->Visit(cursor, parent); +} + +namespace { + +/// \brief Uses the macro expansions in the preprocessing record to find +/// and mark tokens that are macro arguments. This info is used by the +/// AnnotateTokensWorker. +class MarkMacroArgTokensVisitor { + SourceManager &SM; + CXToken *Tokens; + unsigned NumTokens; + unsigned CurIdx; + +public: + MarkMacroArgTokensVisitor(SourceManager &SM, + CXToken *tokens, unsigned numTokens) + : SM(SM), Tokens(tokens), NumTokens(numTokens), CurIdx(0) { } + + CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { + if (cursor.kind != CXCursor_MacroExpansion) + return CXChildVisit_Continue; + + SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange(); + if (macroRange.getBegin() == macroRange.getEnd()) + return CXChildVisit_Continue; // it's not a function macro. + + for (; CurIdx < NumTokens; ++CurIdx) { + if (!SM.isBeforeInTranslationUnit(getTokenLoc(CurIdx), + macroRange.getBegin())) + break; + } + + if (CurIdx == NumTokens) + return CXChildVisit_Break; + + for (; CurIdx < NumTokens; ++CurIdx) { + SourceLocation tokLoc = getTokenLoc(CurIdx); + if (!SM.isBeforeInTranslationUnit(tokLoc, macroRange.getEnd())) + break; + + setFunctionMacroTokenLoc(CurIdx, SM.getMacroArgExpandedLocation(tokLoc)); + } + + if (CurIdx == NumTokens) + return CXChildVisit_Break; + + return CXChildVisit_Continue; + } + +private: + SourceLocation getTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(Tokens[tokI].int_data[1]); + } + + void setFunctionMacroTokenLoc(unsigned tokI, SourceLocation loc) { + // The third field is reserved and currently not used. Use it here + // to mark macro arg expanded tokens with their expanded locations. + Tokens[tokI].int_data[3] = loc.getRawEncoding(); + } +}; + +} // end anonymous namespace + +static CXChildVisitResult +MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + return static_cast<MarkMacroArgTokensVisitor*>(client_data)->visit(cursor, + parent); +} + +namespace { + struct clang_annotateTokens_Data { + CXTranslationUnit TU; + ASTUnit *CXXUnit; + CXToken *Tokens; + unsigned NumTokens; + CXCursor *Cursors; + }; +} + +static void annotatePreprocessorTokens(CXTranslationUnit TU, + SourceRange RegionOfInterest, + AnnotateTokensData &Annotated) { + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + + SourceManager &SourceMgr = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> BeginLocInfo + = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin()); + std::pair<FileID, unsigned> EndLocInfo + = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd()); + + if (BeginLocInfo.first != EndLocInfo.first) + return; + + StringRef Buffer; + bool Invalid = false; + Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); + if (Buffer.empty() || Invalid) + return; + + Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), + CXXUnit->getASTContext().getLangOpts(), + 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 + // don't see it while preprocessing these tokens later, but keep track + // of all of the token locations inside this preprocessing directive so + // that we can annotate them appropriately. + // + // FIXME: Some simple tests here could identify macro definitions and + // #undefs, to provide specific cursor kinds for those. + SmallVector<SourceLocation, 32> 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()), + 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; + } +} + +// 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; + + CIndexer *CXXIdx = (CIndexer*)TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + // 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]))); + + // 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. + annotatePreprocessorTokens(TU, RegionOfInterest, Annotated); + + if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { + // Search and mark tokens that are macro argument expansions. + MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(), + Tokens, NumTokens); + CursorVisitor MacroArgMarker(TU, + MarkMacroArgTokensVisitorDelegate, &Visitor, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + RegionOfInterest); + MacroArgMarker.visitPreprocessedEntitiesInRegion(); + } + + // 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); + + // 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<IdentifierInfo *>(Tokens[I].ptr_data); + if (ObjCPropertyDecl *Property + = dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) { + if (Property->getPropertyAttributesAsWritten() != 0 && + llvm::StringSwitch<bool>(II->getName()) + .Case("readonly", true) + .Case("assign", true) + .Case("unsafe_unretained", true) + .Case("readwrite", true) + .Case("retain", true) + .Case("copy", true) + .Case("nonatomic", true) + .Case("atomic", true) + .Case("getter", true) + .Case("setter", true) + .Case("strong", true) + .Case("weak", 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<IdentifierInfo *>(Tokens[I].ptr_data); + if (llvm::StringSwitch<bool>(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_CXXFinalAttr || + Cursors[I].kind == CXCursor_CXXOverrideAttr) { + 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<ASTUnit *>(TU->TUData); + if (!CXXUnit) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors }; + llvm::CrashRecoveryContext CRC; + if (!RunSafely(CRC, clang_annotateTokensImpl, &data, + GetSafetyThreadStackSize() * 2)) { + fprintf(stderr, "libclang: crash detected while annotating tokens\n"); + } +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Operations for querying linkage of a cursor. +//===----------------------------------------------------------------------===// + +extern "C" { +CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { + if (!clang_isDeclaration(cursor.kind)) + return CXLinkage_Invalid; + + Decl *D = cxcursor::getCursorDecl(cursor); + if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) + switch (ND->getLinkage()) { + case NoLinkage: return CXLinkage_NoLinkage; + case InternalLinkage: return CXLinkage_Internal; + case UniqueExternalLinkage: return CXLinkage_UniqueExternal; + case ExternalLinkage: return CXLinkage_External; + }; + + return CXLinkage_Invalid; +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Operations for querying language of a cursor. +//===----------------------------------------------------------------------===// + +static CXLanguageKind getDeclLanguage(const Decl *D) { + if (!D) + return CXLanguage_C; + + switch (D->getKind()) { + default: + break; + case Decl::ImplicitParam: + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCIvar: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + return CXLanguage_ObjC; + case Decl::CXXConstructor: + case Decl::CXXConversion: + case Decl::CXXDestructor: + case Decl::CXXMethod: + case Decl::CXXRecord: + case Decl::ClassTemplate: + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::FunctionTemplate: + case Decl::LinkageSpec: + case Decl::Namespace: + case Decl::NamespaceAlias: + case Decl::NonTypeTemplateParm: + case Decl::StaticAssert: + case Decl::TemplateTemplateParm: + case Decl::TemplateTypeParm: + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + case Decl::Using: + case Decl::UsingDirective: + case Decl::UsingShadow: + return CXLanguage_CPlusPlus; + } + + return CXLanguage_C; +} + +extern "C" { + +enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + if (Decl *D = cxcursor::getCursorDecl(cursor)) { + if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()) + return CXAvailability_Available; + + 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; +} + +CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + return getDeclLanguage(cxcursor::getCursorDecl(cursor)); + + return CXLanguage_Invalid; +} + + /// \brief If the given cursor is the "templated" declaration + /// descibing a class or function template, return the class or + /// function template. +static Decl *maybeGetTemplateCursor(Decl *D) { + if (!D) + return 0; + + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FunctionTemplateDecl *FunTmpl = FD->getDescribedFunctionTemplate()) + return FunTmpl; + + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) + if (ClassTemplateDecl *ClassTmpl = RD->getDescribedClassTemplate()) + return ClassTmpl; + + return D; +} + +CXCursor clang_getCursorSemanticParent(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) { + if (Decl *D = getCursorDecl(cursor)) { + DeclContext *DC = D->getDeclContext(); + if (!DC) + return clang_getNullCursor(); + + return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), + getCursorTU(cursor)); + } + } + + if (clang_isStatement(cursor.kind) || clang_isExpression(cursor.kind)) { + if (Decl *D = getCursorDecl(cursor)) + return MakeCXCursor(D, getCursorTU(cursor)); + } + + return clang_getNullCursor(); +} + +CXCursor clang_getCursorLexicalParent(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) { + if (Decl *D = getCursorDecl(cursor)) { + DeclContext *DC = D->getLexicalDeclContext(); + if (!DC) + return clang_getNullCursor(); + + return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), + getCursorTU(cursor)); + } + } + + // FIXME: Note that we can't easily compute the lexical context of a + // statement or expression, so we return nothing. + return clang_getNullCursor(); +} + +void clang_getOverriddenCursors(CXCursor cursor, + CXCursor **overridden, + unsigned *num_overridden) { + if (overridden) + *overridden = 0; + if (num_overridden) + *num_overridden = 0; + if (!overridden || !num_overridden) + return; + if (!clang_isDeclaration(cursor.kind)) + return; + + SmallVector<CXCursor, 8> Overridden; + cxcursor::getOverriddenCursors(cursor, Overridden); + + // Don't allocate memory if we have no overriden cursors. + if (Overridden.size() == 0) + return; + + *num_overridden = Overridden.size(); + *overridden = new CXCursor [Overridden.size()]; + std::copy(Overridden.begin(), Overridden.end(), *overridden); +} + +void clang_disposeOverriddenCursors(CXCursor *overridden) { + delete [] overridden; +} + +CXFile clang_getIncludedFile(CXCursor cursor) { + if (cursor.kind != CXCursor_InclusionDirective) + return 0; + + InclusionDirective *ID = getCursorInclusionDirective(cursor); + return (void *)ID->getFile(); +} + +} // end: extern "C" + + +//===----------------------------------------------------------------------===// +// C++ AST instrospection. +//===----------------------------------------------------------------------===// + +extern "C" { +unsigned clang_CXXMethod_isStatic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + CXXMethodDecl *Method = 0; + Decl *D = cxcursor::getCursorDecl(C); + if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast_or_null<CXXMethodDecl>(D); + return (Method && Method->isStatic()) ? 1 : 0; +} + +unsigned clang_CXXMethod_isVirtual(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + CXXMethodDecl *Method = 0; + Decl *D = cxcursor::getCursorDecl(C); + if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast_or_null<CXXMethodDecl>(D); + return (Method && Method->isVirtual()) ? 1 : 0; +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Attribute introspection. +//===----------------------------------------------------------------------===// + +extern "C" { +CXType clang_getIBOutletCollectionType(CXCursor C) { + if (C.kind != CXCursor_IBOutletCollectionAttr) + return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C)); + + IBOutletCollectionAttr *A = + cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C)); + + return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C)); +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// Inspecting memory usage. +//===----------------------------------------------------------------------===// + +typedef std::vector<CXTUResourceUsageEntry> 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; + case CXTUResourceUsage_Preprocessor: + str = "Preprocessor: malloc'ed memory"; + break; + case CXTUResourceUsage_PreprocessingRecord: + str = "Preprocessor: PreprocessingRecord"; + break; + case CXTUResourceUsage_SourceManager_DataStructures: + str = "SourceManager: data structures and tables"; + break; + case CXTUResourceUsage_Preprocessor_HeaderSearch: + str = "Preprocessor: header search tables"; + break; + } + return str; +} + +CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) { + if (!TU) { + CXTUResourceUsage usage = { (void*) 0, 0, 0 }; + return usage; + } + + ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData); + OwningPtr<MemUsageEntries> 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); + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManager_DataStructures, + (unsigned long) astContext.getSourceManager() + .getDataStructureSizes()); + + // 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); + } + + // How much memory is being used by the Preprocessor? + Preprocessor &pp = astUnit->getPreprocessor(); + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_Preprocessor, + pp.getTotalMemory()); + + if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) { + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_PreprocessingRecord, + pRec->getTotalMemory()); + } + + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_Preprocessor_HeaderSearch, + pp.getHeaderSearchInfo().getTotalMemory()); + + 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" + +void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) { + CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU); + for (unsigned I = 0; I != Usage.numEntries; ++I) + fprintf(stderr, " %s: %lu\n", + clang_getTUResourceUsageName(Usage.entries[I].kind), + Usage.entries[I].amount); + + clang_disposeCXTUResourceUsage(Usage); +} + +//===----------------------------------------------------------------------===// +// Misc. utility functions. +//===----------------------------------------------------------------------===// + +/// Default to using an 8 MB stack size on "safety" threads. +static unsigned SafetyStackThreadSize = 8 << 20; + +namespace clang { + +bool RunSafely(llvm::CrashRecoveryContext &CRC, + void (*Fn)(void*), void *UserData, + unsigned Size) { + if (!Size) + Size = GetSafetyThreadStackSize(); + if (Size) + return CRC.RunSafelyOnThread(Fn, UserData, Size); + return CRC.RunSafely(Fn, UserData); +} + +unsigned GetSafetyThreadStackSize() { + return SafetyStackThreadSize; +} + +void SetSafetyThreadStackSize(unsigned Value) { + SafetyStackThreadSize = Value; +} + +} + +void clang::setThreadBackgroundPriority() { + // FIXME: Move to llvm/Support and make it cross-platform. +#ifdef __APPLE__ + setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); +#endif +} + +void cxindex::printDiagsToStderr(ASTUnit *Unit) { + if (!Unit) + return; + + for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(), + DEnd = Unit->stored_diag_end(); + D != DEnd; ++D) { + CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts()); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + } +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif +} + +extern "C" { + +CXString clang_getClangVersion() { + return createCXString(getClangFullVersion()); +} + +} // end: extern "C" + diff --git a/clang/tools/libclang/CIndexCXX.cpp b/clang/tools/libclang/CIndexCXX.cpp new file mode 100644 index 0000000..240b0f6 --- /dev/null +++ b/clang/tools/libclang/CIndexCXX.cpp @@ -0,0 +1,127 @@ +//===- CIndexCXX.cpp - Clang-C Source Indexing Library --------------------===// +// +// 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 libclang support for C++ cursors. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace clang::cxcursor; + +extern "C" { + +unsigned clang_isVirtualBase(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return 0; + + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return B->isVirtual(); +} + +enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) { + AccessSpecifier spec = AS_none; + + if (C.kind == CXCursor_CXXAccessSpecifier) + spec = getCursorDecl(C)->getAccess(); + else if (C.kind == CXCursor_CXXBaseSpecifier) + spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier(); + else + return CX_CXXInvalidAccessSpecifier; + + switch (spec) { + case AS_public: return CX_CXXPublic; + case AS_protected: return CX_CXXProtected; + case AS_private: return CX_CXXPrivate; + case AS_none: return CX_CXXInvalidAccessSpecifier; + } + + llvm_unreachable("Invalid AccessSpecifier!"); +} + +enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { + using namespace clang::cxcursor; + + switch (C.kind) { + case CXCursor_ClassTemplate: + case CXCursor_FunctionTemplate: + if (TemplateDecl *Template + = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C))) + return MakeCXCursor(Template->getTemplatedDecl(), + static_cast<CXTranslationUnit>(C.data[2])).kind; + break; + + case CXCursor_ClassTemplatePartialSpecialization: + if (ClassTemplateSpecializationDecl *PartialSpec + = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( + getCursorDecl(C))) { + switch (PartialSpec->getTagKind()) { + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_NoDeclFound; + } + } + break; + + default: + break; + } + + return CXCursor_NoDeclFound; +} + +CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + Decl *Template = 0; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) + Template = PartialSpec->getSpecializedTemplate(); + else if (ClassTemplateSpecializationDecl *ClassSpec + = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> Result + = ClassSpec->getSpecializedTemplateOrPartial(); + if (Result.is<ClassTemplateDecl *>()) + Template = Result.get<ClassTemplateDecl *>(); + else + Template = Result.get<ClassTemplatePartialSpecializationDecl *>(); + + } else + Template = CXXRecord->getInstantiatedFromMemberClass(); + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + Template = Function->getPrimaryTemplate(); + if (!Template) + Template = Function->getInstantiatedFromMemberFunction(); + } else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->isStaticDataMember()) + Template = Var->getInstantiatedFromStaticDataMember(); + } else if (RedeclarableTemplateDecl *Tmpl + = dyn_cast<RedeclarableTemplateDecl>(D)) + Template = Tmpl->getInstantiatedFromMemberTemplate(); + + if (!Template) + return clang_getNullCursor(); + + return MakeCXCursor(Template, static_cast<CXTranslationUnit>(C.data[2])); +} + +} // end extern "C" diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp new file mode 100644 index 0000000..303fb1f --- /dev/null +++ b/clang/tools/libclang/CIndexCodeCompletion.cpp @@ -0,0 +1,975 @@ +//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===// +// +// 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 Clang-C Source Indexing library hooks for +// code completion. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXString.h" +#include "CXCursor.h" +#include "CXString.h" +#include "CIndexDiagnostic.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Program.h" +#include <cstdlib> +#include <cstdio> + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#include "clang/Basic/Version.h" +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +using namespace clang; +using namespace clang::cxstring; + +extern "C" { + +enum CXCompletionChunkKind +clang_getCompletionChunkKind(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return CXCompletionChunk_Text; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + return CXCompletionChunk_TypedText; + case CodeCompletionString::CK_Text: + return CXCompletionChunk_Text; + case CodeCompletionString::CK_Optional: + return CXCompletionChunk_Optional; + case CodeCompletionString::CK_Placeholder: + return CXCompletionChunk_Placeholder; + case CodeCompletionString::CK_Informative: + return CXCompletionChunk_Informative; + case CodeCompletionString::CK_ResultType: + return CXCompletionChunk_ResultType; + case CodeCompletionString::CK_CurrentParameter: + return CXCompletionChunk_CurrentParameter; + case CodeCompletionString::CK_LeftParen: + return CXCompletionChunk_LeftParen; + case CodeCompletionString::CK_RightParen: + return CXCompletionChunk_RightParen; + case CodeCompletionString::CK_LeftBracket: + return CXCompletionChunk_LeftBracket; + case CodeCompletionString::CK_RightBracket: + return CXCompletionChunk_RightBracket; + case CodeCompletionString::CK_LeftBrace: + return CXCompletionChunk_LeftBrace; + case CodeCompletionString::CK_RightBrace: + return CXCompletionChunk_RightBrace; + case CodeCompletionString::CK_LeftAngle: + return CXCompletionChunk_LeftAngle; + case CodeCompletionString::CK_RightAngle: + return CXCompletionChunk_RightAngle; + case CodeCompletionString::CK_Comma: + return CXCompletionChunk_Comma; + case CodeCompletionString::CK_Colon: + return CXCompletionChunk_Colon; + case CodeCompletionString::CK_SemiColon: + return CXCompletionChunk_SemiColon; + case CodeCompletionString::CK_Equal: + return CXCompletionChunk_Equal; + case CodeCompletionString::CK_HorizontalSpace: + return CXCompletionChunk_HorizontalSpace; + case CodeCompletionString::CK_VerticalSpace: + return CXCompletionChunk_VerticalSpace; + } + + llvm_unreachable("Invalid CompletionKind!"); +} + +CXString clang_getCompletionChunkText(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return createCXString((const char*)0); + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + 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_Optional: + // Note: treated as an empty text block. + return createCXString(""); + } + + llvm_unreachable("Invalid CodeCompletionString Kind!"); +} + + +CXCompletionString +clang_getCompletionChunkCompletionString(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return 0; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: + return 0; + + case CodeCompletionString::CK_Optional: + // Note: treated as an empty text block. + return (*CCStr)[chunk_number].Optional; + } + + llvm_unreachable("Invalid CompletionKind!"); +} + +unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? CCStr->size() : 0; +} + +unsigned clang_getCompletionPriority(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); +} + +enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? static_cast<CXAvailabilityKind>(CCStr->getAvailability()) + : CXAvailability_Available; +} + +unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string) +{ + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? CCStr->getAnnotationCount() : 0; +} + +CXString clang_getCompletionAnnotation(CXCompletionString completion_string, + unsigned annotation_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? createCXString(CCStr->getAnnotation(annotation_number)) + : createCXString((const char *) 0); +} + +CXString +clang_getCompletionParent(CXCompletionString completion_string, + CXCursorKind *kind) { + if (kind) + *kind = CXCursor_NotImplemented; + + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr) + return createCXString((const char *)0); + + if (kind) + *kind = CCStr->getParentContextKind(); + return createCXString(CCStr->getParentContextName(), /*DupString=*/false); +} + +/// \brief The CXCodeCompleteResults structure we allocate internally; +/// the client only sees the initial CXCodeCompleteResults structure. +struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { + AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts); + ~AllocatedCXCodeCompleteResults(); + + /// \brief Diagnostics produced while performing code completion. + SmallVector<StoredDiagnostic, 8> Diagnostics; + + /// \brief Diag object + IntrusiveRefCntPtr<DiagnosticsEngine> Diag; + + /// \brief Language options used to adjust source locations. + LangOptions LangOpts; + + FileSystemOptions FileSystemOpts; + + /// \brief File manager, used for diagnostics. + IntrusiveRefCntPtr<FileManager> FileMgr; + + /// \brief Source manager, used for diagnostics. + IntrusiveRefCntPtr<SourceManager> SourceMgr; + + /// \brief Temporary files that should be removed once we have finished + /// with the code-completion results. + std::vector<llvm::sys::Path> TemporaryFiles; + + /// \brief Temporary buffers that will be deleted once we have finished with + /// the code-completion results. + SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; + + /// \brief Allocator used to store globally cached code-completion results. + IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + + /// \brief Allocator used to store code completion results. + IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator> + CodeCompletionAllocator; + + /// \brief Context under which completion occurred. + enum clang::CodeCompletionContext::Kind ContextKind; + + /// \brief A bitfield representing the acceptable completions for the + /// current context. + unsigned long long Contexts; + + /// \brief The kind of the container for the current context for completions. + enum CXCursorKind ContainerKind; + /// \brief The USR of the container for the current context for completions. + CXString ContainerUSR; + /// \brief a boolean value indicating whether there is complete information + /// about the container + unsigned ContainerIsIncomplete; + + /// \brief A string containing the Objective-C selector entered thus far for a + /// message send. + std::string Selector; +}; + +/// \brief Tracks the number of code-completion result objects that are +/// currently active. +/// +/// Used for debugging purposes only. +static llvm::sys::cas_flag CodeCompletionResultObjects; + +AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( + const FileSystemOptions& FileSystemOpts) + : CXCodeCompleteResults(), + Diag(new DiagnosticsEngine( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))), + FileSystemOpts(FileSystemOpts), + FileMgr(new FileManager(FileSystemOpts)), + SourceMgr(new SourceManager(*Diag, *FileMgr)), + CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator), + Contexts(CXCompletionContext_Unknown), + ContainerKind(CXCursor_InvalidCode), + ContainerUSR(createCXString("")), + ContainerIsIncomplete(1) +{ + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicIncrement(&CodeCompletionResultObjects); + fprintf(stderr, "+++ %d completion results\n", CodeCompletionResultObjects); + } +} + +AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { + delete [] Results; + + clang_disposeString(ContainerUSR); + + for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) + TemporaryFiles[I].eraseFromDisk(); + for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) + delete TemporaryBuffers[I]; + + if (getenv("LIBCLANG_OBJTRACKING")) { + llvm::sys::AtomicDecrement(&CodeCompletionResultObjects); + fprintf(stderr, "--- %d completion results\n", CodeCompletionResultObjects); + } +} + +} // end extern "C" + +static unsigned long long getContextsForContextKind( + enum CodeCompletionContext::Kind kind, + Sema &S) { + unsigned long long contexts = 0; + switch (kind) { + case CodeCompletionContext::CCC_OtherWithMacros: { + //We can allow macros here, but we don't know what else is permissible + //So we'll say the only thing permissible are macros + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_TopLevel: + case CodeCompletionContext::CCC_ObjCIvarList: + case CodeCompletionContext::CCC_ClassStructUnion: + case CodeCompletionContext::CCC_Type: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Statement: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Expression: { + contexts = CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCMessageReceiver: { + contexts = CXCompletionContext_ObjCObjectValue | + CXCompletionContext_ObjCSelectorValue | + CXCompletionContext_ObjCInterface; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_CXXClassTypeValue | + CXCompletionContext_AnyType | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_DotMemberAccess: { + contexts = CXCompletionContext_DotMemberAccess; + break; + } + case CodeCompletionContext::CCC_ArrowMemberAccess: { + contexts = CXCompletionContext_ArrowMemberAccess; + break; + } + case CodeCompletionContext::CCC_ObjCPropertyAccess: { + contexts = CXCompletionContext_ObjCPropertyAccess; + break; + } + case CodeCompletionContext::CCC_EnumTag: { + contexts = CXCompletionContext_EnumTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_UnionTag: { + contexts = CXCompletionContext_UnionTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ClassOrStructTag: { + contexts = CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ObjCProtocolName: { + contexts = CXCompletionContext_ObjCProtocol; + break; + } + case CodeCompletionContext::CCC_Namespace: { + contexts = CXCompletionContext_Namespace; + break; + } + case CodeCompletionContext::CCC_PotentiallyQualifiedName: { + contexts = CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_MacroNameUse: { + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_NaturalLanguage: { + contexts = CXCompletionContext_NaturalLanguage; + break; + } + case CodeCompletionContext::CCC_SelectorName: { + contexts = CXCompletionContext_ObjCSelectorName; + break; + } + case CodeCompletionContext::CCC_ParenthesizedExpression: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCInstanceMessage: { + contexts = CXCompletionContext_ObjCInstanceMessage; + break; + } + case CodeCompletionContext::CCC_ObjCClassMessage: { + contexts = CXCompletionContext_ObjCClassMessage; + break; + } + case CodeCompletionContext::CCC_ObjCInterfaceName: { + contexts = CXCompletionContext_ObjCInterface; + break; + } + case CodeCompletionContext::CCC_ObjCCategoryName: { + contexts = CXCompletionContext_ObjCCategory; + break; + } + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_ObjCInterface: + case CodeCompletionContext::CCC_ObjCImplementation: + case CodeCompletionContext::CCC_Name: + case CodeCompletionContext::CCC_MacroName: + case CodeCompletionContext::CCC_PreprocessorExpression: + case CodeCompletionContext::CCC_PreprocessorDirective: + case CodeCompletionContext::CCC_TypeQualifiers: { + //Only Clang results should be accepted, so we'll set all of the other + //context bits to 0 (i.e. the empty set) + contexts = CXCompletionContext_Unexposed; + break; + } + case CodeCompletionContext::CCC_Recovery: { + //We don't know what the current context is, so we'll return unknown + //This is the equivalent of setting all of the other context bits + contexts = CXCompletionContext_Unknown; + break; + } + } + return contexts; +} + +namespace { + class CaptureCompletionResults : public CodeCompleteConsumer { + AllocatedCXCodeCompleteResults &AllocatedResults; + CodeCompletionTUInfo CCTUInfo; + SmallVector<CXCompletionResult, 16> StoredResults; + CXTranslationUnit *TU; + public: + CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results, + CXTranslationUnit *TranslationUnit) + : CodeCompleteConsumer(true, false, true, false), + AllocatedResults(Results), CCTUInfo(Results.CodeCompletionAllocator), + TU(TranslationUnit) { } + ~CaptureCompletionResults() { Finish(); } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { + StoredResults.reserve(StoredResults.size() + NumResults); + for (unsigned I = 0; I != NumResults; ++I) { + CodeCompletionString *StoredCompletion + = Results[I].CreateCodeCompletionString(S, getAllocator(), + getCodeCompletionTUInfo()); + + CXCompletionResult R; + R.CursorKind = Results[I].CursorKind; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); + } + + enum CodeCompletionContext::Kind contextKind = Context.getKind(); + + AllocatedResults.ContextKind = contextKind; + AllocatedResults.Contexts = getContextsForContextKind(contextKind, S); + + AllocatedResults.Selector = ""; + if (Context.getNumSelIdents() > 0) { + for (unsigned i = 0; i < Context.getNumSelIdents(); i++) { + IdentifierInfo *selIdent = Context.getSelIdents()[i]; + if (selIdent != NULL) { + StringRef selectorString = Context.getSelIdents()[i]->getName(); + AllocatedResults.Selector += selectorString; + } + AllocatedResults.Selector += ":"; + } + } + + QualType baseType = Context.getBaseType(); + NamedDecl *D = NULL; + + if (!baseType.isNull()) { + // Get the declaration for a class/struct/union/enum type + if (const TagType *Tag = baseType->getAs<TagType>()) + D = Tag->getDecl(); + // Get the @interface declaration for a (possibly-qualified) Objective-C + // object pointer type, e.g., NSString* + else if (const ObjCObjectPointerType *ObjPtr = + baseType->getAs<ObjCObjectPointerType>()) + D = ObjPtr->getInterfaceDecl(); + // Get the @interface declaration for an Objective-C object type + else if (const ObjCObjectType *Obj = baseType->getAs<ObjCObjectType>()) + D = Obj->getInterface(); + // Get the class for a C++ injected-class-name + else if (const InjectedClassNameType *Injected = + baseType->getAs<InjectedClassNameType>()) + D = Injected->getDecl(); + } + + if (D != NULL) { + CXCursor cursor = cxcursor::MakeCXCursor(D, *TU); + + CXCursorKind cursorKind = clang_getCursorKind(cursor); + CXString cursorUSR = clang_getCursorUSR(cursor); + + // Normally, clients of CXString shouldn't care whether or not + // a CXString is managed by a pool or by explicitly malloc'ed memory. + // However, there are cases when AllocatedResults outlives the + // CXTranslationUnit. This is a workaround that failure mode. + if (cxstring::isManagedByPool(cursorUSR)) { + CXString heapStr = + cxstring::createCXString(clang_getCString(cursorUSR), true); + clang_disposeString(cursorUSR); + cursorUSR = heapStr; + } + + AllocatedResults.ContainerKind = cursorKind; + AllocatedResults.ContainerUSR = cursorUSR; + + const Type *type = baseType.getTypePtrOrNull(); + if (type != NULL) { + AllocatedResults.ContainerIsIncomplete = type->isIncompleteType(); + } + else { + AllocatedResults.ContainerIsIncomplete = 1; + } + } + else { + AllocatedResults.ContainerKind = CXCursor_InvalidCode; + AllocatedResults.ContainerUSR = createCXString(""); + AllocatedResults.ContainerIsIncomplete = 1; + } + } + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + StoredResults.reserve(StoredResults.size() + NumCandidates); + for (unsigned I = 0; I != NumCandidates; ++I) { + CodeCompletionString *StoredCompletion + = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(), + getCodeCompletionTUInfo()); + + CXCompletionResult R; + R.CursorKind = CXCursor_NotImplemented; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); + } + } + + virtual CodeCompletionAllocator &getAllocator() { + return *AllocatedResults.CodeCompletionAllocator; + } + + virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { return CCTUInfo; } + + private: + void Finish() { + AllocatedResults.Results = new CXCompletionResult [StoredResults.size()]; + AllocatedResults.NumResults = StoredResults.size(); + std::memcpy(AllocatedResults.Results, StoredResults.data(), + StoredResults.size() * sizeof(CXCompletionResult)); + StoredResults.clear(); + } + }; +} + +extern "C" { +struct CodeCompleteAtInfo { + CXTranslationUnit TU; + const char *complete_filename; + unsigned complete_line; + unsigned complete_column; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXCodeCompleteResults *result; +}; +void clang_codeCompleteAt_Impl(void *UserData) { + CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); + CXTranslationUnit TU = CCAI->TU; + const char *complete_filename = CCAI->complete_filename; + unsigned complete_line = CCAI->complete_line; + unsigned complete_column = CCAI->complete_column; + struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files; + unsigned num_unsaved_files = CCAI->num_unsaved_files; + unsigned options = CCAI->options; + CCAI->result = 0; + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); +#endif +#endif + + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; + + ASTUnit *AST = static_cast<ASTUnit *>(TU->TUData); + if (!AST) + return; + + CIndexer *CXXIdx = (CIndexer*)TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + ASTUnit::ConcurrencyCheck Check(*AST); + + // Perform the remapping of source files. + SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + 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)); + } + + if (EnableLogging) { + // FIXME: Add logging. + } + + // Parse the resulting source file to find code-completion results. + AllocatedCXCodeCompleteResults *Results = + new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts()); + Results->Results = 0; + Results->NumResults = 0; + + // Create a code-completion consumer to capture the results. + CaptureCompletionResults Capture(*Results, &TU); + + // Perform completion. + AST->CodeComplete(complete_filename, complete_line, complete_column, + RemappedFiles.data(), RemappedFiles.size(), + (options & CXCodeComplete_IncludeMacros), + (options & CXCodeComplete_IncludeCodePatterns), + Capture, + *Results->Diag, Results->LangOpts, *Results->SourceMgr, + *Results->FileMgr, Results->Diagnostics, + Results->TemporaryBuffers); + + // Keep a reference to the allocator used for cached global completions, so + // that we can be sure that the memory used by our code completion strings + // doesn't get freed due to subsequent reparses (while the code completion + // results are still active). + Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); + + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); + SmallString<256> LogResult; + llvm::raw_svector_ostream os(LogResult); + + // Figure out the language and whether or not it uses PCH. + const char *lang = 0; + bool usesPCH = false; + + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I != E; ++I) { + if (*I == 0) + continue; + if (strcmp(*I, "-x") == 0) { + if (I + 1 != E) { + lang = *(++I); + continue; + } + } + else if (strcmp(*I, "-include") == 0) { + if (I+1 != E) { + const char *arg = *(++I); + SmallString<512> pchName; + { + llvm::raw_svector_ostream os(pchName); + os << arg << ".pth"; + } + pchName.push_back('\0'); + struct stat stat_results; + if (stat(pchName.str().c_str(), &stat_results) == 0) + usesPCH = true; + continue; + } + } + } + + os << "{ "; + os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); + os << ", \"numRes\": " << Results->NumResults; + os << ", \"diags\": " << Results->Diagnostics.size(); + os << ", \"pch\": " << (usesPCH ? "true" : "false"); + os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; + const char *name = getlogin(); + os << ", \"user\": \"" << (name ? name : "unknown") << '"'; + os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; + os << " }"; + + StringRef res = os.str(); + if (res.size() > 0) { + do { + // Setup the UDP socket. + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); + if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, + &servaddr.sin_addr) <= 0) + break; + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + break; + + sendto(sockfd, res.data(), res.size(), 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + close(sockfd); + } + while (false); + } +#endif +#endif + CCAI->result = Results; +} +CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + CodeCompleteAtInfo CCAI = { TU, complete_filename, complete_line, + complete_column, unsaved_files, num_unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_codeCompleteAt_Impl, &CCAI)) { + fprintf(stderr, "libclang: crash detected in code completion\n"); + static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true); + return 0; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return CCAI.result; +} + +unsigned clang_defaultCodeCompleteOptions(void) { + return CXCodeComplete_IncludeMacros; +} + +void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { + if (!ResultsIn) + return; + + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + delete Results; +} + +unsigned +clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results) + return 0; + + return Results->Diagnostics.size(); +} + +CXDiagnostic +clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, + unsigned Index) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results || Index >= Results->Diagnostics.size()) + return 0; + + return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); +} + +unsigned long long +clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results) + return 0; + + return Results->Contexts; +} + +enum CXCursorKind clang_codeCompleteGetContainerKind( + CXCodeCompleteResults *ResultsIn, + unsigned *IsIncomplete) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return CXCursor_InvalidCode; + + if (IsIncomplete != NULL) { + *IsIncomplete = Results->ContainerIsIncomplete; + } + + return Results->ContainerKind; +} + +CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return createCXString(""); + + return createCXString(clang_getCString(Results->ContainerUSR)); +} + + +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return createCXString(""); + + return createCXString(Results->Selector); +} + +} // end extern "C" + +/// \brief Simple utility function that appends a \p New string to the given +/// \p Old string, using the \p Buffer for storage. +/// +/// \param Old The string to which we are appending. This parameter will be +/// updated to reflect the complete string. +/// +/// +/// \param New The string to append to \p Old. +/// +/// \param Buffer A buffer that stores the actual, concatenated string. It will +/// be used if the old string is already-non-empty. +static void AppendToString(StringRef &Old, StringRef New, + SmallString<256> &Buffer) { + if (Old.empty()) { + Old = New; + return; + } + + if (Buffer.empty()) + Buffer.append(Old.begin(), Old.end()); + Buffer.append(New.begin(), New.end()); + Old = Buffer.str(); +} + +/// \brief Get the typed-text blocks from the given code-completion string +/// and return them as a single string. +/// +/// \param String The code-completion string whose typed-text blocks will be +/// concatenated. +/// +/// \param Buffer A buffer used for storage of the completed name. +static StringRef GetTypedName(CodeCompletionString *String, + SmallString<256> &Buffer) { + StringRef Result; + for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end(); + C != CEnd; ++C) { + if (C->Kind == CodeCompletionString::CK_TypedText) + AppendToString(Result, C->Text, Buffer); + } + + return Result; +} + +namespace { + struct OrderCompletionResults { + bool operator()(const CXCompletionResult &XR, + const CXCompletionResult &YR) const { + CodeCompletionString *X + = (CodeCompletionString *)XR.CompletionString; + CodeCompletionString *Y + = (CodeCompletionString *)YR.CompletionString; + + SmallString<256> XBuffer; + StringRef XText = GetTypedName(X, XBuffer); + SmallString<256> YBuffer; + StringRef YText = GetTypedName(Y, YBuffer); + + if (XText.empty() || YText.empty()) + return !XText.empty(); + + int result = XText.compare_lower(YText); + if (result < 0) + return true; + if (result > 0) + return false; + + result = XText.compare(YText); + return result < 0; + } + }; +} + +extern "C" { + void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults) { + std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); + } +} diff --git a/clang/tools/libclang/CIndexDiagnostic.cpp b/clang/tools/libclang/CIndexDiagnostic.cpp new file mode 100644 index 0000000..8fbe3d8 --- /dev/null +++ b/clang/tools/libclang/CIndexDiagnostic.cpp @@ -0,0 +1,458 @@ +/*===-- CIndexDiagnostics.cpp - Diagnostics C Interface ---------*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements the diagnostic functions of the Clang C interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ +#include "CIndexDiagnostic.h" +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXSourceLocation.h" +#include "CXString.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/DiagnosticRenderer.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::cxloc; +using namespace clang::cxstring; +using namespace clang::cxdiag; +using namespace llvm; + + +CXDiagnosticSetImpl::~CXDiagnosticSetImpl() { + for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(), + et = Diagnostics.end(); + it != et; ++it) { + delete *it; + } +} + +CXDiagnosticImpl::~CXDiagnosticImpl() {} + +namespace { +class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl { + std::string Message; + CXSourceLocation Loc; +public: + CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L) + : CXDiagnosticImpl(CustomNoteDiagnosticKind), + Message(Msg), Loc(L) {} + + virtual ~CXDiagnosticCustomNoteImpl() {} + + CXDiagnosticSeverity getSeverity() const { + return CXDiagnostic_Note; + } + + CXSourceLocation getLocation() const { + return Loc; + } + + CXString getSpelling() const { + return createCXString(StringRef(Message), false); + } + + CXString getDiagnosticOption(CXString *Disable) const { + if (Disable) + *Disable = createCXString("", false); + return createCXString("", false); + } + + unsigned getCategory() const { return 0; } + CXString getCategoryText() const { return createCXString(""); } + + unsigned getNumRanges() const { return 0; } + CXSourceRange getRange(unsigned Range) const { return clang_getNullRange(); } + unsigned getNumFixIts() const { return 0; } + CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const { + if (ReplacementRange) + *ReplacementRange = clang_getNullRange(); + return createCXString("", false); + } +}; + +class CXDiagnosticRenderer : public DiagnosticNoteRenderer { +public: + CXDiagnosticRenderer(const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts, + CXDiagnosticSetImpl *mainSet) + : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts), + CurrentSet(mainSet), MainSet(mainSet) {} + + virtual ~CXDiagnosticRenderer() {} + + virtual void beginDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) { + + const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>(); + if (!SD) + return; + + if (Level != DiagnosticsEngine::Note) + CurrentSet = MainSet; + + CXStoredDiagnostic *CD = new CXStoredDiagnostic(*SD, LangOpts); + CurrentSet->appendDiagnostic(CD); + + if (Level != DiagnosticsEngine::Note) + CurrentSet = &CD->getChildDiagnostics(); + } + + virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + ArrayRef<CharSourceRange> Ranges, + DiagOrStoredDiag D) { + if (!D.isNull()) + return; + + CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc); + CXDiagnosticImpl *CD = new CXDiagnosticCustomNoteImpl(Message, L); + CurrentSet->appendDiagnostic(CD); + } + + virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges) {} + + virtual void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints) {} + + virtual void emitNote(SourceLocation Loc, StringRef Message) { + CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc); + CurrentSet->appendDiagnostic(new CXDiagnosticCustomNoteImpl(Message, + L)); + } + + CXDiagnosticSetImpl *CurrentSet; + CXDiagnosticSetImpl *MainSet; +}; +} + +CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU, + bool checkIfChanged) { + ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData); + + if (TU->Diagnostics && checkIfChanged) { + // In normal use, ASTUnit's diagnostics should not change unless we reparse. + // Currently they can only change by using the internal testing flag + // '-error-on-deserialized-decl' which will error during deserialization of + // a declaration. What will happen is: + // + // -c-index-test gets a CXTranslationUnit + // -checks the diagnostics, the diagnostics set is lazily created, + // no errors are reported + // -later does an operation, like annotation of tokens, that triggers + // -error-on-deserialized-decl, that will emit a diagnostic error, + // that ASTUnit will catch and add to its stored diagnostics vector. + // -c-index-test wants to check whether an error occurred after performing + // the operation but can only query the lazily created set. + // + // We check here if a new diagnostic was appended since the last time the + // diagnostic set was created, in which case we reset it. + + CXDiagnosticSetImpl * + Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); + if (AU->stored_diag_size() != Set->getNumDiagnostics()) { + // Diagnostics in the ASTUnit were updated, reset the associated + // diagnostics. + delete Set; + TU->Diagnostics = 0; + } + } + + if (!TU->Diagnostics) { + CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl(); + TU->Diagnostics = Set; + DiagnosticOptions DOpts; + CXDiagnosticRenderer Renderer(AU->getSourceManager(), + AU->getASTContext().getLangOpts(), + DOpts, Set); + + for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(), + ei = AU->stored_diag_end(); it != ei; ++it) { + Renderer.emitStoredDiagnostic(*it); + } + } + return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); +} + +//----------------------------------------------------------------------------- +// C Interface Routines +//----------------------------------------------------------------------------- +extern "C" { + +unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { + if (!Unit->TUData) + return 0; + return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics(); +} + +CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { + CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit); + if (!D) + return 0; + + CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D); + if (Index >= Diags->getNumDiagnostics()) + return 0; + + return Diags->getDiagnostic(Index); +} + +CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) { + if (!Unit->TUData) + return 0; + return static_cast<CXDiagnostic>(lazyCreateDiags(Unit)); +} + +void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { + // No-op. Kept as a legacy API. CXDiagnostics are now managed + // by the enclosing CXDiagnosticSet. +} + +CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { + if (!Diagnostic) + return createCXString(""); + + CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); + + SmallString<256> Str; + llvm::raw_svector_ostream Out(Str); + + if (Options & CXDiagnostic_DisplaySourceLocation) { + // Print source location (file:line), along with optional column + // and source ranges. + CXFile File; + unsigned Line, Column; + clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), + &File, &Line, &Column, 0); + if (File) { + CXString FName = clang_getFileName(File); + Out << clang_getCString(FName) << ":" << Line << ":"; + clang_disposeString(FName); + if (Options & CXDiagnostic_DisplayColumn) + Out << Column << ":"; + + if (Options & CXDiagnostic_DisplaySourceRanges) { + unsigned N = clang_getDiagnosticNumRanges(Diagnostic); + bool PrintedRange = false; + for (unsigned I = 0; I != N; ++I) { + CXFile StartFile, EndFile; + CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); + + unsigned StartLine, StartColumn, EndLine, EndColumn; + clang_getSpellingLocation(clang_getRangeStart(Range), + &StartFile, &StartLine, &StartColumn, + 0); + clang_getSpellingLocation(clang_getRangeEnd(Range), + &EndFile, &EndLine, &EndColumn, 0); + + if (StartFile != EndFile || StartFile != File) + continue; + + Out << "{" << StartLine << ":" << StartColumn << "-" + << EndLine << ":" << EndColumn << "}"; + PrintedRange = true; + } + if (PrintedRange) + Out << ":"; + } + + Out << " "; + } + } + + /* Print warning/error/etc. */ + switch (Severity) { + case CXDiagnostic_Ignored: llvm_unreachable("impossible"); + case CXDiagnostic_Note: Out << "note: "; break; + case CXDiagnostic_Warning: Out << "warning: "; break; + case CXDiagnostic_Error: Out << "error: "; break; + case CXDiagnostic_Fatal: Out << "fatal error: "; break; + } + + CXString Text = clang_getDiagnosticSpelling(Diagnostic); + if (clang_getCString(Text)) + Out << clang_getCString(Text); + else + Out << "<no diagnostic text>"; + clang_disposeString(Text); + + if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + bool NeedBracket = true; + bool NeedComma = false; + + if (Options & CXDiagnostic_DisplayOption) { + CXString OptionName = clang_getDiagnosticOption(Diagnostic, 0); + if (const char *OptionText = clang_getCString(OptionName)) { + if (OptionText[0]) { + Out << " [" << OptionText; + NeedBracket = false; + NeedComma = true; + } + } + clang_disposeString(OptionName); + } + + if (Options & (CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { + if (Options & CXDiagnostic_DisplayCategoryId) { + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << CategoryID; + NeedBracket = false; + NeedComma = true; + } + + if (Options & CXDiagnostic_DisplayCategoryName) { + CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic); + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << clang_getCString(CategoryName); + NeedBracket = false; + NeedComma = true; + clang_disposeString(CategoryName); + } + } + } + + (void) NeedComma; // Silence dead store warning. + if (!NeedBracket) + Out << "]"; + } + + return createCXString(Out.str(), true); +} + +unsigned clang_defaultDiagnosticDisplayOptions() { + return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | + CXDiagnostic_DisplayOption; +} + +enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) + return D->getSeverity(); + return CXDiagnostic_Ignored; +} + +CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) + return D->getLocation(); + return clang_getNullLocation(); +} + +CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getSpelling(); + return createCXString(""); +} + +CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { + if (Disable) + *Disable = createCXString(""); + + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getDiagnosticOption(Disable); + + return createCXString(""); +} + +unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getCategory(); + return 0; +} + +CXString clang_getDiagnosticCategoryName(unsigned Category) { + // Kept for backwards compatibility. + return createCXString(DiagnosticIDs::getCategoryNameFromID(Category)); +} + +CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getCategoryText(); + return createCXString(""); +} + +unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getNumRanges(); + return 0; +} + +CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { + CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); + if (!D || Range >= D->getNumRanges()) + return clang_getNullRange(); + return D->getRange(Range); +} + +unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getNumFixIts(); + return 0; +} + +CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt, + CXSourceRange *ReplacementRange) { + CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); + if (!D || FixIt >= D->getNumFixIts()) { + if (ReplacementRange) + *ReplacementRange = clang_getNullRange(); + return createCXString(""); + } + return D->getFixIt(FixIt, ReplacementRange); +} + +void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { + CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags); + if (D->isExternallyManaged()) + delete D; +} + +CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, + unsigned Index) { + if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) + if (Index < D->getNumDiagnostics()) + return D->getDiagnostic(Index); + return 0; +} + +CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) { + CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics(); + return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags; + } + return 0; +} + +unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) { + if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) + return D->getNumDiagnostics(); + return 0; +} + +} // end extern "C" diff --git a/clang/tools/libclang/CIndexDiagnostic.h b/clang/tools/libclang/CIndexDiagnostic.h new file mode 100644 index 0000000..b1c3978 --- /dev/null +++ b/clang/tools/libclang/CIndexDiagnostic.h @@ -0,0 +1,166 @@ +/*===-- CIndexDiagnostic.h - Diagnostics C Interface ------------*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements the diagnostic functions of the Clang C interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ +#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H +#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H + +#include "clang-c/Index.h" +#include <vector> +#include <assert.h> + +namespace clang { + +class LangOptions; +class StoredDiagnostic; +class CXDiagnosticImpl; + +class CXDiagnosticSetImpl { + std::vector<CXDiagnosticImpl *> Diagnostics; + const bool IsExternallyManaged; +public: + CXDiagnosticSetImpl(bool isManaged = false) + : IsExternallyManaged(isManaged) {} + + virtual ~CXDiagnosticSetImpl(); + + size_t getNumDiagnostics() const { + return Diagnostics.size(); + } + + CXDiagnosticImpl *getDiagnostic(unsigned i) const { + assert(i < getNumDiagnostics()); + return Diagnostics[i]; + } + + void appendDiagnostic(CXDiagnosticImpl *D) { + Diagnostics.push_back(D); + } + + bool empty() const { + return Diagnostics.empty(); + } + + bool isExternallyManaged() const { return IsExternallyManaged; } +}; + +class CXDiagnosticImpl { +public: + enum Kind { StoredDiagnosticKind, LoadedDiagnosticKind, + CustomNoteDiagnosticKind }; + + virtual ~CXDiagnosticImpl(); + + /// \brief Return the severity of the diagnostic. + virtual CXDiagnosticSeverity getSeverity() const = 0; + + /// \brief Return the location of the diagnostic. + virtual CXSourceLocation getLocation() const = 0; + + /// \brief Return the spelling of the diagnostic. + virtual CXString getSpelling() const = 0; + + /// \brief Return the text for the diagnostic option. + virtual CXString getDiagnosticOption(CXString *Disable) const = 0; + + /// \brief Return the category of the diagnostic. + virtual unsigned getCategory() const = 0; + + /// \brief Return the category string of the diagnostic. + virtual CXString getCategoryText() const = 0; + + /// \brief Return the number of source ranges for the diagnostic. + virtual unsigned getNumRanges() const = 0; + + /// \brief Return the source ranges for the diagnostic. + virtual CXSourceRange getRange(unsigned Range) const = 0; + + /// \brief Return the number of FixIts. + virtual unsigned getNumFixIts() const = 0; + + /// \brief Return the FixIt information (source range and inserted text). + virtual CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const = 0; + + Kind getKind() const { return K; } + + CXDiagnosticSetImpl &getChildDiagnostics() { + return ChildDiags; + } + +protected: + CXDiagnosticImpl(Kind k) : K(k) {} + CXDiagnosticSetImpl ChildDiags; + + void append(CXDiagnosticImpl *D) { + ChildDiags.appendDiagnostic(D); + } + +private: + Kind K; +}; + +/// \brief The storage behind a CXDiagnostic +struct CXStoredDiagnostic : public CXDiagnosticImpl { + const StoredDiagnostic &Diag; + const LangOptions &LangOpts; + + CXStoredDiagnostic(const StoredDiagnostic &Diag, + const LangOptions &LangOpts) + : CXDiagnosticImpl(StoredDiagnosticKind), + Diag(Diag), LangOpts(LangOpts) { } + + virtual ~CXStoredDiagnostic() {} + + /// \brief Return the severity of the diagnostic. + virtual CXDiagnosticSeverity getSeverity() const; + + /// \brief Return the location of the diagnostic. + virtual CXSourceLocation getLocation() const; + + /// \brief Return the spelling of the diagnostic. + virtual CXString getSpelling() const; + + /// \brief Return the text for the diagnostic option. + virtual CXString getDiagnosticOption(CXString *Disable) const; + + /// \brief Return the category of the diagnostic. + virtual unsigned getCategory() const; + + /// \brief Return the category string of the diagnostic. + virtual CXString getCategoryText() const; + + /// \brief Return the number of source ranges for the diagnostic. + virtual unsigned getNumRanges() const; + + /// \brief Return the source ranges for the diagnostic. + virtual CXSourceRange getRange(unsigned Range) const; + + /// \brief Return the number of FixIts. + virtual unsigned getNumFixIts() const; + + /// \brief Return the FixIt information (source range and inserted text). + virtual CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const; + + static bool classof(const CXDiagnosticImpl *D) { + return D->getKind() == StoredDiagnosticKind; + } +}; + +namespace cxdiag { +CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU, + bool checkIfChanged = false); +} // end namespace cxdiag + +} // end namespace clang + +#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H diff --git a/clang/tools/libclang/CIndexHigh.cpp b/clang/tools/libclang/CIndexHigh.cpp new file mode 100644 index 0000000..ec76898 --- /dev/null +++ b/clang/tools/libclang/CIndexHigh.cpp @@ -0,0 +1,423 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CursorVisitor.h" +#include "CXCursor.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/DeclObjC.h" + +using namespace clang; +using namespace cxcursor; + +static void getTopOverriddenMethods(CXTranslationUnit TU, + Decl *D, + SmallVectorImpl<Decl *> &Methods) { + if (!D) + return; + if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D)) + return; + + SmallVector<CXCursor, 8> Overridden; + cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden); + + if (Overridden.empty()) { + Methods.push_back(D->getCanonicalDecl()); + return; + } + + for (SmallVector<CXCursor, 8>::iterator + I = Overridden.begin(), E = Overridden.end(); I != E; ++I) + getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods); +} + +namespace { + +struct FindFileIdRefVisitData { + CXTranslationUnit TU; + FileID FID; + Decl *Dcl; + int SelectorIdIdx; + CXCursorAndRangeVisitor visitor; + + typedef SmallVector<Decl *, 8> TopMethodsTy; + TopMethodsTy TopMethods; + + FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID, + Decl *D, int selectorIdIdx, + CXCursorAndRangeVisitor visitor) + : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) { + Dcl = getCanonical(D); + getTopOverriddenMethods(TU, Dcl, TopMethods); + } + + ASTContext &getASTContext() const { + return static_cast<ASTUnit *>(TU->TUData)->getASTContext(); + } + + /// \brief We are looking to find all semantically relevant identifiers, + /// so the definition of "canonical" here is different than in the AST, e.g. + /// + /// \code + /// class C { + /// C() {} + /// }; + /// \endcode + /// + /// we consider the canonical decl of the constructor decl to be the class + /// itself, so both 'C' can be highlighted. + Decl *getCanonical(Decl *D) const { + if (!D) + return 0; + + D = D->getCanonicalDecl(); + + if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) { + if (ImplD->getClassInterface()) + return getCanonical(ImplD->getClassInterface()); + + } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) { + return getCanonical(CXXCtorD->getParent()); + } + + return D; + } + + bool isHit(Decl *D) const { + if (!D) + return false; + + D = getCanonical(D); + if (D == Dcl) + return true; + + if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D)) + return isOverriddingMethod(D); + + return false; + } + +private: + bool isOverriddingMethod(Decl *D) const { + if (std::find(TopMethods.begin(), TopMethods.end(), D) != + TopMethods.end()) + return true; + + TopMethodsTy methods; + getTopOverriddenMethods(TU, D, methods); + for (TopMethodsTy::iterator + I = methods.begin(), E = methods.end(); I != E; ++I) { + if (std::find(TopMethods.begin(), TopMethods.end(), *I) != + TopMethods.end()) + return true; + } + + return false; + } +}; + +} // end anonymous namespace. + +/// \brief For a macro \arg Loc, returns the file spelling location and sets +/// to \arg isMacroArg whether the spelling resides inside a macro definition or +/// a macro argument. +static SourceLocation getFileSpellingLoc(SourceManager &SM, + SourceLocation Loc, + bool &isMacroArg) { + assert(Loc.isMacroID()); + SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc); + if (SpellLoc.isMacroID()) + return getFileSpellingLoc(SM, SpellLoc, isMacroArg); + + isMacroArg = SM.isMacroArgExpansion(Loc); + return SpellLoc; +} + +static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + CXCursor declCursor = clang_getCursorReferenced(cursor); + if (!clang_isDeclaration(declCursor.kind)) + return CXChildVisit_Recurse; + + Decl *D = cxcursor::getCursorDecl(declCursor); + if (!D) + return CXChildVisit_Continue; + + FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data; + if (data->isHit(D)) { + cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor); + + // We are looking for identifiers to highlight so for objc methods (and + // not a parameter) we can only highlight the selector identifiers. + if ((cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) && + cxcursor::getSelectorIdentifierIndex(cursor) == -1) + return CXChildVisit_Recurse; + + if (clang_isExpression(cursor.kind)) { + if (cursor.kind == CXCursor_DeclRefExpr || + cursor.kind == CXCursor_MemberRefExpr) { + // continue.. + + } else if (cursor.kind == CXCursor_ObjCMessageExpr && + cxcursor::getSelectorIdentifierIndex(cursor) != -1) { + // continue.. + + } else + return CXChildVisit_Recurse; + } + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor); + if (SelIdLoc.isValid()) + Loc = SelIdLoc; + + ASTContext &Ctx = data->getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + bool isInMacroDef = false; + if (Loc.isMacroID()) { + bool isMacroArg; + Loc = getFileSpellingLoc(SM, Loc, isMacroArg); + isInMacroDef = !isMacroArg; + } + + // We are looking for identifiers in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first != data->FID) + return CXChildVisit_Recurse; + + if (isInMacroDef) { + // FIXME: For a macro definition make sure that all expansions + // of it expand to the same reference before allowing to point to it. + return CXChildVisit_Recurse; + } + + data->visitor.visit(data->visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)); + } + return CXChildVisit_Recurse; +} + +static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor, + const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + assert(clang_isDeclaration(declCursor.kind)); + ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + + FileID FID = SM.translateFile(File); + Decl *Dcl = cxcursor::getCursorDecl(declCursor); + if (!Dcl) + return; + + FindFileIdRefVisitData data(TU, FID, Dcl, + cxcursor::getSelectorIdentifierIndex(declCursor), + Visitor); + + if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) { + clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU), + findFileIdRefVisit, &data); + return; + } + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor FindIdRefsVisitor(TU, + findFileIdRefVisit, &data, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + Range, + /*VisitDeclsOnly=*/true); + FindIdRefsVisitor.visitFileRegion(); +} + +namespace { + +struct FindFileMacroRefVisitData { + ASTUnit &Unit; + const FileEntry *File; + const IdentifierInfo *Macro; + CXCursorAndRangeVisitor visitor; + + FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File, + const IdentifierInfo *Macro, + CXCursorAndRangeVisitor visitor) + : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { } + + ASTContext &getASTContext() const { + return Unit.getASTContext(); + } +}; + +} // anonymous namespace + +static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + const IdentifierInfo *Macro = 0; + if (cursor.kind == CXCursor_MacroDefinition) + Macro = getCursorMacroDefinition(cursor)->getName(); + else if (cursor.kind == CXCursor_MacroExpansion) + Macro = getCursorMacroExpansion(cursor)->getName(); + if (!Macro) + return CXChildVisit_Continue; + + FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data; + if (data->Macro != Macro) + return CXChildVisit_Continue; + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + + ASTContext &Ctx = data->getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + bool isInMacroDef = false; + if (Loc.isMacroID()) { + bool isMacroArg; + Loc = getFileSpellingLoc(SM, Loc, isMacroArg); + isInMacroDef = !isMacroArg; + } + + // We are looking for identifiers in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (SM.getFileEntryForID(LocInfo.first) != data->File) + return CXChildVisit_Continue; + + if (isInMacroDef) { + // FIXME: For a macro definition make sure that all expansions + // of it expand to the same reference before allowing to point to it. + return CXChildVisit_Continue; + } + + data->visitor.visit(data->visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)); + return CXChildVisit_Continue; +} + +static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor, + const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + if (Cursor.kind != CXCursor_MacroDefinition && + Cursor.kind != CXCursor_MacroExpansion) + return; + + ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + + FileID FID = SM.translateFile(File); + const IdentifierInfo *Macro = 0; + if (Cursor.kind == CXCursor_MacroDefinition) + Macro = getCursorMacroDefinition(Cursor)->getName(); + else + Macro = getCursorMacroExpansion(Cursor)->getName(); + if (!Macro) + return; + + FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor); + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor FindMacroRefsVisitor(TU, + findFileMacroRefVisit, &data, + /*VisitPreprocessorLast=*/false, + /*VisitIncludedEntities=*/false, + Range); + FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion(); +} + + +//===----------------------------------------------------------------------===// +// libclang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +void clang_findReferencesInFile(CXCursor cursor, CXFile file, + CXCursorAndRangeVisitor visitor) { + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + if (clang_Cursor_isNull(cursor)) { + if (Logging) + llvm::errs() << "clang_findReferencesInFile: Null cursor\n"; + return; + } + if (cursor.kind == CXCursor_NoDeclFound) { + if (Logging) + llvm::errs() << "clang_findReferencesInFile: Got CXCursor_NoDeclFound\n"; + return; + } + if (!file) { + if (Logging) + llvm::errs() << "clang_findReferencesInFile: Null file\n"; + return; + } + if (!visitor.visit) { + if (Logging) + llvm::errs() << "clang_findReferencesInFile: Null visitor\n"; + return; + } + + ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor); + if (!CXXUnit) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + if (cursor.kind == CXCursor_MacroDefinition || + cursor.kind == CXCursor_MacroExpansion) { + findMacroRefsInFile(cxcursor::getCursorTU(cursor), + cursor, + static_cast<const FileEntry *>(file), + visitor); + return; + } + + // We are interested in semantics of identifiers so for C++ constructor exprs + // prefer type references, e.g.: + // + // return MyStruct(); + // + // for 'MyStruct' we'll have a cursor pointing at the constructor decl but + // we are actually interested in the type declaration. + cursor = cxcursor::getTypeRefCursor(cursor); + + CXCursor refCursor = clang_getCursorReferenced(cursor); + + if (!clang_isDeclaration(refCursor.kind)) { + if (Logging) + llvm::errs() << "clang_findReferencesInFile: cursor is not referencing a " + "declaration\n"; + return; + } + + findIdRefsInFile(cxcursor::getCursorTU(cursor), + refCursor, + static_cast<const FileEntry *>(file), + visitor); +} + +static enum CXVisitorResult _visitCursorAndRange(void *context, + CXCursor cursor, + CXSourceRange range) { + CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context; + return INVOKE_BLOCK2(block, cursor, range); +} + +void clang_findReferencesInFileWithBlock(CXCursor cursor, + CXFile file, + CXCursorAndRangeVisitorBlock block) { + CXCursorAndRangeVisitor visitor = { block, + block ? _visitCursorAndRange : 0 }; + return clang_findReferencesInFile(cursor, file, visitor); +} + +} // end: extern "C" + diff --git a/clang/tools/libclang/CIndexInclusionStack.cpp b/clang/tools/libclang/CIndexInclusionStack.cpp new file mode 100644 index 0000000..848ca31 --- /dev/null +++ b/clang/tools/libclang/CIndexInclusionStack.cpp @@ -0,0 +1,71 @@ +//===- CIndexInclusionStack.cpp - Clang-C Source Indexing Library ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a callback mechanism for clients to get the inclusion +// stack from a translation unit. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXSourceLocation.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +extern "C" { +void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, + CXClientData clientData) { + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData); + SourceManager &SM = CXXUnit->getSourceManager(); + ASTContext &Ctx = CXXUnit->getASTContext(); + + SmallVector<CXSourceLocation, 10> InclusionStack; + unsigned n = SM.local_sloc_entry_size(); + + // In the case where all the SLocEntries are in an external source, traverse + // those SLocEntries as well. This is the case where we are looking + // at the inclusion stack of an AST/PCH file. + const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const; + if (n == 1) { + Getter = &SourceManager::getLoadedSLocEntry; + n = SM.loaded_sloc_entry_size(); + } else + Getter = &SourceManager::getLocalSLocEntry; + + for (unsigned i = 0 ; i < n ; ++i) { + bool Invalid = false; + const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid); + + if (!SL.isFile() || Invalid) + continue; + + const SrcMgr::FileInfo &FI = SL.getFile(); + if (!FI.getContentCache()->OrigEntry) + continue; + + // Build the inclusion stack. + SourceLocation L = FI.getIncludeLoc(); + InclusionStack.clear(); + while (L.isValid()) { + PresumedLoc PLoc = SM.getPresumedLoc(L); + InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L)); + L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation(); + } + + // Callback to the client. + // FIXME: We should have a function to construct CXFiles. + CB((CXFile) FI.getContentCache()->OrigEntry, + InclusionStack.data(), InclusionStack.size(), clientData); + } +} +} // end extern C diff --git a/clang/tools/libclang/CIndexUSRs.cpp b/clang/tools/libclang/CIndexUSRs.cpp new file mode 100644 index 0000000..7c79b69 --- /dev/null +++ b/clang/tools/libclang/CIndexUSRs.cpp @@ -0,0 +1,932 @@ +//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===// +// +// 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 generation and use of USRs from CXEntities. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXString.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::cxstring; + +//===----------------------------------------------------------------------===// +// USR generation. +//===----------------------------------------------------------------------===// + +namespace { +class USRGenerator : public DeclVisitor<USRGenerator> { + OwningPtr<SmallString<128> > OwnedBuf; + SmallVectorImpl<char> &Buf; + llvm::raw_svector_ostream Out; + bool IgnoreResults; + ASTContext *Context; + bool generatedLoc; + + llvm::DenseMap<const Type *, unsigned> TypeSubstitutions; + +public: + explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0) + : OwnedBuf(extBuf ? 0 : new SmallString<128>()), + Buf(extBuf ? *extBuf : *OwnedBuf.get()), + Out(Buf), + IgnoreResults(false), + Context(Ctx), + generatedLoc(false) + { + // Add the USR space prefix. + Out << "c:"; + } + + 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; } + + // Visitation methods from generating USRs from AST elements. + void VisitDeclContext(DeclContext *D); + void VisitFieldDecl(FieldDecl *D); + void VisitFunctionDecl(FunctionDecl *D); + void VisitNamedDecl(NamedDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitObjCContainerDecl(ObjCContainerDecl *CD); + void VisitObjCMethodDecl(ObjCMethodDecl *MD); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitTagDecl(TagDecl *D); + void VisitTypedefDecl(TypedefDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + void VisitVarDecl(VarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D) { + IgnoreResults = true; + } + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + IgnoreResults = true; + } + void VisitUsingDecl(UsingDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + IgnoreResults = true; + } + + /// Generate the string component containing the location of the + /// declaration. + 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 + /// methods do not construct complete USRs (which incorporate the parents + /// of an AST element), but only the fragments concerning the AST element + /// itself. + + /// Generate a USR for an Objective-C class. + void GenObjCClass(StringRef cls); + /// Generate a USR for an Objective-C class category. + void GenObjCCategory(StringRef cls, StringRef cat); + /// Generate a USR fragment for an Objective-C instance variable. The + /// complete USR can be created by concatenating the USR for the + /// encompassing class with this USR fragment. + void GenObjCIvar(StringRef ivar); + /// Generate a USR fragment for an Objective-C method. + void GenObjCMethod(StringRef sel, bool isInstanceMethod); + /// Generate a USR fragment for an Objective-C property. + void GenObjCProperty(StringRef prop); + /// Generate a USR for an Objective-C protocol. + void GenObjCProtocol(StringRef prot); + + void VisitType(QualType T); + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + + /// 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 + +//===----------------------------------------------------------------------===// +// 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) { + // The USR for an ivar declared in a class extension is based on the + // ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + VisitDeclContext(D->getDeclContext()); + Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@"); + if (EmitDeclName(D)) { + // Bit fields can be anonymous. + IgnoreResults = true; + return; + } +} + +void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { + if (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; + D->printName(Out); + + ASTContext &Ctx = *Context; + if (!Ctx.getLangOpts().CPlusPlus || D->isExternC()) + return; + + if (const TemplateArgumentList * + SpecArgs = D->getTemplateSpecializationArgs()) { + Out << '<'; + for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(SpecArgs->get(I)); + } + Out << '>'; + } + + // 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()); + 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; + } +} + +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 (ShouldGenerateLocation(D) && GenLoc(D)) + return; + + VisitDeclContext(D->getDeclContext()); + + // Variables always have simple names. + StringRef s = D->getName(); + + // 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()) + IgnoreResults = true; + else + Out << '@' << s; +} + +void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { + if (D->isAnonymousNamespace()) { + Out << "@aN"; + return; + } + + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@N@" << D->getName(); +} + +void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + VisitTagDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@NA@" << D->getName(); +} + +void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { + DeclContext *container = D->getDeclContext(); + if (ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) { + Visit(pd); + } + else { + // The USR for a method declared in a class extension or category is based on + // the ObjCInterfaceDecl, not the ObjCCategoryDecl. + ObjCInterfaceDecl *ID = D->getClassInterface(); + if (!ID) { + IgnoreResults = true; + return; + } + Visit(ID); + } + // 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::VisitObjCContainerDecl(ObjCContainerDecl *D) { + switch (D->getKind()) { + default: + llvm_unreachable("Invalid ObjC container."); + case Decl::ObjCInterface: + case Decl::ObjCImplementation: + GenObjCClass(D->getName()); + break; + case Decl::ObjCCategory: { + ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); + ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + // Specially handle class extensions, which are anonymous categories. + // We want to mangle in the location to uniquely distinguish them. + if (CD->IsClassExtension()) { + Out << "objc(ext)" << ID->getName() << '@'; + GenLoc(CD); + } + else + GenObjCCategory(ID->getName(), CD->getName()); + + break; + } + case Decl::ObjCCategoryImpl: { + ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D); + ObjCInterfaceDecl *ID = CD->getClassInterface(); + if (!ID) { + // Handle invalid code where the @interface might not + // have been specified. + // FIXME: We should be able to generate this USR even if the + // @interface isn't available. + IgnoreResults = true; + return; + } + GenObjCCategory(ID->getName(), CD->getName()); + break; + } + case Decl::ObjCProtocol: + GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName()); + break; + } +} + +void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + // The USR for a property declared in a class extension or category is based + // on the ObjCInterfaceDecl, not the ObjCCategoryDecl. + if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D)) + Visit(ID); + else + Visit(cast<Decl>(D->getDeclContext())); + GenObjCProperty(D->getName()); +} + +void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + if (ObjCPropertyDecl *PD = D->getPropertyDecl()) { + VisitObjCPropertyDecl(PD); + return; + } + + IgnoreResults = true; +} + +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()); + + bool AlreadyStarted = false; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@ST"; break; + case TTK_Class: Out << "@CT"; break; + case TTK_Union: Out << "@UT"; break; + case TTK_Enum: llvm_unreachable("enum template"); + } + VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); + } else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@SP"; break; + case TTK_Class: Out << "@CP"; break; + case TTK_Union: Out << "@UP"; break; + case TTK_Enum: llvm_unreachable("enum partial specialization"); + } + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } + } + + if (!AlreadyStarted) { + 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; + } + } + + Out << '@'; + Out.flush(); + assert(Buf.size() > 0); + const unsigned off = Buf.size() - 1; + + if (EmitDeclName(D)) { + if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl()) { + Buf[off] = 'A'; + Out << '@' << *TD; + } + else + Buf[off] = 'a'; + } + + // For a class template specialization, mangle the template arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } +} + +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@"; + Out << D->getName(); +} + +void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + GenLoc(D); + return; +} + +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; + } + + // Use the location of canonical decl. + D = D->getCanonicalDecl(); + + const SourceManager &SM = Context->getSourceManager(); + SourceLocation L = D->getLocStart(); + if (L.isInvalid()) { + IgnoreResults = true; + return true; + } + L = SM.getExpansionLoc(L); + const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(L); + const FileEntry *FE = SM.getFileEntryForID(Decomposed.first); + if (FE) { + Out << llvm::sys::path::filename(FE->getName()); + } + else { + // This case really isn't interesting. + IgnoreResults = true; + return true; + } + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + Out << '@' << 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 = *Context; + + 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 PackExpansionType *Expansion = T->getAs<PackExpansionType>()) { + Out << 'P'; + T = Expansion->getPattern(); + } + + 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_S: + case BuiltinType::WChar_U: + 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::Half: + c = 'h'; 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; +#define BUILTIN_TYPE(Id, SingletonId) +#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id: +#include "clang/AST/BuiltinTypes.def" + case BuiltinType::Dependent: + 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 we have already seen this (non-built-in) type, use a substitution + // encoding. + llvm::DenseMap<const Type *, unsigned>::iterator Substitution + = TypeSubstitutions.find(T.getTypePtr()); + if (Substitution != TypeSubstitutions.end()) { + Out << 'S' << Substitution->second << '_'; + return; + } else { + // Record this as a substitution. + unsigned Number = TypeSubstitutions.size(); + TypeSubstitutions[T.getTypePtr()] = Number; + } + + 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 ComplexType *CT = T->getAs<ComplexType>()) { + Out << '<'; + T = CT->getElementType(); + continue; + } + if (const TagType *TT = T->getAs<TagType>()) { + Out << '$'; + VisitTagDecl(TT->getDecl()); + return; + } + if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs<TemplateSpecializationType>()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + + // Unhandled type. + Out << ' '; + break; + } while (true); +} + +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa<TemplateTypeParmDecl>(*P)) { + if (cast<TemplateTypeParmDecl>(*P)->isParameterPack()) + Out<< 'p'; + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->isParameterPack()) + Out << 'p'; + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + if (TTP->isParameterPack()) + Out << 'p'; + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + if (Decl *D = Arg.getAsDecl()) + Visit(D); + break; + + case TemplateArgument::TemplateExpansion: + Out << 'P'; // pack expansion of... + // Fall through + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + Out << 'p' << Arg.pack_size(); + for (TemplateArgument::pack_iterator P = Arg.pack_begin(), PEnd = Arg.pack_end(); + P != PEnd; ++P) + VisitTemplateArgument(*P); + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << *Arg.getAsIntegral(); + break; + } +} + +//===----------------------------------------------------------------------===// +// General purpose USR generation methods. +//===----------------------------------------------------------------------===// + +void USRGenerator::GenObjCClass(StringRef cls) { + Out << "objc(cs)" << cls; +} + +void USRGenerator::GenObjCCategory(StringRef cls, StringRef cat) { + Out << "objc(cy)" << cls << '@' << cat; +} + +void USRGenerator::GenObjCIvar(StringRef ivar) { + Out << '@' << ivar; +} + +void USRGenerator::GenObjCMethod(StringRef meth, bool isInstanceMethod) { + Out << (isInstanceMethod ? "(im)" : "(cm)") << meth; +} + +void USRGenerator::GenObjCProperty(StringRef prop) { + Out << "(py)" << prop; +} + +void USRGenerator::GenObjCProtocol(StringRef prot) { + Out << "objc(pl)" << prot; +} + +//===----------------------------------------------------------------------===// +// API hooks. +//===----------------------------------------------------------------------===// + +static inline StringRef extractUSRSuffix(StringRef s) { + return s.startswith("c:") ? s.substr(2) : ""; +} + +bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) { + // Don't generate USRs for things with invalid locations. + if (!D || D->getLocStart().isInvalid()) + return true; + + // Check if the cursor has 'NoLinkage'. + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + switch (ND->getLinkage()) { + case ExternalLinkage: + // Generate USRs for all entities with external linkage. + break; + case NoLinkage: + case UniqueExternalLinkage: + // We allow enums, typedefs, and structs that have no linkage to + // have USRs that are anchored to the file they were defined in + // (e.g., the header). This is a little gross, but in principal + // enums/anonymous structs/etc. defined in a common header file + // are referred to across multiple translation units. + if (isa<TagDecl>(ND) || isa<TypedefDecl>(ND) || + isa<EnumConstantDecl>(ND) || isa<FieldDecl>(ND) || + isa<VarDecl>(ND) || isa<NamespaceDecl>(ND)) + break; + // Fall-through. + case InternalLinkage: + if (isa<FunctionDecl>(ND)) + break; + } + + { + USRGenerator UG(&D->getASTContext(), &Buf); + UG->Visit(const_cast<Decl*>(D)); + + if (UG->ignoreResults()) + return true; + } + + return false; +} + +extern "C" { + +CXString clang_getCursorUSR(CXCursor C) { + const CXCursorKind &K = clang_getCursorKind(C); + + if (clang_isDeclaration(K)) { + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return createCXString(""); + + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return createCXString(""); + + CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return createCXString(""); + + bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data); + if (Ignore) { + disposeCXStringBuf(buf); + return createCXString(""); + } + + // Return the C-string, but don't make a copy since it is already in + // the string buffer. + buf->Data.push_back('\0'); + return createCXString(buf); + } + + if (K == CXCursor_MacroDefinition) { + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return createCXString(""); + + CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return createCXString(""); + + { + USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(), + &buf->Data); + UG << "macro@" + << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart(); + } + buf->Data.push_back('\0'); + return createCXString(buf); + } + + return createCXString(""); +} + +CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { + 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) { + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCMethod(name, isInstanceMethod); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCClass(const char *name) { + USRGenerator UG; + UG->GenObjCClass(name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCProtocol(const char *name) { + USRGenerator UG; + UG->GenObjCProtocol(name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name) { + USRGenerator UG; + UG->GenObjCCategory(class_name, category_name); + return createCXString(UG.str(), true); +} + +CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR) { + USRGenerator UG; + UG << extractUSRSuffix(clang_getCString(classUSR)); + UG->GenObjCProperty(property); + return createCXString(UG.str(), true); +} + +} // end extern "C" diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp new file mode 100644 index 0000000..d458789 --- /dev/null +++ b/clang/tools/libclang/CIndexer.cpp @@ -0,0 +1,152 @@ +//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// +// +// 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 Clang-C Source Indexing library. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Program.h" + +#include <cstdio> +#include <vector> +#include <sstream> + +#ifdef __CYGWIN__ +#include <cygwin/version.h> +#include <sys/cygwin.h> +#define LLVM_ON_WIN32 1 +#endif + +#ifdef LLVM_ON_WIN32 +#include <windows.h> +#else +#include <dlfcn.h> +#endif + +using namespace clang; + +std::string CIndexer::getClangResourcesPath() { + // Did we already compute the path? + if (!ResourcesPath.empty()) + return ResourcesPath.str(); + + // Find the location where this library lives (libclang.dylib). +#ifdef LLVM_ON_WIN32 + MEMORY_BASIC_INFORMATION mbi; + char path[MAX_PATH]; + VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi, + sizeof(mbi)); + GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); + +#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); + LibClangPath.eraseComponent(); +#else + // This silly cast below avoids a C++ warning. + Dl_info info; + if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) + llvm_unreachable("Call to dladdr() failed"); + + llvm::sys::Path LibClangPath(info.dli_fname); + + // We now have the CIndex directory, locate clang relative to it. + LibClangPath.eraseComponent(); +#endif + + LibClangPath.appendComponent("clang"); + LibClangPath.appendComponent(CLANG_VERSION_STRING); + + // Cache our result. + ResourcesPath = LibClangPath; + return LibClangPath.str(); +} + +static llvm::sys::Path GetTemporaryPath() { + // FIXME: This is lame; sys::Path should provide this function (in particular, + // it should know how to find the temporary files dir). + std::string Error; + const char *TmpDir = ::getenv("TMPDIR"); + if (!TmpDir) + TmpDir = ::getenv("TEMP"); + if (!TmpDir) + TmpDir = ::getenv("TMP"); + if (!TmpDir) + TmpDir = "/tmp"; + llvm::sys::Path P(TmpDir); + P.appendComponent("remap"); + if (P.makeUnique(false, &Error)) + return llvm::sys::Path(""); + + // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837. + P.eraseFromDisk(false, 0); + + return P; +} + +bool clang::RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles) { + for (unsigned i = 0; i != num_unsaved_files; ++i) { + // Write the contents of this unsaved file into the temporary file. + llvm::sys::Path SavedFile(GetTemporaryPath()); + if (SavedFile.empty()) + return true; + + std::string ErrorInfo; + llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo, + llvm::raw_fd_ostream::F_Binary); + if (!ErrorInfo.empty()) + return true; + + OS.write(unsaved_files[i].Contents, unsaved_files[i].Length); + OS.close(); + if (OS.has_error()) { + SavedFile.eraseFromDisk(); + OS.clear_error(); + return true; + } + + // Remap the file. + std::string RemapArg = unsaved_files[i].Filename; + RemapArg += ';'; + RemapArg += SavedFile.str(); + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back("-remap-file"); + RemapArgs.push_back("-Xclang"); + RemapArgs.push_back(RemapArg); + TemporaryFiles.push_back(SavedFile); + } + + return false; +} + diff --git a/clang/tools/libclang/CIndexer.h b/clang/tools/libclang/CIndexer.h new file mode 100644 index 0000000..1e5fb82 --- /dev/null +++ b/clang/tools/libclang/CIndexer.h @@ -0,0 +1,104 @@ +//===- CIndexer.h - Clang-C Source Indexing Library -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CIndexer, a subclass of Indexer that provides extra +// functionality needed by the CIndex library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CINDEXER_H +#define LLVM_CLANG_CINDEXER_H + +#include "clang-c/Index.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" +#include <vector> + +namespace llvm { + class CrashRecoveryContext; +} + +namespace clang { + class ASTUnit; + +class CIndexer { + bool OnlyLocalDecls; + bool DisplayDiagnostics; + unsigned Options; // CXGlobalOptFlags. + + llvm::sys::Path ResourcesPath; + std::string WorkingDir; + +public: + CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false), + Options(CXGlobalOpt_None) { } + + /// \brief Whether we only want to see "local" declarations (that did not + /// come from a previous precompiled header). If false, we want to see all + /// declarations. + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } + + bool getDisplayDiagnostics() const { return DisplayDiagnostics; } + void setDisplayDiagnostics(bool Display = true) { + DisplayDiagnostics = Display; + } + + unsigned getCXGlobalOptFlags() const { return Options; } + void setCXGlobalOptFlags(unsigned options) { Options = options; } + + bool isOptEnabled(CXGlobalOptFlags opt) const { + return Options & opt; + } + + /// \brief Get the path of the clang resource files. + std::string getClangResourcesPath(); + + const std::string &getWorkingDirectory() const { return WorkingDir; } + void setWorkingDirectory(const std::string &Dir) { WorkingDir = Dir; } +}; + + /** + * \brief Given a set of "unsaved" files, create temporary files and + * construct the clang -cc1 argument list needed to perform the remapping. + * + * \returns true if an error occurred. + */ + bool RemapFiles(unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + std::vector<std::string> &RemapArgs, + std::vector<llvm::sys::Path> &TemporaryFiles); + + /// \brief Return the current size to request for "safety". + unsigned GetSafetyThreadStackSize(); + + /// \brief Set the current size to request for "safety" (or 0, if safety + /// threads should not be used). + void SetSafetyThreadStackSize(unsigned Value); + + /// \brief Execution the given code "safely", using crash recovery or safety + /// threads when possible. + /// + /// \return False if a crash was detected. + bool RunSafely(llvm::CrashRecoveryContext &CRC, + void (*Fn)(void*), void *UserData, unsigned Size = 0); + + /// \brief Set the thread priority to background. + /// FIXME: Move to llvm/Support. + void setThreadBackgroundPriority(); + + /// \brief Print libclang's resource usage to standard error. + void PrintLibclangResourceUsage(CXTranslationUnit TU); + + namespace cxindex { + void printDiagsToStderr(ASTUnit *Unit); + } +} + +#endif diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt new file mode 100644 index 0000000..fb0b91f --- /dev/null +++ b/clang/tools/libclang/CMakeLists.txt @@ -0,0 +1,90 @@ +set(LLVM_USED_LIBS + clangARCMigrate + clangRewrite + clangFrontend + clangDriver + clangSerialization + clangSema + clangEdit + clangAST + clangLex + clangBasic) + +set( LLVM_LINK_COMPONENTS + support + mc + ) + +set(SOURCES + ARCMigrate.cpp + CIndex.cpp + CIndexCXX.cpp + CIndexCodeCompletion.cpp + CIndexDiagnostic.cpp + CIndexDiagnostic.h + CIndexHigh.cpp + CIndexInclusionStack.cpp + CIndexUSRs.cpp + CIndexer.cpp + CIndexer.h + CXCursor.cpp + CXCursor.h + CXLoadedDiagnostic.cpp + CXLoadedDiagnostic.h + CXSourceLocation.cpp + CXSourceLocation.h + CXStoredDiagnostic.cpp + CXString.cpp + CXString.h + CXTranslationUnit.h + CXType.cpp + CXType.h + IndexBody.cpp + IndexDecl.cpp + IndexTypeSourceInfo.cpp + Index_Internal.h + Indexing.cpp + IndexingContext.cpp + IndexingContext.h + ../../include/clang-c/Index.h + ) + +if( LLVM_ENABLE_PIC ) + set(SHARED_LIBRARY TRUE) + add_clang_library(libclang ${SOURCES}) + + set_target_properties(libclang + PROPERTIES + 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() + +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/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp new file mode 100644 index 0000000..a298759 --- /dev/null +++ b/clang/tools/libclang/CXCursor.cpp @@ -0,0 +1,1156 @@ +//===- CXCursor.cpp - Routines for manipulating CXCursors -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXCursor. +// +//===----------------------------------------------------------------------===// + +#include "CXTranslationUnit.h" +#include "CXCursor.h" +#include "CXString.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang-c/Index.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; +using namespace cxcursor; + +CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) { + assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid); + CXCursor C = { K, 0, { 0, 0, 0 } }; + return C; +} + +static CXCursorKind GetCursorKind(const Attr *A) { + assert(A && "Invalid arguments!"); + switch (A->getKind()) { + default: break; + case attr::IBAction: return CXCursor_IBActionAttr; + case attr::IBOutlet: return CXCursor_IBOutletAttr; + case attr::IBOutletCollection: return CXCursor_IBOutletCollectionAttr; + case attr::Final: return CXCursor_CXXFinalAttr; + case attr::Override: return CXCursor_CXXOverrideAttr; + case attr::Annotate: return CXCursor_AnnotateAttr; + case attr::AsmLabel: return CXCursor_AsmLabelAttr; + } + + return CXCursor_UnexposedAttr; +} + +CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent, + CXTranslationUnit TU) { + assert(A && Parent && TU && "Invalid arguments!"); + CXCursor C = { GetCursorKind(A), 0, { Parent, (void*)A, TU } }; + return C; +} + +CXCursor cxcursor::MakeCXCursor(Decl *D, CXTranslationUnit TU, + SourceRange RegionOfInterest, + bool FirstInDeclGroup) { + assert(D && TU && "Invalid arguments!"); + + CXCursorKind K = getCursorKindForDecl(D); + + if (K == CXCursor_ObjCClassMethodDecl || + K == CXCursor_ObjCInstanceMethodDecl) { + int SelectorIdIndex = -1; + // Check if cursor points to a selector id. + if (RegionOfInterest.isValid() && + RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { + SmallVector<SourceLocation, 16> SelLocs; + cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs); + SmallVector<SourceLocation, 16>::iterator + I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin()); + if (I != SelLocs.end()) + SelectorIdIndex = I - SelLocs.begin(); + } + CXCursor C = { K, SelectorIdIndex, + { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }}; + return C; + } + + CXCursor C = { K, 0, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }}; + return C; +} + +CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU, + SourceRange RegionOfInterest) { + assert(S && TU && "Invalid arguments!"); + CXCursorKind K = CXCursor_NotImplemented; + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; + + case Stmt::CaseStmtClass: + K = CXCursor_CaseStmt; + break; + + case Stmt::DefaultStmtClass: + K = CXCursor_DefaultStmt; + break; + + case Stmt::IfStmtClass: + K = CXCursor_IfStmt; + break; + + case Stmt::SwitchStmtClass: + K = CXCursor_SwitchStmt; + break; + + case Stmt::WhileStmtClass: + K = CXCursor_WhileStmt; + break; + + case Stmt::DoStmtClass: + K = CXCursor_DoStmt; + break; + + case Stmt::ForStmtClass: + K = CXCursor_ForStmt; + break; + + case Stmt::GotoStmtClass: + K = CXCursor_GotoStmt; + break; + + case Stmt::IndirectGotoStmtClass: + K = CXCursor_IndirectGotoStmt; + break; + + case Stmt::ContinueStmtClass: + K = CXCursor_ContinueStmt; + break; + + case Stmt::BreakStmtClass: + K = CXCursor_BreakStmt; + break; + + case Stmt::ReturnStmtClass: + K = CXCursor_ReturnStmt; + break; + + case Stmt::AsmStmtClass: + K = CXCursor_AsmStmt; + break; + + case Stmt::ObjCAtTryStmtClass: + K = CXCursor_ObjCAtTryStmt; + break; + + case Stmt::ObjCAtCatchStmtClass: + K = CXCursor_ObjCAtCatchStmt; + break; + + case Stmt::ObjCAtFinallyStmtClass: + K = CXCursor_ObjCAtFinallyStmt; + break; + + case Stmt::ObjCAtThrowStmtClass: + K = CXCursor_ObjCAtThrowStmt; + break; + + case Stmt::ObjCAtSynchronizedStmtClass: + K = CXCursor_ObjCAtSynchronizedStmt; + break; + + case Stmt::ObjCAutoreleasePoolStmtClass: + K = CXCursor_ObjCAutoreleasePoolStmt; + break; + + case Stmt::ObjCForCollectionStmtClass: + K = CXCursor_ObjCForCollectionStmt; + break; + + case Stmt::CXXCatchStmtClass: + K = CXCursor_CXXCatchStmt; + break; + + case Stmt::CXXTryStmtClass: + K = CXCursor_CXXTryStmt; + break; + + case Stmt::CXXForRangeStmtClass: + K = CXCursor_CXXForRangeStmt; + break; + + case Stmt::SEHTryStmtClass: + K = CXCursor_SEHTryStmt; + break; + + case Stmt::SEHExceptStmtClass: + K = CXCursor_SEHExceptStmt; + break; + + case Stmt::SEHFinallyStmtClass: + K = CXCursor_SEHFinallyStmt; + break; + + case Stmt::ArrayTypeTraitExprClass: + case Stmt::AsTypeExprClass: + case Stmt::AtomicExprClass: + case Stmt::BinaryConditionalOperatorClass: + case Stmt::BinaryTypeTraitExprClass: + case Stmt::TypeTraitExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXScalarValueInitExprClass: + case Stmt::CXXUuidofExprClass: + case Stmt::ChooseExprClass: + case Stmt::DesignatedInitExprClass: + case Stmt::ExprWithCleanupsClass: + case Stmt::ExpressionTraitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::ImplicitCastExprClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::MaterializeTemporaryExprClass: + case Stmt::ObjCIndirectCopyRestoreExprClass: + case Stmt::OffsetOfExprClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::UnaryExprOrTypeTraitExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::VAArgExprClass: + case Stmt::ObjCArrayLiteralClass: + case Stmt::ObjCDictionaryLiteralClass: + case Stmt::ObjCNumericLiteralClass: + case Stmt::ObjCSubscriptRefExprClass: + K = CXCursor_UnexposedExpr; + break; + + case Stmt::OpaqueValueExprClass: + if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr()) + return MakeCXCursor(Src, Parent, TU, RegionOfInterest); + K = CXCursor_UnexposedExpr; + break; + + case Stmt::PseudoObjectExprClass: + return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(), + Parent, TU, RegionOfInterest); + + case Stmt::CompoundStmtClass: + K = CXCursor_CompoundStmt; + break; + + case Stmt::NullStmtClass: + K = CXCursor_NullStmt; + break; + + case Stmt::LabelStmtClass: + K = CXCursor_LabelStmt; + break; + + case Stmt::AttributedStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::DeclStmtClass: + K = CXCursor_DeclStmt; + break; + + case Stmt::IntegerLiteralClass: + K = CXCursor_IntegerLiteral; + break; + + case Stmt::FloatingLiteralClass: + K = CXCursor_FloatingLiteral; + break; + + case Stmt::ImaginaryLiteralClass: + K = CXCursor_ImaginaryLiteral; + break; + + case Stmt::StringLiteralClass: + K = CXCursor_StringLiteral; + break; + + case Stmt::CharacterLiteralClass: + K = CXCursor_CharacterLiteral; + break; + + case Stmt::ParenExprClass: + K = CXCursor_ParenExpr; + break; + + case Stmt::UnaryOperatorClass: + K = CXCursor_UnaryOperator; + break; + + case Stmt::CXXNoexceptExprClass: + K = CXCursor_UnaryExpr; + break; + + case Stmt::ArraySubscriptExprClass: + K = CXCursor_ArraySubscriptExpr; + break; + + case Stmt::BinaryOperatorClass: + K = CXCursor_BinaryOperator; + break; + + case Stmt::CompoundAssignOperatorClass: + K = CXCursor_CompoundAssignOperator; + break; + + case Stmt::ConditionalOperatorClass: + K = CXCursor_ConditionalOperator; + break; + + case Stmt::CStyleCastExprClass: + K = CXCursor_CStyleCastExpr; + break; + + case Stmt::CompoundLiteralExprClass: + K = CXCursor_CompoundLiteralExpr; + break; + + case Stmt::InitListExprClass: + K = CXCursor_InitListExpr; + break; + + case Stmt::AddrLabelExprClass: + K = CXCursor_AddrLabelExpr; + break; + + case Stmt::StmtExprClass: + K = CXCursor_StmtExpr; + break; + + case Stmt::GenericSelectionExprClass: + K = CXCursor_GenericSelectionExpr; + break; + + case Stmt::GNUNullExprClass: + K = CXCursor_GNUNullExpr; + break; + + case Stmt::CXXStaticCastExprClass: + K = CXCursor_CXXStaticCastExpr; + break; + + case Stmt::CXXDynamicCastExprClass: + K = CXCursor_CXXDynamicCastExpr; + break; + + case Stmt::CXXReinterpretCastExprClass: + K = CXCursor_CXXReinterpretCastExpr; + break; + + case Stmt::CXXConstCastExprClass: + K = CXCursor_CXXConstCastExpr; + break; + + case Stmt::CXXFunctionalCastExprClass: + K = CXCursor_CXXFunctionalCastExpr; + break; + + case Stmt::CXXTypeidExprClass: + K = CXCursor_CXXTypeidExpr; + break; + + case Stmt::CXXBoolLiteralExprClass: + K = CXCursor_CXXBoolLiteralExpr; + break; + + case Stmt::CXXNullPtrLiteralExprClass: + K = CXCursor_CXXNullPtrLiteralExpr; + break; + + case Stmt::CXXThisExprClass: + K = CXCursor_CXXThisExpr; + break; + + case Stmt::CXXThrowExprClass: + K = CXCursor_CXXThrowExpr; + break; + + case Stmt::CXXNewExprClass: + K = CXCursor_CXXNewExpr; + break; + + case Stmt::CXXDeleteExprClass: + K = CXCursor_CXXDeleteExpr; + break; + + case Stmt::ObjCStringLiteralClass: + K = CXCursor_ObjCStringLiteral; + break; + + case Stmt::ObjCEncodeExprClass: + K = CXCursor_ObjCEncodeExpr; + break; + + case Stmt::ObjCSelectorExprClass: + K = CXCursor_ObjCSelectorExpr; + break; + + case Stmt::ObjCProtocolExprClass: + K = CXCursor_ObjCProtocolExpr; + break; + + case Stmt::ObjCBoolLiteralExprClass: + K = CXCursor_ObjCBoolLiteralExpr; + break; + + case Stmt::ObjCBridgedCastExprClass: + K = CXCursor_ObjCBridgedCastExpr; + break; + + case Stmt::BlockExprClass: + K = CXCursor_BlockExpr; + break; + + case Stmt::PackExpansionExprClass: + K = CXCursor_PackExpansionExpr; + break; + + case Stmt::SizeOfPackExprClass: + K = CXCursor_SizeOfPackExpr; + break; + + case Stmt::DeclRefExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::SubstNonTypeTemplateParmExprClass: + case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::UnresolvedLookupExprClass: + K = CXCursor_DeclRefExpr; + break; + + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::MemberExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCIvarRefExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::UnresolvedMemberExprClass: + K = CXCursor_MemberRefExpr; + break; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CUDAKernelCallExprClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::UserDefinedLiteralClass: + K = CXCursor_CallExpr; + break; + + case Stmt::LambdaExprClass: + K = CXCursor_LambdaExpr; + break; + + case Stmt::ObjCMessageExprClass: { + K = CXCursor_ObjCMessageExpr; + int SelectorIdIndex = -1; + // Check if cursor points to a selector id. + if (RegionOfInterest.isValid() && + RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { + SmallVector<SourceLocation, 16> SelLocs; + cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs); + SmallVector<SourceLocation, 16>::iterator + I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin()); + if (I != SelLocs.end()) + SelectorIdIndex = I - SelLocs.begin(); + } + CXCursor C = { K, 0, { Parent, S, TU } }; + return getSelectorIdentifierCursor(SelectorIdIndex, C); + } + + case Stmt::MSDependentExistsStmtClass: + K = CXCursor_UnexposedStmt; + break; + } + + CXCursor C = { K, 0, { Parent, S, TU } }; + return C; +} + +CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Super && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCSuperClassRef, 0, { Super, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCSuperClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCSuperClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Proto && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCProtocolRef, 0, { (void*)Proto, RawLoc, TU } }; + return C; +} + +std::pair<ObjCProtocolDecl *, SourceLocation> +cxcursor::getCursorObjCProtocolRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCProtocolRef); + return std::make_pair(static_cast<ObjCProtocolDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, + SourceLocation Loc, + CXTranslationUnit TU) { + // 'Class' can be null for invalid code. + if (!Class) + return MakeCXCursorInvalid(CXCursor_InvalidCode); + assert(TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_ObjCClassRef, 0, { (void*)Class, RawLoc, TU } }; + return C; +} + +std::pair<ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCClassRef); + return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, + CXTranslationUnit TU) { + assert(Type && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TypeRef, 0, { (void*)Type, RawLoc, TU } }; + return C; +} + +std::pair<TypeDecl *, SourceLocation> +cxcursor::getCursorTypeRef(CXCursor C) { + assert(C.kind == CXCursor_TypeRef); + return std::make_pair(static_cast<TypeDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorTemplateRef(const TemplateDecl *Template, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Template && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TemplateRef, 0, { (void*)Template, RawLoc, TU } }; + return C; +} + +std::pair<TemplateDecl *, SourceLocation> +cxcursor::getCursorTemplateRef(CXCursor C) { + assert(C.kind == CXCursor_TemplateRef); + return std::make_pair(static_cast<TemplateDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS, + SourceLocation Loc, + CXTranslationUnit TU) { + + assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU && + "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_NamespaceRef, 0, { (void*)NS, RawLoc, TU } }; + return C; +} + +std::pair<NamedDecl *, SourceLocation> +cxcursor::getCursorNamespaceRef(CXCursor C) { + assert(C.kind == CXCursor_NamespaceRef); + return std::make_pair(static_cast<NamedDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Var && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } }; + return C; +} + +std::pair<VarDecl *, SourceLocation> +cxcursor::getCursorVariableRef(CXCursor C) { + assert(C.kind == CXCursor_VariableRef); + return std::make_pair(static_cast<VarDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Field && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_MemberRef, 0, { (void*)Field, RawLoc, TU } }; + return C; +} + +std::pair<FieldDecl *, SourceLocation> +cxcursor::getCursorMemberRef(CXCursor C) { + assert(C.kind == CXCursor_MemberRef); + return std::make_pair(static_cast<FieldDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B, + CXTranslationUnit TU){ + CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { (void*)B, 0, TU } }; + return C; +} + +CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) { + assert(C.kind == CXCursor_CXXBaseSpecifier); + return static_cast<CXXBaseSpecifier*>(C.data[0]); +} + +CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, + CXTranslationUnit TU) { + CXCursor C = { CXCursor_PreprocessingDirective, 0, + { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()), + reinterpret_cast<void *>(Range.getEnd().getRawEncoding()), + TU } + }; + return C; +} + +SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) { + assert(C.kind == CXCursor_PreprocessingDirective); + SourceRange Range = SourceRange(SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t> (C.data[0])), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t> (C.data[1]))); + ASTUnit *TU = getCursorASTUnit(C); + return TU->mapRangeFromPreamble(Range); +} + +CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI, + CXTranslationUnit TU) { + CXCursor C = { CXCursor_MacroDefinition, 0, { MI, 0, TU } }; + return C; +} + +MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) { + assert(C.kind == CXCursor_MacroDefinition); + return static_cast<MacroDefinition *>(C.data[0]); +} + +CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI, + CXTranslationUnit TU) { + CXCursor C = { CXCursor_MacroExpansion, 0, { MI, 0, TU } }; + return C; +} + +MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) { + assert(C.kind == CXCursor_MacroExpansion); + return static_cast<MacroExpansion *>(C.data[0]); +} + +CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID, + CXTranslationUnit TU) { + CXCursor C = { CXCursor_InclusionDirective, 0, { ID, 0, TU } }; + return C; +} + +InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) { + assert(C.kind == CXCursor_InclusionDirective); + return static_cast<InclusionDirective *>(C.data[0]); +} + +CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Label && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_LabelRef, 0, { Label, RawLoc, TU } }; + return C; +} + +std::pair<LabelStmt*, SourceLocation> +cxcursor::getCursorLabelRef(CXCursor C) { + assert(C.kind == CXCursor_LabelRef); + return std::make_pair(static_cast<LabelStmt *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(OverloadExpr *E, + CXTranslationUnit TU) { + assert(E && TU && "Invalid arguments!"); + OverloadedDeclRefStorage Storage(E); + void *RawLoc = reinterpret_cast<void *>(E->getNameLoc().getRawEncoding()); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, + { Storage.getOpaqueValue(), RawLoc, TU } + }; + return C; +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(Decl *D, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(D && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + OverloadedDeclRefStorage Storage(D); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, + { Storage.getOpaqueValue(), RawLoc, TU } + }; + return C; +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Name.getAsOverloadedTemplate() && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + OverloadedDeclRefStorage Storage(Name.getAsOverloadedTemplate()); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, + { Storage.getOpaqueValue(), RawLoc, TU } + }; + return C; +} + +std::pair<cxcursor::OverloadedDeclRefStorage, SourceLocation> +cxcursor::getCursorOverloadedDeclRef(CXCursor C) { + assert(C.kind == CXCursor_OverloadedDeclRef); + return std::make_pair(OverloadedDeclRefStorage::getFromOpaqueValue(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +Decl *cxcursor::getCursorDecl(CXCursor Cursor) { + return (Decl *)Cursor.data[0]; +} + +Expr *cxcursor::getCursorExpr(CXCursor Cursor) { + return dyn_cast_or_null<Expr>(getCursorStmt(Cursor)); +} + +Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { + if (Cursor.kind == CXCursor_ObjCSuperClassRef || + Cursor.kind == CXCursor_ObjCProtocolRef || + Cursor.kind == CXCursor_ObjCClassRef) + return 0; + + return (Stmt *)Cursor.data[1]; +} + +Attr *cxcursor::getCursorAttr(CXCursor Cursor) { + return (Attr *)Cursor.data[1]; +} + +Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) { + return (Decl *)Cursor.data[0]; +} + +ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { + return getCursorASTUnit(Cursor)->getASTContext(); +} + +ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) { + CXTranslationUnit TU = static_cast<CXTranslationUnit>(Cursor.data[2]); + if (!TU) + return 0; + return static_cast<ASTUnit *>(TU->TUData); +} + +CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) { + return static_cast<CXTranslationUnit>(Cursor.data[2]); +} + +static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU, + ObjCContainerDecl *Container, + ObjCMethodDecl *Method, + SmallVectorImpl<CXCursor> &Methods, + bool MovedToSuper) { + if (!Container) + return; + + // In categories look for overriden methods from protocols. A method from + // category is not "overriden" since it is considered as the "same" method + // (same USR) as the one from the interface. + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { + // Check whether we have a matching method at this category but only if we + // are at the super class level. + if (MovedToSuper) + if (ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this category; there is no need to look + // into its protocols. + Methods.push_back(MakeCXCursor(Overridden, TU)); + return; + } + + for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); + return; + } + + // Check whether we have a matching method at this level. + if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this level; there is no need to look + // into other protocols or categories. + Methods.push_back(MakeCXCursor(Overridden, TU)); + return; + } + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); + } + + if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { + for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(), + PEnd = Interface->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper); + + for (ObjCCategoryDecl *Category = Interface->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + CollectOverriddenMethodsRecurse(TU, Category, Method, Methods, + MovedToSuper); + + if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) + return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods, + /*MovedToSuper=*/true); + } +} + +static inline void CollectOverriddenMethods(CXTranslationUnit TU, + ObjCContainerDecl *Container, + ObjCMethodDecl *Method, + SmallVectorImpl<CXCursor> &Methods) { + CollectOverriddenMethodsRecurse(TU, Container, Method, Methods, + /*MovedToSuper=*/false); +} + +void cxcursor::getOverriddenCursors(CXCursor cursor, + SmallVectorImpl<CXCursor> &overridden) { + assert(clang_isDeclaration(cursor.kind)); + Decl *D = getCursorDecl(cursor); + if (!D) + return; + + // Handle C++ member functions. + CXTranslationUnit TU = getCursorTU(cursor); + if (CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { + for (CXXMethodDecl::method_iterator + M = CXXMethod->begin_overridden_methods(), + MEnd = CXXMethod->end_overridden_methods(); + M != MEnd; ++M) + overridden.push_back(MakeCXCursor(const_cast<CXXMethodDecl*>(*M), TU)); + return; + } + + ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D); + if (!Method) + return; + + if (ObjCProtocolDecl * + ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { + CollectOverriddenMethods(TU, ProtD, Method, overridden); + + } else if (ObjCImplDecl * + IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) { + ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(TU, ID, Method, overridden); + + } else if (ObjCCategoryDecl * + CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) { + ObjCInterfaceDecl *ID = CatD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(TU, ID, Method, overridden); + + } else { + CollectOverriddenMethods(TU, + dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()), + Method, overridden); + } +} + +std::pair<int, SourceLocation> +cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) { + if (cursor.kind == CXCursor_ObjCMessageExpr) { + if (cursor.xdata != -1) + return std::make_pair(cursor.xdata, + cast<ObjCMessageExpr>(getCursorExpr(cursor)) + ->getSelectorLoc(cursor.xdata)); + } else if (cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) { + if (cursor.xdata != -1) + return std::make_pair(cursor.xdata, + cast<ObjCMethodDecl>(getCursorDecl(cursor)) + ->getSelectorLoc(cursor.xdata)); + } + + return std::make_pair(-1, SourceLocation()); +} + +CXCursor cxcursor::getSelectorIdentifierCursor(int SelIdx, CXCursor cursor) { + CXCursor newCursor = cursor; + + if (cursor.kind == CXCursor_ObjCMessageExpr) { + if (SelIdx == -1 || + unsigned(SelIdx) >= cast<ObjCMessageExpr>(getCursorExpr(cursor)) + ->getNumSelectorLocs()) + newCursor.xdata = -1; + else + newCursor.xdata = SelIdx; + } else if (cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) { + if (SelIdx == -1 || + unsigned(SelIdx) >= cast<ObjCMethodDecl>(getCursorDecl(cursor)) + ->getNumSelectorLocs()) + newCursor.xdata = -1; + else + newCursor.xdata = SelIdx; + } + + return newCursor; +} + +CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) { + if (cursor.kind != CXCursor_CallExpr) + return cursor; + + if (cursor.xdata == 0) + return cursor; + + Expr *E = getCursorExpr(cursor); + TypeSourceInfo *Type = 0; + if (CXXUnresolvedConstructExpr * + UnCtor = dyn_cast<CXXUnresolvedConstructExpr>(E)) { + Type = UnCtor->getTypeSourceInfo(); + } else if (CXXTemporaryObjectExpr *Tmp = dyn_cast<CXXTemporaryObjectExpr>(E)){ + Type = Tmp->getTypeSourceInfo(); + } + + if (!Type) + return cursor; + + CXTranslationUnit TU = getCursorTU(cursor); + QualType Ty = Type->getType(); + TypeLoc TL = Type->getTypeLoc(); + SourceLocation Loc = TL.getBeginLoc(); + + if (const ElaboratedType *ElabT = Ty->getAs<ElaboratedType>()) { + Ty = ElabT->getNamedType(); + ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(TL); + Loc = ElabTL.getNamedTypeLoc().getBeginLoc(); + } + + if (const TypedefType *Typedef = Ty->getAs<TypedefType>()) + return MakeCursorTypeRef(Typedef->getDecl(), Loc, TU); + if (const TagType *Tag = Ty->getAs<TagType>()) + return MakeCursorTypeRef(Tag->getDecl(), Loc, TU); + if (const TemplateTypeParmType *TemplP = Ty->getAs<TemplateTypeParmType>()) + return MakeCursorTypeRef(TemplP->getDecl(), Loc, TU); + + return cursor; +} + +bool cxcursor::operator==(CXCursor X, CXCursor Y) { + return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] && + X.data[2] == Y.data[2]; +} + +// FIXME: Remove once we can model DeclGroups and their appropriate ranges +// properly in the ASTs. +bool cxcursor::isFirstInDeclGroup(CXCursor C) { + assert(clang_isDeclaration(C.kind)); + return ((uintptr_t) (C.data[1])) != 0; +} + +//===----------------------------------------------------------------------===// +// libclang CXCursor APIs +//===----------------------------------------------------------------------===// + +extern "C" { + +int clang_Cursor_isNull(CXCursor cursor) { + return clang_equalCursors(cursor, clang_getNullCursor()); +} + +CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) { + return getCursorTU(cursor); +} + +int clang_Cursor_getNumArguments(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) + return MD->param_size(); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) + return FD->param_size(); + } + + return -1; +} + +CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) { + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) { + if (i < MD->param_size()) + return cxcursor::MakeCXCursor(MD->param_begin()[i], + cxcursor::getCursorTU(C)); + } else if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { + if (i < FD->param_size()) + return cxcursor::MakeCXCursor(FD->param_begin()[i], + cxcursor::getCursorTU(C)); + } + } + + return clang_getNullCursor(); +} + +} // end: extern "C" + +//===----------------------------------------------------------------------===// +// CXCursorSet. +//===----------------------------------------------------------------------===// + +typedef llvm::DenseMap<CXCursor, unsigned> CXCursorSet_Impl; + +static inline CXCursorSet packCXCursorSet(CXCursorSet_Impl *setImpl) { + return (CXCursorSet) setImpl; +} +static inline CXCursorSet_Impl *unpackCXCursorSet(CXCursorSet set) { + return (CXCursorSet_Impl*) set; +} +namespace llvm { +template<> struct DenseMapInfo<CXCursor> { +public: + static inline CXCursor getEmptyKey() { + return MakeCXCursorInvalid(CXCursor_InvalidFile); + } + static inline CXCursor getTombstoneKey() { + return MakeCXCursorInvalid(CXCursor_NoDeclFound); + } + static inline unsigned getHashValue(const CXCursor &cursor) { + return llvm::DenseMapInfo<std::pair<void*,void*> > + ::getHashValue(std::make_pair(cursor.data[0], cursor.data[1])); + } + static inline bool isEqual(const CXCursor &x, const CXCursor &y) { + return x.kind == y.kind && + x.data[0] == y.data[0] && + x.data[1] == y.data[1]; + } +}; +} + +extern "C" { +CXCursorSet clang_createCXCursorSet() { + return packCXCursorSet(new CXCursorSet_Impl()); +} + +void clang_disposeCXCursorSet(CXCursorSet set) { + delete unpackCXCursorSet(set); +} + +unsigned clang_CXCursorSet_contains(CXCursorSet set, CXCursor cursor) { + CXCursorSet_Impl *setImpl = unpackCXCursorSet(set); + if (!setImpl) + return 0; + return setImpl->find(cursor) == setImpl->end(); +} + +unsigned clang_CXCursorSet_insert(CXCursorSet set, CXCursor cursor) { + // Do not insert invalid cursors into the set. + if (cursor.kind >= CXCursor_FirstInvalid && + cursor.kind <= CXCursor_LastInvalid) + return 1; + + CXCursorSet_Impl *setImpl = unpackCXCursorSet(set); + if (!setImpl) + return 1; + unsigned &entry = (*setImpl)[cursor]; + unsigned flag = entry == 0 ? 1 : 0; + entry = 1; + return flag; +} + +CXCompletionString clang_getCursorCompletionString(CXCursor cursor) { + enum CXCursorKind kind = clang_getCursorKind(cursor); + if (clang_isDeclaration(kind)) { + Decl *decl = getCursorDecl(cursor); + if (NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) { + ASTUnit *unit = getCursorASTUnit(cursor); + CodeCompletionResult Result(namedDecl); + CodeCompletionString *String + = Result.CreateCodeCompletionString(unit->getASTContext(), + unit->getPreprocessor(), + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo()); + return String; + } + } + else if (kind == CXCursor_MacroDefinition) { + MacroDefinition *definition = getCursorMacroDefinition(cursor); + const IdentifierInfo *MacroInfo = definition->getName(); + ASTUnit *unit = getCursorASTUnit(cursor); + CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo)); + CodeCompletionString *String + = Result.CreateCodeCompletionString(unit->getASTContext(), + unit->getPreprocessor(), + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo()); + return String; + } + return NULL; +} + +} // end: extern "C" diff --git a/clang/tools/libclang/CXCursor.h b/clang/tools/libclang/CXCursor.h new file mode 100644 index 0000000..947b0a3 --- /dev/null +++ b/clang/tools/libclang/CXCursor.h @@ -0,0 +1,249 @@ +//===- CXCursor.h - Routines for manipulating CXCursors -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXCURSOR_H +#define LLVM_CLANG_CXCURSOR_H + +#include "clang-c/Index.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" +#include <utility> + +namespace clang { + +class ASTContext; +class ASTUnit; +class Attr; +class CXXBaseSpecifier; +class Decl; +class Expr; +class FieldDecl; +class InclusionDirective; +class LabelStmt; +class MacroDefinition; +class MacroExpansion; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class OverloadedTemplateStorage; +class OverloadExpr; +class Stmt; +class TemplateDecl; +class TemplateName; +class TypeDecl; +class VarDecl; + +namespace cxcursor { + +CXCursor getCursor(CXTranslationUnit, SourceLocation); + +CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent, + CXTranslationUnit TU); +CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU, + SourceRange RegionOfInterest = SourceRange(), + bool FirstInDeclGroup = true); +CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent, + CXTranslationUnit TU, + SourceRange RegionOfInterest = SourceRange()); +CXCursor MakeCXCursorInvalid(CXCursorKind K); + +/// \brief Create an Objective-C superclass reference at the given location. +CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCSuperClassRef(CXCursor C); + +/// \brief Create an Objective-C protocol reference at the given location. +CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, + SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references +/// and optionally the location where the reference occurred. +std::pair<ObjCProtocolDecl *, SourceLocation> + getCursorObjCProtocolRef(CXCursor C); + +/// \brief Create an Objective-C class reference at the given location. +CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, + SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack an ObjCClassRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<ObjCInterfaceDecl *, SourceLocation> + getCursorObjCClassRef(CXCursor C); + +/// \brief Create a type reference at the given location. +CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a TypeRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); + +/// \brief Create a reference to a template at the given location. +CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a TemplateRef cursor into the template it references and +/// the location where the reference occurred. +std::pair<TemplateDecl *, SourceLocation> getCursorTemplateRef(CXCursor C); + +/// \brief Create a reference to a namespace or namespace alias at the given +/// location. +CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias +/// it references and the location where the reference occurred. +std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C); + +/// \brief Create a reference to a variable at the given location. +CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a VariableRef cursor into the variable it references and the +/// location where the where the reference occurred. +std::pair<VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C); + +/// \brief Create a reference to a field at the given location. +CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a MemberRef cursor into the field it references and the +/// location where the reference occurred. +std::pair<FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C); + +/// \brief Create a CXX base specifier cursor. +CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B, + CXTranslationUnit TU); + +/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier. +CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C); + +/// \brief Create a preprocessing directive cursor. +CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, + CXTranslationUnit TU); + +/// \brief Unpack a given preprocessing directive to retrieve its source range. +SourceRange getCursorPreprocessingDirective(CXCursor C); + +/// \brief Create a macro definition cursor. +CXCursor MakeMacroDefinitionCursor(MacroDefinition *, CXTranslationUnit TU); + +/// \brief Unpack a given macro definition cursor to retrieve its +/// source range. +MacroDefinition *getCursorMacroDefinition(CXCursor C); + +/// \brief Create a macro expansion cursor. +CXCursor MakeMacroExpansionCursor(MacroExpansion *, + CXTranslationUnit TU); + +/// \brief Unpack a given macro expansion cursor to retrieve its +/// source range. +MacroExpansion *getCursorMacroExpansion(CXCursor C); + +/// \brief Create an inclusion directive cursor. +CXCursor MakeInclusionDirectiveCursor(InclusionDirective *, + CXTranslationUnit TU); + +/// \brief Unpack a given inclusion directive cursor to retrieve its +/// source range. +InclusionDirective *getCursorInclusionDirective(CXCursor C); + +/// \brief Create a label reference at the given location. +CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, + CXTranslationUnit TU); + +/// \brief Unpack a label reference into the label statement it refers to and +/// the location of the reference. +std::pair<LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C); + +/// \brief Create a overloaded declaration reference cursor for an expression. +CXCursor MakeCursorOverloadedDeclRef(OverloadExpr *E, CXTranslationUnit TU); + +/// \brief Create a overloaded declaration reference cursor for a declaration. +CXCursor MakeCursorOverloadedDeclRef(Decl *D, SourceLocation Location, + CXTranslationUnit TU); + +/// \brief Create a overloaded declaration reference cursor for a template name. +CXCursor MakeCursorOverloadedDeclRef(TemplateName Template, + SourceLocation Location, + CXTranslationUnit TU); + +/// \brief Internal storage for an overloaded declaration reference cursor; +typedef llvm::PointerUnion3<OverloadExpr *, Decl *, + OverloadedTemplateStorage *> + OverloadedDeclRefStorage; + +/// \brief Unpack an overloaded declaration reference into an expression, +/// declaration, or template name along with the source location. +std::pair<OverloadedDeclRefStorage, SourceLocation> + getCursorOverloadedDeclRef(CXCursor C); + +Decl *getCursorDecl(CXCursor Cursor); +Expr *getCursorExpr(CXCursor Cursor); +Stmt *getCursorStmt(CXCursor Cursor); +Attr *getCursorAttr(CXCursor Cursor); +Decl *getCursorParentDecl(CXCursor Cursor); + +ASTContext &getCursorContext(CXCursor Cursor); +ASTUnit *getCursorASTUnit(CXCursor Cursor); +CXTranslationUnit getCursorTU(CXCursor Cursor); + +void getOverriddenCursors(CXCursor cursor, + SmallVectorImpl<CXCursor> &overridden); + +/// \brief Returns a index/location pair for a selector identifier if the cursor +/// points to one. +std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor); +static inline int getSelectorIdentifierIndex(CXCursor cursor) { + return getSelectorIdentifierIndexAndLoc(cursor).first; +} +static inline SourceLocation getSelectorIdentifierLoc(CXCursor cursor) { + return getSelectorIdentifierIndexAndLoc(cursor).second; +} + +CXCursor getSelectorIdentifierCursor(int SelIdx, CXCursor cursor); + +static inline CXCursor getTypeRefedCallExprCursor(CXCursor cursor) { + CXCursor newCursor = cursor; + if (cursor.kind == CXCursor_CallExpr) + newCursor.xdata = 1; + return newCursor; +} + +CXCursor getTypeRefCursor(CXCursor cursor); + +/// \brief Generate a USR for \arg D and put it in \arg Buf. +/// \returns true if no USR was computed or the result should be ignored, +/// false otherwise. +bool getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf); + +bool operator==(CXCursor X, CXCursor Y); + +inline bool operator!=(CXCursor X, CXCursor Y) { + return !(X == Y); +} + +/// \brief Return true if the cursor represents a declaration that is the +/// first in a declaration group. +bool isFirstInDeclGroup(CXCursor C); + +}} // end namespace: clang::cxcursor + +#endif diff --git a/clang/tools/libclang/CXLoadedDiagnostic.cpp b/clang/tools/libclang/CXLoadedDiagnostic.cpp new file mode 100644 index 0000000..e5b6ccc --- /dev/null +++ b/clang/tools/libclang/CXLoadedDiagnostic.cpp @@ -0,0 +1,672 @@ +/*===-- CXLoadedDiagnostic.cpp - Handling of persisent diags -*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements handling of persisent diagnostics. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "CXLoadedDiagnostic.h" +#include "CXString.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/SerializedDiagnosticPrinter.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/Optional.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/MemoryBuffer.h" +#include <assert.h> + +using namespace clang; +using namespace clang::cxstring; + +//===----------------------------------------------------------------------===// +// Extend CXDiagnosticSetImpl which contains strings for diagnostics. +//===----------------------------------------------------------------------===// + +typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings; + +namespace { +class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl { +public: + CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {} + virtual ~CXLoadedDiagnosticSetImpl() {} + + llvm::StringRef makeString(const char *blob, unsigned blobLen); + + llvm::BumpPtrAllocator Alloc; + Strings Categories; + Strings WarningFlags; + Strings FileNames; + + FileSystemOptions FO; + FileManager FakeFiles; + llvm::DenseMap<unsigned, const FileEntry *> Files; +}; +} + +llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob, + unsigned bloblen) { + char *mem = Alloc.Allocate<char>(bloblen + 1); + memcpy(mem, blob, bloblen); + // Add a null terminator for those clients accessing the buffer + // like a c-string. + mem[bloblen] = '\0'; + return llvm::StringRef(mem, bloblen); +} + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +CXLoadedDiagnostic::~CXLoadedDiagnostic() {} + +//===----------------------------------------------------------------------===// +// Public CXLoadedDiagnostic methods. +//===----------------------------------------------------------------------===// + +CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const { + // FIXME: possibly refactor with logic in CXStoredDiagnostic. + switch (severity) { + case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored; + case DiagnosticsEngine::Note: return CXDiagnostic_Note; + case DiagnosticsEngine::Warning: return CXDiagnostic_Warning; + case DiagnosticsEngine::Error: return CXDiagnostic_Error; + case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal; + } + + llvm_unreachable("Invalid diagnostic level"); +} + +static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) { + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + uintptr_t V = (uintptr_t) DLoc; + V |= 0x1; + CXSourceLocation Loc = { { (void*) V, 0 }, 0 }; + return Loc; +} + +CXSourceLocation CXLoadedDiagnostic::getLocation() const { + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + return makeLocation(&DiagLoc); +} + +CXString CXLoadedDiagnostic::getSpelling() const { + return cxstring::createCXString(Spelling, false); +} + +CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const { + if (DiagOption.empty()) + return createCXString(""); + + // FIXME: possibly refactor with logic in CXStoredDiagnostic. + if (Disable) + *Disable = createCXString((Twine("-Wno-") + DiagOption).str()); + return createCXString((Twine("-W") + DiagOption).str()); +} + +unsigned CXLoadedDiagnostic::getCategory() const { + return category; +} + +CXString CXLoadedDiagnostic::getCategoryText() const { + return cxstring::createCXString(CategoryText); +} + +unsigned CXLoadedDiagnostic::getNumRanges() const { + return Ranges.size(); +} + +CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const { + assert(Range < Ranges.size()); + return Ranges[Range]; +} + +unsigned CXLoadedDiagnostic::getNumFixIts() const { + return FixIts.size(); +} + +CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const { + assert(FixIt < FixIts.size()); + if (ReplacementRange) + *ReplacementRange = FixIts[FixIt].first; + return FixIts[FixIt].second; +} + +void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location, + CXFile *file, + unsigned int *line, + unsigned int *column, + unsigned int *offset) { + + + // CXSourceLocation consists of the following fields: + // + // void *ptr_data[2]; + // unsigned int_data; + // + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + // + // For now, do the unoptimized approach and store the data in a side + // data structure. We can optimize this case later. + + uintptr_t V = (uintptr_t) location.ptr_data[0]; + assert((V & 0x1) == 1); + V &= ~(uintptr_t)1; + + const Location &Loc = *((Location*)V); + + if (file) + *file = Loc.file; + if (line) + *line = Loc.line; + if (column) + *column = Loc.column; + if (offset) + *offset = Loc.offset; +} + +//===----------------------------------------------------------------------===// +// Deserialize diagnostics. +//===----------------------------------------------------------------------===// + +enum { MaxSupportedVersion = 1 }; +typedef SmallVector<uint64_t, 64> RecordData; +enum LoadResult { Failure = 1, Success = 0 }; +enum StreamResult { Read_EndOfStream, + Read_BlockBegin, + Read_Failure, + Read_Record, + Read_BlockEnd }; + +namespace { +class DiagLoader { + enum CXLoadDiag_Error *error; + CXString *errorString; + + void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) { + if (error) + *error = code; + if (errorString) + *errorString = createCXString(err); + } + + void reportInvalidFile(llvm::StringRef err) { + return reportBad(CXLoadDiag_InvalidFile, err); + } + + LoadResult readMetaBlock(llvm::BitstreamCursor &Stream); + + LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream, + CXDiagnosticSetImpl &Diags, + CXLoadedDiagnosticSetImpl &TopDiags); + + StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream, + llvm::StringRef errorContext, + unsigned &BlockOrRecordID, + const bool atTopLevel = false); + + + LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags, + Strings &strings, llvm::StringRef errorContext, + RecordData &Record, + const char *BlobStart, + unsigned BlobLen, + bool allowEmptyString = false); + + LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags, + llvm::StringRef &RetStr, + llvm::StringRef errorContext, + RecordData &Record, + const char *BlobStart, + unsigned BlobLen, + bool allowEmptyString = false); + + LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned RecStartIdx, + CXSourceRange &SR); + + LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned &offset, + CXLoadedDiagnostic::Location &Loc); + +public: + DiagLoader(enum CXLoadDiag_Error *e, CXString *es) + : error(e), errorString(es) { + if (error) + *error = CXLoadDiag_None; + if (errorString) + *errorString = createCXString(""); + } + + CXDiagnosticSet load(const char *file); +}; +} + +CXDiagnosticSet DiagLoader::load(const char *file) { + // Open the diagnostics file. + std::string ErrStr; + FileSystemOptions FO; + FileManager FileMgr(FO); + + OwningPtr<llvm::MemoryBuffer> Buffer; + Buffer.reset(FileMgr.getBufferForFile(file)); + + if (!Buffer) { + reportBad(CXLoadDiag_CannotLoad, ErrStr); + return 0; + } + + llvm::BitstreamReader StreamFile; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + + llvm::BitstreamCursor Stream; + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'D' || + Stream.Read(8) != 'I' || + Stream.Read(8) != 'A' || + Stream.Read(8) != 'G') { + reportBad(CXLoadDiag_InvalidFile, + "Bad header in diagnostics file"); + return 0; + } + + OwningPtr<CXLoadedDiagnosticSetImpl> + Diags(new CXLoadedDiagnosticSetImpl()); + + while (true) { + unsigned BlockID = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", + BlockID, true); + switch (Res) { + case Read_EndOfStream: + return (CXDiagnosticSet) Diags.take(); + case Read_Failure: + return 0; + case Read_Record: + llvm_unreachable("Top-level does not have records"); + case Read_BlockEnd: + continue; + case Read_BlockBegin: + break; + } + + switch (BlockID) { + case serialized_diags::BLOCK_META: + if (readMetaBlock(Stream)) + return 0; + break; + case serialized_diags::BLOCK_DIAG: + if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get())) + return 0; + break; + default: + if (!Stream.SkipBlock()) { + reportInvalidFile("Malformed block at top-level of diagnostics file"); + return 0; + } + break; + } + } +} + +StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream, + llvm::StringRef errorContext, + unsigned &blockOrRecordID, + const bool atTopLevel) { + + blockOrRecordID = 0; + + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + // Handle the top-level specially. + if (atTopLevel) { + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) { + if (Stream.ReadBlockInfoBlock()) { + reportInvalidFile("Malformed BlockInfoBlock in diagnostics file"); + return Read_Failure; + } + continue; + } + blockOrRecordID = BlockID; + return Read_BlockBegin; + } + reportInvalidFile("Only blocks can appear at the top of a " + "diagnostic file"); + return Read_Failure; + } + + switch ((llvm::bitc::FixedAbbrevIDs)Code) { + case llvm::bitc::ENTER_SUBBLOCK: + blockOrRecordID = Stream.ReadSubBlockID(); + return Read_BlockBegin; + + case llvm::bitc::END_BLOCK: + if (Stream.ReadBlockEnd()) { + reportInvalidFile("Cannot read end of block"); + return Read_Failure; + } + return Read_BlockEnd; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + + case llvm::bitc::UNABBREV_RECORD: + reportInvalidFile("Diagnostics file should have no unabbreviated " + "records"); + return Read_Failure; + + default: + // We found a record. + blockOrRecordID = Code; + return Read_Record; + } + } + + if (atTopLevel) + return Read_EndOfStream; + + reportInvalidFile(Twine("Premature end of diagnostics file within ").str() + + errorContext.str()); + return Read_Failure; +} + +LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) { + if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { + reportInvalidFile("Malformed metadata block"); + return Failure; + } + + bool versionChecked = false; + + while (true) { + unsigned blockOrCode = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block", + blockOrCode); + + switch(Res) { + case Read_EndOfStream: + llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock"); + case Read_Failure: + return Failure; + case Read_Record: + break; + case Read_BlockBegin: + if (Stream.SkipBlock()) { + reportInvalidFile("Malformed metadata block"); + return Failure; + } + case Read_BlockEnd: + if (!versionChecked) { + reportInvalidFile("Diagnostics file does not contain version" + " information"); + return Failure; + } + return Success; + } + + RecordData Record; + const char *Blob; + unsigned BlobLen; + unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen); + + if (recordID == serialized_diags::RECORD_VERSION) { + if (Record.size() < 1) { + reportInvalidFile("malformed VERSION identifier in diagnostics file"); + return Failure; + } + if (Record[0] > MaxSupportedVersion) { + reportInvalidFile("diagnosics file is a newer version than the one " + "supported"); + return Failure; + } + versionChecked = true; + } + } +} + +LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags, + llvm::StringRef &RetStr, + llvm::StringRef errorContext, + RecordData &Record, + const char *BlobStart, + unsigned BlobLen, + bool allowEmptyString) { + + // Basic buffer overflow check. + if (BlobLen > 65536) { + reportInvalidFile(std::string("Out-of-bounds string in ") + + std::string(errorContext)); + return Failure; + } + + if (allowEmptyString && Record.size() >= 1 && BlobLen == 0) { + RetStr = ""; + return Success; + } + + if (Record.size() < 1 || BlobLen == 0) { + reportInvalidFile(std::string("Corrupted ") + std::string(errorContext) + + std::string(" entry")); + return Failure; + } + + RetStr = TopDiags.makeString(BlobStart, BlobLen); + return Success; +} + +LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags, + Strings &strings, + llvm::StringRef errorContext, + RecordData &Record, + const char *BlobStart, + unsigned BlobLen, + bool allowEmptyString) { + llvm::StringRef RetStr; + if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen, + allowEmptyString)) + return Failure; + strings[Record[0]] = RetStr; + return Success; +} + +LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned &offset, + CXLoadedDiagnostic::Location &Loc) { + if (Record.size() < offset + 3) { + reportInvalidFile("Corrupted source location"); + return Failure; + } + + unsigned fileID = Record[offset++]; + if (fileID == 0) { + // Sentinel value. + Loc.file = 0; + Loc.line = 0; + Loc.column = 0; + Loc.offset = 0; + return Success; + } + + const FileEntry *FE = TopDiags.Files[fileID]; + if (!FE) { + reportInvalidFile("Corrupted file entry in source location"); + return Failure; + } + Loc.file = (void*) FE; + Loc.line = Record[offset++]; + Loc.column = Record[offset++]; + Loc.offset = Record[offset++]; + return Success; +} + +LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, + unsigned int RecStartIdx, + CXSourceRange &SR) { + CXLoadedDiagnostic::Location *Start, *End; + Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>(); + End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>(); + + if (readLocation(TopDiags, Record, RecStartIdx, *Start)) + return Failure; + if (readLocation(TopDiags, Record, RecStartIdx, *End)) + return Failure; + + CXSourceLocation startLoc = makeLocation(Start); + CXSourceLocation endLoc = makeLocation(End); + SR = clang_getRange(startLoc, endLoc); + return Success; +} + +LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream, + CXDiagnosticSetImpl &Diags, + CXLoadedDiagnosticSetImpl &TopDiags){ + + if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { + reportInvalidFile("malformed diagnostic block"); + return Failure; + } + + OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic()); + RecordData Record; + + while (true) { + unsigned blockOrCode = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block", + blockOrCode); + switch (Res) { + case Read_EndOfStream: + llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock"); + case Read_Failure: + return Failure; + case Read_BlockBegin: { + // The only blocks we care about are subdiagnostics. + if (blockOrCode != serialized_diags::BLOCK_DIAG) { + if (!Stream.SkipBlock()) { + reportInvalidFile("Invalid subblock in Diagnostics block"); + return Failure; + } + } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(), + TopDiags)) { + return Failure; + } + + continue; + } + case Read_BlockEnd: + Diags.appendDiagnostic(D.take()); + return Success; + case Read_Record: + break; + } + + // Read the record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + unsigned recID = Stream.ReadRecord(blockOrCode, Record, + BlobStart, BlobLen); + + if (recID < serialized_diags::RECORD_FIRST || + recID > serialized_diags::RECORD_LAST) + continue; + + switch ((serialized_diags::RecordIDs)recID) { + case serialized_diags::RECORD_VERSION: + continue; + case serialized_diags::RECORD_CATEGORY: + if (readString(TopDiags, TopDiags.Categories, "category", Record, + BlobStart, BlobLen, + /* allowEmptyString */ true)) + return Failure; + continue; + + case serialized_diags::RECORD_DIAG_FLAG: + if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record, + BlobStart, BlobLen)) + return Failure; + continue; + + case serialized_diags::RECORD_FILENAME: { + if (readString(TopDiags, TopDiags.FileNames, "filename", Record, + BlobStart, BlobLen)) + return Failure; + + if (Record.size() < 3) { + reportInvalidFile("Invalid file entry"); + return Failure; + } + + const FileEntry *FE = + TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]], + /* size */ Record[1], + /* time */ Record[2]); + + TopDiags.Files[Record[0]] = FE; + continue; + } + + case serialized_diags::RECORD_SOURCE_RANGE: { + CXSourceRange SR; + if (readRange(TopDiags, Record, 0, SR)) + return Failure; + D->Ranges.push_back(SR); + continue; + } + + case serialized_diags::RECORD_FIXIT: { + CXSourceRange SR; + if (readRange(TopDiags, Record, 0, SR)) + return Failure; + llvm::StringRef RetStr; + if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen, + /* allowEmptyString */ true)) + return Failure; + D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false))); + continue; + } + + case serialized_diags::RECORD_DIAG: { + D->severity = Record[0]; + unsigned offset = 1; + if (readLocation(TopDiags, Record, offset, D->DiagLoc)) + return Failure; + D->category = Record[offset++]; + unsigned diagFlag = Record[offset++]; + D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : ""; + D->CategoryText = D->category ? TopDiags.Categories[D->category] : ""; + D->Spelling = TopDiags.makeString(BlobStart, BlobLen); + continue; + } + } + } +} + +extern "C" { +CXDiagnosticSet clang_loadDiagnostics(const char *file, + enum CXLoadDiag_Error *error, + CXString *errorString) { + DiagLoader L(error, errorString); + return L.load(file); +} +} // end extern 'C'. diff --git a/clang/tools/libclang/CXLoadedDiagnostic.h b/clang/tools/libclang/CXLoadedDiagnostic.h new file mode 100644 index 0000000..d4a321e --- /dev/null +++ b/clang/tools/libclang/CXLoadedDiagnostic.h @@ -0,0 +1,94 @@ +/*===-- CXLoadedDiagnostic.h - Handling of persisent diags ------*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements handling of persisent diagnostics. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H +#define LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H + +#include "CIndexDiagnostic.h" +#include "llvm/ADT/StringRef.h" +#include "clang/Basic/LLVM.h" +#include <string> +#include <vector> + +namespace clang { +class CXLoadedDiagnostic : public CXDiagnosticImpl { +public: + CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind), + severity(0), category(0) {} + + virtual ~CXLoadedDiagnostic(); + + /// \brief Return the severity of the diagnostic. + virtual CXDiagnosticSeverity getSeverity() const; + + /// \brief Return the location of the diagnostic. + virtual CXSourceLocation getLocation() const; + + /// \brief Return the spelling of the diagnostic. + virtual CXString getSpelling() const; + + /// \brief Return the text for the diagnostic option. + virtual CXString getDiagnosticOption(CXString *Disable) const; + + /// \brief Return the category of the diagnostic. + virtual unsigned getCategory() const; + + /// \brief Return the category string of the diagnostic. + virtual CXString getCategoryText() const; + + /// \brief Return the number of source ranges for the diagnostic. + virtual unsigned getNumRanges() const; + + /// \brief Return the source ranges for the diagnostic. + virtual CXSourceRange getRange(unsigned Range) const; + + /// \brief Return the number of FixIts. + virtual unsigned getNumFixIts() const; + + /// \brief Return the FixIt information (source range and inserted text). + virtual CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const; + + static bool classof(const CXDiagnosticImpl *D) { + return D->getKind() == LoadedDiagnosticKind; + } + + /// \brief Decode the CXSourceLocation into file, line, column, and offset. + static void decodeLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + + struct Location { + CXFile file; + unsigned line; + unsigned column; + unsigned offset; + + Location() : line(0), column(0), offset(0) {} + }; + + Location DiagLoc; + + std::vector<CXSourceRange> Ranges; + std::vector<std::pair<CXSourceRange, CXString> > FixIts; + llvm::StringRef Spelling; + llvm::StringRef DiagOption; + llvm::StringRef CategoryText; + unsigned severity; + unsigned category; +}; +} + +#endif diff --git a/clang/tools/libclang/CXSourceLocation.cpp b/clang/tools/libclang/CXSourceLocation.cpp new file mode 100644 index 0000000..a6bf8fc --- /dev/null +++ b/clang/tools/libclang/CXSourceLocation.cpp @@ -0,0 +1,326 @@ +//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXSourceLocations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/ASTUnit.h" + +#include "CIndexer.h" +#include "CXString.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "CXLoadedDiagnostic.h" + +using namespace clang; +using namespace clang::cxstring; + +//===----------------------------------------------------------------------===// +// Internal predicates on CXSourceLocations. +//===----------------------------------------------------------------------===// + +static bool isASTUnitSourceLocation(const CXSourceLocation &L) { + // If the lowest bit is clear then the first ptr_data entry is a SourceManager + // pointer, or the CXSourceLocation is a null location. + return ((uintptr_t)L.ptr_data[0] & 0x1) == 0; +} + +//===----------------------------------------------------------------------===// +// Basic construction and comparison of CXSourceLocations and CXSourceRanges. +//===----------------------------------------------------------------------===// + +extern "C" { + +CXSourceLocation clang_getNullLocation() { + CXSourceLocation Result = { { 0, 0 }, 0 }; + return Result; +} + +unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { + return (loc1.ptr_data[0] == loc2.ptr_data[0] && + loc1.ptr_data[1] == loc2.ptr_data[1] && + loc1.int_data == loc2.int_data); +} + +CXSourceRange clang_getNullRange() { + CXSourceRange Result = { { 0, 0 }, 0, 0 }; + return Result; +} + +CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { + if (!isASTUnitSourceLocation(begin)) { + if (isASTUnitSourceLocation(end)) + return clang_getNullRange(); + CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 }; + return Result; + } + + if (begin.ptr_data[0] != end.ptr_data[0] || + begin.ptr_data[1] != end.ptr_data[1]) + return clang_getNullRange(); + + CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, + begin.int_data, end.int_data }; + + return Result; +} + +unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) { + return range1.ptr_data[0] == range2.ptr_data[0] + && range1.ptr_data[1] == range2.ptr_data[1] + && range1.begin_int_data == range2.begin_int_data + && range1.end_int_data == range2.end_int_data; +} + +int clang_Range_isNull(CXSourceRange range) { + return clang_equalRanges(range, clang_getNullRange()); +} + + +CXSourceLocation clang_getRangeStart(CXSourceRange range) { + // Special decoding for CXSourceLocations for CXLoadedDiagnostics. + if ((uintptr_t)range.ptr_data[0] & 0x1) { + CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 }; + return Result; + } + + CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, + range.begin_int_data }; + return Result; +} + +CXSourceLocation clang_getRangeEnd(CXSourceRange range) { + // Special decoding for CXSourceLocations for CXLoadedDiagnostics. + if ((uintptr_t)range.ptr_data[0] & 0x1) { + CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 }; + return Result; + } + + CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, + range.end_int_data }; + return Result; +} + +} // end extern "C" + +//===----------------------------------------------------------------------===// +// Getting CXSourceLocations and CXSourceRanges from a translation unit. +//===----------------------------------------------------------------------===// + +extern "C" { + +CXSourceLocation clang_getLocation(CXTranslationUnit tu, + CXFile file, + unsigned line, + unsigned column) { + if (!tu || !file) + return clang_getNullLocation(); + + bool Logging = ::getenv("LIBCLANG_LOGGING"); + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + const FileEntry *File = static_cast<const FileEntry *>(file); + SourceLocation SLoc = CXXUnit->getLocation(File, line, column); + if (SLoc.isInvalid()) { + if (Logging) + llvm::errs() << "clang_getLocation(\"" << File->getName() + << "\", " << line << ", " << column << ") = invalid\n"; + return clang_getNullLocation(); + } + + if (Logging) + llvm::errs() << "clang_getLocation(\"" << File->getName() + << "\", " << line << ", " << column << ") = " + << SLoc.getRawEncoding() << "\n"; + + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); +} + +CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, + CXFile file, + unsigned offset) { + if (!tu || !file) + return clang_getNullLocation(); + + ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); + + SourceLocation SLoc + = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); + + if (SLoc.isInvalid()) + return clang_getNullLocation(); + + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); +} + +} // end extern "C" + +//===----------------------------------------------------------------------===// +// Routines for expanding and manipulating CXSourceLocations, regardless +// of their origin. +//===----------------------------------------------------------------------===// + +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; +} + +static void createNullLocation(CXString *filename, unsigned *line, + unsigned *column, unsigned *offset = 0) { + if (filename) + *filename = createCXString(""); + if (line) + *line = 0; + if (column) + *column = 0; + if (offset) + *offset = 0; + return; +} + +extern "C" { + +void clang_getExpansionLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + + if (!isASTUnitSourceLocation(location)) { + CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) { + createNullLocation(file, line, column, offset); + return; + } + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); + + // Check that the FileID is invalid on the expansion location. + // This can manifest in invalid code. + FileID fileID = SM.getFileID(ExpansionLoc); + bool Invalid = false; + const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); + if (Invalid || !sloc.isFile()) { + createNullLocation(file, line, column, offset); + return; + } + + if (file) + *file = (void *)SM.getFileEntryForSLocEntry(sloc); + if (line) + *line = SM.getExpansionLineNumber(ExpansionLoc); + if (column) + *column = SM.getExpansionColumnNumber(ExpansionLoc); + if (offset) + *offset = SM.getDecomposedLoc(ExpansionLoc).second; +} + +void clang_getPresumedLocation(CXSourceLocation location, + CXString *filename, + unsigned *line, + unsigned *column) { + + if (!isASTUnitSourceLocation(location)) { + // Other SourceLocation implementations do not support presumed locations + // at this time. + createNullLocation(filename, line, column); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) + createNullLocation(filename, line, column); + else { + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + PresumedLoc PreLoc = SM.getPresumedLoc(Loc); + + if (filename) + *filename = createCXString(PreLoc.getFilename()); + if (line) + *line = PreLoc.getLine(); + if (column) + *column = PreLoc.getColumn(); + } +} + +void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + // Redirect to new API. + clang_getExpansionLocation(location, file, line, column, offset); +} + +void clang_getSpellingLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + + if (!isASTUnitSourceLocation(location)) { + CXLoadedDiagnostic::decodeLocation(location, file, line, + column, offset); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) + return createNullLocation(file, line, column, offset); + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + SourceLocation SpellLoc = Loc; + if (SpellLoc.isMacroID()) { + SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc); + if (SimpleSpellingLoc.isFileID() && + SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first)) + SpellLoc = SimpleSpellingLoc; + else + SpellLoc = SM.getExpansionLoc(SpellLoc); + } + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return createNullLocation(file, line, column, offset); + + if (file) + *file = (void *)SM.getFileEntryForID(FID); + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} + +} // end extern "C" + diff --git a/clang/tools/libclang/CXSourceLocation.h b/clang/tools/libclang/CXSourceLocation.h new file mode 100644 index 0000000..6c5e858 --- /dev/null +++ b/clang/tools/libclang/CXSourceLocation.h @@ -0,0 +1,78 @@ +//===- CXSourceLocation.h - CXSourceLocations Utilities ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXSourceLocations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXSOURCELOCATION_H +#define LLVM_CLANG_CXSOURCELOCATION_H + +#include "clang-c/Index.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/LangOptions.h" +#include "clang/AST/ASTContext.h" + +namespace clang { + +class SourceManager; + +namespace cxloc { + +/// \brief Translate a Clang source location into a CIndex source location. +static inline CXSourceLocation +translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts, + SourceLocation Loc) { + if (Loc.isInvalid()) + clang_getNullLocation(); + + CXSourceLocation Result = { { (void*) &SM, (void*) &LangOpts, }, + Loc.getRawEncoding() }; + return Result; +} + +/// \brief Translate a Clang source location into a CIndex source location. +static inline CXSourceLocation translateSourceLocation(ASTContext &Context, + SourceLocation Loc) { + return translateSourceLocation(Context.getSourceManager(), + Context.getLangOpts(), + Loc); +} + +/// \brief Translate a Clang source range into a CIndex source range. +/// +/// Clang internally represents ranges where the end location points to the +/// start of the token at the end. However, for external clients it is more +/// useful to have a CXSourceRange be a proper half-open interval. This routine +/// does the appropriate translation. +CXSourceRange translateSourceRange(const SourceManager &SM, + const LangOptions &LangOpts, + const CharSourceRange &R); + +/// \brief Translate a Clang source range into a CIndex source range. +static inline CXSourceRange translateSourceRange(ASTContext &Context, + SourceRange R) { + return translateSourceRange(Context.getSourceManager(), + Context.getLangOpts(), + CharSourceRange::getTokenRange(R)); +} + +static inline SourceLocation translateSourceLocation(CXSourceLocation L) { + return SourceLocation::getFromRawEncoding(L.int_data); +} + +static inline SourceRange translateCXSourceRange(CXSourceRange R) { + return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data), + SourceLocation::getFromRawEncoding(R.end_int_data)); +} + + +}} // end namespace: clang::cxloc + +#endif diff --git a/clang/tools/libclang/CXStoredDiagnostic.cpp b/clang/tools/libclang/CXStoredDiagnostic.cpp new file mode 100644 index 0000000..8284dc9 --- /dev/null +++ b/clang/tools/libclang/CXStoredDiagnostic.cpp @@ -0,0 +1,119 @@ +/*===-- CXStoreDiagnostic.cpp - Diagnostics C Interface ----------*- C++ -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements part of the diagnostic functions of the Clang C interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "CIndexDiagnostic.h" +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXSourceLocation.h" +#include "CXString.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::cxloc; +using namespace clang::cxstring; + +CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const { + switch (Diag.getLevel()) { + case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored; + case DiagnosticsEngine::Note: return CXDiagnostic_Note; + case DiagnosticsEngine::Warning: return CXDiagnostic_Warning; + case DiagnosticsEngine::Error: return CXDiagnostic_Error; + case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal; + } + + llvm_unreachable("Invalid diagnostic level"); +} + +CXSourceLocation CXStoredDiagnostic::getLocation() const { + if (Diag.getLocation().isInvalid()) + return clang_getNullLocation(); + + return translateSourceLocation(Diag.getLocation().getManager(), + LangOpts, Diag.getLocation()); +} + +CXString CXStoredDiagnostic::getSpelling() const { + return createCXString(Diag.getMessage(), false); +} + +CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const { + unsigned ID = Diag.getID(); + StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID); + if (!Option.empty()) { + if (Disable) + *Disable = createCXString((Twine("-Wno-") + Option).str()); + return createCXString((Twine("-W") + Option).str()); + } + + if (ID == diag::fatal_too_many_errors) { + if (Disable) + *Disable = createCXString("-ferror-limit=0"); + return createCXString("-ferror-limit="); + } + + bool EnabledByDefault; + if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) && + !EnabledByDefault) + return createCXString("-pedantic"); + + return createCXString(""); +} + +unsigned CXStoredDiagnostic::getCategory() const { + return DiagnosticIDs::getCategoryNumberForDiag(Diag.getID()); +} + +CXString CXStoredDiagnostic::getCategoryText() const { + unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID()); + return createCXString(DiagnosticIDs::getCategoryNameFromID(catID)); +} + +unsigned CXStoredDiagnostic::getNumRanges() const { + if (Diag.getLocation().isInvalid()) + return 0; + + return Diag.range_size(); +} + +CXSourceRange CXStoredDiagnostic::getRange(unsigned int Range) const { + assert(Diag.getLocation().isValid()); + return translateSourceRange(Diag.getLocation().getManager(), + LangOpts, + Diag.range_begin()[Range]); +} + +unsigned CXStoredDiagnostic::getNumFixIts() const { + if (Diag.getLocation().isInvalid()) + return 0; + return Diag.fixit_size(); +} + +CXString CXStoredDiagnostic::getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const { + const FixItHint &Hint = Diag.fixit_begin()[FixIt]; + if (ReplacementRange) { + // Create a range that covers the entire replacement (or + // removal) range, adjusting the end of the range to point to + // the end of the token. + *ReplacementRange = translateSourceRange(Diag.getLocation().getManager(), + LangOpts, Hint.RemoveRange); + } + return createCXString(Hint.CodeToInsert); +} + diff --git a/clang/tools/libclang/CXString.cpp b/clang/tools/libclang/CXString.cpp new file mode 100644 index 0000000..bb09cd5 --- /dev/null +++ b/clang/tools/libclang/CXString.cpp @@ -0,0 +1,134 @@ +//===- CXString.cpp - Routines for manipulating CXStrings -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXStrings. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXStrings. +// +//===----------------------------------------------------------------------===// + +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang-c/Index.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; +using namespace clang::cxstring; + +enum CXStringFlag { CXS_Unmanaged, CXS_Malloc, CXS_StringBuf }; + +//===----------------------------------------------------------------------===// +// Basic generation of CXStrings. +//===----------------------------------------------------------------------===// + +CXString cxstring::createCXString(const char *String, bool DupString){ + CXString Str; + if (DupString) { + Str.data = strdup(String); + Str.private_flags = (unsigned) CXS_Malloc; + } else { + Str.data = (void*)String; + Str.private_flags = (unsigned) CXS_Unmanaged; + } + return Str; +} + +CXString cxstring::createCXString(StringRef String, bool DupString) { + CXString Result; + if (DupString || (!String.empty() && String.data()[String.size()] != 0)) { + char *Spelling = (char *)malloc(String.size() + 1); + memmove(Spelling, String.data(), String.size()); + Spelling[String.size()] = 0; + Result.data = Spelling; + Result.private_flags = (unsigned) CXS_Malloc; + } else { + Result.data = (void*) String.data(); + Result.private_flags = (unsigned) CXS_Unmanaged; + } + return Result; +} + +CXString cxstring::createCXString(CXStringBuf *buf) { + CXString Str; + Str.data = buf; + Str.private_flags = (unsigned) CXS_StringBuf; + return Str; +} + + +//===----------------------------------------------------------------------===// +// String pools. +//===----------------------------------------------------------------------===// + + +typedef std::vector<CXStringBuf *> CXStringPool; + +void *cxstring::createCXStringPool() { + return new CXStringPool(); +} + +void cxstring::disposeCXStringPool(void *p) { + CXStringPool *pool = static_cast<CXStringPool*>(p); + if (pool) { + for (CXStringPool::iterator I = pool->begin(), E = pool->end(); + I != E; ++I) { + delete *I; + } + delete pool; + } +} + +CXStringBuf *cxstring::getCXStringBuf(CXTranslationUnit TU) { + CXStringPool *pool = static_cast<CXStringPool*>(TU->StringPool); + if (pool->empty()) + return new CXStringBuf(TU); + CXStringBuf *buf = pool->back(); + buf->Data.clear(); + pool->pop_back(); + return buf; +} + +void cxstring::disposeCXStringBuf(CXStringBuf *buf) { + if (buf) + static_cast<CXStringPool*>(buf->TU->StringPool)->push_back(buf); +} + +bool cxstring::isManagedByPool(CXString str) { + return ((CXStringFlag) str.private_flags) == CXS_StringBuf; +} + +//===----------------------------------------------------------------------===// +// libClang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { +const char *clang_getCString(CXString string) { + if (string.private_flags == (unsigned) CXS_StringBuf) { + return ((CXStringBuf*)string.data)->Data.data(); + } + return (const char*) string.data; +} + +void clang_disposeString(CXString string) { + switch ((CXStringFlag) string.private_flags) { + case CXS_Unmanaged: + break; + case CXS_Malloc: + if (string.data) + free((void*)string.data); + break; + case CXS_StringBuf: + disposeCXStringBuf((CXStringBuf *) string.data); + break; + } +} +} // end: extern "C" + diff --git a/clang/tools/libclang/CXString.h b/clang/tools/libclang/CXString.h new file mode 100644 index 0000000..c354bd2 --- /dev/null +++ b/clang/tools/libclang/CXString.h @@ -0,0 +1,57 @@ +//===- CXString.h - Routines for manipulating CXStrings -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXStrings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXSTRING_H +#define LLVM_CLANG_CXSTRING_H + +#include "clang-c/Index.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" + +namespace clang { +namespace cxstring { + +struct CXStringBuf { + SmallString<128> Data; + CXTranslationUnit TU; + CXStringBuf(CXTranslationUnit tu) : TU(tu) {} +}; + +/// \brief Create a CXString object from a C string. +CXString createCXString(const char *String, bool DupString = false); + +/// \brief Create a CXString object from a StringRef. +CXString createCXString(StringRef String, bool DupString = true); + +/// \brief Create a CXString object that is backed by a string buffer. +CXString createCXString(CXStringBuf *buf); + +/// \brief Create an opaque string pool used for fast geneneration of strings. +void *createCXStringPool(); + +/// \brief Dispose of a string pool. +void disposeCXStringPool(void *pool); + +CXStringBuf *getCXStringBuf(CXTranslationUnit TU); + +void disposeCXStringBuf(CXStringBuf *buf); + +/// \brief Returns true if the CXString data is managed by a pool. +bool isManagedByPool(CXString str); + +} +} + +#endif + diff --git a/clang/tools/libclang/CXTranslationUnit.h b/clang/tools/libclang/CXTranslationUnit.h new file mode 100644 index 0000000..3ad867c --- /dev/null +++ b/clang/tools/libclang/CXTranslationUnit.h @@ -0,0 +1,53 @@ +//===- CXTranslationUnit.h - Routines for manipulating CXTranslationUnits -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXTranslationUnits. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXTRANSLATIONUNIT_H +#define LLVM_CLANG_CXTRANSLATIONUNIT_H + +extern "C" { +struct CXTranslationUnitImpl { + void *CIdx; + void *TUData; + void *StringPool; + void *Diagnostics; +}; +} + +namespace clang { + class ASTUnit; + class CIndexer; + +namespace cxtu { + +CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU); + +class CXTUOwner { + CXTranslationUnitImpl *TU; + +public: + CXTUOwner(CXTranslationUnitImpl *tu) : TU(tu) { } + ~CXTUOwner(); + + CXTranslationUnitImpl *getTU() const { return TU; } + + CXTranslationUnitImpl *takeTU() { + CXTranslationUnitImpl *retTU = TU; + TU = 0; + return retTU; + } +}; + + +}} // end namespace clang::cxtu + +#endif diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp new file mode 100644 index 0000000..850fac1 --- /dev/null +++ b/clang/tools/libclang/CXType.cpp @@ -0,0 +1,631 @@ +//===- 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 "CXTranslationUnit.h" +#include "CXCursor.h" +#include "CXString.h" +#include "CXType.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.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); + case BuiltinType::WChar_S: return CXType_WChar; + case BuiltinType::WChar_U: return CXType_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) { + const Type *TP = T.getTypePtrOrNull(); + 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); + TKCASE(FunctionNoProto); + TKCASE(FunctionProto); + TKCASE(ConstantArray); + TKCASE(Vector); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + + +CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { + CXTypeKind TK = GetTypeKind(T); + CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; + return CT; +} + +using cxtype::MakeCXType; + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline CXTranslationUnit GetTU(CXType CT) { + return static_cast<CXTranslationUnit>(CT.data[1]); +} + +extern "C" { + +CXType clang_getCursorType(CXCursor C) { + using namespace cxcursor; + + CXTranslationUnit TU = cxcursor::getCursorTU(C); + ASTContext &Context = static_cast<ASTUnit *>(TU->TUData)->getASTContext(); + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, TU); + } + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return MakeCXType(QualType(), TU); + + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCXType(Context.getTypeDeclType(TD), TU); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCXType(Context.getObjCInterfaceType(ID), TU); + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + return MakeCXType(VD->getType(), TU); + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) + return MakeCXType(PD->getType(), TU); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return MakeCXType(FD->getType(), TU); + return MakeCXType(QualType(), TU); + } + + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + QualType T + = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_ObjCClassRef: { + QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_TypeRef: { + QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first); + return MakeCXType(T, TU); + + } + + case CXCursor_CXXBaseSpecifier: + return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU); + + case CXCursor_MemberRef: + return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU); + + case CXCursor_VariableRef: + return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU); + + case CXCursor_ObjCProtocolRef: + case CXCursor_TemplateRef: + case CXCursor_NamespaceRef: + case CXCursor_OverloadedDeclRef: + default: + break; + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { + using namespace cxcursor; + CXTranslationUnit TU = cxcursor::getCursorTU(C); + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) { + QualType T = TD->getUnderlyingType(); + return MakeCXType(T, TU); + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +CXType clang_getEnumDeclIntegerType(CXCursor C) { + using namespace cxcursor; + CXTranslationUnit TU = cxcursor::getCursorTU(C); + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) { + QualType T = TD->getIntegerType(); + return MakeCXType(T, TU); + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +long long clang_getEnumConstantDeclValue(CXCursor C) { + using namespace cxcursor; + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { + return TD->getInitVal().getSExtValue(); + } + + return LLONG_MIN; + } + + return LLONG_MIN; +} + +unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) { + using namespace cxcursor; + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { + return TD->getInitVal().getZExtValue(); + } + + return ULLONG_MAX; + } + + return ULLONG_MAX; +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + CXTranslationUnit TU = GetTU(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData); + return MakeCXType(AU->getASTContext().getCanonicalType(T), TU); +} + +unsigned clang_isConstQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalConstQualified(); +} + +unsigned clang_isVolatileQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalVolatileQualified(); +} + +unsigned clang_isRestrictQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalRestrictQualified(); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (!TP) + return MakeCXType(QualType(), GetTU(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, GetTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + if (CT.kind == CXType_Invalid) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (!TP) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + Decl *D = 0; + +try_again: + 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; + case Type::TemplateSpecialization: + if (const RecordType *Record = TP->getAs<RecordType>()) + D = Record->getDecl(); + else + D = cast<TemplateSpecializationType>(TP)->getTemplateName() + .getAsTemplateDecl(); + break; + + case Type::InjectedClassName: + D = cast<InjectedClassNameType>(TP)->getDecl(); + break; + + // FIXME: Template type parameters! + + case Type::Elaborated: + TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); + goto try_again; + + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetTU(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); + case CXType_WChar: s = "WChar"; break; + 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); + TKIND(FunctionNoProto); + TKIND(FunctionProto); + TKIND(ConstantArray); + TKIND(Vector); + } +#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];; +} + +unsigned clang_isFunctionTypeVariadic(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return 0; + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) + return (unsigned)FD->isVariadic(); + + if (T->getAs<FunctionNoProtoType>()) + return 1; + + return 0; +} + +CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return CXCallingConv_Invalid; + + if (const FunctionType *FD = T->getAs<FunctionType>()) { +#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X + switch (FD->getCallConv()) { + TCALLINGCONV(Default); + TCALLINGCONV(C); + TCALLINGCONV(X86StdCall); + TCALLINGCONV(X86FastCall); + TCALLINGCONV(X86ThisCall); + TCALLINGCONV(X86Pascal); + TCALLINGCONV(AAPCS); + TCALLINGCONV(AAPCS_VFP); + } +#undef TCALLINGCONV + } + + return CXCallingConv_Invalid; +} + +int clang_getNumArgTypes(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return -1; + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { + return FD->getNumArgs(); + } + + if (T->getAs<FunctionNoProtoType>()) { + return 0; + } + + return -1; +} + +CXType clang_getArgType(CXType X, unsigned i) { + QualType T = GetQualType(X); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(X)); + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { + unsigned numArgs = FD->getNumArgs(); + if (i >= numArgs) + return MakeCXType(QualType(), GetTU(X)); + + return MakeCXType(FD->getArgType(i), GetTU(X)); + } + + return MakeCXType(QualType(), GetTU(X)); +} + +CXType clang_getResultType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(X)); + + if (const FunctionType *FD = T->getAs<FunctionType>()) + return MakeCXType(FD->getResultType(), GetTU(X)); + + return MakeCXType(QualType(), GetTU(X)); +} + +CXType clang_getCursorResultType(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) + return MakeCXType(MD->getResultType(), cxcursor::getCursorTU(C)); + + return clang_getResultType(clang_getCursorType(C)); + } + + return MakeCXType(QualType(), cxcursor::getCursorTU(C)); +} + +unsigned clang_isPODType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return 0; + + CXTranslationUnit TU = GetTU(X); + ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData); + + return T.isPODType(AU->getASTContext()) ? 1 : 0; +} + +CXType clang_getElementType(CXType CT) { + QualType ET = QualType(); + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + ET = cast<ConstantArrayType> (TP)->getElementType(); + break; + case Type::Vector: + ET = cast<VectorType> (TP)->getElementType(); + break; + case Type::Complex: + ET = cast<ComplexType> (TP)->getElementType(); + break; + default: + break; + } + } + return MakeCXType(ET, GetTU(CT)); +} + +long long clang_getNumElements(CXType CT) { + long long result = -1; + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); + break; + case Type::Vector: + result = cast<VectorType> (TP)->getNumElements(); + break; + default: + break; + } + } + return result; +} + +CXType clang_getArrayElementType(CXType CT) { + QualType ET = QualType(); + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + ET = cast<ConstantArrayType> (TP)->getElementType(); + break; + default: + break; + } + } + return MakeCXType(ET, GetTU(CT)); +} + +long long clang_getArraySize(CXType CT) { + long long result = -1; + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); + break; + default: + break; + } + } + return result; +} + +CXString clang_getDeclObjCTypeEncoding(CXCursor C) { + if ((C.kind < CXCursor_FirstDecl) || (C.kind > CXCursor_LastDecl)) + return cxstring::createCXString(""); + + Decl *D = static_cast<Decl*>(C.data[0]); + CXTranslationUnit TU = static_cast<CXTranslationUnit>(C.data[2]); + ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData); + ASTContext &Ctx = AU->getASTContext(); + std::string encoding; + + if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { + if (Ctx.getObjCEncodingForMethodDecl(OMD, encoding)) + return cxstring::createCXString("?"); + } else if (ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D)) + Ctx.getObjCEncodingForPropertyDecl(OPD, NULL, encoding); + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + Ctx.getObjCEncodingForFunctionDecl(FD, encoding); + else { + QualType Ty; + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) + Ty = Ctx.getTypeDeclType(TD); + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + Ty = VD->getType(); + else return cxstring::createCXString("?"); + Ctx.getObjCEncodingForType(Ty, encoding); + } + + return cxstring::createCXString(encoding); +} + +} // end: extern "C" diff --git a/clang/tools/libclang/CXType.h b/clang/tools/libclang/CXType.h new file mode 100644 index 0000000..7660beb --- /dev/null +++ b/clang/tools/libclang/CXType.h @@ -0,0 +1,29 @@ +//===- CXTypes.h - Routines for manipulating CXTypes ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXTYPES_H +#define LLVM_CLANG_CXTYPES_H + +#include "clang-c/Index.h" +#include "clang/AST/Type.h" + +namespace clang { + +class ASTUnit; + +namespace cxtype { + +CXType MakeCXType(QualType T, CXTranslationUnit TU); + +}} // end namespace clang::cxtype +#endif diff --git a/clang/tools/libclang/CursorVisitor.h b/clang/tools/libclang/CursorVisitor.h new file mode 100644 index 0000000..88b70a4 --- /dev/null +++ b/clang/tools/libclang/CursorVisitor.h @@ -0,0 +1,259 @@ +//===- CursorVisitor.h - CursorVisitor interface --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIBCLANG_CURSORVISITOR_H +#define LLVM_CLANG_LIBCLANG_CURSORVISITOR_H + +#include "Index_Internal.h" +#include "CXCursor.h" +#include "CXTranslationUnit.h" + +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeLocVisitor.h" + +namespace clang { + class PreprocessingRecord; + class ASTUnit; + +namespace cxcursor { + +class VisitorJob { +public: + enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind, + TypeLocVisitKind, OverloadExprPartsKind, + DeclRefExprPartsKind, LabelRefVisitKind, + ExplicitTemplateArgsVisitKind, + NestedNameSpecifierLocVisitKind, + DeclarationNameInfoVisitKind, + MemberRefVisitKind, SizeOfPackExprPartsKind, + LambdaExprPartsKind }; +protected: + void *data[3]; + CXCursor parent; + Kind K; + VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0) + : parent(C), K(k) { + data[0] = d1; + data[1] = d2; + data[2] = d3; + } +public: + Kind getKind() const { return K; } + const CXCursor &getParent() const { return parent; } + static bool classof(VisitorJob *VJ) { return true; } +}; + +typedef SmallVector<VisitorJob, 10> VisitorWorkList; + +// Cursor visitor. +class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, + public TypeLocVisitor<CursorVisitor, bool> +{ + /// \brief The translation unit we are traversing. + CXTranslationUnit TU; + ASTUnit *AU; + + /// \brief The parent cursor whose children we are traversing. + CXCursor Parent; + + /// \brief The declaration that serves at the parent of any statement or + /// expression nodes. + Decl *StmtParent; + + /// \brief The visitor function. + CXCursorVisitor Visitor; + + /// \brief The opaque client data, to be passed along to the visitor. + CXClientData ClientData; + + /// \brief Whether we should visit the preprocessing record entries last, + /// after visiting other declarations. + bool VisitPreprocessorLast; + + /// \brief Whether we should visit declarations or preprocessing record + /// entries that are #included inside the \arg RegionOfInterest. + bool VisitIncludedEntities; + + /// \brief When valid, a source range to which the cursor should restrict + /// its search. + SourceRange RegionOfInterest; + + /// \brief Whether we should only visit declarations and not preprocessing + /// record entries. + bool VisitDeclsOnly; + + // FIXME: Eventually remove. This part of a hack to support proper + // iteration over all Decls contained lexically within an ObjC container. + DeclContext::decl_iterator *DI_current; + DeclContext::decl_iterator DE_current; + SmallVectorImpl<Decl *>::iterator *FileDI_current; + SmallVectorImpl<Decl *>::iterator FileDE_current; + + // Cache of pre-allocated worklists for data-recursion walk of Stmts. + SmallVector<VisitorWorkList*, 5> WorkListFreeList; + SmallVector<VisitorWorkList*, 5> WorkListCache; + + using DeclVisitor<CursorVisitor, bool>::Visit; + using TypeLocVisitor<CursorVisitor, bool>::Visit; + + /// \brief Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param R a half-open source range retrieved from the abstract syntax tree. + RangeComparisonResult CompareRegionOfInterest(SourceRange R); + + void visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length); + + 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(CXTranslationUnit TU, CXCursorVisitor Visitor, + CXClientData ClientData, + bool VisitPreprocessorLast, + bool VisitIncludedPreprocessingEntries = false, + SourceRange RegionOfInterest = SourceRange(), + bool VisitDeclsOnly = false) + : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)), + Visitor(Visitor), ClientData(ClientData), + VisitPreprocessorLast(VisitPreprocessorLast), + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), + VisitDeclsOnly(VisitDeclsOnly), + DI_current(0), FileDI_current(0) + { + Parent.kind = CXCursor_NoDeclFound; + Parent.data[0] = 0; + Parent.data[1] = 0; + Parent.data[2] = 0; + StmtParent = 0; + } + + ~CursorVisitor() { + // Free the pre-allocated worklists for data-recursion. + for (SmallVectorImpl<VisitorWorkList*>::iterator + I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) { + delete *I; + } + } + + ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); } + CXTranslationUnit getTU() const { return TU; } + + bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); + + /// \brief Visit declarations and preprocessed entities for the file region + /// designated by \see RegionOfInterest. + void visitFileRegion(); + + bool visitPreprocessedEntitiesInRegion(); + + bool shouldVisitIncludedEntities() const { + return VisitIncludedEntities; + } + + template<typename InputIterator> + bool visitPreprocessedEntities(InputIterator First, InputIterator Last, + PreprocessingRecord &PPRec, + FileID FID = FileID()); + + bool VisitChildren(CXCursor Parent); + + // Declaration visitors + bool VisitTypeAliasDecl(TypeAliasDecl *D); + bool VisitAttributes(Decl *D); + bool VisitBlockDecl(BlockDecl *B); + bool VisitCXXRecordDecl(CXXRecordDecl *D); + llvm::Optional<bool> shouldVisitCursor(CXCursor C); + bool VisitDeclContext(DeclContext *DC); + bool VisitTranslationUnitDecl(TranslationUnitDecl *D); + bool VisitTypedefDecl(TypedefDecl *D); + bool VisitTagDecl(TagDecl *D); + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); + bool VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitDeclaratorDecl(DeclaratorDecl *DD); + bool VisitFunctionDecl(FunctionDecl *ND); + bool VisitFieldDecl(FieldDecl *D); + bool VisitVarDecl(VarDecl *); + bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + bool VisitClassTemplateDecl(ClassTemplateDecl *D); + bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + bool VisitObjCMethodDecl(ObjCMethodDecl *ND); + 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); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. + bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD); + bool VisitLinkageSpecDecl(LinkageSpecDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + + // Name visitor + bool VisitDeclarationNameInfo(DeclarationNameInfo Name); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); + bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + // Template visitors + bool VisitTemplateParameters(const TemplateParameterList *Params); + bool VisitTemplateName(TemplateName Name, SourceLocation Loc); + bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); + + // Type visitors +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + bool VisitTagTypeLoc(TagTypeLoc TL); + bool VisitArrayTypeLoc(ArrayTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); + + // Data-recursive visitor functions. + bool IsInRegionOfInterest(CXCursor C); + bool RunVisitorWorkList(VisitorWorkList &WL); + void EnqueueWorkList(VisitorWorkList &WL, Stmt *S); + LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S); +}; + +} +} + +#endif + diff --git a/clang/tools/libclang/IndexBody.cpp b/clang/tools/libclang/IndexBody.cpp new file mode 100644 index 0000000..74a8d37 --- /dev/null +++ b/clang/tools/libclang/IndexBody.cpp @@ -0,0 +1,154 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" + +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + + typedef RecursiveASTVisitor<BodyIndexer> base; +public: + BodyIndexer(IndexingContext &indexCtx, + const NamedDecl *Parent, const DeclContext *DC) + : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseTypeLoc(TypeLoc TL) { + IndexCtx.indexTypeLoc(TL, Parent, ParentDC); + return true; + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, E); + return true; + } + + bool VisitMemberExpr(MemberExpr *E) { + IndexCtx.handleReference(E->getMemberDecl(), E->getMemberLoc(), + Parent, ParentDC, E); + return true; + } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (DesignatedInitExpr::reverse_designators_iterator + D = E->designators_rbegin(), DEnd = E->designators_rend(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) + IndexCtx.handleReference(D->getField(), D->getFieldLoc(), + Parent, ParentDC, E); + } + return true; + } + + bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + IndexCtx.handleReference(E->getDecl(), E->getLocation(), + Parent, ParentDC, E); + return true; + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (TypeSourceInfo *Cls = E->getClassReceiverTypeInfo()) + IndexCtx.indexTypeSourceInfo(Cls, Parent, ParentDC); + + if (ObjCMethodDecl *MD = E->getMethodDecl()) + IndexCtx.handleReference(MD, E->getSelectorStartLoc(), + Parent, ParentDC, E, + E->isImplicit() ? CXIdxEntityRef_Implicit + : CXIdxEntityRef_Direct); + return true; + } + + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + if (E->isExplicitProperty()) + IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(), + Parent, ParentDC, E); + + // No need to do a handleReference for the objc method, because there will + // be a message expr as part of PseudoObjectExpr. + return true; + } + + bool VisitObjCNumericLiteral(ObjCNumericLiteral *E) { + if (ObjCMethodDecl *MD = E->getObjCNumericLiteralMethod()) + IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, E, CXIdxEntityRef_Implicit); + return true; + } + + bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { + if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod()) + IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, E, CXIdxEntityRef_Implicit); + return true; + } + + bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) { + if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod()) + IndexCtx.handleReference(MD, E->getLocStart(), + Parent, ParentDC, E, CXIdxEntityRef_Implicit); + return true; + } + + bool VisitCXXConstructExpr(CXXConstructExpr *E) { + IndexCtx.handleReference(E->getConstructor(), E->getLocation(), + Parent, ParentDC, E); + return true; + } + + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + if (E->getOperatorLoc().isInvalid()) + return true; // implicit. + return base::TraverseCXXOperatorCallExpr(E); + } + + bool VisitDeclStmt(DeclStmt *S) { + if (IndexCtx.shouldIndexFunctionLocalSymbols()) + IndexCtx.indexDeclGroupRef(S->getDeclGroup()); + return true; + } + + bool TraverseLambdaCapture(LambdaExpr::Capture C) { + if (C.capturesThis()) + return true; + + if (IndexCtx.shouldIndexFunctionLocalSymbols()) + IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(), + Parent, ParentDC); + return true; + } + +}; + +} // anonymous namespace + +void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC) { + if (!S) + return; + + if (DC == 0) + DC = Parent->getLexicalDeclContext(); + BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S)); +} diff --git a/clang/tools/libclang/IndexDecl.cpp b/clang/tools/libclang/IndexDecl.cpp new file mode 100644 index 0000000..c257c34 --- /dev/null +++ b/clang/tools/libclang/IndexDecl.cpp @@ -0,0 +1,336 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" + +#include "clang/AST/DeclVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class IndexingDeclVisitor : public DeclVisitor<IndexingDeclVisitor, bool> { + IndexingContext &IndexCtx; + +public: + explicit IndexingDeclVisitor(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + void handleDeclarator(DeclaratorDecl *D, const NamedDecl *Parent = 0) { + if (!Parent) Parent = D; + + if (!IndexCtx.shouldIndexFunctionLocalSymbols()) { + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent); + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); + } else { + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + IndexCtx.handleVar(Parm); + } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + for (FunctionDecl::param_iterator + PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) { + IndexCtx.handleVar(*PI); + } + } + } + } + + void handleObjCMethod(ObjCMethodDecl *D) { + IndexCtx.handleObjCMethod(D); + if (D->isImplicit()) + return; + + IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D); + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + handleDeclarator(*I, D); + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + } + + bool VisitFunctionDecl(FunctionDecl *D) { + IndexCtx.handleFunction(D); + handleDeclarator(D); + + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { + // Constructor initializers. + for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(), + E = Ctor->init_end(); + I != E; ++I) { + CXXCtorInitializer *Init = *I; + if (Init->isWritten()) { + IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); + if (const FieldDecl *Member = Init->getAnyMember()) + IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D); + IndexCtx.indexBody(Init->getInit(), D, D); + } + } + } + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, D); + } + } + return true; + } + + bool VisitVarDecl(VarDecl *D) { + IndexCtx.handleVar(D); + handleDeclarator(D); + IndexCtx.indexBody(D->getInit(), D); + return true; + } + + bool VisitFieldDecl(FieldDecl *D) { + IndexCtx.handleField(D); + handleDeclarator(D); + if (D->isBitField()) + IndexCtx.indexBody(D->getBitWidth(), D); + else if (D->hasInClassInitializer()) + IndexCtx.indexBody(D->getInClassInitializer(), D); + return true; + } + + bool VisitEnumConstantDecl(EnumConstantDecl *D) { + IndexCtx.handleEnumerator(D); + IndexCtx.indexBody(D->getInitExpr(), D); + return true; + } + + bool VisitTypedefDecl(TypedefNameDecl *D) { + IndexCtx.handleTypedefName(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitTagDecl(TagDecl *D) { + // Non-free standing tags are handled in indexTypeSourceInfo. + if (D->isFreeStanding()) + IndexCtx.indexTagDecl(D); + return true; + } + + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + IndexCtx.handleObjCInterface(D); + + if (D->isThisDeclarationADefinition()) { + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.indexDeclContext(D); + } + return true; + } + + bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + IndexCtx.handleObjCProtocol(D); + + if (D->isThisDeclarationADefinition()) { + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.indexDeclContext(D); + } + return true; + } + + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + const ObjCInterfaceDecl *Class = D->getClassInterface(); + if (!Class) + return true; + + if (Class->isImplicitInterfaceDecl()) + IndexCtx.handleObjCInterface(Class); + + IndexCtx.handleObjCImplementation(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + IndexCtx.handleObjCCategory(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + const ObjCCategoryDecl *Cat = D->getCategoryDecl(); + if (!Cat) + return true; + + IndexCtx.handleObjCCategoryImpl(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitObjCMethodDecl(ObjCMethodDecl *D) { + // Methods associated with a property, even user-declared ones, are + // handled when we handle the property. + if (D->isSynthesized()) + return true; + + handleObjCMethod(D); + return true; + } + + bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) + if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) + handleObjCMethod(MD); + if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) + if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) + handleObjCMethod(MD); + IndexCtx.handleObjCProperty(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *PD = D->getPropertyDecl(); + IndexCtx.handleSynthesizedObjCProperty(D); + + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return true; + assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); + + if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { + if (!IvarD->getSynthesize()) + IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), 0, + D->getDeclContext()); + } + + if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { + if (MD->isSynthesized()) + IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(), + D->getLexicalDeclContext()); + } + if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { + if (MD->isSynthesized()) + IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(), + D->getLexicalDeclContext()); + } + return true; + } + + bool VisitNamespaceDecl(NamespaceDecl *D) { + IndexCtx.handleNamespace(D); + IndexCtx.indexDeclContext(D); + return true; + } + + bool VisitUsingDecl(UsingDecl *D) { + // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR, + // we should do better. + + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); + for (UsingDecl::shadow_iterator + I = D->shadow_begin(), E = D->shadow_end(); I != E; ++I) { + IndexCtx.handleReference((*I)->getUnderlyingDecl(), D->getLocation(), + D, D->getLexicalDeclContext()); + } + return true; + } + + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR, + // we should do better. + + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); + IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), + D->getLocation(), D, D->getLexicalDeclContext()); + return true; + } + + bool VisitClassTemplateDecl(ClassTemplateDecl *D) { + IndexCtx.handleClassTemplate(D); + if (D->isThisDeclarationADefinition()) + IndexCtx.indexDeclContext(D->getTemplatedDecl()); + return true; + } + + bool VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + // FIXME: Notify subsequent callbacks if info comes from implicit + // instantiation. + if (D->isThisDeclarationADefinition() && + (IndexCtx.shouldIndexImplicitTemplateInsts() || + !IndexCtx.isTemplateImplicitInstantiation(D))) + IndexCtx.indexTagDecl(D); + return true; + } + + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + IndexCtx.handleFunctionTemplate(D); + FunctionDecl *FD = D->getTemplatedDecl(); + handleDeclarator(FD, D); + if (FD->isThisDeclarationADefinition()) { + const Stmt *Body = FD->getBody(); + if (Body) { + IndexCtx.indexBody(Body, D, FD); + } + } + return true; + } + + bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + IndexCtx.handleTypeAliasTemplate(D); + IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexDecl(const Decl *D) { + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return; + + bool Handled = IndexingDeclVisitor(*this).Visit(const_cast<Decl*>(D)); + if (!Handled && isa<DeclContext>(D)) + indexDeclContext(cast<DeclContext>(D)); +} + +void IndexingContext::indexDeclContext(const DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + indexDecl(*I); + } +} + +void IndexingContext::indexTopLevelDecl(Decl *D) { + if (isNotFromSourceFile(D->getLocation())) + return; + + if (isa<ObjCMethodDecl>(D)) + return; // Wait for the objc container. + + indexDecl(D); +} + +void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) + indexTopLevelDecl(*I); +} + +void IndexingContext::indexTUDeclsInObjCContainer() { + while (!TUDeclsInObjCContainer.empty()) { + DeclGroupRef DG = TUDeclsInObjCContainer.front(); + TUDeclsInObjCContainer.pop_front(); + indexDeclGroupRef(DG); + } +} diff --git a/clang/tools/libclang/IndexTypeSourceInfo.cpp b/clang/tools/libclang/IndexTypeSourceInfo.cpp new file mode 100644 index 0000000..b62d521 --- /dev/null +++ b/clang/tools/libclang/IndexTypeSourceInfo.cpp @@ -0,0 +1,156 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" + +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + +public: + TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent, + const DeclContext *DC) + : IndexCtx(indexCtx), Parent(parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { + IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC); + return true; + } + + bool VisitTagTypeLoc(TagTypeLoc TL) { + TagDecl *D = TL.getDecl(); + if (D->getParentFunctionOrMethod()) + return true; + + if (TL.isDefinition()) { + IndexCtx.indexTagDecl(D); + return true; + } + + if (D->getLocation() == TL.getNameLoc()) + IndexCtx.handleTagDecl(D); + else + IndexCtx.handleReference(D, TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { + IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), + Parent, ParentDC); + } + return true; + } + + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { + if (const TemplateSpecializationType *T = TL.getTypePtr()) { + if (IndexCtx.shouldIndexImplicitTemplateInsts()) { + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + IndexCtx.handleReference(RD, TL.getTemplateNameLoc(), + Parent, ParentDC); + } else { + if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl()) + IndexCtx.handleReference(D, TL.getTemplateNameLoc(), + Parent, ParentDC); + } + } + return true; + } + + bool TraverseStmt(Stmt *S) { + IndexCtx.indexBody(S, Parent, ParentDC); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, + const NamedDecl *Parent, + const DeclContext *DC) { + if (!TInfo || TInfo->getTypeLoc().isNull()) + return; + + indexTypeLoc(TInfo->getTypeLoc(), Parent, DC); +} + +void IndexingContext::indexTypeLoc(TypeLoc TL, + const NamedDecl *Parent, + const DeclContext *DC) { + if (TL.isNull()) + return; + + if (DC == 0) + DC = Parent->getLexicalDeclContext(); + TypeIndexer(*this, Parent, DC).TraverseTypeLoc(TL); +} + +void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC) { + if (!NNS) + return; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + indexNestedNameSpecifierLoc(Prefix, Parent, DC); + + if (DC == 0) + DC = Parent->getLexicalDeclContext(); + SourceLocation Loc = NNS.getSourceRange().getBegin(); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Global: + break; + + case NestedNameSpecifier::Namespace: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), + Loc, Parent, DC); + break; + case NestedNameSpecifier::NamespaceAlias: + handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(), + Loc, Parent, DC); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + indexTypeLoc(NNS.getTypeLoc(), Parent, DC); + break; + } +} + +void IndexingContext::indexTagDecl(const TagDecl *D) { + if (handleTagDecl(D)) { + if (D->isThisDeclarationADefinition()) + indexDeclContext(D); + } +} diff --git a/clang/tools/libclang/Index_Internal.h b/clang/tools/libclang/Index_Internal.h new file mode 100644 index 0000000..2d42cb8 --- /dev/null +++ b/clang/tools/libclang/Index_Internal.h @@ -0,0 +1,55 @@ +//===- CXString.h - Routines for manipulating CXStrings -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXStrings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBCLANG_INDEX_INTERNAL_H +#define LLVM_LIBCLANG_INDEX_INTERNAL_H + +#include "clang-c/Index.h" + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_feature(blocks) + +#define INVOKE_BLOCK2(block, arg1, arg2) block(arg1, arg2) + +#else +// If we are compiled with a compiler that doesn't have native blocks support, +// define and call the block manually. + +#define INVOKE_BLOCK2(block, arg1, arg2) block->invoke(block, arg1, arg2) + +typedef struct _CXCursorAndRangeVisitorBlock { + void *isa; + int flags; + int reserved; + enum CXVisitorResult (*invoke)(_CXCursorAndRangeVisitorBlock *, + CXCursor, CXSourceRange); +} *CXCursorAndRangeVisitorBlock; + +#endif // !__has_feature(blocks) + +/// \brief The result of comparing two source ranges. +enum RangeComparisonResult { + /// \brief Either the ranges overlap or one of the ranges is invalid. + RangeOverlap, + + /// \brief The first range ends before the second range starts. + RangeBefore, + + /// \brief The first range starts after the second range ends. + RangeAfter +}; + +#endif diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp new file mode 100644 index 0000000..e660c4d --- /dev/null +++ b/clang/tools/libclang/Indexing.cpp @@ -0,0 +1,818 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "CXCursor.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "CXString.h" +#include "CIndexDiagnostic.h" +#include "CIndexer.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/Utils.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/CrashRecoveryContext.h" + +using namespace clang; +using namespace cxstring; +using namespace cxtu; +using namespace cxindex; + +static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx); + +namespace { + +//===----------------------------------------------------------------------===// +// IndexPPCallbacks +//===----------------------------------------------------------------------===// + +class IndexPPCallbacks : public PPCallbacks { + Preprocessor &PP; + IndexingContext &IndexCtx; + bool IsMainFileEntered; + +public: + IndexPPCallbacks(Preprocessor &PP, IndexingContext &indexCtx) + : PP(PP), IndexCtx(indexCtx), IsMainFileEntered(false) { } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, FileID PrevFID) { + if (IsMainFileEntered) + return; + + SourceManager &SM = PP.getSourceManager(); + SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + + if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) { + IsMainFileEntered = true; + IndexCtx.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID())); + } + } + + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc, + StringRef SearchPath, + StringRef RelativePath) { + bool isImport = (IncludeTok.is(tok::identifier) && + IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import); + IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled); + } + + /// MacroDefined - This hook is called whenever a macro definition is seen. + virtual void MacroDefined(const Token &Id, const MacroInfo *MI) { + } + + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + /// MI is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + } + + /// MacroExpands - This is called by when a macro invocation is found. + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, + SourceRange Range) { + } + + /// SourceRangeSkipped - This hook is called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// #if/#else directive and ends after the #endif/#else directive. + virtual void SourceRangeSkipped(SourceRange Range) { + } +}; + +//===----------------------------------------------------------------------===// +// IndexingConsumer +//===----------------------------------------------------------------------===// + +class IndexingConsumer : public ASTConsumer { + IndexingContext &IndexCtx; + +public: + explicit IndexingConsumer(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + // ASTConsumer Implementation + + virtual void Initialize(ASTContext &Context) { + IndexCtx.setASTContext(Context); + IndexCtx.startedTranslationUnit(); + } + + virtual void HandleTranslationUnit(ASTContext &Ctx) { + } + + virtual bool HandleTopLevelDecl(DeclGroupRef DG) { + IndexCtx.indexDeclGroupRef(DG); + return !IndexCtx.shouldAbort(); + } + + /// \brief Handle the specified top-level declaration that occurred inside + /// and ObjC container. + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) { + // They will be handled after the interface is seen first. + IndexCtx.addTUDeclInObjCContainer(D); + } + + /// \brief This is called by the AST reader when deserializing things. + /// The default implementation forwards to HandleTopLevelDecl but we don't + /// care about them when indexing, so have an empty definition. + virtual void HandleInterestingDecl(DeclGroupRef D) {} + + virtual void HandleTagDeclDefinition(TagDecl *D) { + if (!IndexCtx.shouldIndexImplicitTemplateInsts()) + return; + + if (IndexCtx.isTemplateImplicitInstantiation(D)) + IndexCtx.indexDecl(D); + } + + virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) { + if (!IndexCtx.shouldIndexImplicitTemplateInsts()) + return; + + IndexCtx.indexDecl(D); + } +}; + +//===----------------------------------------------------------------------===// +// CaptureDiagnosticConsumer +//===----------------------------------------------------------------------===// + +class CaptureDiagnosticConsumer : public DiagnosticConsumer { + SmallVector<StoredDiagnostic, 4> Errors; +public: + + virtual void HandleDiagnostic(DiagnosticsEngine::Level level, + const Diagnostic &Info) { + if (level >= DiagnosticsEngine::Error) + Errors.push_back(StoredDiagnostic(level, Info)); + } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IgnoringDiagConsumer(); + } +}; + +//===----------------------------------------------------------------------===// +// IndexingFrontendAction +//===----------------------------------------------------------------------===// + +class IndexingFrontendAction : public ASTFrontendAction { + IndexingContext IndexCtx; + CXTranslationUnit CXTU; + +public: + IndexingFrontendAction(CXClientData clientData, + IndexerCallbacks &indexCallbacks, + unsigned indexOptions, + CXTranslationUnit cxTU) + : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU), + CXTU(cxTU) { } + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + IndexCtx.setASTContext(CI.getASTContext()); + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx)); + IndexCtx.setPreprocessor(PP); + return new IndexingConsumer(IndexCtx); + } + + virtual void EndSourceFileAction() { + indexDiagnostics(CXTU, IndexCtx); + } + + virtual TranslationUnitKind getTranslationUnitKind() { + if (IndexCtx.shouldIndexImplicitTemplateInsts()) + return TU_Complete; + else + return TU_Prefix; + } + virtual bool hasCodeCompletionSupport() const { return false; } +}; + +//===----------------------------------------------------------------------===// +// clang_indexSourceFileUnit Implementation +//===----------------------------------------------------------------------===// + +struct IndexSourceFileInfo { + CXIndexAction idxAction; + CXClientData client_data; + IndexerCallbacks *index_callbacks; + unsigned index_callbacks_size; + unsigned index_options; + const char *source_filename; + const char *const *command_line_args; + int num_command_line_args; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + CXTranslationUnit *out_TU; + unsigned TU_options; + int result; +}; + +struct MemBufferOwner { + SmallVector<const llvm::MemoryBuffer *, 8> Buffers; + + ~MemBufferOwner() { + for (SmallVectorImpl<const llvm::MemoryBuffer *>::iterator + I = Buffers.begin(), E = Buffers.end(); I != E; ++I) + delete *I; + } +}; + +} // anonymous namespace + +static void clang_indexSourceFile_Impl(void *UserData) { + IndexSourceFileInfo *ITUI = + static_cast<IndexSourceFileInfo*>(UserData); + CXIndex CIdx = (CXIndex)ITUI->idxAction; + CXClientData client_data = ITUI->client_data; + IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; + unsigned index_callbacks_size = ITUI->index_callbacks_size; + unsigned index_options = ITUI->index_options; + const char *source_filename = ITUI->source_filename; + const char * const *command_line_args = ITUI->command_line_args; + int num_command_line_args = ITUI->num_command_line_args; + struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files; + unsigned num_unsaved_files = ITUI->num_unsaved_files; + CXTranslationUnit *out_TU = ITUI->out_TU; + unsigned TU_options = ITUI->TU_options; + ITUI->result = 1; // init as error. + + if (out_TU) + *out_TU = 0; + bool requestedToGetTU = (out_TU != 0); + + if (!CIdx) + return; + if (!client_index_callbacks || index_callbacks_size == 0) + return; + + IndexerCallbacks CB; + memset(&CB, 0, sizeof(CB)); + unsigned ClientCBSize = index_callbacks_size < sizeof(CB) + ? index_callbacks_size : sizeof(CB); + memcpy(&CB, client_index_callbacks, ClientCBSize); + + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer(); + + // Configure the diagnostics. + DiagnosticOptions DiagOpts; + IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, + command_line_args, + CaptureDiag, + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/false)); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > + DiagCleanup(Diags.getPtr()); + + OwningPtr<std::vector<const char *> > + Args(new std::vector<const char*>()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > + ArgsCleanup(Args.get()); + + 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); + + IntrusiveRefCntPtr<CompilerInvocation> + CInvok(createInvocationFromCommandLine(*Args, Diags)); + + if (!CInvok) + return; + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, + llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > + CInvokCleanup(CInvok.getPtr()); + + if (CInvok->getFrontendOpts().Inputs.empty()) + return; + + OwningPtr<MemBufferOwner> BufOwner(new MemBufferOwner()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> + BufOwnerCleanup(BufOwner.get()); + + for (unsigned I = 0; I != num_unsaved_files; ++I) { + StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer); + BufOwner->Buffers.push_back(Buffer); + } + + // Since libclang 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 + // precompiled headers are involved), we disable it. + CInvok->getLangOpts()->SpellChecking = false; + + if (!requestedToGetTU) + CInvok->getPreprocessorOpts().DetailedRecord = false; + + if (index_options & CXIndexOpt_SuppressWarnings) + CInvok->getDiagnosticOpts().IgnoreWarnings = true; + + ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags, + /*CaptureDiagnostics=*/true); + OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> + CXTUCleanup(CXTU.get()); + + OwningPtr<IndexingFrontendAction> IndexAction; + IndexAction.reset(new IndexingFrontendAction(client_data, CB, + index_options, CXTU->getTU())); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction> + IndexActionCleanup(IndexAction.get()); + + bool Persistent = requestedToGetTU; + StringRef ResourceFilesPath = CXXIdx->getClangResourcesPath(); + bool OnlyLocalDecls = false; + bool PrecompilePreamble = false; + bool CacheCodeCompletionResults = false; + PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); + PPOpts.DetailedRecord = false; + PPOpts.AllowPCHWithCompilerErrors = true; + + if (requestedToGetTU) { + OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); + PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; + // FIXME: Add a flag for modules. + CacheCodeCompletionResults + = TU_options & CXTranslationUnit_CacheCompletionResults; + if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { + PPOpts.DetailedRecord = true; + } + } + + DiagnosticErrorTrap DiagTrap(*Diags); + bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, + IndexAction.get(), + Unit, + Persistent, + ResourceFilesPath, + OnlyLocalDecls, + /*CaptureDiagnostics=*/true, + PrecompilePreamble, + CacheCodeCompletionResults); + if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(Unit); + + if (!Success) + return; + + if (out_TU) + *out_TU = CXTU->takeTU(); + + ITUI->result = 0; // success. +} + +//===----------------------------------------------------------------------===// +// clang_indexTranslationUnit Implementation +//===----------------------------------------------------------------------===// + +namespace { + +struct IndexTranslationUnitInfo { + CXIndexAction idxAction; + CXClientData client_data; + IndexerCallbacks *index_callbacks; + unsigned index_callbacks_size; + unsigned index_options; + CXTranslationUnit TU; + int result; +}; + +} // anonymous namespace + +static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) { + Preprocessor &PP = Unit.getPreprocessor(); + if (!PP.getPreprocessingRecord()) + return; + + PreprocessingRecord &PPRec = *PP.getPreprocessingRecord(); + + // FIXME: Only deserialize inclusion directives. + // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module + // that it depends on. + + bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls(); + PreprocessingRecord::iterator I, E; + if (OnlyLocal) { + I = PPRec.local_begin(); + E = PPRec.local_end(); + } else { + I = PPRec.begin(); + E = PPRec.end(); + } + + for (; I != E; ++I) { + PreprocessedEntity *PPE = *I; + + if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { + IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(), + ID->getFile(), ID->getKind() == InclusionDirective::Import, + !ID->wasInQuotes()); + } + } +} + +static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) { + // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module + // that it depends on. + + bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls(); + + if (OnlyLocal) { + for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(), + TLEnd = Unit.top_level_end(); + TL != TLEnd; ++TL) { + IdxCtx.indexTopLevelDecl(*TL); + if (IdxCtx.shouldAbort()) + return; + } + + } else { + TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl(); + for (TranslationUnitDecl::decl_iterator + I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) { + IdxCtx.indexTopLevelDecl(*I); + if (IdxCtx.shouldAbort()) + return; + } + } +} + +static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) { + if (!IdxCtx.hasDiagnosticCallback()) + return; + + CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU); + IdxCtx.handleDiagnosticSet(DiagSet); +} + +static void clang_indexTranslationUnit_Impl(void *UserData) { + IndexTranslationUnitInfo *ITUI = + static_cast<IndexTranslationUnitInfo*>(UserData); + CXTranslationUnit TU = ITUI->TU; + CXClientData client_data = ITUI->client_data; + IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; + unsigned index_callbacks_size = ITUI->index_callbacks_size; + unsigned index_options = ITUI->index_options; + ITUI->result = 1; // init as error. + + if (!TU) + return; + if (!client_index_callbacks || index_callbacks_size == 0) + return; + + CIndexer *CXXIdx = (CIndexer*)TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + IndexerCallbacks CB; + memset(&CB, 0, sizeof(CB)); + unsigned ClientCBSize = index_callbacks_size < sizeof(CB) + ? index_callbacks_size : sizeof(CB); + memcpy(&CB, client_index_callbacks, ClientCBSize); + + OwningPtr<IndexingContext> IndexCtx; + IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext> + IndexCtxCleanup(IndexCtx.get()); + + OwningPtr<IndexingConsumer> IndexConsumer; + IndexConsumer.reset(new IndexingConsumer(*IndexCtx)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer> + IndexConsumerCleanup(IndexConsumer.get()); + + ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData); + if (!Unit) + return; + + FileManager &FileMgr = Unit->getFileManager(); + + if (Unit->getOriginalSourceFileName().empty()) + IndexCtx->enteredMainFile(0); + else + IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName())); + + IndexConsumer->Initialize(Unit->getASTContext()); + + indexPreprocessingRecord(*Unit, *IndexCtx); + indexTranslationUnit(*Unit, *IndexCtx); + indexDiagnostics(TU, *IndexCtx); + + ITUI->result = 0; +} + +//===----------------------------------------------------------------------===// +// libclang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) { + return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory; +} + +const CXIdxObjCContainerDeclInfo * +clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCContainerDeclInfo * + ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI)) + return &ContInfo->ObjCContDeclInfo; + + return 0; +} + +const CXIdxObjCInterfaceDeclInfo * +clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) + return &InterInfo->ObjCInterDeclInfo; + + return 0; +} + +const CXIdxObjCCategoryDeclInfo * +clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){ + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCCategoryDeclInfo * + CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) + return &CatInfo->ObjCCatDeclInfo; + + return 0; +} + +const CXIdxObjCProtocolRefListInfo * +clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) + return InterInfo->ObjCInterDeclInfo.protocols; + + if (const ObjCProtocolDeclInfo * + ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI)) + return &ProtInfo->ObjCProtoRefListInfo; + + if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) + return CatInfo->ObjCCatDeclInfo.protocols; + + return 0; +} + +const CXIdxObjCPropertyDeclInfo * +clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI)) + return &PropInfo->ObjCPropDeclInfo; + + return 0; +} + +const CXIdxIBOutletCollectionAttrInfo * +clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) { + if (!AInfo) + return 0; + + const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo); + if (const IBOutletCollectionInfo * + IBInfo = dyn_cast<IBOutletCollectionInfo>(DI)) + return &IBInfo->IBCollInfo; + + return 0; +} + +const CXIdxCXXClassDeclInfo * +clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI)) + return &ClassInfo->CXXClassInfo; + + return 0; +} + +CXIdxClientContainer +clang_index_getClientContainer(const CXIdxContainerInfo *info) { + if (!info) + return 0; + const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); + return Container->IndexCtx->getClientContainerForDC(Container->DC); +} + +void clang_index_setClientContainer(const CXIdxContainerInfo *info, + CXIdxClientContainer client) { + if (!info) + return; + const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); + Container->IndexCtx->addContainerInMap(Container->DC, client); +} + +CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) { + if (!info) + return 0; + const EntityInfo *Entity = static_cast<const EntityInfo *>(info); + return Entity->IndexCtx->getClientEntity(Entity->Dcl); +} + +void clang_index_setClientEntity(const CXIdxEntityInfo *info, + CXIdxClientEntity client) { + if (!info) + return; + const EntityInfo *Entity = static_cast<const EntityInfo *>(info); + Entity->IndexCtx->setClientEntity(Entity->Dcl, client); +} + +CXIndexAction clang_IndexAction_create(CXIndex CIdx) { + // For now, CXIndexAction is featureless. + return CIdx; +} + +void clang_IndexAction_dispose(CXIndexAction idxAction) { + // For now, CXIndexAction is featureless. +} + +int clang_indexSourceFile(CXIndexAction idxAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + CXTranslationUnit *out_TU, + unsigned TU_options) { + + IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks, + index_callbacks_size, index_options, + source_filename, command_line_args, + num_command_line_args, unsaved_files, + num_unsaved_files, out_TU, TU_options, 0 }; + + if (getenv("LIBCLANG_NOTHREADS")) { + clang_indexSourceFile_Impl(&ITUI); + return ITUI.result; + } + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) { + fprintf(stderr, "libclang: crash detected during indexing source file: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", TU_options); + fprintf(stderr, "}\n"); + + return 1; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + if (out_TU) + PrintLibclangResourceUsage(*out_TU); + } + + return ITUI.result; +} + +int clang_indexTranslationUnit(CXIndexAction idxAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + CXTranslationUnit TU) { + + IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks, + index_callbacks_size, index_options, TU, + 0 }; + + if (getenv("LIBCLANG_NOTHREADS")) { + clang_indexTranslationUnit_Impl(&ITUI); + return ITUI.result; + } + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) { + fprintf(stderr, "libclang: crash detected during indexing TU\n"); + + return 1; + } + + return ITUI.result; +} + +void clang_indexLoc_getFileLocation(CXIdxLoc location, + CXIdxClientFile *indexFile, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (indexFile) *indexFile = 0; + if (file) *file = 0; + if (line) *line = 0; + if (column) *column = 0; + if (offset) *offset = 0; + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return; + + IndexingContext &IndexCtx = + *static_cast<IndexingContext*>(location.ptr_data[0]); + IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset); +} + +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return clang_getNullLocation(); + + IndexingContext &IndexCtx = + *static_cast<IndexingContext*>(location.ptr_data[0]); + return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc); +} + +} // end: extern "C" + diff --git a/clang/tools/libclang/IndexingContext.cpp b/clang/tools/libclang/IndexingContext.cpp new file mode 100644 index 0000000..ace5c75 --- /dev/null +++ b/clang/tools/libclang/IndexingContext.cpp @@ -0,0 +1,1080 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "IndexingContext.h" +#include "CXTranslationUnit.h" +#include "CIndexDiagnostic.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace cxindex; +using namespace cxcursor; + +IndexingContext::ObjCProtocolListInfo::ObjCProtocolListInfo( + const ObjCProtocolList &ProtList, + IndexingContext &IdxCtx, + ScratchAlloc &SA) { + ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator + I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { + SourceLocation Loc = *LI; + ObjCProtocolDecl *PD = *I; + ProtEntities.push_back(EntityInfo()); + IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA); + CXIdxObjCProtocolRefInfo ProtInfo = { 0, + MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU), + IdxCtx.getIndexLoc(Loc) }; + ProtInfos.push_back(ProtInfo); + + if (IdxCtx.shouldSuppressRefs()) + IdxCtx.markEntityOccurrenceInFile(PD, Loc); + } + + for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) + ProtInfos[i].protocol = &ProtEntities[i]; + + for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) + Prots.push_back(&ProtInfos[i]); +} + + +IBOutletCollectionInfo::IBOutletCollectionInfo( + const IBOutletCollectionInfo &other) + : AttrInfo(CXIdxAttr_IBOutletCollection, other.cursor, other.loc, other.A) { + + IBCollInfo.attrInfo = this; + IBCollInfo.classCursor = other.IBCollInfo.classCursor; + IBCollInfo.classLoc = other.IBCollInfo.classLoc; + if (other.IBCollInfo.objcClass) { + ClassInfo = other.ClassInfo; + IBCollInfo.objcClass = &ClassInfo; + } else + IBCollInfo.objcClass = 0; +} + +AttrListInfo::AttrListInfo(const Decl *D, IndexingContext &IdxCtx) + : SA(IdxCtx), ref_cnt(0) { + + if (!D->hasAttrs()) + return; + + for (AttrVec::const_iterator AttrI = D->attr_begin(), AttrE = D->attr_end(); + AttrI != AttrE; ++AttrI) { + const Attr *A = *AttrI; + CXCursor C = MakeCXCursor(A, const_cast<Decl *>(D), IdxCtx.CXTU); + CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation()); + switch (C.kind) { + default: + Attrs.push_back(AttrInfo(CXIdxAttr_Unexposed, C, Loc, A)); + break; + case CXCursor_IBActionAttr: + Attrs.push_back(AttrInfo(CXIdxAttr_IBAction, C, Loc, A)); + break; + case CXCursor_IBOutletAttr: + Attrs.push_back(AttrInfo(CXIdxAttr_IBOutlet, C, Loc, A)); + break; + case CXCursor_IBOutletCollectionAttr: + IBCollAttrs.push_back(IBOutletCollectionInfo(C, Loc, A)); + break; + } + } + + for (unsigned i = 0, e = IBCollAttrs.size(); i != e; ++i) { + IBOutletCollectionInfo &IBInfo = IBCollAttrs[i]; + CXAttrs.push_back(&IBInfo); + + const IBOutletCollectionAttr * + IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A); + IBInfo.IBCollInfo.attrInfo = &IBInfo; + IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(IBAttr->getInterfaceLoc()); + IBInfo.IBCollInfo.objcClass = 0; + IBInfo.IBCollInfo.classCursor = clang_getNullCursor(); + QualType Ty = IBAttr->getInterface(); + if (const ObjCInterfaceType *InterTy = Ty->getAs<ObjCInterfaceType>()) { + if (const ObjCInterfaceDecl *InterD = InterTy->getInterface()) { + IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA); + IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo; + IBInfo.IBCollInfo.classCursor = MakeCursorObjCClassRef(InterD, + IBAttr->getInterfaceLoc(), IdxCtx.CXTU); + } + } + } + + for (unsigned i = 0, e = Attrs.size(); i != e; ++i) + CXAttrs.push_back(&Attrs[i]); +} + +IntrusiveRefCntPtr<AttrListInfo> +AttrListInfo::create(const Decl *D, IndexingContext &IdxCtx) { + ScratchAlloc SA(IdxCtx); + AttrListInfo *attrs = SA.allocate<AttrListInfo>(); + return new (attrs) AttrListInfo(D, IdxCtx); +} + +IndexingContext::CXXBasesListInfo::CXXBasesListInfo(const CXXRecordDecl *D, + IndexingContext &IdxCtx, + ScratchAlloc &SA) { + for (CXXRecordDecl::base_class_const_iterator + I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + BaseEntities.push_back(EntityInfo()); + const NamedDecl *BaseD = 0; + QualType T = Base.getType(); + SourceLocation Loc = getBaseLoc(Base); + + if (const TypedefType *TDT = T->getAs<TypedefType>()) { + BaseD = TDT->getDecl(); + } else if (const TemplateSpecializationType * + TST = T->getAs<TemplateSpecializationType>()) { + BaseD = TST->getTemplateName().getAsTemplateDecl(); + } else if (const RecordType *RT = T->getAs<RecordType>()) { + BaseD = RT->getDecl(); + } + + if (BaseD) + IdxCtx.getEntityInfo(BaseD, BaseEntities.back(), SA); + CXIdxBaseClassInfo BaseInfo = { 0, + MakeCursorCXXBaseSpecifier(&Base, IdxCtx.CXTU), + IdxCtx.getIndexLoc(Loc) }; + BaseInfos.push_back(BaseInfo); + } + + for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) { + if (BaseEntities[i].name && BaseEntities[i].USR) + BaseInfos[i].base = &BaseEntities[i]; + } + + for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) + CXBases.push_back(&BaseInfos[i]); +} + +SourceLocation IndexingContext::CXXBasesListInfo::getBaseLoc( + const CXXBaseSpecifier &Base) const { + SourceLocation Loc = Base.getSourceRange().getBegin(); + TypeLoc TL; + if (Base.getTypeSourceInfo()) + TL = Base.getTypeSourceInfo()->getTypeLoc(); + if (TL.isNull()) + return Loc; + + if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) + TL = QL->getUnqualifiedLoc(); + + if (const ElaboratedTypeLoc *EL = dyn_cast<ElaboratedTypeLoc>(&TL)) + return EL->getNamedTypeLoc().getBeginLoc(); + if (const DependentNameTypeLoc *DL = dyn_cast<DependentNameTypeLoc>(&TL)) + return DL->getNameLoc(); + if (const DependentTemplateSpecializationTypeLoc * + DTL = dyn_cast<DependentTemplateSpecializationTypeLoc>(&TL)) + return DTL->getTemplateNameLoc(); + + return Loc; +} + +const char *ScratchAlloc::toCStr(StringRef Str) { + if (Str.empty()) + return ""; + if (Str.data()[Str.size()] == '\0') + return Str.data(); + return copyCStr(Str); +} + +const char *ScratchAlloc::copyCStr(StringRef Str) { + char *buf = IdxCtx.StrScratch.Allocate<char>(Str.size() + 1); + std::uninitialized_copy(Str.begin(), Str.end(), buf); + buf[Str.size()] = '\0'; + return buf; +} + +void IndexingContext::setASTContext(ASTContext &ctx) { + Ctx = &ctx; + static_cast<ASTUnit*>(CXTU->TUData)->setASTContext(&ctx); +} + +void IndexingContext::setPreprocessor(Preprocessor &PP) { + static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP); +} + +bool IndexingContext::shouldAbort() { + if (!CB.abortQuery) + return false; + return CB.abortQuery(ClientData, 0); +} + +void IndexingContext::enteredMainFile(const FileEntry *File) { + if (File && CB.enteredMainFile) { + CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0); + FileMap[File] = idxFile; + } +} + +void IndexingContext::ppIncludedFile(SourceLocation hashLoc, + StringRef filename, + const FileEntry *File, + bool isImport, bool isAngled) { + if (!CB.ppIncludedFile) + return; + + ScratchAlloc SA(*this); + CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc), + SA.toCStr(filename), + (CXFile)File, + isImport, isAngled }; + CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info); + FileMap[File] = idxFile; +} + +void IndexingContext::startedTranslationUnit() { + CXIdxClientContainer idxCont = 0; + if (CB.startedTranslationUnit) + idxCont = CB.startedTranslationUnit(ClientData, 0); + addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); +} + +void IndexingContext::handleDiagnosticSet(CXDiagnostic CXDiagSet) { + if (!CB.diagnostic) + return; + + CB.diagnostic(ClientData, CXDiagSet, 0); +} + +bool IndexingContext::handleDecl(const NamedDecl *D, + SourceLocation Loc, CXCursor Cursor, + DeclInfo &DInfo, + const DeclContext *LexicalDC) { + if (!CB.indexDeclaration || !D) + return false; + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return false; + + ScratchAlloc SA(*this); + getEntityInfo(D, DInfo.EntInfo, SA); + if ((!shouldIndexFunctionLocalSymbols() && !DInfo.EntInfo.USR) + || Loc.isInvalid()) + return false; + + if (!LexicalDC) + LexicalDC = D->getLexicalDeclContext(); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(D, Loc); + + DInfo.entityInfo = &DInfo.EntInfo; + DInfo.cursor = Cursor; + DInfo.loc = getIndexLoc(Loc); + DInfo.isImplicit = D->isImplicit(); + + DInfo.attributes = DInfo.EntInfo.attributes; + DInfo.numAttributes = DInfo.EntInfo.numAttributes; + + getContainerInfo(D->getDeclContext(), DInfo.SemanticContainer); + DInfo.semanticContainer = &DInfo.SemanticContainer; + + if (LexicalDC == D->getDeclContext()) { + DInfo.lexicalContainer = &DInfo.SemanticContainer; + } else if (isTemplateImplicitInstantiation(D)) { + // Implicit instantiations have the lexical context of where they were + // instantiated first. We choose instead the semantic context because: + // 1) at the time that we see the instantiation we have not seen the + // function where it occurred yet. + // 2) the lexical context of the first instantiation is not useful + // information anyway. + DInfo.lexicalContainer = &DInfo.SemanticContainer; + } else { + getContainerInfo(LexicalDC, DInfo.LexicalContainer); + DInfo.lexicalContainer = &DInfo.LexicalContainer; + } + + if (DInfo.isContainer) { + getContainerInfo(getEntityContainer(D), DInfo.DeclAsContainer); + DInfo.declAsContainer = &DInfo.DeclAsContainer; + } + + CB.indexDeclaration(ClientData, &DInfo); + return true; +} + +bool IndexingContext::handleObjCContainer(const ObjCContainerDecl *D, + SourceLocation Loc, CXCursor Cursor, + ObjCContainerDeclInfo &ContDInfo) { + ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo; + return handleDecl(D, Loc, Cursor, ContDInfo); +} + +bool IndexingContext::handleFunction(const FunctionDecl *D) { + DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), + D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleVar(const VarDecl *D) { + DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleField(const FieldDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleEnumerator(const EnumConstantDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleTagDecl(const TagDecl *D) { + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(D)) + return handleCXXRecordDecl(CXXRD, D); + + DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(), + D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleTypedefName(const TypedefNameDecl *D) { + DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) { + // For @class forward declarations, suppress them the same way as references. + if (!D->isThisDeclarationADefinition()) { + if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation())) + return false; // already occurred. + + // FIXME: This seems like the wrong definition for redeclaration. + bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, + /*isImplementation=*/false); + return handleObjCContainer(D, D->getLocation(), + MakeCursorObjCClassRef(D, D->getLocation(), + CXTU), + ContDInfo); + } + + ScratchAlloc SA(*this); + + CXIdxBaseClassInfo BaseClass; + EntityInfo BaseEntity; + BaseClass.cursor = clang_getNullCursor(); + if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) { + getEntityInfo(SuperD, BaseEntity, SA); + SourceLocation SuperLoc = D->getSuperClassLoc(); + BaseClass.base = &BaseEntity; + BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU); + BaseClass.loc = getIndexLoc(SuperLoc); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(SuperD, SuperLoc); + } + + ObjCProtocolList EmptyProtoList; + ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition() + ? D->getReferencedProtocols() + : EmptyProtoList, + *this, SA); + + ObjCInterfaceDeclInfo InterInfo(D); + InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); + InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo; + InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass : 0; + InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo; + + return handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo); +} + +bool IndexingContext::handleObjCImplementation( + const ObjCImplementationDecl *D) { + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, + /*isRedeclaration=*/true, + /*isImplementation=*/true); + return handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo); +} + +bool IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) { + if (!D->isThisDeclarationADefinition()) { + if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation())) + return false; // already occurred. + + // FIXME: This seems like the wrong definition for redeclaration. + bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, + isRedeclaration, + /*isImplementation=*/false); + return handleObjCContainer(D, D->getLocation(), + MakeCursorObjCProtocolRef(D, D->getLocation(), + CXTU), + ContDInfo); + } + + ScratchAlloc SA(*this); + ObjCProtocolList EmptyProtoList; + ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition() + ? D->getReferencedProtocols() + : EmptyProtoList, + *this, SA); + + ObjCProtocolDeclInfo ProtInfo(D); + ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); + + return handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo); +} + +bool IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) { + ScratchAlloc SA(*this); + + ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); + EntityInfo ClassEntity; + const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); + SourceLocation ClassLoc = D->getLocation(); + SourceLocation CategoryLoc = D->IsClassExtension() ? ClassLoc + : D->getCategoryNameLoc(); + getEntityInfo(IFaceD, ClassEntity, SA); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(IFaceD, ClassLoc); + + ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA); + + CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; + if (IFaceD) { + CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; + CatDInfo.ObjCCatDeclInfo.classCursor = + MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); + } else { + CatDInfo.ObjCCatDeclInfo.objcClass = 0; + CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); + } + CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); + CatDInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); + CatDInfo.ObjCCatDeclInfo.protocols = &CatDInfo.ObjCProtoListInfo; + + return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); +} + +bool IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { + ScratchAlloc SA(*this); + + const ObjCCategoryDecl *CatD = D->getCategoryDecl(); + ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); + EntityInfo ClassEntity; + const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface(); + SourceLocation ClassLoc = D->getLocation(); + SourceLocation CategoryLoc = D->getCategoryNameLoc(); + getEntityInfo(IFaceD, ClassEntity, SA); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(IFaceD, ClassLoc); + + CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; + if (IFaceD) { + CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; + CatDInfo.ObjCCatDeclInfo.classCursor = + MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); + } else { + CatDInfo.ObjCCatDeclInfo.objcClass = 0; + CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); + } + CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); + CatDInfo.ObjCCatDeclInfo.protocols = 0; + + return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); +} + +bool IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) { + DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(), + D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleSynthesizedObjCProperty( + const ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *PD = D->getPropertyDecl(); + return handleReference(PD, D->getLocation(), getCursor(D), 0, D->getDeclContext()); +} + +bool IndexingContext::handleSynthesizedObjCMethod(const ObjCMethodDecl *D, + SourceLocation Loc, + const DeclContext *LexicalDC) { + DeclInfo DInfo(/*isRedeclaration=*/true, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, Loc, getCursor(D), DInfo, LexicalDC); +} + +bool IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) { + ScratchAlloc SA(*this); + + ObjCPropertyDeclInfo DInfo; + EntityInfo GetterEntity; + EntityInfo SetterEntity; + + DInfo.ObjCPropDeclInfo.declInfo = &DInfo; + + if (ObjCMethodDecl *Getter = D->getGetterMethodDecl()) { + getEntityInfo(Getter, GetterEntity, SA); + DInfo.ObjCPropDeclInfo.getter = &GetterEntity; + } else { + DInfo.ObjCPropDeclInfo.getter = 0; + } + if (ObjCMethodDecl *Setter = D->getSetterMethodDecl()) { + getEntityInfo(Setter, SetterEntity, SA); + DInfo.ObjCPropDeclInfo.setter = &SetterEntity; + } else { + DInfo.ObjCPropDeclInfo.setter = 0; + } + + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleNamespace(const NamespaceDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isOriginalNamespace(), + /*isDefinition=*/true, + /*isContainer=*/true); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleClassTemplate(const ClassTemplateDecl *D) { + return handleCXXRecordDecl(D->getTemplatedDecl(), D); +} + +bool IndexingContext::handleFunctionTemplate(const FunctionTemplateDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), + /*isDefinition=*/D->isThisDeclarationADefinition(), + /*isContainer=*/D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), + /*isDefinition=*/true, /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E, + CXIdxEntityRefKind Kind) { + if (!D) + return false; + + CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E), + const_cast<Decl*>(cast<Decl>(DC)), CXTU) + : getRefCursor(D, Loc); + return handleReference(D, Loc, Cursor, Parent, DC, E, Kind); +} + +bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, + CXCursor Cursor, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E, + CXIdxEntityRefKind Kind) { + if (!CB.indexEntityReference) + return false; + + if (!D) + return false; + if (Loc.isInvalid()) + return false; + if (!shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod()) + return false; + if (isNotFromSourceFile(D->getLocation())) + return false; + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return false; + + if (shouldSuppressRefs()) { + if (markEntityOccurrenceInFile(D, Loc)) + return false; // already occurred. + } + + ScratchAlloc SA(*this); + EntityInfo RefEntity, ParentEntity; + getEntityInfo(D, RefEntity, SA); + if (!RefEntity.USR) + return false; + + getEntityInfo(Parent, ParentEntity, SA); + + ContainerInfo Container; + getContainerInfo(DC, Container); + + CXIdxEntityRefInfo Info = { Kind, + Cursor, + getIndexLoc(Loc), + &RefEntity, + Parent ? &ParentEntity : 0, + &Container }; + CB.indexEntityReference(ClientData, &Info); + return true; +} + +bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const { + if (Loc.isInvalid()) + return true; + SourceManager &SM = Ctx->getSourceManager(); + SourceLocation FileLoc = SM.getFileLoc(Loc); + FileID FID = SM.getFileID(FileLoc); + return SM.getFileEntryForID(FID) == 0; +} + +void IndexingContext::addContainerInMap(const DeclContext *DC, + CXIdxClientContainer container) { + if (!DC) + return; + + ContainerMapTy::iterator I = ContainerMap.find(DC); + if (I == ContainerMap.end()) { + if (container) + ContainerMap[DC] = container; + return; + } + // Allow changing the container of a previously seen DeclContext so we + // can handle invalid user code, like a function re-definition. + if (container) + I->second = container; + else + ContainerMap.erase(I); +} + +CXIdxClientEntity IndexingContext::getClientEntity(const Decl *D) const { + if (!D) + return 0; + EntityMapTy::const_iterator I = EntityMap.find(D); + if (I == EntityMap.end()) + return 0; + return I->second; +} + +void IndexingContext::setClientEntity(const Decl *D, CXIdxClientEntity client) { + if (!D) + return; + EntityMap[D] = client; +} + +bool IndexingContext::handleCXXRecordDecl(const CXXRecordDecl *RD, + const NamedDecl *OrigD) { + if (RD->isThisDeclarationADefinition()) { + ScratchAlloc SA(*this); + CXXClassDeclInfo CXXDInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), + /*isDefinition=*/RD->isThisDeclarationADefinition()); + CXXBasesListInfo BaseList(RD, *this, SA); + CXXDInfo.CXXClassInfo.declInfo = &CXXDInfo; + CXXDInfo.CXXClassInfo.bases = BaseList.getBases(); + CXXDInfo.CXXClassInfo.numBases = BaseList.getNumBases(); + + if (shouldSuppressRefs()) { + // Go through bases and mark them as referenced. + for (unsigned i = 0, e = BaseList.getNumBases(); i != e; ++i) { + const CXIdxBaseClassInfo *baseInfo = BaseList.getBases()[i]; + if (baseInfo->base) { + const NamedDecl *BaseD = BaseList.BaseEntities[i].Dcl; + SourceLocation + Loc = SourceLocation::getFromRawEncoding(baseInfo->loc.int_data); + markEntityOccurrenceInFile(BaseD, Loc); + } + } + } + + return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), CXXDInfo); + } + + DeclInfo DInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), + /*isDefinition=*/RD->isThisDeclarationADefinition(), + /*isContainer=*/RD->isThisDeclarationADefinition()); + return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), DInfo); +} + +bool IndexingContext::markEntityOccurrenceInFile(const NamedDecl *D, + SourceLocation Loc) { + if (!D || Loc.isInvalid()) + return true; + + SourceManager &SM = Ctx->getSourceManager(); + D = getEntityDecl(D); + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc)); + FileID FID = LocInfo.first; + if (FID.isInvalid()) + return true; + + const FileEntry *FE = SM.getFileEntryForID(FID); + if (!FE) + return true; + RefFileOccurence RefOccur(FE, D); + std::pair<llvm::DenseSet<RefFileOccurence>::iterator, bool> + res = RefFileOccurences.insert(RefOccur); + if (!res.second) + return true; // already in map. + + return false; +} + +const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { + assert(D); + D = cast<NamedDecl>(D->getCanonicalDecl()); + + if (const ObjCImplementationDecl * + ImplD = dyn_cast<ObjCImplementationDecl>(D)) { + return getEntityDecl(ImplD->getClassInterface()); + + } else if (const ObjCCategoryImplDecl * + CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) { + return getEntityDecl(CatImplD->getCategoryDecl()); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate()) + return getEntityDecl(TemplD); + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate()) + return getEntityDecl(TemplD); + } + + return D; +} + +const DeclContext * +IndexingContext::getEntityContainer(const Decl *D) const { + const DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) + return DC; + + if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(D)) { + DC = ClassTempl->getTemplatedDecl(); + } if (const FunctionTemplateDecl * + FuncTempl = dyn_cast<FunctionTemplateDecl>(D)) { + DC = FuncTempl->getTemplatedDecl(); + } + + return DC; +} + +CXIdxClientContainer +IndexingContext::getClientContainerForDC(const DeclContext *DC) const { + if (!DC) + return 0; + + ContainerMapTy::const_iterator I = ContainerMap.find(DC); + if (I == ContainerMap.end()) + return 0; + + return I->second; +} + +CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) { + if (!File) + return 0; + + FileMapTy::iterator FI = FileMap.find(File); + if (FI != FileMap.end()) + return FI->second; + + return 0; +} + +CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const { + CXIdxLoc idxLoc = { {0, 0}, 0 }; + if (Loc.isInvalid()) + return idxLoc; + + idxLoc.ptr_data[0] = (void*)this; + idxLoc.int_data = Loc.getRawEncoding(); + return idxLoc; +} + +void IndexingContext::translateLoc(SourceLocation Loc, + CXIdxClientFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, + unsigned *offset) { + if (Loc.isInvalid()) + return; + + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return; + + const FileEntry *FE = SM.getFileEntryForID(FID); + if (indexFile) + *indexFile = getIndexFile(FE); + if (file) + *file = (void *)FE; + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} + +void IndexingContext::getEntityInfo(const NamedDecl *D, + EntityInfo &EntityInfo, + ScratchAlloc &SA) { + if (!D) + return; + + D = getEntityDecl(D); + EntityInfo.cursor = getCursor(D); + EntityInfo.Dcl = D; + EntityInfo.IndexCtx = this; + EntityInfo.kind = CXIdxEntity_Unexposed; + EntityInfo.templateKind = CXIdxEntity_NonTemplate; + EntityInfo.lang = CXIdxEntityLang_C; + + if (D->hasAttrs()) { + EntityInfo.AttrList = AttrListInfo::create(D, *this); + EntityInfo.attributes = EntityInfo.AttrList->getAttrs(); + EntityInfo.numAttributes = EntityInfo.AttrList->getNumAttrs(); + } + + if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { + switch (TD->getTagKind()) { + case TTK_Struct: + EntityInfo.kind = CXIdxEntity_Struct; break; + case TTK_Union: + EntityInfo.kind = CXIdxEntity_Union; break; + case TTK_Class: + EntityInfo.kind = CXIdxEntity_CXXClass; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case TTK_Enum: + EntityInfo.kind = CXIdxEntity_Enum; break; + } + + if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) + if (!CXXRec->isCLike()) + EntityInfo.lang = CXIdxEntityLang_CXX; + + if (isa<ClassTemplatePartialSpecializationDecl>(D)) { + EntityInfo.templateKind = CXIdxEntity_TemplatePartialSpecialization; + } else if (isa<ClassTemplateSpecializationDecl>(D)) { + EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization; + } + + } else { + switch (D->getKind()) { + case Decl::Typedef: + EntityInfo.kind = CXIdxEntity_Typedef; break; + case Decl::Function: + EntityInfo.kind = CXIdxEntity_Function; + break; + case Decl::ParmVar: + EntityInfo.kind = CXIdxEntity_Variable; + break; + case Decl::Var: + EntityInfo.kind = CXIdxEntity_Variable; + if (isa<CXXRecordDecl>(D->getDeclContext())) { + EntityInfo.kind = CXIdxEntity_CXXStaticVariable; + EntityInfo.lang = CXIdxEntityLang_CXX; + } + break; + case Decl::Field: + EntityInfo.kind = CXIdxEntity_Field; + if (const CXXRecordDecl * + CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { + // FIXME: isPOD check is not sufficient, a POD can contain methods, + // we want a isCStructLike check. + if (!CXXRec->isPOD()) + EntityInfo.lang = CXIdxEntityLang_CXX; + } + break; + case Decl::EnumConstant: + EntityInfo.kind = CXIdxEntity_EnumConstant; break; + case Decl::ObjCInterface: + EntityInfo.kind = CXIdxEntity_ObjCClass; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::ObjCProtocol: + EntityInfo.kind = CXIdxEntity_ObjCProtocol; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::ObjCCategory: + EntityInfo.kind = CXIdxEntity_ObjCCategory; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::ObjCMethod: + if (cast<ObjCMethodDecl>(D)->isInstanceMethod()) + EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod; + else + EntityInfo.kind = CXIdxEntity_ObjCClassMethod; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::ObjCProperty: + EntityInfo.kind = CXIdxEntity_ObjCProperty; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::ObjCIvar: + EntityInfo.kind = CXIdxEntity_ObjCIvar; + EntityInfo.lang = CXIdxEntityLang_ObjC; + break; + case Decl::Namespace: + EntityInfo.kind = CXIdxEntity_CXXNamespace; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case Decl::NamespaceAlias: + EntityInfo.kind = CXIdxEntity_CXXNamespaceAlias; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case Decl::CXXConstructor: + EntityInfo.kind = CXIdxEntity_CXXConstructor; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case Decl::CXXDestructor: + EntityInfo.kind = CXIdxEntity_CXXDestructor; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case Decl::CXXConversion: + EntityInfo.kind = CXIdxEntity_CXXConversionFunction; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + case Decl::CXXMethod: { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); + if (MD->isStatic()) + EntityInfo.kind = CXIdxEntity_CXXStaticMethod; + else + EntityInfo.kind = CXIdxEntity_CXXInstanceMethod; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + } + case Decl::ClassTemplate: + EntityInfo.kind = CXIdxEntity_CXXClass; + EntityInfo.templateKind = CXIdxEntity_Template; + break; + case Decl::FunctionTemplate: + EntityInfo.kind = CXIdxEntity_Function; + EntityInfo.templateKind = CXIdxEntity_Template; + if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( + cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { + if (isa<CXXConstructorDecl>(MD)) + EntityInfo.kind = CXIdxEntity_CXXConstructor; + else if (isa<CXXDestructorDecl>(MD)) + EntityInfo.kind = CXIdxEntity_CXXDestructor; + else if (isa<CXXConversionDecl>(MD)) + EntityInfo.kind = CXIdxEntity_CXXConversionFunction; + else { + if (MD->isStatic()) + EntityInfo.kind = CXIdxEntity_CXXStaticMethod; + else + EntityInfo.kind = CXIdxEntity_CXXInstanceMethod; + } + } + break; + case Decl::TypeAliasTemplate: + EntityInfo.kind = CXIdxEntity_CXXTypeAlias; + EntityInfo.templateKind = CXIdxEntity_Template; + break; + case Decl::TypeAlias: + EntityInfo.kind = CXIdxEntity_CXXTypeAlias; + EntityInfo.lang = CXIdxEntityLang_CXX; + break; + default: + break; + } + } + + if (EntityInfo.kind == CXIdxEntity_Unexposed) + return; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) + EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization; + } + + if (EntityInfo.templateKind != CXIdxEntity_NonTemplate) + EntityInfo.lang = CXIdxEntityLang_CXX; + + if (IdentifierInfo *II = D->getIdentifier()) { + EntityInfo.name = SA.toCStr(II->getName()); + + } else if (isa<TagDecl>(D) || isa<FieldDecl>(D) || isa<NamespaceDecl>(D)) { + EntityInfo.name = 0; // anonymous tag/field/namespace. + + } else { + SmallString<256> StrBuf; + { + llvm::raw_svector_ostream OS(StrBuf); + D->printName(OS); + } + EntityInfo.name = SA.copyCStr(StrBuf.str()); + } + + { + SmallString<512> StrBuf; + bool Ignore = getDeclCursorUSR(D, StrBuf); + if (Ignore) { + EntityInfo.USR = 0; + } else { + EntityInfo.USR = SA.copyCStr(StrBuf.str()); + } + } +} + +void IndexingContext::getContainerInfo(const DeclContext *DC, + ContainerInfo &ContInfo) { + ContInfo.cursor = getCursor(cast<Decl>(DC)); + ContInfo.DC = DC; + ContInfo.IndexCtx = this; +} + +CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCursorTypeRef(TD, Loc, CXTU); + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCursorObjCClassRef(ID, Loc, CXTU); + if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) + return MakeCursorObjCProtocolRef(PD, Loc, CXTU); + if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) + return MakeCursorTemplateRef(Template, Loc, CXTU); + if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const NamespaceAliasDecl *Namespace = dyn_cast<NamespaceAliasDecl>(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) + return MakeCursorMemberRef(Field, Loc, CXTU); + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) + return MakeCursorVariableRef(Var, Loc, CXTU); + + return clang_getNullCursor(); +} + +bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { + if (isa<ObjCInterfaceDecl>(D)) + return false; + if (isa<ObjCCategoryDecl>(D)) + return false; + if (isa<ObjCIvarDecl>(D)) + return false; + if (isa<ObjCMethodDecl>(D)) + return false; + return true; +} + +bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + return SD->getSpecializationKind() == TSK_ImplicitInstantiation; + } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + } + return false; +} diff --git a/clang/tools/libclang/IndexingContext.h b/clang/tools/libclang/IndexingContext.h new file mode 100644 index 0000000..6271660 --- /dev/null +++ b/clang/tools/libclang/IndexingContext.h @@ -0,0 +1,556 @@ +//===- IndexingContext.h - Higher level API functions ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Index_Internal.h" +#include "CXCursor.h" + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclGroup.h" +#include "llvm/ADT/DenseSet.h" +#include <deque> + +namespace clang { + class FileEntry; + class ObjCPropertyDecl; + class ClassTemplateDecl; + class FunctionTemplateDecl; + class TypeAliasTemplateDecl; + class ClassTemplateSpecializationDecl; + +namespace cxindex { + class IndexingContext; + class AttrListInfo; + +class ScratchAlloc { + IndexingContext &IdxCtx; + +public: + explicit ScratchAlloc(IndexingContext &indexCtx); + ScratchAlloc(const ScratchAlloc &SA); + + ~ScratchAlloc(); + + const char *toCStr(StringRef Str); + const char *copyCStr(StringRef Str); + + template <typename T> + T *allocate(); +}; + +struct EntityInfo : public CXIdxEntityInfo { + const NamedDecl *Dcl; + IndexingContext *IndexCtx; + IntrusiveRefCntPtr<AttrListInfo> AttrList; + + EntityInfo() { + name = USR = 0; + attributes = 0; + numAttributes = 0; + } +}; + +struct ContainerInfo : public CXIdxContainerInfo { + const DeclContext *DC; + IndexingContext *IndexCtx; +}; + +struct DeclInfo : public CXIdxDeclInfo { + enum DInfoKind { + Info_Decl, + + Info_ObjCContainer, + Info_ObjCInterface, + Info_ObjCProtocol, + Info_ObjCCategory, + + Info_ObjCProperty, + + Info_CXXClass + }; + + DInfoKind Kind; + + EntityInfo EntInfo; + ContainerInfo SemanticContainer; + ContainerInfo LexicalContainer; + ContainerInfo DeclAsContainer; + + DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer) + : Kind(Info_Decl) { + this->isRedeclaration = isRedeclaration; + this->isDefinition = isDefinition; + this->isContainer = isContainer; + attributes = 0; + numAttributes = 0; + declAsContainer = semanticContainer = lexicalContainer = 0; + } + DeclInfo(DInfoKind K, + bool isRedeclaration, bool isDefinition, bool isContainer) + : Kind(K) { + this->isRedeclaration = isRedeclaration; + this->isDefinition = isDefinition; + this->isContainer = isContainer; + attributes = 0; + numAttributes = 0; + declAsContainer = semanticContainer = lexicalContainer = 0; + } + + static bool classof(const DeclInfo *) { return true; } +}; + +struct ObjCContainerDeclInfo : public DeclInfo { + CXIdxObjCContainerDeclInfo ObjCContDeclInfo; + + ObjCContainerDeclInfo(bool isForwardRef, + bool isRedeclaration, + bool isImplementation) + : DeclInfo(Info_ObjCContainer, isRedeclaration, + /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) { + init(isForwardRef, isImplementation); + } + ObjCContainerDeclInfo(DInfoKind K, + bool isForwardRef, + bool isRedeclaration, + bool isImplementation) + : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef, + /*isContainer=*/!isForwardRef) { + init(isForwardRef, isImplementation); + } + + static bool classof(const DeclInfo *D) { + return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory; + } + static bool classof(const ObjCContainerDeclInfo *D) { return true; } + +private: + void init(bool isForwardRef, bool isImplementation) { + if (isForwardRef) + ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef; + else if (isImplementation) + ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation; + else + ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface; + } +}; + +struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo; + CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; + + ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D) + : ObjCContainerDeclInfo(Info_ObjCInterface, + /*isForwardRef=*/false, + /*isRedeclaration=*/D->getPreviousDecl() != 0, + /*isImplementation=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCInterface; + } + static bool classof(const ObjCInterfaceDeclInfo *D) { return true; } +}; + +struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo; + + ObjCProtocolDeclInfo(const ObjCProtocolDecl *D) + : ObjCContainerDeclInfo(Info_ObjCProtocol, + /*isForwardRef=*/false, + /*isRedeclaration=*/D->getPreviousDecl(), + /*isImplementation=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCProtocol; + } + static bool classof(const ObjCProtocolDeclInfo *D) { return true; } +}; + +struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo; + CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; + + explicit ObjCCategoryDeclInfo(bool isImplementation) + : ObjCContainerDeclInfo(Info_ObjCCategory, + /*isForwardRef=*/false, + /*isRedeclaration=*/isImplementation, + /*isImplementation=*/isImplementation) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCCategory; + } + static bool classof(const ObjCCategoryDeclInfo *D) { return true; } +}; + +struct ObjCPropertyDeclInfo : public DeclInfo { + CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo; + + ObjCPropertyDeclInfo() + : DeclInfo(Info_ObjCProperty, + /*isRedeclaration=*/false, /*isDefinition=*/false, + /*isContainer=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCProperty; + } + static bool classof(const ObjCPropertyDeclInfo *D) { return true; } +}; + +struct CXXClassDeclInfo : public DeclInfo { + CXIdxCXXClassDeclInfo CXXClassInfo; + + CXXClassDeclInfo(bool isRedeclaration, bool isDefinition) + : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_CXXClass; + } + static bool classof(const CXXClassDeclInfo *D) { return true; } +}; + +struct AttrInfo : public CXIdxAttrInfo { + const Attr *A; + + AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) { + kind = Kind; + cursor = C; + loc = Loc; + this->A = A; + } + + static bool classof(const AttrInfo *) { return true; } +}; + +struct IBOutletCollectionInfo : public AttrInfo { + EntityInfo ClassInfo; + CXIdxIBOutletCollectionAttrInfo IBCollInfo; + + IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) : + AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) { + assert(C.kind == CXCursor_IBOutletCollectionAttr); + IBCollInfo.objcClass = 0; + } + + IBOutletCollectionInfo(const IBOutletCollectionInfo &other); + + static bool classof(const AttrInfo *A) { + return A->kind == CXIdxAttr_IBOutletCollection; + } + static bool classof(const IBOutletCollectionInfo *D) { return true; } +}; + +class AttrListInfo { + ScratchAlloc SA; + + SmallVector<AttrInfo, 2> Attrs; + SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs; + SmallVector<CXIdxAttrInfo *, 2> CXAttrs; + unsigned ref_cnt; + + AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT + void operator=(const AttrListInfo&); // DO NOT IMPLEMENT +public: + AttrListInfo(const Decl *D, IndexingContext &IdxCtx); + + static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D, + IndexingContext &IdxCtx); + + const CXIdxAttrInfo *const *getAttrs() const { + if (CXAttrs.empty()) + return 0; + return CXAttrs.data(); + } + unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); } + + /// \brief Retain/Release only useful when we allocate a AttrListInfo from the + /// BumpPtrAllocator, and not from the stack; so that we keep a pointer + // in the EntityInfo + void Retain() { ++ref_cnt; } + void Release() { + assert (ref_cnt > 0 && "Reference count is already zero."); + if (--ref_cnt == 0) { + // Memory is allocated from a BumpPtrAllocator, no need to delete it. + this->~AttrListInfo(); + } + } +}; + +struct RefFileOccurence { + const FileEntry *File; + const Decl *Dcl; + + RefFileOccurence(const FileEntry *File, const Decl *Dcl) + : File(File), Dcl(Dcl) { } +}; + +class IndexingContext { + ASTContext *Ctx; + CXClientData ClientData; + IndexerCallbacks &CB; + unsigned IndexOptions; + CXTranslationUnit CXTU; + + typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy; + typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer> + ContainerMapTy; + typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy; + + FileMapTy FileMap; + ContainerMapTy ContainerMap; + EntityMapTy EntityMap; + + llvm::DenseSet<RefFileOccurence> RefFileOccurences; + + std::deque<DeclGroupRef> TUDeclsInObjCContainer; + + llvm::BumpPtrAllocator StrScratch; + unsigned StrAdapterCount; + friend class ScratchAlloc; + + struct ObjCProtocolListInfo { + SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos; + SmallVector<EntityInfo, 4> ProtEntities; + SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots; + + CXIdxObjCProtocolRefListInfo getListInfo() const { + CXIdxObjCProtocolRefListInfo Info = { Prots.data(), + (unsigned)Prots.size() }; + return Info; + } + + ObjCProtocolListInfo(const ObjCProtocolList &ProtList, + IndexingContext &IdxCtx, + ScratchAlloc &SA); + }; + + struct CXXBasesListInfo { + SmallVector<CXIdxBaseClassInfo, 4> BaseInfos; + SmallVector<EntityInfo, 4> BaseEntities; + SmallVector<CXIdxBaseClassInfo *, 4> CXBases; + + const CXIdxBaseClassInfo *const *getBases() const { + return CXBases.data(); + } + unsigned getNumBases() const { return (unsigned)CXBases.size(); } + + CXXBasesListInfo(const CXXRecordDecl *D, + IndexingContext &IdxCtx, ScratchAlloc &SA); + + private: + SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const; + }; + + friend class AttrListInfo; + +public: + IndexingContext(CXClientData clientData, IndexerCallbacks &indexCallbacks, + unsigned indexOptions, CXTranslationUnit cxTU) + : Ctx(0), ClientData(clientData), CB(indexCallbacks), + IndexOptions(indexOptions), CXTU(cxTU), + StrScratch(/*size=*/1024), StrAdapterCount(0) { } + + ASTContext &getASTContext() const { return *Ctx; } + + void setASTContext(ASTContext &ctx); + void setPreprocessor(Preprocessor &PP); + + bool shouldSuppressRefs() const { + return IndexOptions & CXIndexOpt_SuppressRedundantRefs; + } + + bool shouldIndexFunctionLocalSymbols() const { + return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols; + } + + bool shouldIndexImplicitTemplateInsts() const { + return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations; + } + + bool shouldAbort(); + + bool hasDiagnosticCallback() const { return CB.diagnostic; } + + void enteredMainFile(const FileEntry *File); + + void ppIncludedFile(SourceLocation hashLoc, + StringRef filename, const FileEntry *File, + bool isImport, bool isAngled); + + void startedTranslationUnit(); + + void indexDecl(const Decl *D); + + void indexTagDecl(const TagDecl *D); + + void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, + const DeclContext *DC = 0); + + void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, + const DeclContext *DC = 0); + + void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC = 0); + + void indexDeclContext(const DeclContext *DC); + + void indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC = 0); + + void handleDiagnosticSet(CXDiagnosticSet CXDiagSet); + + bool handleFunction(const FunctionDecl *FD); + + bool handleVar(const VarDecl *D); + + bool handleField(const FieldDecl *D); + + bool handleEnumerator(const EnumConstantDecl *D); + + bool handleTagDecl(const TagDecl *D); + + bool handleTypedefName(const TypedefNameDecl *D); + + bool handleObjCInterface(const ObjCInterfaceDecl *D); + bool handleObjCImplementation(const ObjCImplementationDecl *D); + + bool handleObjCProtocol(const ObjCProtocolDecl *D); + + bool handleObjCCategory(const ObjCCategoryDecl *D); + bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D); + + bool handleObjCMethod(const ObjCMethodDecl *D); + + bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D); + bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc, + const DeclContext *LexicalDC); + + bool handleObjCProperty(const ObjCPropertyDecl *D); + + bool handleNamespace(const NamespaceDecl *D); + + bool handleClassTemplate(const ClassTemplateDecl *D); + bool handleFunctionTemplate(const FunctionTemplateDecl *D); + bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E = 0, + CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E = 0, + CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct); + + bool isNotFromSourceFile(SourceLocation Loc) const; + + void indexTopLevelDecl(Decl *D); + void indexTUDeclsInObjCContainer(); + void indexDeclGroupRef(DeclGroupRef DG); + + void addTUDeclInObjCContainer(DeclGroupRef DG) { + TUDeclsInObjCContainer.push_back(DG); + } + + void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, unsigned *offset); + + CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const; + void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container); + + CXIdxClientEntity getClientEntity(const Decl *D) const; + void setClientEntity(const Decl *D, CXIdxClientEntity client); + + static bool isTemplateImplicitInstantiation(const Decl *D); + +private: + bool handleDecl(const NamedDecl *D, + SourceLocation Loc, CXCursor Cursor, + DeclInfo &DInfo, + const DeclContext *LexicalDC = 0); + + bool handleObjCContainer(const ObjCContainerDecl *D, + SourceLocation Loc, CXCursor Cursor, + ObjCContainerDeclInfo &ContDInfo); + + bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD); + + bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc); + + const NamedDecl *getEntityDecl(const NamedDecl *D) const; + + const DeclContext *getEntityContainer(const Decl *D) const; + + CXIdxClientFile getIndexFile(const FileEntry *File); + + CXIdxLoc getIndexLoc(SourceLocation Loc) const; + + void getEntityInfo(const NamedDecl *D, + EntityInfo &EntityInfo, + ScratchAlloc &SA); + + void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo); + + CXCursor getCursor(const Decl *D) { + return cxcursor::MakeCXCursor(const_cast<Decl*>(D), CXTU); + } + + CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc); + + static bool shouldIgnoreIfImplicit(const Decl *D); +}; + +inline ScratchAlloc::ScratchAlloc(IndexingContext &idxCtx) : IdxCtx(idxCtx) { + ++IdxCtx.StrAdapterCount; +} +inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) { + ++IdxCtx.StrAdapterCount; +} + +inline ScratchAlloc::~ScratchAlloc() { + --IdxCtx.StrAdapterCount; + if (IdxCtx.StrAdapterCount == 0) + IdxCtx.StrScratch.Reset(); +} + +template <typename T> +inline T *ScratchAlloc::allocate() { + return IdxCtx.StrScratch.Allocate<T>(); +} + +}} // end clang::cxindex + +namespace llvm { + /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and + /// DenseSets. + template <> + struct DenseMapInfo<clang::cxindex::RefFileOccurence> { + static inline clang::cxindex::RefFileOccurence getEmptyKey() { + return clang::cxindex::RefFileOccurence(0, 0); + } + + static inline clang::cxindex::RefFileOccurence getTombstoneKey() { + return clang::cxindex::RefFileOccurence((const clang::FileEntry *)~0, + (const clang::Decl *)~0); + } + + static unsigned getHashValue(clang::cxindex::RefFileOccurence S) { + llvm::FoldingSetNodeID ID; + ID.AddPointer(S.File); + ID.AddPointer(S.Dcl); + return ID.ComputeHash(); + } + + static bool isEqual(clang::cxindex::RefFileOccurence LHS, + clang::cxindex::RefFileOccurence RHS) { + return LHS.File == RHS.File && LHS.Dcl == RHS.Dcl; + } + }; +} diff --git a/clang/tools/libclang/Makefile b/clang/tools/libclang/Makefile new file mode 100644 index 0000000..08bf3c6 --- /dev/null +++ b/clang/tools/libclang/Makefile @@ -0,0 +1,53 @@ +##===- tools/libclang/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME = clang + +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/libclang.exports + +LINK_LIBS_IN_SHARED = 1 +SHARED_LIBRARY = 1 + +LINK_COMPONENTS := support mc +USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \ + clangSerialization.a \ + clangParse.a clangSema.a clangEdit.a clangAnalysis.a \ + clangAST.a clangLex.a clangBasic.a + +include $(CLANG_LEVEL)/Makefile + +# Add soname to the library. +ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU)) + LDFLAGS += -Wl,-soname,lib$(LIBRARYNAME)$(SHLIBEXT) +endif + +##===----------------------------------------------------------------------===## +# FIXME: This is copied from the 'lto' makefile. Should we share this? +##===----------------------------------------------------------------------===## + +ifeq ($(HOST_OS),Darwin) + LLVMLibsOptions += -Wl,-compatibility_version,1 + + # Set dylib internal version number to submission number. + ifdef LLVM_SUBMIT_VERSION + LLVMLibsOptions += -Wl,-current_version \ + -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) + endif + + # Extra options to override libtool defaults. + LLVMLibsOptions += -Wl,-dead_strip -Wl,-seg1addr,0xE0000000 + + # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line + DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') + ifneq ($(DARWIN_VERS),8) + LLVMLibsOptions += -Wl,-install_name \ + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" + endif +endif diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports new file mode 100644 index 0000000..d3b64db --- /dev/null +++ b/clang/tools/libclang/libclang.exports @@ -0,0 +1,203 @@ +clang_CXCursorSet_contains +clang_CXCursorSet_insert +clang_CXIndex_getGlobalOptions +clang_CXIndex_setGlobalOptions +clang_CXXMethod_isStatic +clang_CXXMethod_isVirtual +clang_Cursor_getArgument +clang_Cursor_getNumArguments +clang_Cursor_getObjCSelectorIndex +clang_Cursor_getSpellingNameRange +clang_Cursor_getTranslationUnit +clang_Cursor_isNull +clang_IndexAction_create +clang_IndexAction_dispose +clang_Range_isNull +clang_annotateTokens +clang_codeCompleteAt +clang_codeCompleteGetContainerKind +clang_codeCompleteGetContainerUSR +clang_codeCompleteGetContexts +clang_codeCompleteGetDiagnostic +clang_codeCompleteGetNumDiagnostics +clang_codeCompleteGetObjCSelector +clang_constructUSR_ObjCCategory +clang_constructUSR_ObjCClass +clang_constructUSR_ObjCIvar +clang_constructUSR_ObjCMethod +clang_constructUSR_ObjCProperty +clang_constructUSR_ObjCProtocol +clang_createCXCursorSet +clang_createIndex +clang_createTranslationUnit +clang_createTranslationUnitFromSourceFile +clang_defaultCodeCompleteOptions +clang_defaultDiagnosticDisplayOptions +clang_defaultEditingTranslationUnitOptions +clang_defaultReparseOptions +clang_defaultSaveOptions +clang_disposeCXCursorSet +clang_disposeCXTUResourceUsage +clang_disposeCodeCompleteResults +clang_disposeDiagnostic +clang_disposeDiagnosticSet +clang_disposeIndex +clang_disposeOverriddenCursors +clang_disposeString +clang_disposeTokens +clang_disposeTranslationUnit +clang_enableStackTraces +clang_equalCursors +clang_equalLocations +clang_equalRanges +clang_equalTypes +clang_executeOnThread +clang_findReferencesInFile +clang_findReferencesInFileWithBlock +clang_formatDiagnostic +clang_getArgType +clang_getArrayElementType +clang_getArraySize +clang_getCString +clang_getCXTUResourceUsage +clang_getCXXAccessSpecifier +clang_getCanonicalCursor +clang_getCanonicalType +clang_getChildDiagnostics +clang_getClangVersion +clang_getCompletionAnnotation +clang_getCompletionAvailability +clang_getCompletionChunkCompletionString +clang_getCompletionChunkKind +clang_getCompletionChunkText +clang_getCompletionNumAnnotations +clang_getCompletionParent +clang_getCompletionPriority +clang_getCursor +clang_getCursorAvailability +clang_getCursorCompletionString +clang_getCursorDefinition +clang_getCursorDisplayName +clang_getCursorExtent +clang_getCursorKind +clang_getCursorKindSpelling +clang_getCursorLanguage +clang_getCursorLexicalParent +clang_getCursorLinkage +clang_getCursorLocation +clang_getCursorReferenceNameRange +clang_getCursorReferenced +clang_getCursorResultType +clang_getCursorSemanticParent +clang_getCursorSpelling +clang_getCursorType +clang_getCursorUSR +clang_getDeclObjCTypeEncoding +clang_getDefinitionSpellingAndExtent +clang_getDiagnostic +clang_getDiagnosticCategory +clang_getDiagnosticCategoryName +clang_getDiagnosticCategoryText +clang_getDiagnosticFixIt +clang_getDiagnosticInSet +clang_getDiagnosticLocation +clang_getDiagnosticNumFixIts +clang_getDiagnosticNumRanges +clang_getDiagnosticOption +clang_getDiagnosticRange +clang_getDiagnosticSetFromTU +clang_getDiagnosticSeverity +clang_getDiagnosticSpelling +clang_getElementType +clang_getEnumConstantDeclUnsignedValue +clang_getEnumConstantDeclValue +clang_getEnumDeclIntegerType +clang_getExpansionLocation +clang_getFile +clang_getFileName +clang_getFileTime +clang_getFunctionTypeCallingConv +clang_getIBOutletCollectionType +clang_getIncludedFile +clang_getInclusions +clang_getInstantiationLocation +clang_getLocation +clang_getLocationForOffset +clang_getNullCursor +clang_getNullLocation +clang_getNullRange +clang_getNumArgTypes +clang_getNumCompletionChunks +clang_getNumDiagnostics +clang_getNumDiagnosticsInSet +clang_getNumElements +clang_getNumOverloadedDecls +clang_getOverloadedDecl +clang_getOverriddenCursors +clang_getPointeeType +clang_getPresumedLocation +clang_getRange +clang_getRangeEnd +clang_getRangeStart +clang_getRemappings +clang_getRemappingsFromFileList +clang_getResultType +clang_getSpecializedCursorTemplate +clang_getSpellingLocation +clang_getTUResourceUsageName +clang_getTemplateCursorKind +clang_getTokenExtent +clang_getTokenKind +clang_getTokenLocation +clang_getTokenSpelling +clang_getTranslationUnitCursor +clang_getTranslationUnitSpelling +clang_getTypeDeclaration +clang_getTypeKindSpelling +clang_getTypedefDeclUnderlyingType +clang_hashCursor +clang_indexLoc_getCXSourceLocation +clang_indexLoc_getFileLocation +clang_indexSourceFile +clang_indexTranslationUnit +clang_index_getCXXClassDeclInfo +clang_index_getClientContainer +clang_index_getClientEntity +clang_index_getIBOutletCollectionAttrInfo +clang_index_getObjCCategoryDeclInfo +clang_index_getObjCContainerDeclInfo +clang_index_getObjCInterfaceDeclInfo +clang_index_getObjCPropertyDeclInfo +clang_index_getObjCProtocolRefListInfo +clang_index_isEntityObjCContainerKind +clang_index_setClientContainer +clang_index_setClientEntity +clang_isAttribute +clang_isConstQualifiedType +clang_isCursorDefinition +clang_isDeclaration +clang_isExpression +clang_isFileMultipleIncludeGuarded +clang_isFunctionTypeVariadic +clang_isInvalid +clang_isPODType +clang_isPreprocessing +clang_isReference +clang_isRestrictQualifiedType +clang_isStatement +clang_isTranslationUnit +clang_isUnexposed +clang_isVirtualBase +clang_isVolatileQualifiedType +clang_loadDiagnostics +clang_parseTranslationUnit +clang_remap_dispose +clang_remap_getFilenames +clang_remap_getNumFiles +clang_reparseTranslationUnit +clang_saveTranslationUnit +clang_sortCodeCompletionResults +clang_toggleCrashRecovery +clang_tokenize +clang_visitChildren +clang_visitChildrenWithBlock |