| //===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the main API hooks in the Clang-C Source Indexing |
| // library. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "CIndexDiagnostic.h" |
| #include "CIndexer.h" |
| #include "CLog.h" |
| #include "CXCursor.h" |
| #include "CXSourceLocation.h" |
| #include "CXString.h" |
| #include "CXTranslationUnit.h" |
| #include "CXType.h" |
| #include "CursorVisitor.h" |
| #include "clang-c/FatalErrorHandler.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/AST/DeclObjCCommon.h" |
| #include "clang/AST/Mangle.h" |
| #include "clang/AST/OpenMPClause.h" |
| #include "clang/AST/StmtVisitor.h" |
| #include "clang/Basic/Diagnostic.h" |
| #include "clang/Basic/DiagnosticCategories.h" |
| #include "clang/Basic/DiagnosticIDs.h" |
| #include "clang/Basic/Stack.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Basic/Version.h" |
| #include "clang/Frontend/ASTUnit.h" |
| #include "clang/Frontend/CompilerInstance.h" |
| #include "clang/Index/CommentToXML.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/llvm-config.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/CrashRecoveryContext.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/ManagedStatic.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/Program.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| #include "llvm/Support/Signals.h" |
| #include "llvm/Support/TargetSelect.h" |
| #include "llvm/Support/Threading.h" |
| #include "llvm/Support/Timer.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Support/thread.h" |
| #include <mutex> |
| |
| #if LLVM_ENABLE_THREADS != 0 && defined(__APPLE__) |
| #define USE_DARWIN_THREADS |
| #endif |
| |
| #ifdef USE_DARWIN_THREADS |
| #include <pthread.h> |
| #endif |
| |
| using namespace clang; |
| using namespace clang::cxcursor; |
| using namespace clang::cxtu; |
| using namespace clang::cxindex; |
| |
| CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, |
| std::unique_ptr<ASTUnit> AU) { |
| if (!AU) |
| return nullptr; |
| assert(CIdx); |
| CXTranslationUnit D = new CXTranslationUnitImpl(); |
| D->CIdx = CIdx; |
| D->TheASTUnit = AU.release(); |
| D->StringPool = new cxstring::CXStringPool(); |
| D->Diagnostics = nullptr; |
| D->OverridenCursorsPool = createOverridenCXCursorsPool(); |
| D->CommentToXML = nullptr; |
| D->ParsingOptions = 0; |
| D->Arguments = {}; |
| return D; |
| } |
| |
| bool cxtu::isASTReadError(ASTUnit *AU) { |
| for (ASTUnit::stored_diag_iterator D = AU->stored_diag_begin(), |
| DEnd = AU->stored_diag_end(); |
| D != DEnd; ++D) { |
| if (D->getLevel() >= DiagnosticsEngine::Error && |
| DiagnosticIDs::getCategoryNumberForDiag(D->getID()) == |
| diag::DiagCat_AST_Deserialization_Issue) |
| return true; |
| } |
| return false; |
| } |
| |
| cxtu::CXTUOwner::~CXTUOwner() { |
| if (TU) |
| clang_disposeTranslationUnit(TU); |
| } |
| |
| /// 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; |
| } |
| |
| /// 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; |
| } |
| |
| /// 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(); |
| bool IsTokenRange = R.isTokenRange(); |
| if (EndLoc.isValid() && EndLoc.isMacroID() && |
| !SM.isMacroArgExpansion(EndLoc)) { |
| CharSourceRange Expansion = SM.getExpansionRange(EndLoc); |
| EndLoc = Expansion.getEnd(); |
| IsTokenRange = Expansion.isTokenRange(); |
| } |
| if (IsTokenRange && EndLoc.isValid()) { |
| unsigned Length = |
| Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc), SM, LangOpts); |
| EndLoc = EndLoc.getLocWithOffset(Length); |
| } |
| |
| CXSourceRange Result = { |
| {&SM, &LangOpts}, R.getBegin().getRawEncoding(), EndLoc.getRawEncoding()}; |
| return Result; |
| } |
| |
| CharSourceRange cxloc::translateCXRangeToCharRange(CXSourceRange R) { |
| return CharSourceRange::getCharRange( |
| SourceLocation::getFromRawEncoding(R.begin_int_data), |
| SourceLocation::getFromRawEncoding(R.end_int_data)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // 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); |
| } |
| |
| /// 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(); |
| } |
| |
| const auto &Entities = PPRec.getPreprocessedEntitiesInRange(R); |
| return Visitor.visitPreprocessedEntities(Entities.begin(), Entities.end(), |
| 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; |
| |
| std::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer); |
| Length = 0; |
| Unit->findFileRegionDecls(File, Offset, Length, Decls); |
| } |
| |
| assert(!Decls.empty()); |
| |
| bool VisitedAtLeastOnce = false; |
| DeclContext *CurDC = nullptr; |
| SmallVectorImpl<Decl *>::iterator DIt = Decls.begin(); |
| for (SmallVectorImpl<Decl *>::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 = nullptr; |
| } |
| |
| 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 (!PPE) |
| continue; |
| |
| if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) { |
| if (Visit(MakeMacroExpansionCursor(ME, TU))) |
| return true; |
| |
| continue; |
| } |
| |
| if (MacroDefinitionRecord *MD = dyn_cast<MacroDefinitionRecord>(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; |
| } |
| |
| /// 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) { |
| const Optional<bool> V = handleDeclForVisitation(*TL); |
| if (!V.hasValue()) |
| continue; |
| return V.getValue(); |
| } |
| } 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 ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>()) |
| return Visit(cxcursor::MakeCursorObjCClassRef( |
| ObjT->getInterface(), |
| A->getInterfaceLoc()->getTypeLoc().getBeginLoc(), 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 (MacroDefinitionRecord *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; |
| // Filter out synthesized property accessor redeclarations. |
| if (isa<ObjCImplDecl>(DC)) |
| if (auto *OMD = dyn_cast<ObjCMethodDecl>(D)) |
| if (OMD->isSynthesizedAccessorStub()) |
| continue; |
| const Optional<bool> V = handleDeclForVisitation(D); |
| if (!V.hasValue()) |
| continue; |
| return V.getValue(); |
| } |
| return false; |
| } |
| |
| Optional<bool> CursorVisitor::handleDeclForVisitation(const Decl *D) { |
| 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 (auto *ivarD = dyn_cast<ObjCIvarDecl>(D)) { |
| if (ivarD->getSynthesize()) |
| return None; |
| } |
| |
| // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol |
| // declarations is a mismatch with the compiler semantics. |
| if (Cursor.kind == CXCursor_ObjCInterfaceDecl) { |
| auto *ID = cast<ObjCInterfaceDecl>(D); |
| if (!ID->isThisDeclarationADefinition()) |
| Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU); |
| |
| } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) { |
| auto *PD = cast<ObjCProtocolDecl>(D); |
| if (!PD->isThisDeclarationADefinition()) |
| Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU); |
| } |
| |
| const Optional<bool> V = shouldVisitCursor(Cursor); |
| if (!V.hasValue()) |
| return None; |
| if (!V.getValue()) |
| return false; |
| if (Visit(Cursor, true)) |
| return true; |
| return None; |
| } |
| |
| bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { |
| llvm_unreachable("Translation units are visited directly by Visit()"); |
| } |
| |
| bool CursorVisitor::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { |
| if (VisitTemplateParameters(D->getTemplateParameters())) |
| return true; |
| |
| return Visit(MakeCXCursor(D->getTemplatedDecl(), TU, RegionOfInterest)); |
| } |
| |
| 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; |
| } |
| } |
| |
| return ShouldVisitBody && VisitCXXRecordDecl(D); |
| } |
| |
| 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 ASTTemplateArgumentListInfo *Info = D->getTemplateArgsAsWritten(); |
| const TemplateArgumentLoc *TemplateArgs = Info->getTemplateArgs(); |
| for (unsigned I = 0, N = Info->NumTemplateArgs; I != N; ++I) |
| if (VisitTemplateArgumentLoc(TemplateArgs[I])) |
| return true; |
| |
| return VisitCXXRecordDecl(D); |
| } |
| |
| bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { |
| if (const auto *TC = D->getTypeConstraint()) |
| if (Visit(MakeCXCursor(TC->getImmediatelyDeclaredConstraint(), StmtParent, |
| TU, RegionOfInterest))) |
| return true; |
| |
| // 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; |
| } |
| |
| static bool HasTrailingReturnType(FunctionDecl *ND) { |
| const QualType Ty = ND->getType(); |
| if (const FunctionType *AFT = Ty->getAs<FunctionType>()) { |
| if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT)) |
| return FT->hasTrailingReturn(); |
| } |
| |
| return false; |
| } |
| |
| /// Compare two base or member initializers based on their source order. |
| static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X, |
| CXXCtorInitializer *const *Y) { |
| return (*X)->getSourceOrder() - (*Y)->getSourceOrder(); |
| } |
| |
| 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>(); |
| const bool HasTrailingRT = HasTrailingReturnType(ND); |
| |
| // 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) && !HasTrailingRT && |
| Visit(FTL.getReturnLoc())) || |
| (!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 (!isa<CXXDestructorDecl>(ND)) |
| 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; |
| |
| // Visit the function's trailing return type. |
| if (FTL && HasTrailingRT && Visit(FTL.getReturnLoc())) |
| 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 (auto *I : Constructor->inits()) { |
| 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)); |
| |
| if (Expr *Init = D->getInClassInitializer()) |
| return Visit(MakeCXCursor(Init, 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; |
| |
| auto *FD = D->getTemplatedDecl(); |
| return VisitAttributes(FD) || VisitFunctionDecl(FD); |
| } |
| |
| 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; |
| |
| auto *CD = D->getTemplatedDecl(); |
| return VisitAttributes(CD) || VisitCXXRecordDecl(CD); |
| } |
| |
| 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::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { |
| // Visit the bound, if it's explicit. |
| if (D->hasExplicitBound()) { |
| if (auto TInfo = D->getTypeSourceInfo()) { |
| if (Visit(TInfo->getTypeLoc())) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { |
| if (TypeSourceInfo *TSInfo = ND->getReturnTypeSourceInfo()) |
| if (Visit(TSInfo->getTypeLoc())) |
| return true; |
| |
| for (const auto *P : ND->parameters()) { |
| if (Visit(MakeCXCursor(P, TU, RegionOfInterest))) |
| return true; |
| } |
| |
| return ND->isThisDeclarationADefinition() && |
| Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)); |
| } |
| |
| 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->getBeginLoc(); |
| if (!L.isValid()) |
| break; |
| if (SM.isBeforeInTranslationUnit(L, EndLoc)) { |
| *DI_current = next; |
| Decls.push_back(D_next); |
| continue; |
| } |
| break; |
| } |
| } |
| |
| 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 (auto *SubDecl : D->decls()) { |
| if (!SubDecl || SubDecl->getLexicalDeclContext() != D || |
| SubDecl->getBeginLoc().isInvalid()) |
| continue; |
| DeclsInContainer.push_back(SubDecl); |
| } |
| |
| // Now sort the Decls so that they appear in lexical order. |
| llvm::sort(DeclsInContainer, [&SM](Decl *A, Decl *B) { |
| SourceLocation L_A = A->getBeginLoc(); |
| SourceLocation L_B = B->getBeginLoc(); |
| return L_A != L_B |
| ? SM.isBeforeInTranslationUnit(L_A, L_B) |
| : SM.isBeforeInTranslationUnit(A->getEndLoc(), B->getEndLoc()); |
| }); |
| |
| // 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; |
| |
| if (VisitObjCTypeParamList(ND->getTypeParamList())) |
| 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, PD->getQueryKind()); |
| |
| 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::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) { |
| if (!typeParamList) |
| return false; |
| |
| for (auto *typeParam : *typeParamList) { |
| // Visit the type parameter. |
| if (Visit(MakeCXCursor(typeParam, 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)); |
| } |
| |
| // Objective-C type parameters. |
| if (VisitObjCTypeParamList(D->getTypeParamListAsWritten())) |
| return true; |
| |
| // Issue callbacks for super class. |
| if (D->getSuperClass() && Visit(MakeCursorObjCSuperClassRef( |
| D->getSuperClass(), D->getSuperClassLoc(), TU))) |
| return true; |
| |
| if (TypeSourceInfo *SuperClassTInfo = D->getSuperClassTInfo()) |
| if (Visit(SuperClassTInfo->getTypeLoc())) |
| 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::VisitStaticAssertDecl(StaticAssertDecl *D) { |
| if (Visit(MakeCXCursor(D->getAssertExpr(), StmtParent, TU, RegionOfInterest))) |
| return true; |
| if (StringLiteral *Message = D->getMessage()) |
| if (Visit(MakeCXCursor(Message, StmtParent, TU, RegionOfInterest))) |
| return true; |
| return false; |
| } |
| |
| bool CursorVisitor::VisitFriendDecl(FriendDecl *D) { |
| if (NamedDecl *FriendD = D->getFriendDecl()) { |
| if (Visit(MakeCXCursor(FriendD, TU, RegionOfInterest))) |
| return true; |
| } else if (TypeSourceInfo *TI = D->getFriendType()) { |
| if (Visit(TI->getTypeLoc())) |
| return true; |
| } |
| return false; |
| } |
| |
| bool CursorVisitor::VisitDecompositionDecl(DecompositionDecl *D) { |
| for (auto *B : D->bindings()) { |
| if (Visit(MakeCXCursor(B, TU, RegionOfInterest))) |
| return true; |
| } |
| return VisitVarDecl(D); |
| } |
| |
| bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { |
| switch (Name.getName().getNameKind()) { |
| case clang::DeclarationName::Identifier: |
| case clang::DeclarationName::CXXLiteralOperatorName: |
| case clang::DeclarationName::CXXDeductionGuideName: |
| 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: |
| case NestedNameSpecifier::Super: |
| 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: |
| case NestedNameSpecifier::Super: |
| 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::AssumedTemplate: |
| // FIXME: Visit DeclarationName? |
| 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: |
| #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ |
| case BuiltinType::Id: |
| #include "clang/Basic/OpenCLImageTypes.def" |
| #define EXT_OPAQUE_TYPE(ExtTYpe, Id, Ext) case BuiltinType::Id: |
| #include "clang/Basic/OpenCLExtensionTypes.def" |
| case BuiltinType::OCLSampler: |
| case BuiltinType::OCLEvent: |
| case BuiltinType::OCLClkEvent: |
| case BuiltinType::OCLQueue: |
| case BuiltinType::OCLReserveID: |
| #define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
| #include "clang/Basic/AArch64SVEACLETypes.def" |
| #define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id: |
| #include "clang/Basic/PPCTypes.def" |
| #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: |
| #include "clang/Basic/RISCVVTypes.def" |
| #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) { |
| return Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)); |
| } |
| |
| bool CursorVisitor::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { |
| if (Visit(MakeCursorTypeRef(TL.getDecl(), TL.getBeginLoc(), TU))) |
| 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::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { |
| if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) |
| return true; |
| |
| for (unsigned I = 0, N = TL.getNumTypeArgs(); I != N; ++I) { |
| if (Visit(TL.getTypeArgTInfo(I)->getTypeLoc())) |
| 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::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc 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.getReturnLoc())) |
| return true; |
| |
| for (unsigned I = 0, N = TL.getNumParams(); I != N; ++I) |
| if (Decl *D = TL.getParam(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::VisitDecayedTypeLoc(DecayedTypeLoc TL) { |
| return Visit(TL.getOriginalLoc()); |
| } |
| |
| bool CursorVisitor::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { |
| return Visit(TL.getOriginalLoc()); |
| } |
| |
| bool CursorVisitor::VisitDeducedTemplateSpecializationTypeLoc( |
| DeducedTemplateSpecializationTypeLoc TL) { |
| if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), |
| TL.getTemplateNameLoc())) |
| return true; |
| |
| 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) { |
| return VisitNestedNameSpecifierLoc(TL.getQualifierLoc()); |
| } |
| |
| 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()); |
| } |
| |
| bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc 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(DependentAddressSpace, Type) |
| DEFAULT_TYPELOC_IMPL(DependentVector, Type) |
| DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type) |
| DEFAULT_TYPELOC_IMPL(Vector, Type) |
| DEFAULT_TYPELOC_IMPL(ExtVector, VectorType) |
| DEFAULT_TYPELOC_IMPL(ConstantMatrix, MatrixType) |
| DEFAULT_TYPELOC_IMPL(DependentSizedMatrix, MatrixType) |
| 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) |
| DEFAULT_TYPELOC_IMPL(ExtInt, Type) |
| DEFAULT_TYPELOC_IMPL(DependentExtInt, 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 (const auto &I : D->bases()) { |
| if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(&I, TU))) |
| return true; |
| } |
| } |
| |
| return VisitTagDecl(D); |
| } |
| |
| bool CursorVisitor::VisitAttributes(Decl *D) { |
| for (const auto *I : D->attrs()) |
| if ((TU->ParsingOptions & CXTranslationUnit_VisitImplicitAttributes || |
| !I->isImplicit()) && |
| 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(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind) |
| DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind) |
| DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind) |
| #undef DEF_JOB |
| |
| class ExplicitTemplateArgsVisit : public VisitorJob { |
| public: |
| ExplicitTemplateArgsVisit(const TemplateArgumentLoc *Begin, |
| const TemplateArgumentLoc *End, CXCursor parent) |
| : VisitorJob(parent, VisitorJob::ExplicitTemplateArgsVisitKind, Begin, |
| End) {} |
| static bool classof(const VisitorJob *VJ) { |
| return VJ->getKind() == ExplicitTemplateArgsVisitKind; |
| } |
| const TemplateArgumentLoc *begin() const { |
| return static_cast<const TemplateArgumentLoc *>(data[0]); |
| } |
| const TemplateArgumentLoc *end() { |
| return static_cast<const TemplateArgumentLoc *>(data[1]); |
| } |
| }; |
| class DeclVisit : public VisitorJob { |
| public: |
| DeclVisit(const Decl *D, CXCursor parent, bool isFirst) |
| : VisitorJob(parent, VisitorJob::DeclVisitKind, D, |
| isFirst ? (void *)1 : (void *)nullptr) {} |
| 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] != nullptr; } |
| }; |
| 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(); |
| case Stmt::OMPCriticalDirectiveClass: |
| return cast<OMPCriticalDirective>(S)->getDirectiveName(); |
| } |
| } |
| }; |
| 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( |
| (SourceLocation::UIntTy)(uintptr_t)data[1]); |
| } |
| }; |
| class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> { |
| friend class OMPClauseEnqueue; |
| 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 VisitCXXForRangeStmt(const CXXForRangeStmt *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 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); |
| void VisitOMPExecutableDirective(const OMPExecutableDirective *D); |
| void VisitOMPLoopBasedDirective(const OMPLoopBasedDirective *D); |
| void VisitOMPLoopDirective(const OMPLoopDirective *D); |
| void VisitOMPParallelDirective(const OMPParallelDirective *D); |
| void VisitOMPSimdDirective(const OMPSimdDirective *D); |
| void |
| VisitOMPLoopTransformationDirective(const OMPLoopTransformationDirective *D); |
| void VisitOMPTileDirective(const OMPTileDirective *D); |
| void VisitOMPUnrollDirective(const OMPUnrollDirective *D); |
| void VisitOMPForDirective(const OMPForDirective *D); |
| void VisitOMPForSimdDirective(const OMPForSimdDirective *D); |
| void VisitOMPSectionsDirective(const OMPSectionsDirective *D); |
| void VisitOMPSectionDirective(const OMPSectionDirective *D); |
| void VisitOMPSingleDirective(const OMPSingleDirective *D); |
| void VisitOMPMasterDirective(const OMPMasterDirective *D); |
| void VisitOMPCriticalDirective(const OMPCriticalDirective *D); |
| void VisitOMPParallelForDirective(const OMPParallelForDirective *D); |
| void VisitOMPParallelForSimdDirective(const OMPParallelForSimdDirective *D); |
| void VisitOMPParallelMasterDirective(const OMPParallelMasterDirective *D); |
| void VisitOMPParallelSectionsDirective(const OMPParallelSectionsDirective *D); |
| void VisitOMPTaskDirective(const OMPTaskDirective *D); |
| void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D); |
| void VisitOMPBarrierDirective(const OMPBarrierDirective *D); |
| void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D); |
| void VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D); |
| void |
| VisitOMPCancellationPointDirective(const OMPCancellationPointDirective *D); |
| void VisitOMPCancelDirective(const OMPCancelDirective *D); |
| void VisitOMPFlushDirective(const OMPFlushDirective *D); |
| void VisitOMPDepobjDirective(const OMPDepobjDirective *D); |
| void VisitOMPScanDirective(const OMPScanDirective *D); |
| void VisitOMPOrderedDirective(const OMPOrderedDirective *D); |
| void VisitOMPAtomicDirective(const OMPAtomicDirective *D); |
| void VisitOMPTargetDirective(const OMPTargetDirective *D); |
| void VisitOMPTargetDataDirective(const OMPTargetDataDirective *D); |
| void VisitOMPTargetEnterDataDirective(const OMPTargetEnterDataDirective *D); |
| void VisitOMPTargetExitDataDirective(const OMPTargetExitDataDirective *D); |
| void VisitOMPTargetParallelDirective(const OMPTargetParallelDirective *D); |
| void |
| VisitOMPTargetParallelForDirective(const OMPTargetParallelForDirective *D); |
| void VisitOMPTeamsDirective(const OMPTeamsDirective *D); |
| void VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D); |
| void VisitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective *D); |
| void VisitOMPMasterTaskLoopDirective(const OMPMasterTaskLoopDirective *D); |
| void |
| VisitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective *D); |
| void VisitOMPParallelMasterTaskLoopDirective( |
| const OMPParallelMasterTaskLoopDirective *D); |
| void VisitOMPParallelMasterTaskLoopSimdDirective( |
| const OMPParallelMasterTaskLoopSimdDirective *D); |
| void VisitOMPDistributeDirective(const OMPDistributeDirective *D); |
| void VisitOMPDistributeParallelForDirective( |
| const OMPDistributeParallelForDirective *D); |
| void VisitOMPDistributeParallelForSimdDirective( |
| const OMPDistributeParallelForSimdDirective *D); |
| void VisitOMPDistributeSimdDirective(const OMPDistributeSimdDirective *D); |
| void VisitOMPTargetParallelForSimdDirective( |
| const OMPTargetParallelForSimdDirective *D); |
| void VisitOMPTargetSimdDirective(const OMPTargetSimdDirective *D); |
| void VisitOMPTeamsDistributeDirective(const OMPTeamsDistributeDirective *D); |
| void VisitOMPTeamsDistributeSimdDirective( |
| const OMPTeamsDistributeSimdDirective *D); |
| void VisitOMPTeamsDistributeParallelForSimdDirective( |
| const OMPTeamsDistributeParallelForSimdDirective *D); |
| void VisitOMPTeamsDistributeParallelForDirective( |
| const OMPTeamsDistributeParallelForDirective *D); |
| void VisitOMPTargetTeamsDirective(const OMPTargetTeamsDirective *D); |
| void VisitOMPTargetTeamsDistributeDirective( |
| const OMPTargetTeamsDistributeDirective *D); |
| void VisitOMPTargetTeamsDistributeParallelForDirective( |
| const OMPTargetTeamsDistributeParallelForDirective *D); |
| void VisitOMPTargetTeamsDistributeParallelForSimdDirective( |
| const OMPTargetTeamsDistributeParallelForSimdDirective *D); |
| void VisitOMPTargetTeamsDistributeSimdDirective( |
| const OMPTargetTeamsDistributeSimdDirective *D); |
| |
| private: |
| void AddDeclarationNameInfo(const Stmt *S); |
| void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); |
| void AddExplicitTemplateArgs(const TemplateArgumentLoc *A, |
| unsigned NumTemplateArgs); |
| 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); |
| void EnqueueChildren(const OMPClause *S); |
| }; |
| } // 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 TemplateArgumentLoc *A, |
| unsigned NumTemplateArgs) { |
| WL.push_back(ExplicitTemplateArgsVisit(A, A + NumTemplateArgs, 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 (const Stmt *SubStmt : S->children()) { |
| AddStmt(SubStmt); |
| } |
| 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); |
| } |
| namespace { |
| class OMPClauseEnqueue : public ConstOMPClauseVisitor<OMPClauseEnqueue> { |
| EnqueueVisitor *Visitor; |
| /// Process clauses with list of variables. |
| template <typename T> void VisitOMPClauseList(T *Node); |
| |
| public: |
| OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) {} |
| #define GEN_CLANG_CLAUSE_CLASS |
| #define CLAUSE_CLASS(Enum, Str, Class) void Visit##Class(const Class *C); |
| #include "llvm/Frontend/OpenMP/OMP.inc" |
| void VisitOMPClauseWithPreInit(const OMPClauseWithPreInit *C); |
| void VisitOMPClauseWithPostUpdate(const OMPClauseWithPostUpdate *C); |
| }; |
| |
| void OMPClauseEnqueue::VisitOMPClauseWithPreInit( |
| const OMPClauseWithPreInit *C) { |
| Visitor->AddStmt(C->getPreInitStmt()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPClauseWithPostUpdate( |
| const OMPClauseWithPostUpdate *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getPostUpdateExpr()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPIfClause(const OMPIfClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getCondition()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPFinalClause(const OMPFinalClause *C) { |
| Visitor->AddStmt(C->getCondition()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getNumThreads()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPSafelenClause(const OMPSafelenClause *C) { |
| Visitor->AddStmt(C->getSafelen()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPSimdlenClause(const OMPSimdlenClause *C) { |
| Visitor->AddStmt(C->getSimdlen()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPSizesClause(const OMPSizesClause *C) { |
| for (auto E : C->getSizesRefs()) |
| Visitor->AddStmt(E); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPFullClause(const OMPFullClause *C) {} |
| |
| void OMPClauseEnqueue::VisitOMPPartialClause(const OMPPartialClause *C) { |
| Visitor->AddStmt(C->getFactor()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPAllocatorClause(const OMPAllocatorClause *C) { |
| Visitor->AddStmt(C->getAllocator()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPCollapseClause(const OMPCollapseClause *C) { |
| Visitor->AddStmt(C->getNumForLoops()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) {} |
| |
| void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) {} |
| |
| void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getChunkSize()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) { |
| Visitor->AddStmt(C->getNumForLoops()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPDetachClause(const OMPDetachClause *C) { |
| Visitor->AddStmt(C->getEventHandler()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPUntiedClause(const OMPUntiedClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPMergeableClause(const OMPMergeableClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPReadClause(const OMPReadClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPWriteClause(const OMPWriteClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPUpdateClause(const OMPUpdateClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPAcquireClause(const OMPAcquireClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPReleaseClause(const OMPReleaseClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPRelaxedClause(const OMPRelaxedClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPThreadsClause(const OMPThreadsClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPNogroupClause(const OMPNogroupClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPInitClause(const OMPInitClause *C) { |
| VisitOMPClauseList(C); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPUseClause(const OMPUseClause *C) { |
| Visitor->AddStmt(C->getInteropVar()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPDestroyClause(const OMPDestroyClause *C) { |
| if (C->getInteropVar()) |
| Visitor->AddStmt(C->getInteropVar()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNovariantsClause(const OMPNovariantsClause *C) { |
| Visitor->AddStmt(C->getCondition()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNocontextClause(const OMPNocontextClause *C) { |
| Visitor->AddStmt(C->getCondition()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPFilterClause(const OMPFilterClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getThreadID()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPAlignClause(const OMPAlignClause *C) { |
| Visitor->AddStmt(C->getAlignment()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPUnifiedAddressClause( |
| const OMPUnifiedAddressClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPUnifiedSharedMemoryClause( |
| const OMPUnifiedSharedMemoryClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPReverseOffloadClause( |
| const OMPReverseOffloadClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPDynamicAllocatorsClause( |
| const OMPDynamicAllocatorsClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPAtomicDefaultMemOrderClause( |
| const OMPAtomicDefaultMemOrderClause *) {} |
| |
| void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) { |
| Visitor->AddStmt(C->getDevice()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getNumTeams()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPThreadLimitClause( |
| const OMPThreadLimitClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getThreadLimit()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPPriorityClause(const OMPPriorityClause *C) { |
| Visitor->AddStmt(C->getPriority()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) { |
| Visitor->AddStmt(C->getGrainsize()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPNumTasksClause(const OMPNumTasksClause *C) { |
| Visitor->AddStmt(C->getNumTasks()); |
| } |
| |
| void OMPClauseEnqueue::VisitOMPHintClause(const OMPHintClause *C) { |
| Visitor->AddStmt(C->getHint()); |
| } |
| |
| template <typename T> void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { |
| for (const auto *I : Node->varlists()) { |
| Visitor->AddStmt(I); |
| } |
| } |
| |
| void OMPClauseEnqueue::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPAllocateClause(const OMPAllocateClause *C) { |
| VisitOMPClauseList(C); |
| Visitor->AddStmt(C->getAllocator()); |
| } |
| void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { |
| VisitOMPClauseList(C); |
| for (const auto *E : C->private_copies()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPFirstprivateClause( |
| const OMPFirstprivateClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPreInit(C); |
| for (const auto *E : C->private_copies()) { |
| Visitor->AddStmt(E); |
| } |
| for (const auto *E : C->inits()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPLastprivateClause( |
| const OMPLastprivateClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPostUpdate(C); |
| for (auto *E : C->private_copies()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->source_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->destination_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->assignment_ops()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPostUpdate(C); |
| for (auto *E : C->privates()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->lhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->rhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->reduction_ops()) { |
| Visitor->AddStmt(E); |
| } |
| if (C->getModifier() == clang::OMPC_REDUCTION_inscan) { |
| for (auto *E : C->copy_ops()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->copy_array_temps()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->copy_array_elems()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPTaskReductionClause( |
| const OMPTaskReductionClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPostUpdate(C); |
| for (auto *E : C->privates()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->lhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->rhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->reduction_ops()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPInReductionClause( |
| const OMPInReductionClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPostUpdate(C); |
| for (auto *E : C->privates()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->lhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->rhs_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->reduction_ops()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->taskgroup_descriptors()) |
| Visitor->AddStmt(E); |
| } |
| void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) { |
| VisitOMPClauseList(C); |
| VisitOMPClauseWithPostUpdate(C); |
| for (const auto *E : C->privates()) { |
| Visitor->AddStmt(E); |
| } |
| for (const auto *E : C->inits()) { |
| Visitor->AddStmt(E); |
| } |
| for (const auto *E : C->updates()) { |
| Visitor->AddStmt(E); |
| } |
| for (const auto *E : C->finals()) { |
| Visitor->AddStmt(E); |
| } |
| Visitor->AddStmt(C->getStep()); |
| Visitor->AddStmt(C->getCalcStep()); |
| } |
| void OMPClauseEnqueue::VisitOMPAlignedClause(const OMPAlignedClause *C) { |
| VisitOMPClauseList(C); |
| Visitor->AddStmt(C->getAlignment()); |
| } |
| void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) { |
| VisitOMPClauseList(C); |
| for (auto *E : C->source_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->destination_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->assignment_ops()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPCopyprivateClause( |
| const OMPCopyprivateClause *C) { |
| VisitOMPClauseList(C); |
| for (auto *E : C->source_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->destination_exprs()) { |
| Visitor->AddStmt(E); |
| } |
| for (auto *E : C->assignment_ops()) { |
| Visitor->AddStmt(E); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPFlushClause(const OMPFlushClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPDepobjClause(const OMPDepobjClause *C) { |
| Visitor->AddStmt(C->getDepobj()); |
| } |
| void OMPClauseEnqueue::VisitOMPDependClause(const OMPDependClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPMapClause(const OMPMapClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPDistScheduleClause( |
| const OMPDistScheduleClause *C) { |
| VisitOMPClauseWithPreInit(C); |
| Visitor->AddStmt(C->getChunkSize()); |
| } |
| void OMPClauseEnqueue::VisitOMPDefaultmapClause( |
| const OMPDefaultmapClause * /*C*/) {} |
| void OMPClauseEnqueue::VisitOMPToClause(const OMPToClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPFromClause(const OMPFromClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPUseDevicePtrClause( |
| const OMPUseDevicePtrClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPUseDeviceAddrClause( |
| const OMPUseDeviceAddrClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPIsDevicePtrClause( |
| const OMPIsDevicePtrClause *C) { |
| VisitOMPClauseList(C); |
| } |
| void OMPClauseEnqueue::VisitOMPNontemporalClause( |
| const OMPNontemporalClause *C) { |
| VisitOMPClauseList(C); |
| for (const auto *E : C->private_refs()) |
| Visitor->AddStmt(E); |
| } |
| void OMPClauseEnqueue::VisitOMPOrderClause(const OMPOrderClause *C) {} |
| void OMPClauseEnqueue::VisitOMPUsesAllocatorsClause( |
| const OMPUsesAllocatorsClause *C) { |
| for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) { |
| const OMPUsesAllocatorsClause::Data &D = C->getAllocatorData(I); |
| Visitor->AddStmt(D.Allocator); |
| Visitor->AddStmt(D.AllocatorTraits); |
| } |
| } |
| void OMPClauseEnqueue::VisitOMPAffinityClause(const OMPAffinityClause *C) { |
| Visitor->AddStmt(C->getModifier()); |
| for (const Expr *E : C->varlists()) |
| Visitor->AddStmt(E); |
| } |
| void OMPClauseEnqueue::VisitOMPBindClause(const OMPBindClause *C) {} |
| |
| } // namespace |
| |
| void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { |
| unsigned size = WL.size(); |
| OMPClauseEnqueue Visitor(this); |
| Visitor.Visit(S); |
| 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 (auto &I : llvm::reverse(S->body())) |
| 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) { |
| if (E->hasExplicitTemplateArgs()) |
| AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); |
| 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().getValueOr(nullptr)); |
| // 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 |