| //===- 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 "CIndexDiagnostic.h" |
| #include "CLog.h" |
| #include "CXComment.h" |
| #include "CXCursor.h" |
| #include "CXSourceLocation.h" |
| #include "CXString.h" |
| #include "CXTranslationUnit.h" |
| #include "CXType.h" |
| #include "CursorVisitor.h" |
| #include "SimpleFormatContext.h" |
| #include "clang/AST/StmtVisitor.h" |
| #include "clang/Basic/Diagnostic.h" |
| #include "clang/Basic/Version.h" |
| #include "clang/Frontend/ASTUnit.h" |
| #include "clang/Frontend/CompilerInstance.h" |
| #include "clang/Frontend/FrontendDiagnostic.h" |
| #include "clang/Lex/HeaderSearch.h" |
| #include "clang/Lex/Lexer.h" |
| #include "clang/Lex/PreprocessingRecord.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Config/config.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/CrashRecoveryContext.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/Mutex.h" |
| #include "llvm/Support/PrettyStackTrace.h" |
| #include "llvm/Support/Program.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| #include "llvm/Support/Signals.h" |
| #include "llvm/Support/Threading.h" |
| #include "llvm/Support/Timer.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #if HAVE_PTHREAD_H |
| #include <pthread.h> |
| #endif |
| |
| using namespace clang; |
| using namespace clang::cxcursor; |
| using namespace clang::cxtu; |
| using namespace clang::cxindex; |
| |
| CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) { |
| if (!AU) |
| return 0; |
| CXTranslationUnit D = new CXTranslationUnitImpl(); |
| D->CIdx = CIdx; |
| D->TheASTUnit = AU; |
| D->StringPool = new cxstring::CXStringPool(); |
| D->Diagnostics = 0; |
| D->OverridenCursorsPool = createOverridenCXCursorsPool(); |
| D->FormatContext = 0; |
| D->FormatInMemoryUniqueId = 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 = { |
| { &SM, &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 CheckedRegionOfInterest if true, then the caller already checked |
| /// that this cursor is within the region of interest. |
| /// |
| /// \returns true if the visitation should be aborted, false if it |
| /// should continue. |
| bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { |
| if (clang_isInvalid(Cursor.kind)) |
| return false; |
| |
| if (clang_isDeclaration(Cursor.kind)) { |
| const 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: { |
| bool ret = VisitChildren(Cursor); |
| if (PostChildrenVisitor) |
| if (PostChildrenVisitor(Cursor, ClientData)) |
| return true; |
| return ret; |
| } |
| } |
| |
| 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); |
| } |
| |
| bool CursorVisitor::visitFileRegion() { |
| if (RegionOfInterest.isInvalid()) |
| return false; |
| |
| ASTUnit *Unit = cxtu::getASTUnit(TU); |
| 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 false; |
| |
| FileID File = Begin.first; |
| unsigned Offset = Begin.second; |
| unsigned Length = End.second - Begin.second; |
| |
| if (!VisitDeclsOnly && !VisitPreprocessorLast) |
| if (visitPreprocessedEntitiesInRegion()) |
| return true; // visitation break. |
| |
| if (visitDeclsFromFileRegion(File, Offset, Length)) |
| return true; // visitation break. |
| |
| if (!VisitDeclsOnly && VisitPreprocessorLast) |
| return visitPreprocessedEntitiesInRegion(); |
| |
| return false; |
| } |
| |
| 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; |
| } |
| |
| bool CursorVisitor::visitDeclsFromFileRegion(FileID File, |
| unsigned Offset, unsigned Length) { |
| ASTUnit *Unit = cxtu::getASTUnit(TU); |
| 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 false; |
| |
| SourceLocation Outer; |
| if (SLEntry.isFile()) |
| Outer = SLEntry.getFile().getIncludeLoc(); |
| else |
| Outer = SLEntry.getExpansion().getExpansionLocStart(); |
| if (Outer.isInvalid()) |
| return false; |
| |
| 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)) |
| return true; // visitation break. |
| } |
| |
| if (VisitedAtLeastOnce) |
| return false; |
| |
| // 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) { |
| if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true)) |
| return true; // visitation break. |
| } |
| |
| DC = D->getLexicalDeclContext(); |
| } |
| |
| return false; |
| } |
| |
| 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 = const_cast<Decl *>(getCursorDecl(Cursor)); |
| if (!D) |
| return false; |
| |
| return VisitAttributes(D) || Visit(D); |
| } |
| |
| if (clang_isStatement(Cursor.kind)) { |
| if (const Stmt *S = getCursorStmt(Cursor)) |
| return Visit(S); |
| |
| return false; |
| } |
| |
| if (clang_isExpression(Cursor.kind)) { |
| if (const Expr *E = getCursorExpr(Cursor)) |
| return Visit(E); |
| |
| return false; |
| } |
| |
| if (clang_isTranslationUnit(Cursor.kind)) { |
| CXTranslationUnit TU = getCursorTU(Cursor); |
| ASTUnit *CXXUnit = cxtu::getASTUnit(TU); |
| |
| 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 (const CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) { |
| if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) { |
| return Visit(BaseTSInfo->getTypeLoc()); |
| } |
| } |
| } |
| |
| if (Cursor.kind == CXCursor_IBOutletCollectionAttr) { |
| const IBOutletCollectionAttr *A = |
| cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor)); |
| if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>()) |
| return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(), |
| A->getInterfaceLoc(), TU)); |
| } |
| |
| // If pointing inside a macro definition, check if the token is an identifier |
| // that was ever defined as a macro. In such a case, create a "pseudo" macro |
| // expansion cursor for that token. |
| SourceLocation BeginLoc = RegionOfInterest.getBegin(); |
| if (Cursor.kind == CXCursor_MacroDefinition && |
| BeginLoc == RegionOfInterest.getEnd()) { |
| SourceLocation Loc = AU->mapLocationToPreamble(BeginLoc); |
| const MacroInfo *MI = |
| getMacroInfo(cxcursor::getCursorMacroDefinition(Cursor), TU); |
| if (MacroDefinition *MacroDef = |
| checkForMacroInMacroDefinition(MI, Loc, TU)) |
| return Visit(cxcursor::MakeMacroExpansionCursor(MacroDef, BeginLoc, 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; |
| } |
| |
| Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) { |
| if (RegionOfInterest.isValid()) { |
| SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager()); |
| if (Range.isInvalid()) |
| return None; |
| |
| switch (CompareRegionOfInterest(Range)) { |
| case RangeBefore: |
| // This declaration comes before the region of interest; skip it. |
| return None; |
| |
| 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); |
| |
| // Ignore synthesized ivars here, otherwise if we have something like: |
| // @synthesize prop = _prop; |
| // and '_prop' is not declared, we will encounter a '_prop' ivar before |
| // encountering the 'prop' synthesize declaration and we will think that |
| // we passed the region-of-interest. |
| if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) { |
| if (ivarD->getSynthesize()) |
| continue; |
| } |
| |
| // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol |
| // declarations is a mismatch with the compiler semantics. |
| if (Cursor.kind == CXCursor_ObjCInterfaceDecl) { |
| 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 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 = |
| TL.getAs<TemplateSpecializationTypeLoc>()) { |
| 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) { |
| unsigned NumParamList = DD->getNumTemplateParameterLists(); |
| for (unsigned i = 0; i < NumParamList; i++) { |
| TemplateParameterList* Params = DD->getTemplateParameterList(i); |
| if (VisitTemplateParameters(Params)) |
| return true; |
| } |
| |
| 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) { |
| unsigned NumParamList = ND->getNumTemplateParameterLists(); |
| for (unsigned i = 0; i < NumParamList; i++) { |
| TemplateParameterList* Params = ND->getTemplateParameterList(i); |
| if (VisitTemplateParameters(Params)) |
| return true; |
| } |
| |
| 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 = TL.getAs<FunctionTypeLoc>(); |
| |
| // 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 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->isPropertyAccessor() && MD->getLexicalDeclContext() == CDecl) |
| if (Visit(MakeCXCursor(MD, TU, RegionOfInterest))) |
| return true; |
| |
| if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl()) |
| if (MD->isPropertyAccessor() && 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()) |
| if (PD->isIvarNameSpecified()) |
| 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::NullPtr: |
| if (Expr *E = TAL.getSourceNullPtrExpression()) |
| return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); |
| return false; |
| |
| case TemplateArgument::Expression: |
| if (Expr *E = TAL.getSourceExpression()) |
| return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest)); |
| 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: |
| case BuiltinType::OCLImage1d: |
| case BuiltinType::OCLImage1dArray: |
| case BuiltinType::OCLImage1dBuffer: |
| case BuiltinType::OCLImage2d: |
| case BuiltinType::OCLImage2dArray: |
| case BuiltinType::OCLImage3d: |
| case BuiltinType::OCLSampler: |
| case BuiltinType::OCLEvent: |
| #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(const DATA *d, CXCursor parent) : \ |
| VisitorJob(parent, VisitorJob::KIND, d) {} \ |
| static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\ |
| const DATA *get() const { return static_cast<const 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) |
| DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind) |
| #undef DEF_JOB |
| |
| class DeclVisit : public VisitorJob { |
| public: |
| DeclVisit(const 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; |
| } |
| const Decl *get() const { return static_cast<const 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, const_cast<void *>(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; |
| } |
| const LabelDecl *get() const { |
| return static_cast<const 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( |
| const_cast<NestedNameSpecifier *>( |
| static_cast<const NestedNameSpecifier *>(data[0])), |
| const_cast<void *>(data[1])); |
| } |
| }; |
| |
| class DeclarationNameInfoVisit : public VisitorJob { |
| public: |
| DeclarationNameInfoVisit(const Stmt *S, CXCursor parent) |
| : VisitorJob(parent, VisitorJob::DeclarationNameInfoVisitKind, S) {} |
| static bool classof(const VisitorJob *VJ) { |
| return VJ->getKind() == VisitorJob::DeclarationNameInfoVisitKind; |
| } |
| DeclarationNameInfo get() const { |
| const Stmt *S = static_cast<const 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(const FieldDecl *D, SourceLocation L, CXCursor parent) |
| : VisitorJob(parent, VisitorJob::MemberRefVisitKind, D, |
| L.getPtrEncoding()) {} |
| static bool classof(const VisitorJob *VJ) { |
| return VJ->getKind() == VisitorJob::MemberRefVisitKind; |
| } |
| const FieldDecl *get() const { |
| return static_cast<const FieldDecl *>(data[0]); |
| } |
| SourceLocation getLoc() const { |
| return SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]); |
| } |
| }; |
| class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> { |
| VisitorWorkList &WL; |
| CXCursor Parent; |
| public: |
| EnqueueVisitor(VisitorWorkList &wl, CXCursor parent) |
| : WL(wl), Parent(parent) {} |
| |
| void VisitAddrLabelExpr(const AddrLabelExpr *E); |
| void VisitBlockExpr(const BlockExpr *B); |
| void VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); |
| void VisitCompoundStmt(const CompoundStmt *S); |
| void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */ } |
| void VisitMSDependentExistsStmt(const MSDependentExistsStmt *S); |
| void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E); |
| void VisitCXXNewExpr(const CXXNewExpr *E); |
| void VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E); |
| void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *E); |
| void VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E); |
| void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *E); |
| void VisitCXXTypeidExpr(const CXXTypeidExpr *E); |
| void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *E); |
| void VisitCXXUuidofExpr(const CXXUuidofExpr *E); |
| void VisitCXXCatchStmt(const CXXCatchStmt *S); |
| void VisitDeclRefExpr(const DeclRefExpr *D); |
| void VisitDeclStmt(const DeclStmt *S); |
| void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E); |
| void VisitDesignatedInitExpr(const DesignatedInitExpr *E); |
| void VisitExplicitCastExpr(const ExplicitCastExpr *E); |
| void VisitForStmt(const ForStmt *FS); |
| void VisitGotoStmt(const GotoStmt *GS); |
| void VisitIfStmt(const IfStmt *If); |
| void VisitInitListExpr(const InitListExpr *IE); |
| void VisitMemberExpr(const MemberExpr *M); |
| void VisitOffsetOfExpr(const OffsetOfExpr *E); |
| void VisitObjCEncodeExpr(const ObjCEncodeExpr *E); |
| void VisitObjCMessageExpr(const ObjCMessageExpr *M); |
| void VisitOverloadExpr(const OverloadExpr *E); |
| void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); |
| void VisitStmt(const Stmt *S); |
| void VisitSwitchStmt(const SwitchStmt *S); |
| void VisitWhileStmt(const WhileStmt *W); |
| void VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E); |
| void VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E); |
| void VisitTypeTraitExpr(const TypeTraitExpr *E); |
| void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E); |
| void VisitExpressionTraitExpr(const ExpressionTraitExpr *E); |
| void VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *U); |
| void VisitVAArgExpr(const VAArgExpr *E); |
| void VisitSizeOfPackExpr(const SizeOfPackExpr *E); |
| void VisitPseudoObjectExpr(const PseudoObjectExpr *E); |
| void VisitOpaqueValueExpr(const OpaqueValueExpr *E); |
| void VisitLambdaExpr(const LambdaExpr *E); |
| |
| private: |
| void AddDeclarationNameInfo(const Stmt *S); |
| void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); |
| void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A); |
| void AddMemberRef(const FieldDecl *D, SourceLocation L); |
| void AddStmt(const Stmt *S); |
| void AddDecl(const Decl *D, bool isFirst = true); |
| void AddTypeLoc(TypeSourceInfo *TI); |
| void EnqueueChildren(const Stmt *S); |
| }; |
| } // end anonyous namespace |
| |
| void EnqueueVisitor::AddDeclarationNameInfo(const 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(const Stmt *S) { |
| if (S) |
| WL.push_back(StmtVisit(S, Parent)); |
| } |
| void EnqueueVisitor::AddDecl(const 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(A, Parent)); |
| } |
| void EnqueueVisitor::AddMemberRef(const 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(const Stmt *S) { |
| unsigned size = WL.size(); |
| for (Stmt::const_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(const AddrLabelExpr *E) { |
| WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent)); |
| } |
| void EnqueueVisitor::VisitBlockExpr(const BlockExpr *B) { |
| AddDecl(B->getBlockDecl()); |
| } |
| void EnqueueVisitor::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { |
| EnqueueChildren(E); |
| AddTypeLoc(E->getTypeSourceInfo()); |
| } |
| void EnqueueVisitor::VisitCompoundStmt(const CompoundStmt *S) { |
| for (CompoundStmt::const_reverse_body_iterator I = S->body_rbegin(), |
| E = S->body_rend(); I != E; ++I) { |
| AddStmt(*I); |
| } |
| } |
| void EnqueueVisitor:: |
| VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) { |
| AddStmt(S->getSubStmt()); |
| AddDeclarationNameInfo(S); |
| if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc()) |
| AddNestedNameSpecifierLoc(QualifierLoc); |
| } |
| |
| void EnqueueVisitor:: |
| VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) { |
| AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); |
| AddDeclarationNameInfo(E); |
| if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) |
| AddNestedNameSpecifierLoc(QualifierLoc); |
| if (!E->isImplicitAccess()) |
| AddStmt(E->getBase()); |
| } |
| void EnqueueVisitor::VisitCXXNewExpr(const 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(const 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( |
| const 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( |
| const CXXScalarValueInitExpr *E) { |
| AddTypeLoc(E->getTypeSourceInfo()); |
| } |
| void EnqueueVisitor::VisitCXXTemporaryObjectExpr( |
| const CXXTemporaryObjectExpr *E) { |
| EnqueueChildren(E); |
| AddTypeLoc(E->getTypeSourceInfo()); |
| } |
| void EnqueueVisitor::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { |
| EnqueueChildren(E); |
| if (E->isTypeOperand()) |
| AddTypeLoc(E->getTypeOperandSourceInfo()); |
| } |
| |
| void EnqueueVisitor::VisitCXXUnresolvedConstructExpr( |
| const CXXUnresolvedConstructExpr *E) { |
| EnqueueChildren(E); |
| AddTypeLoc(E->getTypeSourceInfo()); |
| } |
| void EnqueueVisitor::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { |
| EnqueueChildren(E); |
| if (E->isTypeOperand()) |
| AddTypeLoc(E->getTypeOperandSourceInfo()); |
| } |
| |
| void EnqueueVisitor::VisitCXXCatchStmt(const CXXCatchStmt *S) { |
| EnqueueChildren(S); |
| AddDecl(S->getExceptionDecl()); |
| } |
| |
| void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) { |
| if (DR->hasExplicitTemplateArgs()) { |
| AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs()); |
| } |
| WL.push_back(DeclRefExprParts(DR, Parent)); |
| } |
| void EnqueueVisitor::VisitDependentScopeDeclRefExpr( |
| const DependentScopeDeclRefExpr *E) { |
| AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); |
| AddDeclarationNameInfo(E); |
| AddNestedNameSpecifierLoc(E->getQualifierLoc()); |
| } |
| void EnqueueVisitor::VisitDeclStmt(const DeclStmt *S) { |
| unsigned size = WL.size(); |
| bool isFirst = true; |
| for (DeclStmt::const_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(const DesignatedInitExpr *E) { |
| AddStmt(E->getInit()); |
| typedef DesignatedInitExpr::Designator Designator; |
| for (DesignatedInitExpr::const_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(const ExplicitCastExpr *E) { |
| EnqueueChildren(E); |
| AddTypeLoc(E->getTypeInfoAsWritten()); |
| } |
| void EnqueueVisitor::VisitForStmt(const ForStmt *FS) { |
| AddStmt(FS->getBody()); |
| AddStmt(FS->getInc()); |
| AddStmt(FS->getCond()); |
| AddDecl(FS->getConditionVariable()); |
| AddStmt(FS->getInit()); |
| } |
| void EnqueueVisitor::VisitGotoStmt(const GotoStmt *GS) { |
| WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent)); |
| } |
| void EnqueueVisitor::VisitIfStmt(const IfStmt *If) { |
| AddStmt(If->getElse()); |
| AddStmt(If->getThen()); |
| AddStmt(If->getCond()); |
| AddDecl(If->getConditionVariable()); |
| } |
| void EnqueueVisitor::VisitInitListExpr(const 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(const 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(const ObjCEncodeExpr *E) { |
| AddTypeLoc(E->getEncodedTypeSourceInfo()); |
| } |
| void EnqueueVisitor::VisitObjCMessageExpr(const ObjCMessageExpr *M) { |
| EnqueueChildren(M); |
| AddTypeLoc(M->getClassReceiverTypeInfo()); |
| } |
| void EnqueueVisitor::VisitOffsetOfExpr(const 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(const OverloadExpr *E) { |
| AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); |
| WL.push_back(OverloadExprParts(E, Parent)); |
| } |
| void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( |
| const UnaryExprOrTypeTraitExpr *E) { |
| EnqueueChildren(E); |
| if (E->isArgumentType()) |
| AddTypeLoc(E->getArgumentTypeInfo()); |
| } |
| void EnqueueVisitor::VisitStmt(const Stmt *S) { |
| EnqueueChildren(S); |
| } |
| void EnqueueVisitor::VisitSwitchStmt(const SwitchStmt *S) { |
| AddStmt(S->getBody()); |
| AddStmt(S->getCond()); |
| AddDecl(S->getConditionVariable()); |
| } |
| |
| void EnqueueVisitor::VisitWhileStmt(const WhileStmt *W) { |
| AddStmt(W->getBody()); |
| AddStmt(W->getCond()); |
| AddDecl(W->getConditionVariable()); |
| } |
| |
| void EnqueueVisitor::VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { |
| AddTypeLoc(E->getQueriedTypeSourceInfo()); |
| } |
| |
| void EnqueueVisitor::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) { |
| AddTypeLoc(E->getRhsTypeSourceInfo()); |
| AddTypeLoc(E->getLhsTypeSourceInfo()); |
| } |
| |
| void EnqueueVisitor::VisitTypeTraitExpr(const TypeTraitExpr *E) { |
| for (unsigned I = E->getNumArgs(); I > 0; --I) |
| AddTypeLoc(E->getArg(I-1)); |
| } |
| |
| void EnqueueVisitor::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { |
| AddTypeLoc(E->getQueriedTypeSourceInfo()); |
| } |
| |
| void EnqueueVisitor::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { |
| EnqueueChildren(E); |
| } |
| |
| void EnqueueVisitor::VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *U) { |
| VisitOverloadExpr(U); |
| if (!U->isImplicitAccess()) |
| AddStmt(U->getBase()); |
| } |
| void EnqueueVisitor::VisitVAArgExpr(const VAArgExpr *E) { |
| AddStmt(E->getSubExpr()); |
| AddTypeLoc(E->getWrittenTypeInfo()); |
| } |
| void EnqueueVisitor::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { |
| WL.push_back(SizeOfPackExprParts(E, Parent)); |
| } |
| void EnqueueVisitor::VisitOpaqueValueExpr(const 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(const LambdaExpr *E) { |
| AddStmt(E->getBody()); |
| WL.push_back(LambdaExprParts(E, Parent)); |
| } |
| void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { |
| // Treat the expression like its syntactic form. |
| Visit(E->getSyntacticForm()); |
| } |
| |
| void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const 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: { |
| const 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: { |
| const 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: { |
| const 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: |
| if (PostChildrenVisitor) |
| WL.push_back(PostChildrenVisit(0, Cursor)); |
| EnqueueWorkList(WL, S); |
| break; |
| } |
| continue; |
| } |
| case VisitorJob::MemberExprPartsKind: { |
| // Handle the other pieces in the MemberExpr besides the base. |
| const 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: { |
| const 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: { |
| const 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: { |
| const 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. |
| const 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 (FunctionProtoTypeLoc Proto = |
| TL.getAs<FunctionProtoTypeLoc>()) { |
| 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; |
| } |
| |
| case VisitorJob::PostChildrenVisitKind: |
| if (PostChildrenVisitor(Parent, ClientData)) |
| return true; |
| break; |
| } |
| } |
| return false; |
| } |
| |
| bool CursorVisitor::Visit(const 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 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, |
| bool gen_crash_diag) { |
| // 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; |
| |
| IntrusiveRefCntPtr<DiagnosticsEngine> Diags; |
| ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts, |
| CXXIdx->getOnlyLocalDecls(), |
| 0, 0, |
| /*CaptureDiagnostics=*/true, |
| /*AllowPCHWithCompilerErrors=*/true, |
| /*UserFilesAreVolatile=*/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 IncludeBriefCommentsInCodeCompletion |
| = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; |
| bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies; |
| bool ForSerialization = options & CXTranslationUnit_ForSerialization; |
| |
| // Configure the diagnostics. |
| IntrusiveRefCntPtr<DiagnosticsEngine> |
| Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); |
| |
| // 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, |
| IncludeBriefCommentsInCodeCompletion, |
| /*AllowPCHWithCompilerErrors=*/true, |
| SkipFunctionBodies, |
| /*UserFilesAreVolatile=*/true, |
| ForSerialization, |
| &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, |
|