blob: 5fa2566a8edd7a4a66181185e61c8372e169490a [file] [log] [blame]
//===- CIndex.cpp - Clang-C Source Indexing Library -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the main API hooks in the Clang-C Source Indexing
// library.
//
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
#include "CIndexDiagnostic.h"
#include "CLog.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "CXType.h"
#include "CursorVisitor.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.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 "clang/Serialization/SerializationDiagnostic.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.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/Mutex.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"
#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, ASTUnit *AU) {
if (!AU)
return nullptr;
assert(CIdx);
CXTranslationUnit D = new CXTranslationUnitImpl();
D->CIdx = CIdx;
D->TheASTUnit = AU;
D->StringPool = new cxstring::CXStringPool();
D->Diagnostics = nullptr;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
D->CommentToXML = nullptr;
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);
}
/// \brief Compare two source ranges to determine their relative position in
/// the translation unit.
static RangeComparisonResult RangeCompare(SourceManager &SM,
SourceRange R1,
SourceRange R2) {
assert(R1.isValid() && "First range is invalid?");
assert(R2.isValid() && "Second range is invalid?");
if (R1.getEnd() != R2.getBegin() &&
SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
return RangeBefore;
if (R2.getEnd() != R1.getBegin() &&
SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
return RangeAfter;
return RangeOverlap;
}
/// \brief Determine if a source location falls within, before, or after a
/// a given source range.
static RangeComparisonResult LocationCompare(SourceManager &SM,
SourceLocation L, SourceRange R) {
assert(R.isValid() && "First range is invalid?");
assert(L.isValid() && "Second range is invalid?");
if (L == R.getBegin() || L == R.getEnd())
return RangeOverlap;
if (SM.isBeforeInTranslationUnit(L, R.getBegin()))
return RangeBefore;
if (SM.isBeforeInTranslationUnit(R.getEnd(), L))
return RangeAfter;
return RangeOverlap;
}
/// \brief Translate a Clang source range into a CIndex source range.
///
/// Clang internally represents ranges where the end location points to the
/// start of the token at the end. However, for external clients it is more
/// useful to have a CXSourceRange be a proper half-open interval. This routine
/// does the appropriate translation.
CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
const LangOptions &LangOpts,
const CharSourceRange &R) {
// We want the last character in this location, so we will adjust the
// location accordingly.
SourceLocation EndLoc = R.getEnd();
if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc))
EndLoc = SM.getExpansionRange(EndLoc).second;
if (R.isTokenRange() && EndLoc.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;
}
//===----------------------------------------------------------------------===//
// Cursor visitor.
//===----------------------------------------------------------------------===//
static SourceRange getRawCursorExtent(CXCursor C);
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr);
RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
return RangeCompare(AU->getSourceManager(), R, RegionOfInterest);
}
/// \brief Visit the given cursor and, if requested by the visitor,
/// its children.
///
/// \param Cursor the cursor to visit.
///
/// \param CheckedRegionOfInterest if true, then the caller already checked
/// that this cursor is within the region of interest.
///
/// \returns true if the visitation should be aborted, false if it
/// should continue.
bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
if (clang_isInvalid(Cursor.kind))
return false;
if (clang_isDeclaration(Cursor.kind)) {
const Decl *D = getCursorDecl(Cursor);
if (!D) {
assert(0 && "Invalid declaration cursor");
return true; // abort.
}
// Ignore implicit declarations, unless it's an objc method because
// currently we should report implicit methods for properties when indexing.
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
return false;
}
// If we have a range of interest, and this cursor doesn't intersect with it,
// we're done.
if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
SourceRange Range = getRawCursorExtent(Cursor);
if (Range.isInvalid() || CompareRegionOfInterest(Range))
return false;
}
switch (Visitor(Cursor, Parent, ClientData)) {
case CXChildVisit_Break:
return true;
case CXChildVisit_Continue:
return false;
case CXChildVisit_Recurse: {
bool ret = VisitChildren(Cursor);
if (PostChildrenVisitor)
if (PostChildrenVisitor(Cursor, ClientData))
return true;
return ret;
}
}
llvm_unreachable("Invalid CXChildVisitResult!");
}
static bool visitPreprocessedEntitiesInRange(SourceRange R,
PreprocessingRecord &PPRec,
CursorVisitor &Visitor) {
SourceManager &SM = Visitor.getASTUnit()->getSourceManager();
FileID FID;
if (!Visitor.shouldVisitIncludedEntities()) {
// If the begin/end of the range lie in the same FileID, do the optimization
// where we skip preprocessed entities that do not come from the same FileID.
FID = SM.getFileID(SM.getFileLoc(R.getBegin()));
if (FID != SM.getFileID(SM.getFileLoc(R.getEnd())))
FID = FileID();
}
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;
}
/// \brief Visit the children of the given cursor.
///
/// \returns true if the visitation should be aborted, false if it
/// should continue.
bool CursorVisitor::VisitChildren(CXCursor Cursor) {
if (clang_isReference(Cursor.kind) &&
Cursor.kind != CXCursor_CXXBaseSpecifier) {
// By definition, references have no children.
return false;
}
// Set the Parent field to Cursor, then back to its old value once we're
// done.
SetParentRAII SetParent(Parent, StmtParent, Cursor);
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = const_cast<Decl *>(getCursorDecl(Cursor));
if (!D)
return false;
return VisitAttributes(D) || Visit(D);
}
if (clang_isStatement(Cursor.kind)) {
if (const Stmt *S = getCursorStmt(Cursor))
return Visit(S);
return false;
}
if (clang_isExpression(Cursor.kind)) {
if (const Expr *E = getCursorExpr(Cursor))
return Visit(E);
return false;
}
if (clang_isTranslationUnit(Cursor.kind)) {
CXTranslationUnit TU = getCursorTU(Cursor);
ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast };
for (unsigned I = 0; I != 2; ++I) {
if (VisitOrder[I]) {
if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
RegionOfInterest.isInvalid()) {
for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
TLEnd = CXXUnit->top_level_end();
TL != TLEnd; ++TL) {
if (Visit(MakeCXCursor(*TL, TU, RegionOfInterest), true))
return true;
}
} else if (VisitDeclContext(
CXXUnit->getASTContext().getTranslationUnitDecl()))
return true;
continue;
}
// Walk the preprocessing record.
if (CXXUnit->getPreprocessor().getPreprocessingRecord())
visitPreprocessedEntitiesInRegion();
}
return false;
}
if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
if (const CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) {
if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) {
return Visit(BaseTSInfo->getTypeLoc());
}
}
}
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
if (const ObjCObjectType *ObjT = A->getInterface()->getAs<ObjCObjectType>())
return Visit(cxcursor::MakeCursorObjCClassRef(
ObjT->getInterface(),
A->getInterfaceLoc()->getTypeLoc().getLocStart(), 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;
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
// Ignore synthesized ivars here, otherwise if we have something like:
// @synthesize prop = _prop;
// and '_prop' is not declared, we will encounter a '_prop' ivar before
// encountering the 'prop' synthesize declaration and we will think that
// we passed the region-of-interest.
if (ObjCIvarDecl *ivarD = dyn_cast<ObjCIvarDecl>(D)) {
if (ivarD->getSynthesize())
continue;
}
// FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
// declarations is a mismatch with the compiler semantics.
if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D);
if (!ID->isThisDeclarationADefinition())
Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU);
} else if (Cursor.kind == CXCursor_ObjCProtocolDecl) {
ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
if (!PD->isThisDeclarationADefinition())
Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
}
const Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
if (!V.getValue())
return false;
if (Visit(Cursor, true))
return true;
}
return false;
}
bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units are visited directly by Visit()");
}
bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
return false;
}
bool CursorVisitor::VisitTypedefDecl(TypedefDecl *D) {
if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
return false;
}
bool CursorVisitor::VisitTagDecl(TagDecl *D) {
return VisitDeclContext(D);
}
bool CursorVisitor::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D) {
bool ShouldVisitBody = false;
switch (D->getSpecializationKind()) {
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
// Nothing to visit
return false;
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
break;
case TSK_ExplicitSpecialization:
ShouldVisitBody = true;
break;
}
// Visit the template arguments used in the specialization.
if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) {
TypeLoc TL = SpecType->getTypeLoc();
if (TemplateSpecializationTypeLoc TSTLoc =
TL.getAs<TemplateSpecializationTypeLoc>()) {
for (unsigned I = 0, N = TSTLoc.getNumArgs(); I != N; ++I)
if (VisitTemplateArgumentLoc(TSTLoc.getArgLoc(I)))
return true;
}
}
if (ShouldVisitBody && VisitCXXRecordDecl(D))
return true;
return false;
}
bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
// FIXME: Visit the "outer" template parameter lists on the TagDecl
// before visiting these template parameters.
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
// Visit the partial specialization arguments.
const 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) {
// Visit the default argument.
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo())
if (Visit(DefArg->getTypeLoc()))
return true;
return false;
}
bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (Expr *Init = D->getInitExpr())
return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
unsigned NumParamList = DD->getNumTemplateParameterLists();
for (unsigned i = 0; i < NumParamList; i++) {
TemplateParameterList* Params = DD->getTemplateParameterList(i);
if (VisitTemplateParameters(Params))
return true;
}
if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo())
if (Visit(TSInfo->getTypeLoc()))
return true;
// Visit the nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = DD->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
return false;
}
/// \brief Compare two base or member initializers based on their source order.
static int CompareCXXCtorInitializers(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>();
// If we have a function declared directly (without the use of a typedef),
// visit just the return type. Otherwise, just visit the function's type
// now.
if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL.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;
// 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));
return false;
}
bool CursorVisitor::VisitVarDecl(VarDecl *D) {
if (VisitDeclaratorDecl(D))
return true;
if (Expr *Init = D->getInit())
return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
if (VisitDeclaratorDecl(D))
return true;
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (Expr *DefArg = D->getDefaultArgument())
return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest));
return false;
}
bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// FIXME: Visit the "outer" template parameter lists on the FunctionDecl
// before visiting these template parameters.
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
return VisitFunctionDecl(D->getTemplatedDecl());
}
bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// FIXME: Visit the "outer" template parameter lists on the TagDecl
// before visiting these template parameters.
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
return VisitCXXRecordDecl(D->getTemplatedDecl());
}
bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() &&
VisitTemplateArgumentLoc(D->getDefaultArgument()))
return true;
return false;
}
bool CursorVisitor::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->params()) {
if (Visit(MakeCXCursor(P, TU, RegionOfInterest)))
return true;
}
if (ND->isThisDeclarationADefinition() &&
Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
return true;
return false;
}
template <typename DeclIt>
static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current,
SourceManager &SM, SourceLocation EndLoc,
SmallVectorImpl<Decl *> &Decls) {
DeclIt next = *DI_current;
while (++next != DE_current) {
Decl *D_next = *next;
if (!D_next)
break;
SourceLocation L = D_next->getLocStart();
if (!L.isValid())
break;
if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
*DI_current = next;
Decls.push_back(D_next);
continue;
}
break;
}
}
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->getLocStart().isInvalid())
continue;
DeclsInContainer.push_back(SubDecl);
}
// Now sort the Decls so that they appear in lexical order.
std::sort(DeclsInContainer.begin(), DeclsInContainer.end(),
[&SM](Decl *A, Decl *B) {
SourceLocation L_A = A->getLocStart();
SourceLocation L_B = B->getLocStart();
assert(L_A.isValid() && L_B.isValid());
return SM.isBeforeInTranslationUnit(L_A, L_B);
});
// 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);
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::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
switch (Name.getName().getNameKind()) {
case clang::DeclarationName::Identifier:
case clang::DeclarationName::CXXLiteralOperatorName:
case clang::DeclarationName::CXXOperatorName:
case clang::DeclarationName::CXXUsingDirective:
return false;
case clang::DeclarationName::CXXConstructorName:
case clang::DeclarationName::CXXDestructorName:
case clang::DeclarationName::CXXConversionFunctionName:
if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo())
return Visit(TSInfo->getTypeLoc());
return false;
case clang::DeclarationName::ObjCZeroArgSelector:
case clang::DeclarationName::ObjCOneArgSelector:
case clang::DeclarationName::ObjCMultiArgSelector:
// FIXME: Per-identifier location info?
return false;
}
llvm_unreachable("Invalid DeclarationName::Kind!");
}
bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
SourceRange Range) {
// FIXME: This whole routine is a hack to work around the lack of proper
// source information in nested-name-specifiers (PR5791). Since we do have
// a beginning source location, we can visit the first component of the
// nested-name-specifier, if it's a single-token component.
if (!NNS)
return false;
// Get the first component in the nested-name-specifier.
while (NestedNameSpecifier *Prefix = NNS->getPrefix())
NNS = Prefix;
switch (NNS->getKind()) {
case NestedNameSpecifier::Namespace:
return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(),
TU));
case NestedNameSpecifier::NamespaceAlias:
return Visit(MakeCursorNamespaceRef(NNS->getAsNamespaceAlias(),
Range.getBegin(), TU));
case NestedNameSpecifier::TypeSpec: {
// If the type has a form where we know that the beginning of the source
// range matches up with a reference cursor. Visit the appropriate reference
// cursor.
const Type *T = NNS->getAsType();
if (const TypedefType *Typedef = dyn_cast<TypedefType>(T))
return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU));
if (const TagType *Tag = dyn_cast<TagType>(T))
return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU));
if (const TemplateSpecializationType *TST
= dyn_cast<TemplateSpecializationType>(T))
return VisitTemplateName(TST->getTemplateName(), Range.getBegin());
break;
}
case NestedNameSpecifier::TypeSpecWithTemplate:
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Identifier:
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::DependentTemplate:
// FIXME: Visit nested-name-specifier.
return false;
case TemplateName::QualifiedTemplate:
// FIXME: Visit nested-name-specifier.
return Visit(MakeCursorTemplateRef(
Name.getAsQualifiedTemplateName()->getDecl(),
Loc, TU));
case TemplateName::SubstTemplateTemplateParm:
return Visit(MakeCursorTemplateRef(
Name.getAsSubstTemplateTemplateParm()->getParameter(),
Loc, TU));
case TemplateName::SubstTemplateTemplateParmPack:
return Visit(MakeCursorTemplateRef(
Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(),
Loc, TU));
}
llvm_unreachable("Invalid TemplateName::Kind!");
}
bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
switch (TAL.getArgument().getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Pack:
return false;
case TemplateArgument::Type:
if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo())
return Visit(TSInfo->getTypeLoc());
return false;
case TemplateArgument::Declaration:
if (Expr *E = TAL.getSourceDeclExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::NullPtr:
if (Expr *E = TAL.getSourceNullPtrExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Expression:
if (Expr *E = TAL.getSourceExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc()))
return true;
return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(),
TAL.getTemplateNameLoc());
}
llvm_unreachable("Invalid TemplateArgument::Kind!");
}
bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
return VisitDeclContext(D);
}
bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
return Visit(TL.getUnqualifiedLoc());
}
bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
ASTContext &Context = AU->getASTContext();
// Some builtin types (such as Objective-C's "id", "sel", and
// "Class") have associated declarations. Create cursors for those.
QualType VisitType;
switch (TL.getTypePtr()->getKind()) {
case BuiltinType::Void:
case BuiltinType::NullPtr:
case BuiltinType::Dependent:
case BuiltinType::OCLImage1d:
case BuiltinType::OCLImage1dArray:
case BuiltinType::OCLImage1dBuffer:
case BuiltinType::OCLImage2d:
case BuiltinType::OCLImage2dArray:
case BuiltinType::OCLImage2dDepth:
case BuiltinType::OCLImage2dArrayDepth:
case BuiltinType::OCLImage2dMSAA:
case BuiltinType::OCLImage2dArrayMSAA:
case BuiltinType::OCLImage2dMSAADepth:
case BuiltinType::OCLImage2dArrayMSAADepth:
case BuiltinType::OCLImage3d:
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLNDRange:
case BuiltinType::OCLReserveID:
#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::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::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::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());
}
#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \
bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
return Visit##PARENT##Loc(TL); \
}
DEFAULT_TYPELOC_IMPL(Complex, Type)
DEFAULT_TYPELOC_IMPL(ConstantArray, ArrayType)
DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType)
DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType)
DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType)
DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type)
DEFAULT_TYPELOC_IMPL(Vector, Type)
DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)
DEFAULT_TYPELOC_IMPL(FunctionProto, FunctionType)
DEFAULT_TYPELOC_IMPL(FunctionNoProto, FunctionType)
DEFAULT_TYPELOC_IMPL(Record, TagType)
DEFAULT_TYPELOC_IMPL(Enum, TagType)
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParm, Type)
DEFAULT_TYPELOC_IMPL(SubstTemplateTypeParmPack, Type)
DEFAULT_TYPELOC_IMPL(Auto, Type)
bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
// Visit the nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
return true;
if (D->isCompleteDefinition()) {
for (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 (Visit(MakeCXCursor(I, D, TU)))
return true;
return false;
}
//===----------------------------------------------------------------------===//
// Data-recursive visitor methods.
//===----------------------------------------------------------------------===//
namespace {
#define DEF_JOB(NAME, DATA, KIND)\
class NAME : public VisitorJob {\
public:\
NAME(const DATA *d, CXCursor parent) : \
VisitorJob(parent, VisitorJob::KIND, d) {} \
static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\
const DATA *get() const { return static_cast<const DATA*>(data[0]); }\
};
DEF_JOB(StmtVisit, Stmt, StmtVisitKind)
DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind)
DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind)
DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
#undef DEF_JOB
class DeclVisit : public VisitorJob {
public:
DeclVisit(const Decl *D, CXCursor parent, bool isFirst) :
VisitorJob(parent, VisitorJob::DeclVisitKind,
D, isFirst ? (void*) 1 : (void*) 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((unsigned)(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 VisitOMPLoopDirective(const OMPLoopDirective *D);
void VisitOMPParallelDirective(const OMPParallelDirective *D);
void VisitOMPSimdDirective(const OMPSimdDirective *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 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 VisitOMPOrderedDirective(const OMPOrderedDirective *D);
void VisitOMPAtomicDirective(const OMPAtomicDirective *D);
void VisitOMPTargetDirective(const OMPTargetDirective *D);
void VisitOMPTargetDataDirective(const OMPTargetDataDirective *D);
void VisitOMPTeamsDirective(const OMPTeamsDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A);
void AddMemberRef(const FieldDecl *D, SourceLocation L);
void AddStmt(const Stmt *S);
void AddDecl(const Decl *D, bool isFirst = true);
void AddTypeLoc(TypeSourceInfo *TI);
void EnqueueChildren(const Stmt *S);
void EnqueueChildren(const OMPClause *S);
};
} // end anonyous namespace
void EnqueueVisitor::AddDeclarationNameInfo(const Stmt *S) {
// 'S' should always be non-null, since it comes from the
// statement we are visiting.
WL.push_back(DeclarationNameInfoVisit(S, Parent));
}
void
EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
if (Qualifier)
WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent));
}
void EnqueueVisitor::AddStmt(const Stmt *S) {
if (S)
WL.push_back(StmtVisit(S, Parent));
}
void EnqueueVisitor::AddDecl(const Decl *D, bool isFirst) {
if (D)
WL.push_back(DeclVisit(D, Parent, isFirst));
}
void EnqueueVisitor::
AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) {
if (A)
WL.push_back(ExplicitTemplateArgsVisit(A, Parent));
}
void EnqueueVisitor::AddMemberRef(const FieldDecl *D, SourceLocation L) {
if (D)
WL.push_back(MemberRefVisit(D, L, Parent));
}
void EnqueueVisitor::AddTypeLoc(TypeSourceInfo *TI) {
if (TI)
WL.push_back(TypeLocVisit(TI->getTypeLoc(), Parent));
}
void EnqueueVisitor::EnqueueChildren(const Stmt *S) {
unsigned size = WL.size();
for (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;
/// \brief Process clauses with list of variables.
template <typename T>
void VisitOMPClauseList(T *Node);
public:
OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) { }
#define OPENMP_CLAUSE(Name, Class) \
void Visit##Class(const Class *C);
#include "clang/Basic/OpenMPKinds.def"
};
void OMPClauseEnqueue::VisitOMPIfClause(const OMPIfClause *C) {
Visitor->AddStmt(C->getCondition());
}
void OMPClauseEnqueue::VisitOMPFinalClause(const OMPFinalClause *C) {
Visitor->AddStmt(C->getCondition());
}
void OMPClauseEnqueue::VisitOMPNumThreadsClause(const OMPNumThreadsClause *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::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) {
Visitor->AddStmt(C->getChunkSize());
Visitor->AddStmt(C->getHelperChunkSize());
}
void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) {
Visitor->AddStmt(C->getNumForLoops());
}
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::VisitOMPThreadsClause(const OMPThreadsClause *) {}
void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {}
void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Visitor->AddStmt(C->getDevice());
}
template<typename T>
void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
for (const auto *I : Node->varlists()) {
Visitor->AddStmt(I);
}
}
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);
}
void OMPClauseEnqueue::VisitOMPLastprivateClause(
const OMPLastprivateClause *C) {
VisitOMPClauseList(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);
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::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(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::VisitOMPDependClause(const OMPDependClause *C) {
VisitOMPClauseList(C);
}
}
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) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
AddNestedNameSpecifierLoc(QualifierLoc);
if (!E->isImplicitAccess())
AddStmt(E->getBase());
}
void EnqueueVisitor::VisitCXXNewExpr(const CXXNewExpr *E) {
// Enqueue the initializer , if any.
AddStmt(E->getInitializer());
// Enqueue the array size, if any.
AddStmt(E->getArraySize());
// Enqueue the allocated type.
AddTypeLoc(E->getAllocatedTypeSourceInfo());
// Enqueue the placement arguments.
for (unsigned I = E->getNumPlacementArgs(); I > 0; --I)
AddStmt(E->getPlacementArg(I-1));
}
void EnqueueVisitor::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CE) {
for (unsigned I = CE->getNumArgs(); I > 1 /* Yes, this is 1 */; --I)
AddStmt(CE->getArg(I-1));
AddStmt(CE->getCallee());
AddStmt(CE->getArg(0));
}
void EnqueueVisitor::VisitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *E) {
// Visit the name of the type being destroyed.
AddTypeLoc(E->getDestroyedTypeInfo());
// Visit the scope type that looks disturbingly like the nested-name-specifier
// but isn't.
AddTypeLoc(E->getScopeTypeInfo());
// Visit the nested-name-specifier.
if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
AddNestedNameSpecifierLoc(QualifierLoc);
// Visit base expression.
AddStmt(E->getBase());
}
void EnqueueVisitor::VisitCXXScalarValueInitExpr(
const CXXScalarValueInitExpr *E) {
AddTypeLoc(E->getTypeSourceInfo());
}
void EnqueueVisitor::VisitCXXTemporaryObjectExpr(
const CXXTemporaryObjectExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeSourceInfo());
}
void EnqueueVisitor::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
EnqueueChildren(E);
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(
const CXXUnresolvedConstructExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeSourceInfo());
}
void EnqueueVisitor::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
EnqueueChildren(E);
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
void EnqueueVisitor::VisitCXXCatchStmt(const CXXCatchStmt *S) {
EnqueueChildren(S);
AddDecl(S->getExceptionDecl());
}
void EnqueueVisitor::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
AddStmt(S->getBody());
AddStmt(S->getRangeInit());
AddDecl(S->getLoopVariable());
}
void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) {
if (DR->hasExplicitTemplateArgs()) {
AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
}
WL.push_back(DeclRefExprParts(DR, Parent));
}
void EnqueueVisitor::VisitDependentScopeDeclRefExpr(
const DependentScopeDeclRefExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
AddNestedNameSpecifierLoc(E->getQualifierLoc());
}
void EnqueueVisitor::VisitDeclStmt(const DeclStmt *S) {
unsigned size = WL.size();
bool isFirst = true;
for (const auto *D : S->decls()) {
AddDecl(D, isFirst);
isFirst = false;
}
if (size == WL.size())
return;
// Now reverse the entries we just added. This will match the DFS
// ordering performed by the worklist.
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
std::reverse(I, E);
}
void EnqueueVisitor::VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
AddStmt(E->getInit());
for (DesignatedInitExpr::const_reverse_designators_iterator
D = E->designators_rbegin(), DEnd = E->designators_rend();
D != DEnd; ++D) {
if (D->isFieldDesignator()) {
if (FieldDecl *Field = D->getField())
AddMemberRef(Field, D->getFieldLoc());
continue;
}
if (D->isArrayDesignator()) {
AddStmt(E->getArrayIndex(*D));
continue;
}
assert(D->isArrayRangeDesignator() && "Unknown designator kind");
AddStmt(E->getArrayRangeEnd(*D));
AddStmt(E->getArrayRangeStart(*D));
}
}
void EnqueueVisitor::VisitExplicitCastExpr(const ExplicitCastExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeInfoAsWritten());
}
void EnqueueVisitor::VisitForStmt(const ForStmt *FS) {
AddStmt(FS->getBody());
AddStmt(FS->getInc());
AddStmt(FS->getCond());
AddDecl(FS->getConditionVariable());
AddStmt(FS->getInit());
}
void EnqueueVisitor::VisitGotoStmt(const GotoStmt *GS) {
WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent));
}
void EnqueueVisitor::VisitIfStmt(const IfStmt *If) {
AddStmt(If->getElse());
AddStmt(If->getThen());
AddStmt(If->getCond());
AddDecl(If->getConditionVariable());
}
void EnqueueVisitor::VisitInitListExpr(const InitListExpr *IE) {
// We care about the syntactic form of the initializer list, only.
if (InitListExpr *Syntactic = IE->getSyntacticForm())
IE = Syntactic;
EnqueueChildren(IE);
}
void EnqueueVisitor::VisitMemberExpr(const MemberExpr *M) {
WL.push_back(MemberExprParts(M, Parent));
// If the base of the member access expression is an implicit 'this', don't
// visit it.
// FIXME: If we ever want to show these implicit accesses, this will be
// unfortunate. However, clang_getCursor() relies on this behavior.
if (M->isImplicitAccess())
return;
// Ignore base anonymous struct/union fields, otherwise they will shadow the
// real field that that we are interested in.
if (auto *SubME = dyn_cast<MemberExpr>(M->getBase())) {
if (auto *FD = dyn_cast_or_null<FieldDecl>(SubME->getMemberDecl())) {
if (FD->isAnonymousStructOrUnion()) {
AddStmt(SubME->getBase());
return;
}
}
}
AddStmt(M->getBase());
}
void EnqueueVisitor::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
AddTypeLoc(E->getEncodedTypeSourceInfo());
}
void EnqueueVisitor::VisitObjCMessageExpr(const ObjCMessageExpr *M) {
EnqueueChildren(M);
AddTypeLoc(M->getClassReceiverTypeInfo());
}
void EnqueueVisitor::VisitOffsetOfExpr(const OffsetOfExpr *E) {
// Visit the components of the offsetof expression.
for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) {
typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
const OffsetOfNode &Node = E->getComponent(I-1);
switch (Node.getKind()) {
case OffsetOfNode::Array:
AddStmt(E->getIndexExpr(Node.getArrayExprIndex()));
break;
case OffsetOfNode::Field:
AddMemberRef(Node.getField(), Node.getSourceRange().getEnd());
break;
case OffsetOfNode::Identifier:
case OffsetOfNode::Base:
continue;
}
}
// Visit the type into which we're computing the offset.
AddTypeLoc(E->getTypeSourceInfo());
}
void EnqueueVisitor::VisitOverloadExpr(const OverloadExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
WL.push_back(OverloadExprParts(E, Parent));
}
void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr(
const UnaryExprOrTypeTraitExpr *E) {
EnqueueChildren(E);
if (E->isArgumentType())
AddTypeLoc(E->getArgumentTypeInfo());
}
void EnqueueVisitor::VisitStmt(const Stmt *S) {
EnqueueChildren(S);
}
void EnqueueVisitor::VisitSwitchStmt(const SwitchStmt *S) {
AddStmt(S->getBody());
AddStmt(S->getCond());
AddDecl(S->getConditionVariable());
}
void EnqueueVisitor::VisitWhileStmt(const WhileStmt *W) {
AddStmt(W->getBody());
AddStmt(W->getCond());
AddDecl(W->getConditionVariable());
}
void EnqueueVisitor::VisitTypeTraitExpr(const TypeTraitExpr *E) {
for (unsigned I = E->getNumArgs(); I > 0; --I)
AddTypeLoc(E->getArg(I-1));
}
void EnqueueVisitor::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
void EnqueueVisitor::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
EnqueueChildren(E);
}
void EnqueueVisitor::VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *U) {
VisitOverloadExpr(U);
if (!U->isImplicitAccess())
AddStmt(U->getBase());
}
void EnqueueVisitor::VisitVAArgExpr(const VAArgExpr *E) {
AddStmt(E->getSubExpr());
AddTypeLoc(E->getWrittenTypeInfo());
}
void EnqueueVisitor::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
WL.push_back(SizeOfPackExprParts(E, Parent));
}
void EnqueueVisitor::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
// If the opaque value has a source expression, just transparently
// visit that. This is useful for (e.g.) pseudo-object expressions.
if (Expr *SourceExpr = E->getSourceExpr())
return Visit