summaryrefslogtreecommitdiff
path: root/clang/tools/libclang
diff options
context:
space:
mode:
Diffstat (limited to 'clang/tools/libclang')
-rw-r--r--clang/tools/libclang/ARCMigrate.cpp139
-rw-r--r--clang/tools/libclang/CIndex.cpp5876
-rw-r--r--clang/tools/libclang/CIndexCXX.cpp127
-rw-r--r--clang/tools/libclang/CIndexCodeCompletion.cpp975
-rw-r--r--clang/tools/libclang/CIndexDiagnostic.cpp458
-rw-r--r--clang/tools/libclang/CIndexDiagnostic.h166
-rw-r--r--clang/tools/libclang/CIndexHigh.cpp423
-rw-r--r--clang/tools/libclang/CIndexInclusionStack.cpp71
-rw-r--r--clang/tools/libclang/CIndexUSRs.cpp932
-rw-r--r--clang/tools/libclang/CIndexer.cpp152
-rw-r--r--clang/tools/libclang/CIndexer.h104
-rw-r--r--clang/tools/libclang/CMakeLists.txt90
-rw-r--r--clang/tools/libclang/CXCursor.cpp1156
-rw-r--r--clang/tools/libclang/CXCursor.h249
-rw-r--r--clang/tools/libclang/CXLoadedDiagnostic.cpp672
-rw-r--r--clang/tools/libclang/CXLoadedDiagnostic.h94
-rw-r--r--clang/tools/libclang/CXSourceLocation.cpp326
-rw-r--r--clang/tools/libclang/CXSourceLocation.h78
-rw-r--r--clang/tools/libclang/CXStoredDiagnostic.cpp119
-rw-r--r--clang/tools/libclang/CXString.cpp134
-rw-r--r--clang/tools/libclang/CXString.h57
-rw-r--r--clang/tools/libclang/CXTranslationUnit.h53
-rw-r--r--clang/tools/libclang/CXType.cpp631
-rw-r--r--clang/tools/libclang/CXType.h29
-rw-r--r--clang/tools/libclang/CursorVisitor.h259
-rw-r--r--clang/tools/libclang/IndexBody.cpp154
-rw-r--r--clang/tools/libclang/IndexDecl.cpp336
-rw-r--r--clang/tools/libclang/IndexTypeSourceInfo.cpp156
-rw-r--r--clang/tools/libclang/Index_Internal.h55
-rw-r--r--clang/tools/libclang/Indexing.cpp818
-rw-r--r--clang/tools/libclang/IndexingContext.cpp1080
-rw-r--r--clang/tools/libclang/IndexingContext.h556
-rw-r--r--clang/tools/libclang/Makefile53
-rw-r--r--clang/tools/libclang/libclang.exports203
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