diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang14/tools/libclang | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz |
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang14/tools/libclang')
38 files changed, 21746 insertions, 0 deletions
diff --git a/contrib/libs/clang14/tools/libclang/ARCMigrate.cpp b/contrib/libs/clang14/tools/libclang/ARCMigrate.cpp new file mode 100644 index 0000000000..da8a7e4b91 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/ARCMigrate.cpp @@ -0,0 +1,138 @@ +//===- ARCMigrate.cpp - Clang-C ARC Migration 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 ARC Migration library. +// +//===----------------------------------------------------------------------===// + +#include "clang-c/Index.h" +#include "CXString.h" +#include "clang/ARCMigrate/ARCMT.h" +#include "clang/Config/config.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "llvm/Support/FileSystem.h" + +using namespace clang; +using namespace arcmt; + +namespace { + +struct Remap { + std::vector<std::pair<std::string, std::string> > Vec; +}; + +} // anonymous namespace. + +//===----------------------------------------------------------------------===// +// libClang public APIs. +//===----------------------------------------------------------------------===// + +CXRemapping clang_getRemappings(const char *migrate_dir_path) { +#if !CLANG_ENABLE_ARCMT + llvm::errs() << "error: feature not enabled in this build\n"; + return nullptr; +#else + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + if (!migrate_dir_path) { + if (Logging) + llvm::errs() << "clang_getRemappings was called with NULL parameter\n"; + return nullptr; + } + + if (!llvm::sys::fs::exists(migrate_dir_path)) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + llvm::errs() << "\"" << migrate_dir_path << "\" does not exist\n"; + } + return nullptr; + } + + TextDiagnosticBuffer diagBuffer; + std::unique_ptr<Remap> remap(new Remap()); + + bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return nullptr; + } + + return remap.release(); +#endif +} + +CXRemapping clang_getRemappingsFromFileList(const char **filePaths, + unsigned numFiles) { +#if !CLANG_ENABLE_ARCMT + llvm::errs() << "error: feature not enabled in this build\n"; + return nullptr; +#else + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + std::unique_ptr<Remap> remap(new Remap()); + + if (numFiles == 0) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "numFiles=0\n"; + return remap.release(); + } + + if (!filePaths) { + if (Logging) + llvm::errs() << "clang_getRemappingsFromFileList was called with " + "NULL filePaths\n"; + return nullptr; + } + + TextDiagnosticBuffer diagBuffer; + SmallVector<StringRef, 32> Files(filePaths, filePaths + numFiles); + + bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files, + &diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappingsFromFileList\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return remap.release(); + } + + return remap.release(); +#endif +} + +unsigned clang_remap_getNumFiles(CXRemapping map) { + return static_cast<Remap *>(map)->Vec.size(); + +} + +void clang_remap_getFilenames(CXRemapping map, unsigned index, + CXString *original, CXString *transformed) { + if (original) + *original = cxstring::createDup( + static_cast<Remap *>(map)->Vec[index].first); + if (transformed) + *transformed = cxstring::createDup( + static_cast<Remap *>(map)->Vec[index].second); +} + +void clang_remap_dispose(CXRemapping map) { + delete static_cast<Remap *>(map); +} diff --git a/contrib/libs/clang14/tools/libclang/BuildSystem.cpp b/contrib/libs/clang14/tools/libclang/BuildSystem.cpp new file mode 100644 index 0000000000..2f638ee870 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/BuildSystem.cpp @@ -0,0 +1,152 @@ +//===- BuildSystem.cpp - Utilities for use by build systems ---------------===// +// +// 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 various utilities for use by build systems. +// +//===----------------------------------------------------------------------===// + +#include "clang-c/BuildSystem.h" +#include "CXString.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemAlloc.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace llvm::sys; + +unsigned long long clang_getBuildSessionTimestamp(void) { + return llvm::sys::toTimeT(std::chrono::system_clock::now()); +} + +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(llvm::vfs::YAMLVFSWriter, + CXVirtualFileOverlay) + +CXVirtualFileOverlay clang_VirtualFileOverlay_create(unsigned) { + return wrap(new llvm::vfs::YAMLVFSWriter()); +} + +enum CXErrorCode +clang_VirtualFileOverlay_addFileMapping(CXVirtualFileOverlay VFO, + const char *virtualPath, + const char *realPath) { + if (!VFO || !virtualPath || !realPath) + return CXError_InvalidArguments; + if (!path::is_absolute(virtualPath)) + return CXError_InvalidArguments; + if (!path::is_absolute(realPath)) + return CXError_InvalidArguments; + + for (path::const_iterator + PI = path::begin(virtualPath), + PE = path::end(virtualPath); PI != PE; ++PI) { + StringRef Comp = *PI; + if (Comp == "." || Comp == "..") + return CXError_InvalidArguments; + } + + unwrap(VFO)->addFileMapping(virtualPath, realPath); + return CXError_Success; +} + +enum CXErrorCode +clang_VirtualFileOverlay_setCaseSensitivity(CXVirtualFileOverlay VFO, + int caseSensitive) { + if (!VFO) + return CXError_InvalidArguments; + unwrap(VFO)->setCaseSensitivity(caseSensitive); + return CXError_Success; +} + +enum CXErrorCode +clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned, + char **out_buffer_ptr, + unsigned *out_buffer_size) { + if (!VFO || !out_buffer_ptr || !out_buffer_size) + return CXError_InvalidArguments; + + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + unwrap(VFO)->write(OS); + + StringRef Data = OS.str(); + *out_buffer_ptr = static_cast<char*>(llvm::safe_malloc(Data.size())); + *out_buffer_size = Data.size(); + memcpy(*out_buffer_ptr, Data.data(), Data.size()); + return CXError_Success; +} + +void clang_free(void *buffer) { + free(buffer); +} + +void clang_VirtualFileOverlay_dispose(CXVirtualFileOverlay VFO) { + delete unwrap(VFO); +} + + +struct CXModuleMapDescriptorImpl { + std::string ModuleName; + std::string UmbrellaHeader; +}; + +CXModuleMapDescriptor clang_ModuleMapDescriptor_create(unsigned) { + return new CXModuleMapDescriptorImpl(); +} + +enum CXErrorCode +clang_ModuleMapDescriptor_setFrameworkModuleName(CXModuleMapDescriptor MMD, + const char *name) { + if (!MMD || !name) + return CXError_InvalidArguments; + + MMD->ModuleName = name; + return CXError_Success; +} + +enum CXErrorCode +clang_ModuleMapDescriptor_setUmbrellaHeader(CXModuleMapDescriptor MMD, + const char *name) { + if (!MMD || !name) + return CXError_InvalidArguments; + + MMD->UmbrellaHeader = name; + return CXError_Success; +} + +enum CXErrorCode +clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor MMD, unsigned, + char **out_buffer_ptr, + unsigned *out_buffer_size) { + if (!MMD || !out_buffer_ptr || !out_buffer_size) + return CXError_InvalidArguments; + + llvm::SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + OS << "framework module " << MMD->ModuleName << " {\n"; + OS << " umbrella header \""; + OS.write_escaped(MMD->UmbrellaHeader) << "\"\n"; + OS << '\n'; + OS << " export *\n"; + OS << " module * { export * }\n"; + OS << "}\n"; + + StringRef Data = OS.str(); + *out_buffer_ptr = static_cast<char*>(llvm::safe_malloc(Data.size())); + *out_buffer_size = Data.size(); + memcpy(*out_buffer_ptr, Data.data(), Data.size()); + return CXError_Success; +} + +void clang_ModuleMapDescriptor_dispose(CXModuleMapDescriptor MMD) { + delete MMD; +} diff --git a/contrib/libs/clang14/tools/libclang/CIndex.cpp b/contrib/libs/clang14/tools/libclang/CIndex.cpp new file mode 100644 index 0000000000..53494ecc7a --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndex.cpp @@ -0,0 +1,9234 @@ +//===- 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::VisitUsingTypeLoc(UsingTypeLoc TL) { return false; } + +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(BitInt, Type) +DEFAULT_TYPELOC_IMPL(DependentBitInt, 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::VisitOMPCompareClause(const OMPCompareClause *) {} + +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(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->getTemplateArgs(), DR->getNumTemplateArgs()); + WL.push_back(DeclRefExprParts(DR, Parent)); +} +void EnqueueVisitor::VisitDependentScopeDeclRefExpr( + const DependentScopeDeclRefExpr *E) { + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); + 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 (const DesignatedInitExpr::Designator &D : + llvm::reverse(E->designators())) { + 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()); + AddStmt(If->getInit()); + 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 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) { + 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) { + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); + 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(SourceExpr); +} +void EnqueueVisitor::VisitLambdaExpr(const LambdaExpr *E) { + AddStmt(E->getBody()); + WL.push_back(LambdaExprParts(E, Parent)); +} +void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { + // Treat the expression like its syntactic form. + Visit(E->getSyntacticForm()); +} + +void EnqueueVisitor::VisitOMPExecutableDirective( + const OMPExecutableDirective *D) { + EnqueueChildren(D); + for (ArrayRef<OMPClause *>::iterator I = D->clauses().begin(), + E = D->clauses().end(); + I != E; ++I) + EnqueueChildren(*I); +} + +void EnqueueVisitor::VisitOMPLoopBasedDirective( + const OMPLoopBasedDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPLoopDirective(const OMPLoopDirective *D) { + VisitOMPLoopBasedDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSimdDirective(const OMPSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPLoopTransformationDirective( + const OMPLoopTransformationDirective *D) { + VisitOMPLoopBasedDirective(D); +} + +void EnqueueVisitor::VisitOMPTileDirective(const OMPTileDirective *D) { + VisitOMPLoopTransformationDirective(D); +} + +void EnqueueVisitor::VisitOMPUnrollDirective(const OMPUnrollDirective *D) { + VisitOMPLoopTransformationDirective(D); +} + +void EnqueueVisitor::VisitOMPForDirective(const OMPForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPForSimdDirective(const OMPForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPSectionsDirective(const OMPSectionsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSectionDirective(const OMPSectionDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPSingleDirective(const OMPSingleDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPMasterDirective(const OMPMasterDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCriticalDirective(const OMPCriticalDirective *D) { + VisitOMPExecutableDirective(D); + AddDeclarationNameInfo(D); +} + +void EnqueueVisitor::VisitOMPParallelForDirective( + const OMPParallelForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelForSimdDirective( + const OMPParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelMasterDirective( + const OMPParallelMasterDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelSectionsDirective( + const OMPParallelSectionsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskDirective(const OMPTaskDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskyieldDirective( + const OMPTaskyieldDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPBarrierDirective(const OMPBarrierDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskgroupDirective( + const OMPTaskgroupDirective *D) { + VisitOMPExecutableDirective(D); + if (const Expr *E = D->getReductionRef()) + VisitStmt(E); +} + +void EnqueueVisitor::VisitOMPFlushDirective(const OMPFlushDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPDepobjDirective(const OMPDepobjDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPScanDirective(const OMPScanDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPOrderedDirective(const OMPOrderedDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPAtomicDirective(const OMPAtomicDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetDirective(const OMPTargetDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetDataDirective( + const OMPTargetDataDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetEnterDataDirective( + const OMPTargetEnterDataDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetExitDataDirective( + const OMPTargetExitDataDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetParallelDirective( + const OMPTargetParallelDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetParallelForDirective( + const OMPTargetParallelForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDirective(const OMPTeamsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCancellationPointDirective( + const OMPCancellationPointDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPCancelDirective(const OMPCancelDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskLoopSimdDirective( + const OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPMasterTaskLoopDirective( + const OMPMasterTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPMasterTaskLoopSimdDirective( + const OMPMasterTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelMasterTaskLoopDirective( + const OMPParallelMasterTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPParallelMasterTaskLoopSimdDirective( + const OMPParallelMasterTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeDirective( + const OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeParallelForDirective( + const OMPDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeParallelForSimdDirective( + const OMPDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeSimdDirective( + const OMPDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetParallelForSimdDirective( + const OMPTargetParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetSimdDirective( + const OMPTargetSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDistributeDirective( + const OMPTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDistributeSimdDirective( + const OMPTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDistributeParallelForSimdDirective( + const OMPTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTeamsDistributeParallelForDirective( + const OMPTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetTeamsDirective( + const OMPTargetTeamsDirective *D) { + VisitOMPExecutableDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetTeamsDistributeDirective( + const OMPTargetTeamsDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetTeamsDistributeParallelForDirective( + const OMPTargetTeamsDistributeParallelForDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetTeamsDistributeParallelForSimdDirective( + const OMPTargetTeamsDistributeParallelForSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTargetTeamsDistributeSimdDirective( + const OMPTargetTeamsDistributeSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { + EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU, RegionOfInterest)) + .Visit(S); +} + +bool CursorVisitor::IsInRegionOfInterest(CXCursor C) { + if (RegionOfInterest.isValid()) { + SourceRange Range = getRawCursorExtent(C); + if (Range.isInvalid() || CompareRegionOfInterest(Range)) + return false; + } + return true; +} + +bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { + while (!WL.empty()) { + // Dequeue the worklist item. + VisitorJob LI = WL.pop_back_val(); + + // Set the Parent field, then back to its old value once we're done. + SetParentRAII SetParent(Parent, StmtParent, LI.getParent()); + + switch (LI.getKind()) { + case VisitorJob::DeclVisitKind: { + const Decl *D = cast<DeclVisit>(&LI)->get(); + if (!D) + continue; + + // For now, perform default visitation for Decls. + if (Visit(MakeCXCursor(D, TU, RegionOfInterest, + cast<DeclVisit>(&LI)->isFirst()))) + return true; + + continue; + } + case VisitorJob::ExplicitTemplateArgsVisitKind: { + for (const TemplateArgumentLoc &Arg : + *cast<ExplicitTemplateArgsVisit>(&LI)) { + if (VisitTemplateArgumentLoc(Arg)) + return true; + } + continue; + } + case VisitorJob::TypeLocVisitKind: { + // Perform default visitation for TypeLocs. + if (Visit(cast<TypeLocVisit>(&LI)->get())) + return true; + continue; + } + case VisitorJob::LabelRefVisitKind: { + const LabelDecl *LS = cast<LabelRefVisit>(&LI)->get(); + if (LabelStmt *stmt = LS->getStmt()) { + if (Visit(MakeCursorLabelRef(stmt, cast<LabelRefVisit>(&LI)->getLoc(), + TU))) { + return true; + } + } + continue; + } + + case VisitorJob::NestedNameSpecifierLocVisitKind: { + NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI); + if (VisitNestedNameSpecifierLoc(V->get())) + return true; + continue; + } + + case VisitorJob::DeclarationNameInfoVisitKind: { + if (VisitDeclarationNameInfo(cast<DeclarationNameInfoVisit>(&LI)->get())) + return true; + continue; + } + case VisitorJob::MemberRefVisitKind: { + MemberRefVisit *V = cast<MemberRefVisit>(&LI); + if (Visit(MakeCursorMemberRef(V->get(), V->getLoc(), TU))) + return true; + continue; + } + case VisitorJob::StmtVisitKind: { + const Stmt *S = cast<StmtVisit>(&LI)->get(); + if (!S) + continue; + + // Update the current cursor. + CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest); + if (!IsInRegionOfInterest(Cursor)) + continue; + switch (Visitor(Cursor, Parent, ClientData)) { + case CXChildVisit_Break: + return true; + case CXChildVisit_Continue: + break; + case CXChildVisit_Recurse: + if (PostChildrenVisitor) + WL.push_back(PostChildrenVisit(nullptr, Cursor)); + EnqueueWorkList(WL, S); + break; + } + continue; + } + case VisitorJob::MemberExprPartsKind: { + // Handle the other pieces in the MemberExpr besides the base. + const MemberExpr *M = cast<MemberExprParts>(&LI)->get(); + + // Visit the nested-name-specifier + if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(M->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments, if any. + if (M->hasExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = M->getTemplateArgs(), + *ArgEnd = Arg + M->getNumTemplateArgs(); + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + continue; + } + case VisitorJob::DeclRefExprPartsKind: { + const DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get(); + // Visit nested-name-specifier, if present. + if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + // Visit declaration name. + if (VisitDeclarationNameInfo(DR->getNameInfo())) + return true; + continue; + } + case VisitorJob::OverloadExprPartsKind: { + const OverloadExpr *O = cast<OverloadExprParts>(&LI)->get(); + // Visit the nested-name-specifier. + if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc()) + if (VisitNestedNameSpecifierLoc(QualifierLoc)) + return true; + // Visit the declaration name. + if (VisitDeclarationNameInfo(O->getNameInfo())) + return true; + // Visit the overloaded declaration reference. + if (Visit(MakeCursorOverloadedDeclRef(O, TU))) + return true; + continue; + } + case VisitorJob::SizeOfPackExprPartsKind: { + const SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get(); + NamedDecl *Pack = E->getPack(); + if (isa<TemplateTypeParmDecl>(Pack)) { + if (Visit(MakeCursorTypeRef(cast<TemplateTypeParmDecl>(Pack), + E->getPackLoc(), TU))) + return true; + + continue; + } + + if (isa<TemplateTemplateParmDecl>(Pack)) { + if (Visit(MakeCursorTemplateRef(cast<TemplateTemplateParmDecl>(Pack), + E->getPackLoc(), TU))) + return true; + + continue; + } + + // Non-type template parameter packs and function parameter packs are + // treated like DeclRefExpr cursors. + continue; + } + + case VisitorJob::LambdaExprPartsKind: { + // Visit non-init captures. + const LambdaExpr *E = cast<LambdaExprParts>(&LI)->get(); + for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(), + CEnd = E->explicit_capture_end(); + C != CEnd; ++C) { + if (!C->capturesVariable()) + continue; + + if (Visit(MakeCursorVariableRef(C->getCapturedVar(), C->getLocation(), + TU))) + return true; + } + // Visit init captures + for (auto InitExpr : E->capture_inits()) { + if (InitExpr && Visit(InitExpr)) + return true; + } + + TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + // Visit parameters and return type, if present. + if (FunctionTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { + if (E->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) + if (Visit(MakeCXCursor(Proto.getParam(I), TU))) + return true; + } + if (E->hasExplicitResultType()) { + // Visit result type. + if (Visit(Proto.getReturnLoc())) + return true; + } + } + break; + } + + case VisitorJob::PostChildrenVisitKind: + if (PostChildrenVisitor(Parent, ClientData)) + return true; + break; + } + } + return false; +} + +bool CursorVisitor::Visit(const Stmt *S) { + VisitorWorkList *WL = nullptr; + if (!WorkListFreeList.empty()) { + WL = WorkListFreeList.back(); + WL->clear(); + WorkListFreeList.pop_back(); + } else { + WL = new VisitorWorkList(); + WorkListCache.push_back(WL); + } + EnqueueWorkList(*WL, S); + bool result = RunVisitorWorkList(*WL); + WorkListFreeList.push_back(WL); + return result; +} + +namespace { +typedef SmallVector<SourceRange, 4> RefNamePieces; +RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, + const DeclarationNameInfo &NI, SourceRange QLoc, + const SourceRange *TemplateArgsLoc = nullptr) { + const bool WantQualifier = NameFlags & CXNameRange_WantQualifier; + const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs; + const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece; + + const DeclarationName::NameKind Kind = NI.getName().getNameKind(); + + RefNamePieces Pieces; + + if (WantQualifier && QLoc.isValid()) + Pieces.push_back(QLoc); + + if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr) + Pieces.push_back(NI.getLoc()); + + if (WantTemplateArgs && TemplateArgsLoc && TemplateArgsLoc->isValid()) + Pieces.push_back(*TemplateArgsLoc); + + if (Kind == DeclarationName::CXXOperatorName) { + Pieces.push_back(NI.getInfo().getCXXOperatorNameBeginLoc()); + Pieces.push_back(NI.getInfo().getCXXOperatorNameEndLoc()); + } + + if (WantSinglePiece) { + SourceRange R(Pieces.front().getBegin(), Pieces.back().getEnd()); + Pieces.clear(); + Pieces.push_back(R); + } + + return Pieces; +} +} // namespace + +//===----------------------------------------------------------------------===// +// Misc. API hooks. +//===----------------------------------------------------------------------===// + +namespace { +struct RegisterFatalErrorHandler { + RegisterFatalErrorHandler() { + clang_install_aborting_llvm_fatal_error_handler(); + } +}; +} // namespace + +static llvm::ManagedStatic<RegisterFatalErrorHandler> + RegisterFatalErrorHandlerOnce; + +CXIndex clang_createIndex(int excludeDeclarationsFromPCH, + int displayDiagnostics) { + // We use crash recovery to make some of our APIs more reliable, implicitly + // enable it. + if (!getenv("LIBCLANG_DISABLE_CRASH_RECOVERY")) + llvm::CrashRecoveryContext::Enable(); + + // Look through the managed static to trigger construction of the managed + // static which registers our fatal error handler. This ensures it is only + // registered once. + (void)*RegisterFatalErrorHandlerOnce; + + // Initialize targets for clang module support. + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + llvm::InitializeAllAsmParsers(); + + CIndexer *CIdxr = new CIndexer(); + + if (excludeDeclarationsFromPCH) + CIdxr->setOnlyLocalDecls(); + if (displayDiagnostics) + CIdxr->setDisplayDiagnostics(); + + if (getenv("LIBCLANG_BGPRIO_INDEX")) + CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | + CXGlobalOpt_ThreadBackgroundPriorityForIndexing); + if (getenv("LIBCLANG_BGPRIO_EDIT")) + CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() | + CXGlobalOpt_ThreadBackgroundPriorityForEditing); + + return CIdxr; +} + +void clang_disposeIndex(CXIndex CIdx) { + if (CIdx) + delete static_cast<CIndexer *>(CIdx); +} + +void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) { + if (CIdx) + static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options); +} + +unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) { + if (CIdx) + return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags(); + return 0; +} + +void clang_CXIndex_setInvocationEmissionPathOption(CXIndex CIdx, + const char *Path) { + if (CIdx) + static_cast<CIndexer *>(CIdx)->setInvocationEmissionPath(Path ? Path : ""); +} + +void clang_toggleCrashRecovery(unsigned isEnabled) { + if (isEnabled) + llvm::CrashRecoveryContext::Enable(); + else + llvm::CrashRecoveryContext::Disable(); +} + +CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, + const char *ast_filename) { + CXTranslationUnit TU; + enum CXErrorCode Result = + clang_createTranslationUnit2(CIdx, ast_filename, &TU); + (void)Result; + assert((TU && Result == CXError_Success) || + (!TU && Result != CXError_Success)); + return TU; +} + +enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx, + const char *ast_filename, + CXTranslationUnit *out_TU) { + if (out_TU) + *out_TU = nullptr; + + if (!CIdx || !ast_filename || !out_TU) + return CXError_InvalidArguments; + + LOG_FUNC_SECTION { *Log << ast_filename; } + + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + FileSystemOptions FileSystemOpts; + + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + CompilerInstance::createDiagnostics(new DiagnosticOptions()); + std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile( + ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), + ASTUnit::LoadEverything, Diags, FileSystemOpts, /*UseDebugInfo=*/false, + CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All, + /*AllowASTWithCompilerErrors=*/true, + /*UserFilesAreVolatile=*/true); + *out_TU = MakeCXTranslationUnit(CXXIdx, std::move(AU)); + return *out_TU ? CXError_Success : CXError_Failure; +} + +unsigned clang_defaultEditingTranslationUnitOptions() { + return CXTranslationUnit_PrecompiledPreamble | + CXTranslationUnit_CacheCompletionResults; +} + +CXTranslationUnit clang_createTranslationUnitFromSourceFile( + CXIndex CIdx, const char *source_filename, int num_command_line_args, + const char *const *command_line_args, unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files) { + unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord; + return clang_parseTranslationUnit(CIdx, source_filename, command_line_args, + num_command_line_args, unsaved_files, + num_unsaved_files, Options); +} + +static CXErrorCode +clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { + // Set up the initial return values. + if (out_TU) + *out_TU = nullptr; + + // Check arguments. + if (!CIdx || !out_TU) + return CXError_InvalidArguments; + + CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CreatePreambleOnFirstParse = + options & CXTranslationUnit_CreatePreambleOnFirstParse; + // FIXME: Add a flag for modules. + TranslationUnitKind TUKind = (options & (CXTranslationUnit_Incomplete | + CXTranslationUnit_SingleFileParse)) + ? TU_Prefix + : TU_Complete; + bool CacheCodeCompletionResults = + options & CXTranslationUnit_CacheCompletionResults; + bool IncludeBriefCommentsInCodeCompletion = + options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; + bool SingleFileParse = options & CXTranslationUnit_SingleFileParse; + bool ForSerialization = options & CXTranslationUnit_ForSerialization; + bool RetainExcludedCB = + options & CXTranslationUnit_RetainExcludedConditionalBlocks; + SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None; + if (options & CXTranslationUnit_SkipFunctionBodies) { + SkipFunctionBodies = + (options & CXTranslationUnit_LimitSkipFunctionBodiesToPreamble) + ? SkipFunctionBodiesScope::Preamble + : SkipFunctionBodiesScope::PreambleAndMainFile; + } + + // Configure the diagnostics. + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + CompilerInstance::createDiagnostics(new DiagnosticOptions)); + + if (options & CXTranslationUnit_KeepGoing) + Diags->setFatalsAsError(true); + + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All; + if (options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles) + CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes; + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine>> + DiagCleanup(Diags.get()); + + std::unique_ptr<std::vector<ASTUnit::RemappedFile>> RemappedFiles( + new std::vector<ASTUnit::RemappedFile>()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<ASTUnit::RemappedFile>> + RemappedCleanup(RemappedFiles.get()); + + for (auto &UF : unsaved_files) { + std::unique_ptr<llvm::MemoryBuffer> MB = + llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); + RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release())); + } + + std::unique_ptr<std::vector<const char *>> Args( + new std::vector<const char *>()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char *>> + ArgsCleanup(Args.get()); + + // Since the Clang C library is primarily used by batch tools dealing with + // (often very broken) source code, where spell-checking can have a + // significant negative impact on performance (particularly when + // precompiled headers are involved), we disable it by default. + // Only do this if we haven't found a spell-checking-related argument. + bool FoundSpellCheckingArgument = false; + for (int I = 0; I != num_command_line_args; ++I) { + if (strcmp(command_line_args[I], "-fno-spell-checking") == 0 || + strcmp(command_line_args[I], "-fspell-checking") == 0) { + FoundSpellCheckingArgument = true; + break; + } + } + Args->insert(Args->end(), command_line_args, + command_line_args + num_command_line_args); + + if (!FoundSpellCheckingArgument) + Args->insert(Args->begin() + 1, "-fno-spell-checking"); + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + // Put the source file after command_line_args otherwise if '-x' flag is + // present it will be unused. + if (source_filename) + Args->push_back(source_filename); + + // Do we need the detailed preprocessing record? + if (options & CXTranslationUnit_DetailedPreprocessingRecord) { + Args->push_back("-Xclang"); + Args->push_back("-detailed-preprocessing-record"); + } + + // Suppress any editor placeholder diagnostics. + Args->push_back("-fallow-editor-placeholders"); + + unsigned NumErrors = Diags->getClient()->getNumErrors(); + std::unique_ptr<ASTUnit> ErrUnit; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; + + LibclangInvocationReporter InvocationReporter( + *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, + options, llvm::makeArrayRef(*Args), /*InvocationArgs=*/None, + unsaved_files); + std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine( + Args->data(), Args->data() + Args->size(), + CXXIdx->getPCHContainerOperations(), Diags, + CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), + CaptureDiagnostics, *RemappedFiles.get(), + /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, + TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, + /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse, + /*UserFilesAreVolatile=*/true, ForSerialization, RetainExcludedCB, + CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(), + &ErrUnit)); + + // Early failures in LoadFromCommandLine may return with ErrUnit unset. + if (!Unit && !ErrUnit) + return CXError_ASTReadError; + + if (NumErrors != Diags->getClient()->getNumErrors()) { + // Make sure to check that 'Unit' is non-NULL. + if (CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); + } + + if (isASTReadError(Unit ? Unit.get() : ErrUnit.get())) + return CXError_ASTReadError; + + *out_TU = MakeCXTranslationUnit(CXXIdx, std::move(Unit)); + if (CXTranslationUnitImpl *TU = *out_TU) { + TU->ParsingOptions = options; + TU->Arguments.reserve(Args->size()); + for (const char *Arg : *Args) + TU->Arguments.push_back(Arg); + return CXError_Success; + } + return CXError_Failure; +} + +CXTranslationUnit +clang_parseTranslationUnit(CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, unsigned options) { + CXTranslationUnit TU; + enum CXErrorCode Result = clang_parseTranslationUnit2( + CIdx, source_filename, command_line_args, num_command_line_args, + unsaved_files, num_unsaved_files, options, &TU); + (void)Result; + assert((TU && Result == CXError_Success) || + (!TU && Result != CXError_Success)); + return TU; +} + +enum CXErrorCode clang_parseTranslationUnit2( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { + noteBottomOfStack(); + SmallVector<const char *, 4> Args; + Args.push_back("clang"); + Args.append(command_line_args, command_line_args + num_command_line_args); + return clang_parseTranslationUnit2FullArgv( + CIdx, source_filename, Args.data(), Args.size(), unsaved_files, + num_unsaved_files, options, out_TU); +} + +enum CXErrorCode clang_parseTranslationUnit2FullArgv( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { + LOG_FUNC_SECTION { + *Log << source_filename << ": "; + for (int i = 0; i != num_command_line_args; ++i) + *Log << command_line_args[i] << " "; + } + + if (num_unsaved_files && !unsaved_files) + return CXError_InvalidArguments; + + CXErrorCode result = CXError_Failure; + auto ParseTranslationUnitImpl = [=, &result] { + noteBottomOfStack(); + result = clang_parseTranslationUnit_Impl( + CIdx, source_filename, command_line_args, num_command_line_args, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), options, out_TU); + }; + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, ParseTranslationUnitImpl)) { + fprintf(stderr, "libclang: crash detected during parsing: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return CXError_Crashed; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + if (CXTranslationUnit *TU = out_TU) + PrintLibclangResourceUsage(*TU); + } + + return result; +} + +CXString clang_Type_getObjCEncoding(CXType CT) { + CXTranslationUnit tu = static_cast<CXTranslationUnit>(CT.data[1]); + ASTContext &Ctx = getASTUnit(tu)->getASTContext(); + std::string encoding; + Ctx.getObjCEncodingForType(QualType::getFromOpaquePtr(CT.data[0]), encoding); + + return cxstring::createDup(encoding); +} + +static const IdentifierInfo *getMacroIdentifier(CXCursor C) { + if (C.kind == CXCursor_MacroDefinition) { + if (const MacroDefinitionRecord *MDR = getCursorMacroDefinition(C)) + return MDR->getName(); + } else if (C.kind == CXCursor_MacroExpansion) { + MacroExpansionCursor ME = getCursorMacroExpansion(C); + return ME.getName(); + } + return nullptr; +} + +unsigned clang_Cursor_isMacroFunctionLike(CXCursor C) { + const IdentifierInfo *II = getMacroIdentifier(C); + if (!II) { + return false; + } + ASTUnit *ASTU = getCursorASTUnit(C); + Preprocessor &PP = ASTU->getPreprocessor(); + if (const MacroInfo *MI = PP.getMacroInfo(II)) + return MI->isFunctionLike(); + return false; +} + +unsigned clang_Cursor_isMacroBuiltin(CXCursor C) { + const IdentifierInfo *II = getMacroIdentifier(C); + if (!II) { + return false; + } + ASTUnit *ASTU = getCursorASTUnit(C); + Preprocessor &PP = ASTU->getPreprocessor(); + if (const MacroInfo *MI = PP.getMacroInfo(II)) + return MI->isBuiltinMacro(); + return false; +} + +unsigned clang_Cursor_isFunctionInlined(CXCursor C) { + const Decl *D = getCursorDecl(C); + const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); + if (!FD) { + return false; + } + return FD->isInlined(); +} + +static StringLiteral *getCFSTR_value(CallExpr *callExpr) { + if (callExpr->getNumArgs() != 1) { + return nullptr; + } + + StringLiteral *S = nullptr; + auto *arg = callExpr->getArg(0); + if (arg->getStmtClass() == Stmt::ImplicitCastExprClass) { + ImplicitCastExpr *I = static_cast<ImplicitCastExpr *>(arg); + auto *subExpr = I->getSubExprAsWritten(); + + if (subExpr->getStmtClass() != Stmt::StringLiteralClass) { + return nullptr; + } + + S = static_cast<StringLiteral *>(I->getSubExprAsWritten()); + } else if (arg->getStmtClass() == Stmt::StringLiteralClass) { + S = static_cast<StringLiteral *>(callExpr->getArg(0)); + } else { + return nullptr; + } + return S; +} + +struct ExprEvalResult { + CXEvalResultKind EvalType; + union { + unsigned long long unsignedVal; + long long intVal; + double floatVal; + char *stringVal; + } EvalData; + bool IsUnsignedInt; + ~ExprEvalResult() { + if (EvalType != CXEval_UnExposed && EvalType != CXEval_Float && + EvalType != CXEval_Int) { + delete[] EvalData.stringVal; + } + } +}; + +void clang_EvalResult_dispose(CXEvalResult E) { + delete static_cast<ExprEvalResult *>(E); +} + +CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E) { + if (!E) { + return CXEval_UnExposed; + } + return ((ExprEvalResult *)E)->EvalType; +} + +int clang_EvalResult_getAsInt(CXEvalResult E) { + return clang_EvalResult_getAsLongLong(E); +} + +long long clang_EvalResult_getAsLongLong(CXEvalResult E) { + if (!E) { + return 0; + } + ExprEvalResult *Result = (ExprEvalResult *)E; + if (Result->IsUnsignedInt) + return Result->EvalData.unsignedVal; + return Result->EvalData.intVal; +} + +unsigned clang_EvalResult_isUnsignedInt(CXEvalResult E) { + return ((ExprEvalResult *)E)->IsUnsignedInt; +} + +unsigned long long clang_EvalResult_getAsUnsigned(CXEvalResult E) { + if (!E) { + return 0; + } + + ExprEvalResult *Result = (ExprEvalResult *)E; + if (Result->IsUnsignedInt) + return Result->EvalData.unsignedVal; + return Result->EvalData.intVal; +} + +double clang_EvalResult_getAsDouble(CXEvalResult E) { + if (!E) { + return 0; + } + return ((ExprEvalResult *)E)->EvalData.floatVal; +} + +const char *clang_EvalResult_getAsStr(CXEvalResult E) { + if (!E) { + return nullptr; + } + return ((ExprEvalResult *)E)->EvalData.stringVal; +} + +static const ExprEvalResult *evaluateExpr(Expr *expr, CXCursor C) { + Expr::EvalResult ER; + ASTContext &ctx = getCursorContext(C); + if (!expr) + return nullptr; + + expr = expr->IgnoreParens(); + if (expr->isValueDependent()) + return nullptr; + if (!expr->EvaluateAsRValue(ER, ctx)) + return nullptr; + + QualType rettype; + CallExpr *callExpr; + auto result = std::make_unique<ExprEvalResult>(); + result->EvalType = CXEval_UnExposed; + result->IsUnsignedInt = false; + + if (ER.Val.isInt()) { + result->EvalType = CXEval_Int; + + auto &val = ER.Val.getInt(); + if (val.isUnsigned()) { + result->IsUnsignedInt = true; + result->EvalData.unsignedVal = val.getZExtValue(); + } else { + result->EvalData.intVal = val.getExtValue(); + } + + return result.release(); + } + + if (ER.Val.isFloat()) { + llvm::SmallVector<char, 100> Buffer; + ER.Val.getFloat().toString(Buffer); + std::string floatStr(Buffer.data(), Buffer.size()); + result->EvalType = CXEval_Float; + bool ignored; + llvm::APFloat apFloat = ER.Val.getFloat(); + apFloat.convert(llvm::APFloat::IEEEdouble(), + llvm::APFloat::rmNearestTiesToEven, &ignored); + result->EvalData.floatVal = apFloat.convertToDouble(); + return result.release(); + } + + if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) { + const ImplicitCastExpr *I = dyn_cast<ImplicitCastExpr>(expr); + auto *subExpr = I->getSubExprAsWritten(); + if (subExpr->getStmtClass() == Stmt::StringLiteralClass || + subExpr->getStmtClass() == Stmt::ObjCStringLiteralClass) { + const StringLiteral *StrE = nullptr; + const ObjCStringLiteral *ObjCExpr; + ObjCExpr = dyn_cast<ObjCStringLiteral>(subExpr); + + if (ObjCExpr) { + StrE = ObjCExpr->getString(); + result->EvalType = CXEval_ObjCStrLiteral; + } else { + StrE = cast<StringLiteral>(I->getSubExprAsWritten()); + result->EvalType = CXEval_StrLiteral; + } + + std::string strRef(StrE->getString().str()); + result->EvalData.stringVal = new char[strRef.size() + 1]; + strncpy((char *)result->EvalData.stringVal, strRef.c_str(), + strRef.size()); + result->EvalData.stringVal[strRef.size()] = '\0'; + return result.release(); + } + } else if (expr->getStmtClass() == Stmt::ObjCStringLiteralClass || + expr->getStmtClass() == Stmt::StringLiteralClass) { + const StringLiteral *StrE = nullptr; + const ObjCStringLiteral *ObjCExpr; + ObjCExpr = dyn_cast<ObjCStringLiteral>(expr); + + if (ObjCExpr) { + StrE = ObjCExpr->getString(); + result->EvalType = CXEval_ObjCStrLiteral; + } else { + StrE = cast<StringLiteral>(expr); + result->EvalType = CXEval_StrLiteral; + } + + std::string strRef(StrE->getString().str()); + result->EvalData.stringVal = new char[strRef.size() + 1]; + strncpy((char *)result->EvalData.stringVal, strRef.c_str(), strRef.size()); + result->EvalData.stringVal[strRef.size()] = '\0'; + return result.release(); + } + + if (expr->getStmtClass() == Stmt::CStyleCastExprClass) { + CStyleCastExpr *CC = static_cast<CStyleCastExpr *>(expr); + + rettype = CC->getType(); + if (rettype.getAsString() == "CFStringRef" && + CC->getSubExpr()->getStmtClass() == Stmt::CallExprClass) { + + callExpr = static_cast<CallExpr *>(CC->getSubExpr()); + StringLiteral *S = getCFSTR_value(callExpr); + if (S) { + std::string strLiteral(S->getString().str()); + result->EvalType = CXEval_CFStr; + + result->EvalData.stringVal = new char[strLiteral.size() + 1]; + strncpy((char *)result->EvalData.stringVal, strLiteral.c_str(), + strLiteral.size()); + result->EvalData.stringVal[strLiteral.size()] = '\0'; + return result.release(); + } + } + + } else if (expr->getStmtClass() == Stmt::CallExprClass) { + callExpr = static_cast<CallExpr *>(expr); + rettype = callExpr->getCallReturnType(ctx); + + if (rettype->isVectorType() || callExpr->getNumArgs() > 1) + return nullptr; + + if (rettype->isIntegralType(ctx) || rettype->isRealFloatingType()) { + if (callExpr->getNumArgs() == 1 && + !callExpr->getArg(0)->getType()->isIntegralType(ctx)) + return nullptr; + } else if (rettype.getAsString() == "CFStringRef") { + + StringLiteral *S = getCFSTR_value(callExpr); + if (S) { + std::string strLiteral(S->getString().str()); + result->EvalType = CXEval_CFStr; + result->EvalData.stringVal = new char[strLiteral.size() + 1]; + strncpy((char *)result->EvalData.stringVal, strLiteral.c_str(), + strLiteral.size()); + result->EvalData.stringVal[strLiteral.size()] = '\0'; + return result.release(); + } + } + } else if (expr->getStmtClass() == Stmt::DeclRefExprClass) { + DeclRefExpr *D = static_cast<DeclRefExpr *>(expr); + ValueDecl *V = D->getDecl(); + if (V->getKind() == Decl::Function) { + std::string strName = V->getNameAsString(); + result->EvalType = CXEval_Other; + result->EvalData.stringVal = new char[strName.size() + 1]; + strncpy(result->EvalData.stringVal, strName.c_str(), strName.size()); + result->EvalData.stringVal[strName.size()] = '\0'; + return result.release(); + } + } + + return nullptr; +} + +static const Expr *evaluateDeclExpr(const Decl *D) { + if (!D) + return nullptr; + if (auto *Var = dyn_cast<VarDecl>(D)) + return Var->getInit(); + else if (auto *Field = dyn_cast<FieldDecl>(D)) + return Field->getInClassInitializer(); + return nullptr; +} + +static const Expr *evaluateCompoundStmtExpr(const CompoundStmt *CS) { + assert(CS && "invalid compound statement"); + for (auto *bodyIterator : CS->body()) { + if (const auto *E = dyn_cast<Expr>(bodyIterator)) + return E; + } + return nullptr; +} + +CXEvalResult clang_Cursor_Evaluate(CXCursor C) { + const Expr *E = nullptr; + if (clang_getCursorKind(C) == CXCursor_CompoundStmt) + E = evaluateCompoundStmtExpr(cast<CompoundStmt>(getCursorStmt(C))); + else if (clang_isDeclaration(C.kind)) + E = evaluateDeclExpr(getCursorDecl(C)); + else if (clang_isExpression(C.kind)) + E = getCursorExpr(C); + if (E) + return const_cast<CXEvalResult>( + reinterpret_cast<const void *>(evaluateExpr(const_cast<Expr *>(E), C))); + return nullptr; +} + +unsigned clang_Cursor_hasAttrs(CXCursor C) { + const Decl *D = getCursorDecl(C); + if (!D) { + return 0; + } + + if (D->hasAttrs()) { + return 1; + } + + return 0; +} +unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { + return CXSaveTranslationUnit_None; +} + +static CXSaveError clang_saveTranslationUnit_Impl(CXTranslationUnit TU, + const char *FileName, + unsigned options) { + CIndexer *CXXIdx = TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + bool hadError = cxtu::getASTUnit(TU)->Save(FileName); + return hadError ? CXSaveError_Unknown : CXSaveError_None; +} + +int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, + unsigned options) { + LOG_FUNC_SECTION { *Log << TU << ' ' << FileName; } + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return CXSaveError_InvalidTU; + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + if (!CXXUnit->hasSema()) + return CXSaveError_InvalidTU; + + CXSaveError result; + auto SaveTranslationUnitImpl = [=, &result]() { + result = clang_saveTranslationUnit_Impl(TU, FileName, options); + }; + + if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred()) { + SaveTranslationUnitImpl(); + + if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return result; + } + + // We have an AST that has invalid nodes due to compiler errors. + // Use a crash recovery thread for protection. + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, SaveTranslationUnitImpl)) { + fprintf(stderr, "libclang: crash detected during AST saving: {\n"); + fprintf(stderr, " 'filename' : '%s'\n", FileName); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return CXSaveError_Unknown; + + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + PrintLibclangResourceUsage(TU); + } + + return result; +} + +void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { + if (CTUnit) { + // If the translation unit has been marked as unsafe to free, just discard + // it. + ASTUnit *Unit = cxtu::getASTUnit(CTUnit); + if (Unit && Unit->isUnsafeToFree()) + return; + + delete cxtu::getASTUnit(CTUnit); + delete CTUnit->StringPool; + delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics); + disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool); + delete CTUnit->CommentToXML; + delete CTUnit; + } +} + +unsigned clang_suspendTranslationUnit(CXTranslationUnit CTUnit) { + if (CTUnit) { + ASTUnit *Unit = cxtu::getASTUnit(CTUnit); + + if (Unit && Unit->isUnsafeToFree()) + return false; + + Unit->ResetForParse(); + return true; + } + + return false; +} + +unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { + return CXReparse_None; +} + +static CXErrorCode +clang_reparseTranslationUnit_Impl(CXTranslationUnit TU, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options) { + // Check arguments. + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return CXError_InvalidArguments; + } + + // Reset the associated diagnostics. + delete static_cast<CXDiagnosticSetImpl *>(TU->Diagnostics); + TU->Diagnostics = nullptr; + + CIndexer *CXXIdx = TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + std::unique_ptr<std::vector<ASTUnit::RemappedFile>> RemappedFiles( + new std::vector<ASTUnit::RemappedFile>()); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<ASTUnit::RemappedFile>> + RemappedCleanup(RemappedFiles.get()); + + for (auto &UF : unsaved_files) { + std::unique_ptr<llvm::MemoryBuffer> MB = + llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); + RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release())); + } + + if (!CXXUnit->Reparse(CXXIdx->getPCHContainerOperations(), + *RemappedFiles.get())) + return CXError_Success; + if (isASTReadError(CXXUnit)) + return CXError_ASTReadError; + return CXError_Failure; +} + +int clang_reparseTranslationUnit(CXTranslationUnit TU, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options) { + LOG_FUNC_SECTION { *Log << TU; } + + if (num_unsaved_files && !unsaved_files) + return CXError_InvalidArguments; + + CXErrorCode result; + auto ReparseTranslationUnitImpl = [=, &result]() { + result = clang_reparseTranslationUnit_Impl( + TU, llvm::makeArrayRef(unsaved_files, num_unsaved_files), options); + }; + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, ReparseTranslationUnitImpl)) { + fprintf(stderr, "libclang: crash detected during reparsing\n"); + cxtu::getASTUnit(TU)->setUnsafeToFree(true); + return CXError_Crashed; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return result; +} + +CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { + if (isNotUsableTU(CTUnit)) { + LOG_BAD_TU(CTUnit); + return cxstring::createEmpty(); + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit); + return cxstring::createDup(CXXUnit->getOriginalSourceFileName()); +} + +CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullCursor(); + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU); +} + +CXTargetInfo clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit) { + if (isNotUsableTU(CTUnit)) { + LOG_BAD_TU(CTUnit); + return nullptr; + } + + CXTargetInfoImpl *impl = new CXTargetInfoImpl(); + impl->TranslationUnit = CTUnit; + return impl; +} + +CXString clang_TargetInfo_getTriple(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return cxstring::createEmpty(); + + CXTranslationUnit CTUnit = TargetInfo->TranslationUnit; + assert(!isNotUsableTU(CTUnit) && + "Unexpected unusable translation unit in TargetInfo"); + + ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit); + std::string Triple = + CXXUnit->getASTContext().getTargetInfo().getTriple().normalize(); + return cxstring::createDup(Triple); +} + +int clang_TargetInfo_getPointerWidth(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return -1; + + CXTranslationUnit CTUnit = TargetInfo->TranslationUnit; + assert(!isNotUsableTU(CTUnit) && + "Unexpected unusable translation unit in TargetInfo"); + + ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit); + return CXXUnit->getASTContext().getTargetInfo().getMaxPointerWidth(); +} + +void clang_TargetInfo_dispose(CXTargetInfo TargetInfo) { + if (!TargetInfo) + return; + + delete TargetInfo; +} + +//===----------------------------------------------------------------------===// +// CXFile Operations. +//===----------------------------------------------------------------------===// + +CXString clang_getFileName(CXFile SFile) { + if (!SFile) + return cxstring::createNull(); + + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return cxstring::createRef(FEnt->getName()); +} + +time_t clang_getFileTime(CXFile SFile) { + if (!SFile) + return 0; + + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return FEnt->getModificationTime(); +} + +CXFile clang_getFile(CXTranslationUnit TU, const char *file_name) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + + FileManager &FMgr = CXXUnit->getFileManager(); + auto File = FMgr.getFile(file_name); + if (!File) + return nullptr; + return const_cast<FileEntry *>(*File); +} + +const char *clang_getFileContents(CXTranslationUnit TU, CXFile file, + size_t *size) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + + const SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); + FileID fid = SM.translateFile(static_cast<FileEntry *>(file)); + llvm::Optional<llvm::MemoryBufferRef> buf = SM.getBufferOrNone(fid); + if (!buf) { + if (size) + *size = 0; + return nullptr; + } + if (size) + *size = buf->getBufferSize(); + return buf->getBufferStart(); +} + +unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit TU, CXFile file) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return 0; + } + + if (!file) + return 0; + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + FileEntry *FEnt = static_cast<FileEntry *>(file); + return CXXUnit->getPreprocessor() + .getHeaderSearchInfo() + .isFileMultipleIncludeGuarded(FEnt); +} + +int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID) { + if (!file || !outID) + return 1; + + FileEntry *FEnt = static_cast<FileEntry *>(file); + const llvm::sys::fs::UniqueID &ID = FEnt->getUniqueID(); + outID->data[0] = ID.getDevice(); + outID->data[1] = ID.getFile(); + outID->data[2] = FEnt->getModificationTime(); + return 0; +} + +int clang_File_isEqual(CXFile file1, CXFile file2) { + if (file1 == file2) + return true; + + if (!file1 || !file2) + return false; + + FileEntry *FEnt1 = static_cast<FileEntry *>(file1); + FileEntry *FEnt2 = static_cast<FileEntry *>(file2); + return FEnt1->getUniqueID() == FEnt2->getUniqueID(); +} + +CXString clang_File_tryGetRealPathName(CXFile SFile) { + if (!SFile) + return cxstring::createNull(); + + FileEntry *FEnt = static_cast<FileEntry *>(SFile); + return cxstring::createRef(FEnt->tryGetRealPathName()); +} + +//===----------------------------------------------------------------------===// +// CXCursor Operations. +//===----------------------------------------------------------------------===// + +static const Decl *getDeclFromExpr(const Stmt *E) { + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + return getDeclFromExpr(CE->getSubExpr()); + + if (const DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) + return RefExpr->getDecl(); + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + if (const ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) + return RE->getDecl(); + if (const ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (PRE->isExplicitProperty()) + return PRE->getExplicitProperty(); + // It could be messaging both getter and setter as in: + // ++myobj.myprop; + // in which case prefer to associate the setter since it is less obvious + // from inspecting the source that the setter is going to get called. + if (PRE->isMessagingSetter()) + return PRE->getImplicitPropertySetter(); + return PRE->getImplicitPropertyGetter(); + } + if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) + return getDeclFromExpr(POE->getSyntacticForm()); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) + if (Expr *Src = OVE->getSourceExpr()) + return getDeclFromExpr(Src); + + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) + return getDeclFromExpr(CE->getCallee()); + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) + if (!CE->isElidable()) + return CE->getConstructor(); + if (const CXXInheritedCtorInitExpr *CE = + dyn_cast<CXXInheritedCtorInitExpr>(E)) + return CE->getConstructor(); + if (const ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E)) + return OME->getMethodDecl(); + + if (const ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E)) + return PE->getProtocol(); + if (const SubstNonTypeTemplateParmPackExpr *NTTP = + dyn_cast<SubstNonTypeTemplateParmPackExpr>(E)) + return NTTP->getParameterPack(); + if (const SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) + if (isa<NonTypeTemplateParmDecl>(SizeOfPack->getPack()) || + isa<ParmVarDecl>(SizeOfPack->getPack())) + return SizeOfPack->getPack(); + + return nullptr; +} + +static SourceLocation getLocationFromExpr(const Expr *E) { + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + return getLocationFromExpr(CE->getSubExpr()); + + if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) + return /*FIXME:*/ Msg->getLeftLoc(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return DRE->getLocation(); + if (const MemberExpr *Member = dyn_cast<MemberExpr>(E)) + return Member->getMemberLoc(); + if (const ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) + return Ivar->getLocation(); + if (const SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E)) + return SizeOfPack->getPackLoc(); + if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) + return PropRef->getLocation(); + + return E->getBeginLoc(); +} + +extern "C" { + +unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, + CXClientData client_data) { + CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data, + /*VisitPreprocessorLast=*/false); + return CursorVis.VisitChildren(parent); +} + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif +#if __has_feature(blocks) +typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor, + CXCursor parent); + +static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; + return block(cursor, parent); +} +#else +// If we are compiled with a compiler that doesn't have native blocks support, +// define and call the block manually, so the +typedef struct _CXChildVisitResult { + void *isa; + int flags; + int reserved; + enum CXChildVisitResult (*invoke)(struct _CXChildVisitResult *, CXCursor, + CXCursor); +} * CXCursorVisitorBlock; + +static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + CXCursorVisitorBlock block = (CXCursorVisitorBlock)client_data; + return block->invoke(block, cursor, parent); +} +#endif + +unsigned clang_visitChildrenWithBlock(CXCursor parent, + CXCursorVisitorBlock block) { + return clang_visitChildren(parent, visitWithBlock, block); +} + +static CXString getDeclSpelling(const Decl *D) { + if (!D) + return cxstring::createEmpty(); + + const NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND) { + if (const ObjCPropertyImplDecl *PropImpl = + dyn_cast<ObjCPropertyImplDecl>(D)) + if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) + return cxstring::createDup(Property->getIdentifier()->getName()); + + if (const ImportDecl *ImportD = dyn_cast<ImportDecl>(D)) + if (Module *Mod = ImportD->getImportedModule()) + return cxstring::createDup(Mod->getFullModuleName()); + + return cxstring::createEmpty(); + } + + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND)) + return cxstring::createDup(OMD->getSelector().getAsString()); + + if (const ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND)) + // No, this isn't the same as the code below. getIdentifier() is non-virtual + // and returns different names. NamedDecl returns the class name and + // ObjCCategoryImplDecl returns the category name. + return cxstring::createRef(CIMP->getIdentifier()->getNameStart()); + + if (isa<UsingDirectiveDecl>(D)) + return cxstring::createEmpty(); + + SmallString<1024> S; + llvm::raw_svector_ostream os(S); + ND->printName(os); + + return cxstring::createDup(os.str()); +} + +CXString clang_getCursorSpelling(CXCursor C) { + if (clang_isTranslationUnit(C.kind)) + return clang_getTranslationUnitSpelling(getCursorTU(C)); + + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + const ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first; + return cxstring::createRef(Super->getIdentifier()->getNameStart()); + } + case CXCursor_ObjCClassRef: { + const ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + return cxstring::createRef(Class->getIdentifier()->getNameStart()); + } + case CXCursor_ObjCProtocolRef: { + const ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first; + assert(OID && "getCursorSpelling(): Missing protocol decl"); + return cxstring::createRef(OID->getIdentifier()->getNameStart()); + } + case CXCursor_CXXBaseSpecifier: { + const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return cxstring::createDup(B->getType().getAsString()); + } + case CXCursor_TypeRef: { + const TypeDecl *Type = getCursorTypeRef(C).first; + assert(Type && "Missing type decl"); + + return cxstring::createDup( + getCursorContext(C).getTypeDeclType(Type).getAsString()); + } + case CXCursor_TemplateRef: { + const TemplateDecl *Template = getCursorTemplateRef(C).first; + assert(Template && "Missing template decl"); + + return cxstring::createDup(Template->getNameAsString()); + } + + case CXCursor_NamespaceRef: { + const NamedDecl *NS = getCursorNamespaceRef(C).first; + assert(NS && "Missing namespace decl"); + + return cxstring::createDup(NS->getNameAsString()); + } + + case CXCursor_MemberRef: { + const FieldDecl *Field = getCursorMemberRef(C).first; + assert(Field && "Missing member decl"); + + return cxstring::createDup(Field->getNameAsString()); + } + + case CXCursor_LabelRef: { + const LabelStmt *Label = getCursorLabelRef(C).first; + assert(Label && "Missing label"); + + return cxstring::createRef(Label->getName()); + } + + case CXCursor_OverloadedDeclRef: { + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; + if (const Decl *D = Storage.dyn_cast<const Decl *>()) { + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + return cxstring::createDup(ND->getNameAsString()); + return cxstring::createEmpty(); + } + if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>()) + return cxstring::createDup(E->getName().getAsString()); + OverloadedTemplateStorage *Ovl = + Storage.get<OverloadedTemplateStorage *>(); + if (Ovl->size() == 0) + return cxstring::createEmpty(); + return cxstring::createDup((*Ovl->begin())->getNameAsString()); + } + + case CXCursor_VariableRef: { + const VarDecl *Var = getCursorVariableRef(C).first; + assert(Var && "Missing variable decl"); + + return cxstring::createDup(Var->getNameAsString()); + } + + default: + return cxstring::createRef("<not implemented>"); + } + } + + if (clang_isExpression(C.kind)) { + const Expr *E = getCursorExpr(C); + + if (C.kind == CXCursor_ObjCStringLiteral || + C.kind == CXCursor_StringLiteral) { + const StringLiteral *SLit; + if (const ObjCStringLiteral *OSL = dyn_cast<ObjCStringLiteral>(E)) { + SLit = OSL->getString(); + } else { + SLit = cast<StringLiteral>(E); + } + SmallString<256> Buf; + llvm::raw_svector_ostream OS(Buf); + SLit->outputString(OS); + return cxstring::createDup(OS.str()); + } + + const Decl *D = getDeclFromExpr(getCursorExpr(C)); + if (D) + return getDeclSpelling(D); + return cxstring::createEmpty(); + } + + if (clang_isStatement(C.kind)) { + const Stmt *S = getCursorStmt(C); + if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) + return cxstring::createRef(Label->getName()); + + return cxstring::createEmpty(); + } + + if (C.kind == CXCursor_MacroExpansion) + return cxstring::createRef( + getCursorMacroExpansion(C).getName()->getNameStart()); + + if (C.kind == CXCursor_MacroDefinition) + return cxstring::createRef( + getCursorMacroDefinition(C)->getName()->getNameStart()); + + if (C.kind == CXCursor_InclusionDirective) + return cxstring::createDup(getCursorInclusionDirective(C)->getFileName()); + + if (clang_isDeclaration(C.kind)) + return getDeclSpelling(getCursorDecl(C)); + + if (C.kind == CXCursor_AnnotateAttr) { + const AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C)); + return cxstring::createDup(AA->getAnnotation()); + } + + if (C.kind == CXCursor_AsmLabelAttr) { + const AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C)); + return cxstring::createDup(AA->getLabel()); + } + + if (C.kind == CXCursor_PackedAttr) { + return cxstring::createRef("packed"); + } + + if (C.kind == CXCursor_VisibilityAttr) { + const VisibilityAttr *AA = cast<VisibilityAttr>(cxcursor::getCursorAttr(C)); + switch (AA->getVisibility()) { + case VisibilityAttr::VisibilityType::Default: + return cxstring::createRef("default"); + case VisibilityAttr::VisibilityType::Hidden: + return cxstring::createRef("hidden"); + case VisibilityAttr::VisibilityType::Protected: + return cxstring::createRef("protected"); + } + llvm_unreachable("unknown visibility type"); + } + + return cxstring::createEmpty(); +} + +CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C, unsigned pieceIndex, + unsigned options) { + if (clang_Cursor_isNull(C)) + return clang_getNullRange(); + + ASTContext &Ctx = getCursorContext(C); + + if (clang_isStatement(C.kind)) { + const Stmt *S = getCursorStmt(C); + if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) { + if (pieceIndex > 0) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, Label->getIdentLoc()); + } + + return clang_getNullRange(); + } + + if (C.kind == CXCursor_ObjCMessageExpr) { + if (const ObjCMessageExpr *ME = + dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) { + if (pieceIndex >= ME->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex)); + } + } + + if (C.kind == CXCursor_ObjCInstanceMethodDecl || + C.kind == CXCursor_ObjCClassMethodDecl) { + if (const ObjCMethodDecl *MD = + dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) { + if (pieceIndex >= MD->getNumSelectorLocs()) + return clang_getNullRange(); + return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex)); + } + } + + if (C.kind == CXCursor_ObjCCategoryDecl || + C.kind == CXCursor_ObjCCategoryImplDecl) { + if (pieceIndex > 0) + return clang_getNullRange(); + if (const ObjCCategoryDecl *CD = + dyn_cast_or_null<ObjCCategoryDecl>(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc()); + if (const ObjCCategoryImplDecl *CID = + dyn_cast_or_null<ObjCCategoryImplDecl>(getCursorDecl(C))) + return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc()); + } + + if (C.kind == CXCursor_ModuleImportDecl) { + if (pieceIndex > 0) + return clang_getNullRange(); + if (const ImportDecl *ImportD = + dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) { + ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs(); + if (!Locs.empty()) + return cxloc::translateSourceRange( + Ctx, SourceRange(Locs.front(), Locs.back())); + } + return clang_getNullRange(); + } + + if (C.kind == CXCursor_CXXMethod || C.kind == CXCursor_Destructor || + C.kind == CXCursor_ConversionFunction || + C.kind == CXCursor_FunctionDecl) { + if (pieceIndex > 0) + return clang_getNullRange(); + if (const FunctionDecl *FD = + dyn_cast_or_null<FunctionDecl>(getCursorDecl(C))) { + DeclarationNameInfo FunctionName = FD->getNameInfo(); + return cxloc::translateSourceRange(Ctx, FunctionName.getSourceRange()); + } + return clang_getNullRange(); + } + + // FIXME: A CXCursor_InclusionDirective should give the location of the + // filename, but we don't keep track of this. + + // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation + // but we don't keep track of this. + + // FIXME: A CXCursor_AsmLabelAttr should give the location of the label + // but we don't keep track of this. + + // Default handling, give the location of the cursor. + + if (pieceIndex > 0) + return clang_getNullRange(); + + CXSourceLocation CXLoc = clang_getCursorLocation(C); + SourceLocation Loc = cxloc::translateSourceLocation(CXLoc); + return cxloc::translateSourceRange(Ctx, Loc); +} + +CXString clang_Cursor_getMangling(CXCursor C) { + if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind)) + return cxstring::createEmpty(); + + // Mangling only works for functions and variables. + const Decl *D = getCursorDecl(C); + if (!D || !(isa<FunctionDecl>(D) || isa<VarDecl>(D))) + return cxstring::createEmpty(); + + ASTContext &Ctx = D->getASTContext(); + ASTNameGenerator ASTNameGen(Ctx); + return cxstring::createDup(ASTNameGen.getName(D)); +} + +CXStringSet *clang_Cursor_getCXXManglings(CXCursor C) { + if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind)) + return nullptr; + + const Decl *D = getCursorDecl(C); + if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D))) + return nullptr; + + ASTContext &Ctx = D->getASTContext(); + ASTNameGenerator ASTNameGen(Ctx); + std::vector<std::string> Manglings = ASTNameGen.getAllManglings(D); + return cxstring::createSet(Manglings); +} + +CXStringSet *clang_Cursor_getObjCManglings(CXCursor C) { + if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind)) + return nullptr; + + const Decl *D = getCursorDecl(C); + if (!(isa<ObjCInterfaceDecl>(D) || isa<ObjCImplementationDecl>(D))) + return nullptr; + + ASTContext &Ctx = D->getASTContext(); + ASTNameGenerator ASTNameGen(Ctx); + std::vector<std::string> Manglings = ASTNameGen.getAllManglings(D); + return cxstring::createSet(Manglings); +} + +CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor C) { + if (clang_Cursor_isNull(C)) + return nullptr; + return new PrintingPolicy(getCursorContext(C).getPrintingPolicy()); +} + +void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy) { + if (Policy) + delete static_cast<PrintingPolicy *>(Policy); +} + +unsigned +clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property) { + if (!Policy) + return 0; + + PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy); + switch (Property) { + case CXPrintingPolicy_Indentation: + return P->Indentation; + case CXPrintingPolicy_SuppressSpecifiers: + return P->SuppressSpecifiers; + case CXPrintingPolicy_SuppressTagKeyword: + return P->SuppressTagKeyword; + case CXPrintingPolicy_IncludeTagDefinition: + return P->IncludeTagDefinition; + case CXPrintingPolicy_SuppressScope: + return P->SuppressScope; + case CXPrintingPolicy_SuppressUnwrittenScope: + return P->SuppressUnwrittenScope; + case CXPrintingPolicy_SuppressInitializers: + return P->SuppressInitializers; + case CXPrintingPolicy_ConstantArraySizeAsWritten: + return P->ConstantArraySizeAsWritten; + case CXPrintingPolicy_AnonymousTagLocations: + return P->AnonymousTagLocations; + case CXPrintingPolicy_SuppressStrongLifetime: + return P->SuppressStrongLifetime; + case CXPrintingPolicy_SuppressLifetimeQualifiers: + return P->SuppressLifetimeQualifiers; + case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors: + return P->SuppressTemplateArgsInCXXConstructors; + case CXPrintingPolicy_Bool: + return P->Bool; + case CXPrintingPolicy_Restrict: + return P->Restrict; + case CXPrintingPolicy_Alignof: + return P->Alignof; + case CXPrintingPolicy_UnderscoreAlignof: + return P->UnderscoreAlignof; + case CXPrintingPolicy_UseVoidForZeroParams: + return P->UseVoidForZeroParams; + case CXPrintingPolicy_TerseOutput: + return P->TerseOutput; + case CXPrintingPolicy_PolishForDeclaration: + return P->PolishForDeclaration; + case CXPrintingPolicy_Half: + return P->Half; + case CXPrintingPolicy_MSWChar: + return P->MSWChar; + case CXPrintingPolicy_IncludeNewlines: + return P->IncludeNewlines; + case CXPrintingPolicy_MSVCFormatting: + return P->MSVCFormatting; + case CXPrintingPolicy_ConstantsAsWritten: + return P->ConstantsAsWritten; + case CXPrintingPolicy_SuppressImplicitBase: + return P->SuppressImplicitBase; + case CXPrintingPolicy_FullyQualifiedName: + return P->FullyQualifiedName; + } + + assert(false && "Invalid CXPrintingPolicyProperty"); + return 0; +} + +void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property, + unsigned Value) { + if (!Policy) + return; + + PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy); + switch (Property) { + case CXPrintingPolicy_Indentation: + P->Indentation = Value; + return; + case CXPrintingPolicy_SuppressSpecifiers: + P->SuppressSpecifiers = Value; + return; + case CXPrintingPolicy_SuppressTagKeyword: + P->SuppressTagKeyword = Value; + return; + case CXPrintingPolicy_IncludeTagDefinition: + P->IncludeTagDefinition = Value; + return; + case CXPrintingPolicy_SuppressScope: + P->SuppressScope = Value; + return; + case CXPrintingPolicy_SuppressUnwrittenScope: + P->SuppressUnwrittenScope = Value; + return; + case CXPrintingPolicy_SuppressInitializers: + P->SuppressInitializers = Value; + return; + case CXPrintingPolicy_ConstantArraySizeAsWritten: + P->ConstantArraySizeAsWritten = Value; + return; + case CXPrintingPolicy_AnonymousTagLocations: + P->AnonymousTagLocations = Value; + return; + case CXPrintingPolicy_SuppressStrongLifetime: + P->SuppressStrongLifetime = Value; + return; + case CXPrintingPolicy_SuppressLifetimeQualifiers: + P->SuppressLifetimeQualifiers = Value; + return; + case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors: + P->SuppressTemplateArgsInCXXConstructors = Value; + return; + case CXPrintingPolicy_Bool: + P->Bool = Value; + return; + case CXPrintingPolicy_Restrict: + P->Restrict = Value; + return; + case CXPrintingPolicy_Alignof: + P->Alignof = Value; + return; + case CXPrintingPolicy_UnderscoreAlignof: + P->UnderscoreAlignof = Value; + return; + case CXPrintingPolicy_UseVoidForZeroParams: + P->UseVoidForZeroParams = Value; + return; + case CXPrintingPolicy_TerseOutput: + P->TerseOutput = Value; + return; + case CXPrintingPolicy_PolishForDeclaration: + P->PolishForDeclaration = Value; + return; + case CXPrintingPolicy_Half: + P->Half = Value; + return; + case CXPrintingPolicy_MSWChar: + P->MSWChar = Value; + return; + case CXPrintingPolicy_IncludeNewlines: + P->IncludeNewlines = Value; + return; + case CXPrintingPolicy_MSVCFormatting: + P->MSVCFormatting = Value; + return; + case CXPrintingPolicy_ConstantsAsWritten: + P->ConstantsAsWritten = Value; + return; + case CXPrintingPolicy_SuppressImplicitBase: + P->SuppressImplicitBase = Value; + return; + case CXPrintingPolicy_FullyQualifiedName: + P->FullyQualifiedName = Value; + return; + } + + assert(false && "Invalid CXPrintingPolicyProperty"); +} + +CXString clang_getCursorPrettyPrinted(CXCursor C, CXPrintingPolicy cxPolicy) { + if (clang_Cursor_isNull(C)) + return cxstring::createEmpty(); + + if (clang_isDeclaration(C.kind)) { + const Decl *D = getCursorDecl(C); + if (!D) + return cxstring::createEmpty(); + + SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + PrintingPolicy *UserPolicy = static_cast<PrintingPolicy *>(cxPolicy); + D->print(OS, UserPolicy ? *UserPolicy + : getCursorContext(C).getPrintingPolicy()); + + return cxstring::createDup(OS.str()); + } + + return cxstring::createEmpty(); +} + +CXString clang_getCursorDisplayName(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getCursorSpelling(C); + + const Decl *D = getCursorDecl(C); + if (!D) + return cxstring::createEmpty(); + + PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy(); + if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) + D = FunTmpl->getTemplatedDecl(); + + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << *Function; + if (Function->getPrimaryTemplate()) + OS << "<>"; + OS << "("; + for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) { + if (I) + OS << ", "; + OS << Function->getParamDecl(I)->getType().getAsString(Policy); + } + + if (Function->isVariadic()) { + if (Function->getNumParams()) + OS << ", "; + OS << "..."; + } + OS << ")"; + return cxstring::createDup(OS.str()); + } + + if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) { + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << *ClassTemplate; + OS << "<"; + TemplateParameterList *Params = ClassTemplate->getTemplateParameters(); + for (unsigned I = 0, N = Params->size(); I != N; ++I) { + if (I) + OS << ", "; + + NamedDecl *Param = Params->getParam(I); + if (Param->getIdentifier()) { + OS << Param->getIdentifier()->getName(); + continue; + } + + // There is no parameter name, which makes this tricky. Try to come up + // with something useful that isn't too long. + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + if (const auto *TC = TTP->getTypeConstraint()) { + TC->getConceptNameInfo().printName(OS, Policy); + if (TC->hasExplicitTemplateArgs()) + OS << "<...>"; + } else + OS << (TTP->wasDeclaredWithTypename() ? "typename" : "class"); + else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) + OS << NTTP->getType().getAsString(Policy); + else + OS << "template<...> class"; + } + + OS << ">"; + return cxstring::createDup(OS.str()); + } + + if (const ClassTemplateSpecializationDecl *ClassSpec = + dyn_cast<ClassTemplateSpecializationDecl>(D)) { + // If the type was explicitly written, use that. + if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten()) + return cxstring::createDup(TSInfo->getType().getAsString(Policy)); + + SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + OS << *ClassSpec; + printTemplateArgumentList( + OS, ClassSpec->getTemplateArgs().asArray(), Policy, + ClassSpec->getSpecializedTemplate()->getTemplateParameters()); + return cxstring::createDup(OS.str()); + } + + return clang_getCursorSpelling(C); +} + +CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { + switch (Kind) { + case CXCursor_FunctionDecl: + return cxstring::createRef("FunctionDecl"); + case CXCursor_TypedefDecl: + return cxstring::createRef("TypedefDecl"); + case CXCursor_EnumDecl: + return cxstring::createRef("EnumDecl"); + case CXCursor_EnumConstantDecl: + return cxstring::createRef("EnumConstantDecl"); + case CXCursor_StructDecl: + return cxstring::createRef("StructDecl"); + case CXCursor_UnionDecl: + return cxstring::createRef("UnionDecl"); + case CXCursor_ClassDecl: + return cxstring::createRef("ClassDecl"); + case CXCursor_FieldDecl: + return cxstring::createRef("FieldDecl"); + case CXCursor_VarDecl: + return cxstring::createRef("VarDecl"); + case CXCursor_ParmDecl: + return cxstring::createRef("ParmDecl"); + case CXCursor_ObjCInterfaceDecl: + return cxstring::createRef("ObjCInterfaceDecl"); + case CXCursor_ObjCCategoryDecl: + return cxstring::createRef("ObjCCategoryDecl"); + case CXCursor_ObjCProtocolDecl: + return cxstring::createRef("ObjCProtocolDecl"); + case CXCursor_ObjCPropertyDecl: + return cxstring::createRef("ObjCPropertyDecl"); + case CXCursor_ObjCIvarDecl: + return cxstring::createRef("ObjCIvarDecl"); + case CXCursor_ObjCInstanceMethodDecl: + return cxstring::createRef("ObjCInstanceMethodDecl"); + case CXCursor_ObjCClassMethodDecl: + return cxstring::createRef("ObjCClassMethodDecl"); + case CXCursor_ObjCImplementationDecl: + return cxstring::createRef("ObjCImplementationDecl"); + case CXCursor_ObjCCategoryImplDecl: + return cxstring::createRef("ObjCCategoryImplDecl"); + case CXCursor_CXXMethod: + return cxstring::createRef("CXXMethod"); + case CXCursor_UnexposedDecl: + return cxstring::createRef("UnexposedDecl"); + case CXCursor_ObjCSuperClassRef: + return cxstring::createRef("ObjCSuperClassRef"); + case CXCursor_ObjCProtocolRef: + return cxstring::createRef("ObjCProtocolRef"); + case CXCursor_ObjCClassRef: + return cxstring::createRef("ObjCClassRef"); + case CXCursor_TypeRef: + return cxstring::createRef("TypeRef"); + case CXCursor_TemplateRef: + return cxstring::createRef("TemplateRef"); + case CXCursor_NamespaceRef: + return cxstring::createRef("NamespaceRef"); + case CXCursor_MemberRef: + return cxstring::createRef("MemberRef"); + case CXCursor_LabelRef: + return cxstring::createRef("LabelRef"); + case CXCursor_OverloadedDeclRef: + return cxstring::createRef("OverloadedDeclRef"); + case CXCursor_VariableRef: + return cxstring::createRef("VariableRef"); + case CXCursor_IntegerLiteral: + return cxstring::createRef("IntegerLiteral"); + case CXCursor_FixedPointLiteral: + return cxstring::createRef("FixedPointLiteral"); + case CXCursor_FloatingLiteral: + return cxstring::createRef("FloatingLiteral"); + case CXCursor_ImaginaryLiteral: + return cxstring::createRef("ImaginaryLiteral"); + case CXCursor_StringLiteral: + return cxstring::createRef("StringLiteral"); + case CXCursor_CharacterLiteral: + return cxstring::createRef("CharacterLiteral"); + case CXCursor_ParenExpr: + return cxstring::createRef("ParenExpr"); + case CXCursor_UnaryOperator: + return cxstring::createRef("UnaryOperator"); + case CXCursor_ArraySubscriptExpr: + return cxstring::createRef("ArraySubscriptExpr"); + case CXCursor_OMPArraySectionExpr: + return cxstring::createRef("OMPArraySectionExpr"); + case CXCursor_OMPArrayShapingExpr: + return cxstring::createRef("OMPArrayShapingExpr"); + case CXCursor_OMPIteratorExpr: + return cxstring::createRef("OMPIteratorExpr"); + case CXCursor_BinaryOperator: + return cxstring::createRef("BinaryOperator"); + case CXCursor_CompoundAssignOperator: + return cxstring::createRef("CompoundAssignOperator"); + case CXCursor_ConditionalOperator: + return cxstring::createRef("ConditionalOperator"); + case CXCursor_CStyleCastExpr: + return cxstring::createRef("CStyleCastExpr"); + case CXCursor_CompoundLiteralExpr: + return cxstring::createRef("CompoundLiteralExpr"); + case CXCursor_InitListExpr: + return cxstring::createRef("InitListExpr"); + case CXCursor_AddrLabelExpr: + return cxstring::createRef("AddrLabelExpr"); + case CXCursor_StmtExpr: + return cxstring::createRef("StmtExpr"); + case CXCursor_GenericSelectionExpr: + return cxstring::createRef("GenericSelectionExpr"); + case CXCursor_GNUNullExpr: + return cxstring::createRef("GNUNullExpr"); + case CXCursor_CXXStaticCastExpr: + return cxstring::createRef("CXXStaticCastExpr"); + case CXCursor_CXXDynamicCastExpr: + return cxstring::createRef("CXXDynamicCastExpr"); + case CXCursor_CXXReinterpretCastExpr: + return cxstring::createRef("CXXReinterpretCastExpr"); + case CXCursor_CXXConstCastExpr: + return cxstring::createRef("CXXConstCastExpr"); + case CXCursor_CXXFunctionalCastExpr: + return cxstring::createRef("CXXFunctionalCastExpr"); + case CXCursor_CXXAddrspaceCastExpr: + return cxstring::createRef("CXXAddrspaceCastExpr"); + case CXCursor_CXXTypeidExpr: + return cxstring::createRef("CXXTypeidExpr"); + case CXCursor_CXXBoolLiteralExpr: + return cxstring::createRef("CXXBoolLiteralExpr"); + case CXCursor_CXXNullPtrLiteralExpr: + return cxstring::createRef("CXXNullPtrLiteralExpr"); + case CXCursor_CXXThisExpr: + return cxstring::createRef("CXXThisExpr"); + case CXCursor_CXXThrowExpr: + return cxstring::createRef("CXXThrowExpr"); + case CXCursor_CXXNewExpr: + return cxstring::createRef("CXXNewExpr"); + case CXCursor_CXXDeleteExpr: + return cxstring::createRef("CXXDeleteExpr"); + case CXCursor_UnaryExpr: + return cxstring::createRef("UnaryExpr"); + case CXCursor_ObjCStringLiteral: + return cxstring::createRef("ObjCStringLiteral"); + case CXCursor_ObjCBoolLiteralExpr: + return cxstring::createRef("ObjCBoolLiteralExpr"); + case CXCursor_ObjCAvailabilityCheckExpr: + return cxstring::createRef("ObjCAvailabilityCheckExpr"); + case CXCursor_ObjCSelfExpr: + return cxstring::createRef("ObjCSelfExpr"); + case CXCursor_ObjCEncodeExpr: + return cxstring::createRef("ObjCEncodeExpr"); + case CXCursor_ObjCSelectorExpr: + return cxstring::createRef("ObjCSelectorExpr"); + case CXCursor_ObjCProtocolExpr: + return cxstring::createRef("ObjCProtocolExpr"); + case CXCursor_ObjCBridgedCastExpr: + return cxstring::createRef("ObjCBridgedCastExpr"); + case CXCursor_BlockExpr: + return cxstring::createRef("BlockExpr"); + case CXCursor_PackExpansionExpr: + return cxstring::createRef("PackExpansionExpr"); + case CXCursor_SizeOfPackExpr: + return cxstring::createRef("SizeOfPackExpr"); + case CXCursor_LambdaExpr: + return cxstring::createRef("LambdaExpr"); + case CXCursor_UnexposedExpr: + return cxstring::createRef("UnexposedExpr"); + case CXCursor_DeclRefExpr: + return cxstring::createRef("DeclRefExpr"); + case CXCursor_MemberRefExpr: + return cxstring::createRef("MemberRefExpr"); + case CXCursor_CallExpr: + return cxstring::createRef("CallExpr"); + case CXCursor_ObjCMessageExpr: + return cxstring::createRef("ObjCMessageExpr"); + case CXCursor_BuiltinBitCastExpr: + return cxstring::createRef("BuiltinBitCastExpr"); + case CXCursor_UnexposedStmt: + return cxstring::createRef("UnexposedStmt"); + case CXCursor_DeclStmt: + return cxstring::createRef("DeclStmt"); + case CXCursor_LabelStmt: + return cxstring::createRef("LabelStmt"); + case CXCursor_CompoundStmt: + return cxstring::createRef("CompoundStmt"); + case CXCursor_CaseStmt: + return cxstring::createRef("CaseStmt"); + case CXCursor_DefaultStmt: + return cxstring::createRef("DefaultStmt"); + case CXCursor_IfStmt: + return cxstring::createRef("IfStmt"); + case CXCursor_SwitchStmt: + return cxstring::createRef("SwitchStmt"); + case CXCursor_WhileStmt: + return cxstring::createRef("WhileStmt"); + case CXCursor_DoStmt: + return cxstring::createRef("DoStmt"); + case CXCursor_ForStmt: + return cxstring::createRef("ForStmt"); + case CXCursor_GotoStmt: + return cxstring::createRef("GotoStmt"); + case CXCursor_IndirectGotoStmt: + return cxstring::createRef("IndirectGotoStmt"); + case CXCursor_ContinueStmt: + return cxstring::createRef("ContinueStmt"); + case CXCursor_BreakStmt: + return cxstring::createRef("BreakStmt"); + case CXCursor_ReturnStmt: + return cxstring::createRef("ReturnStmt"); + case CXCursor_GCCAsmStmt: + return cxstring::createRef("GCCAsmStmt"); + case CXCursor_MSAsmStmt: + return cxstring::createRef("MSAsmStmt"); + case CXCursor_ObjCAtTryStmt: + return cxstring::createRef("ObjCAtTryStmt"); + case CXCursor_ObjCAtCatchStmt: + return cxstring::createRef("ObjCAtCatchStmt"); + case CXCursor_ObjCAtFinallyStmt: + return cxstring::createRef("ObjCAtFinallyStmt"); + case CXCursor_ObjCAtThrowStmt: + return cxstring::createRef("ObjCAtThrowStmt"); + case CXCursor_ObjCAtSynchronizedStmt: + return cxstring::createRef("ObjCAtSynchronizedStmt"); + case CXCursor_ObjCAutoreleasePoolStmt: + return cxstring::createRef("ObjCAutoreleasePoolStmt"); + case CXCursor_ObjCForCollectionStmt: + return cxstring::createRef("ObjCForCollectionStmt"); + case CXCursor_CXXCatchStmt: + return cxstring::createRef("CXXCatchStmt"); + case CXCursor_CXXTryStmt: + return cxstring::createRef("CXXTryStmt"); + case CXCursor_CXXForRangeStmt: + return cxstring::createRef("CXXForRangeStmt"); + case CXCursor_SEHTryStmt: + return cxstring::createRef("SEHTryStmt"); + case CXCursor_SEHExceptStmt: + return cxstring::createRef("SEHExceptStmt"); + case CXCursor_SEHFinallyStmt: + return cxstring::createRef("SEHFinallyStmt"); + case CXCursor_SEHLeaveStmt: + return cxstring::createRef("SEHLeaveStmt"); + case CXCursor_NullStmt: + return cxstring::createRef("NullStmt"); + case CXCursor_InvalidFile: + return cxstring::createRef("InvalidFile"); + case CXCursor_InvalidCode: + return cxstring::createRef("InvalidCode"); + case CXCursor_NoDeclFound: + return cxstring::createRef("NoDeclFound"); + case CXCursor_NotImplemented: + return cxstring::createRef("NotImplemented"); + case CXCursor_TranslationUnit: + return cxstring::createRef("TranslationUnit"); + case CXCursor_UnexposedAttr: + return cxstring::createRef("UnexposedAttr"); + case CXCursor_IBActionAttr: + return cxstring::createRef("attribute(ibaction)"); + case CXCursor_IBOutletAttr: + return cxstring::createRef("attribute(iboutlet)"); + case CXCursor_IBOutletCollectionAttr: + return cxstring::createRef("attribute(iboutletcollection)"); + case CXCursor_CXXFinalAttr: + return cxstring::createRef("attribute(final)"); + case CXCursor_CXXOverrideAttr: + return cxstring::createRef("attribute(override)"); + case CXCursor_AnnotateAttr: + return cxstring::createRef("attribute(annotate)"); + case CXCursor_AsmLabelAttr: + return cxstring::createRef("asm label"); + case CXCursor_PackedAttr: + return cxstring::createRef("attribute(packed)"); + case CXCursor_PureAttr: + return cxstring::createRef("attribute(pure)"); + case CXCursor_ConstAttr: + return cxstring::createRef("attribute(const)"); + case CXCursor_NoDuplicateAttr: + return cxstring::createRef("attribute(noduplicate)"); + case CXCursor_CUDAConstantAttr: + return cxstring::createRef("attribute(constant)"); + case CXCursor_CUDADeviceAttr: + return cxstring::createRef("attribute(device)"); + case CXCursor_CUDAGlobalAttr: + return cxstring::createRef("attribute(global)"); + case CXCursor_CUDAHostAttr: + return cxstring::createRef("attribute(host)"); + case CXCursor_CUDASharedAttr: + return cxstring::createRef("attribute(shared)"); + case CXCursor_VisibilityAttr: + return cxstring::createRef("attribute(visibility)"); + case CXCursor_DLLExport: + return cxstring::createRef("attribute(dllexport)"); + case CXCursor_DLLImport: + return cxstring::createRef("attribute(dllimport)"); + case CXCursor_NSReturnsRetained: + return cxstring::createRef("attribute(ns_returns_retained)"); + case CXCursor_NSReturnsNotRetained: + return cxstring::createRef("attribute(ns_returns_not_retained)"); + case CXCursor_NSReturnsAutoreleased: + return cxstring::createRef("attribute(ns_returns_autoreleased)"); + case CXCursor_NSConsumesSelf: + return cxstring::createRef("attribute(ns_consumes_self)"); + case CXCursor_NSConsumed: + return cxstring::createRef("attribute(ns_consumed)"); + case CXCursor_ObjCException: + return cxstring::createRef("attribute(objc_exception)"); + case CXCursor_ObjCNSObject: + return cxstring::createRef("attribute(NSObject)"); + case CXCursor_ObjCIndependentClass: + return cxstring::createRef("attribute(objc_independent_class)"); + case CXCursor_ObjCPreciseLifetime: + return cxstring::createRef("attribute(objc_precise_lifetime)"); + case CXCursor_ObjCReturnsInnerPointer: + return cxstring::createRef("attribute(objc_returns_inner_pointer)"); + case CXCursor_ObjCRequiresSuper: + return cxstring::createRef("attribute(objc_requires_super)"); + case CXCursor_ObjCRootClass: + return cxstring::createRef("attribute(objc_root_class)"); + case CXCursor_ObjCSubclassingRestricted: + return cxstring::createRef("attribute(objc_subclassing_restricted)"); + case CXCursor_ObjCExplicitProtocolImpl: + return cxstring::createRef( + "attribute(objc_protocol_requires_explicit_implementation)"); + case CXCursor_ObjCDesignatedInitializer: + return cxstring::createRef("attribute(objc_designated_initializer)"); + case CXCursor_ObjCRuntimeVisible: + return cxstring::createRef("attribute(objc_runtime_visible)"); + case CXCursor_ObjCBoxable: + return cxstring::createRef("attribute(objc_boxable)"); + case CXCursor_FlagEnum: + return cxstring::createRef("attribute(flag_enum)"); + case CXCursor_PreprocessingDirective: + return cxstring::createRef("preprocessing directive"); + case CXCursor_MacroDefinition: + return cxstring::createRef("macro definition"); + case CXCursor_MacroExpansion: + return cxstring::createRef("macro expansion"); + case CXCursor_InclusionDirective: + return cxstring::createRef("inclusion directive"); + case CXCursor_Namespace: + return cxstring::createRef("Namespace"); + case CXCursor_LinkageSpec: + return cxstring::createRef("LinkageSpec"); + case CXCursor_CXXBaseSpecifier: + return cxstring::createRef("C++ base class specifier"); + case CXCursor_Constructor: + return cxstring::createRef("CXXConstructor"); + case CXCursor_Destructor: + return cxstring::createRef("CXXDestructor"); + case CXCursor_ConversionFunction: + return cxstring::createRef("CXXConversion"); + case CXCursor_TemplateTypeParameter: + return cxstring::createRef("TemplateTypeParameter"); + case CXCursor_NonTypeTemplateParameter: + return cxstring::createRef("NonTypeTemplateParameter"); + case CXCursor_TemplateTemplateParameter: + return cxstring::createRef("TemplateTemplateParameter"); + case CXCursor_FunctionTemplate: + return cxstring::createRef("FunctionTemplate"); + case CXCursor_ClassTemplate: + return cxstring::createRef("ClassTemplate"); + case CXCursor_ClassTemplatePartialSpecialization: + return cxstring::createRef("ClassTemplatePartialSpecialization"); + case CXCursor_NamespaceAlias: + return cxstring::createRef("NamespaceAlias"); + case CXCursor_UsingDirective: + return cxstring::createRef("UsingDirective"); + case CXCursor_UsingDeclaration: + return cxstring::createRef("UsingDeclaration"); + case CXCursor_TypeAliasDecl: + return cxstring::createRef("TypeAliasDecl"); + case CXCursor_ObjCSynthesizeDecl: + return cxstring::createRef("ObjCSynthesizeDecl"); + case CXCursor_ObjCDynamicDecl: + return cxstring::createRef("ObjCDynamicDecl"); + case CXCursor_CXXAccessSpecifier: + return cxstring::createRef("CXXAccessSpecifier"); + case CXCursor_ModuleImportDecl: + return cxstring::createRef("ModuleImport"); + case CXCursor_OMPCanonicalLoop: + return cxstring::createRef("OMPCanonicalLoop"); + case CXCursor_OMPMetaDirective: + return cxstring::createRef("OMPMetaDirective"); + case CXCursor_OMPParallelDirective: + return cxstring::createRef("OMPParallelDirective"); + case CXCursor_OMPSimdDirective: + return cxstring::createRef("OMPSimdDirective"); + case CXCursor_OMPTileDirective: + return cxstring::createRef("OMPTileDirective"); + case CXCursor_OMPUnrollDirective: + return cxstring::createRef("OMPUnrollDirective"); + case CXCursor_OMPForDirective: + return cxstring::createRef("OMPForDirective"); + case CXCursor_OMPForSimdDirective: + return cxstring::createRef("OMPForSimdDirective"); + case CXCursor_OMPSectionsDirective: + return cxstring::createRef("OMPSectionsDirective"); + case CXCursor_OMPSectionDirective: + return cxstring::createRef("OMPSectionDirective"); + case CXCursor_OMPSingleDirective: + return cxstring::createRef("OMPSingleDirective"); + case CXCursor_OMPMasterDirective: + return cxstring::createRef("OMPMasterDirective"); + case CXCursor_OMPCriticalDirective: + return cxstring::createRef("OMPCriticalDirective"); + case CXCursor_OMPParallelForDirective: + return cxstring::createRef("OMPParallelForDirective"); + case CXCursor_OMPParallelForSimdDirective: + return cxstring::createRef("OMPParallelForSimdDirective"); + case CXCursor_OMPParallelMasterDirective: + return cxstring::createRef("OMPParallelMasterDirective"); + case CXCursor_OMPParallelSectionsDirective: + return cxstring::createRef("OMPParallelSectionsDirective"); + case CXCursor_OMPTaskDirective: + return cxstring::createRef("OMPTaskDirective"); + case CXCursor_OMPTaskyieldDirective: + return cxstring::createRef("OMPTaskyieldDirective"); + case CXCursor_OMPBarrierDirective: + return cxstring::createRef("OMPBarrierDirective"); + case CXCursor_OMPTaskwaitDirective: + return cxstring::createRef("OMPTaskwaitDirective"); + case CXCursor_OMPTaskgroupDirective: + return cxstring::createRef("OMPTaskgroupDirective"); + case CXCursor_OMPFlushDirective: + return cxstring::createRef("OMPFlushDirective"); + case CXCursor_OMPDepobjDirective: + return cxstring::createRef("OMPDepobjDirective"); + case CXCursor_OMPScanDirective: + return cxstring::createRef("OMPScanDirective"); + case CXCursor_OMPOrderedDirective: + return cxstring::createRef("OMPOrderedDirective"); + case CXCursor_OMPAtomicDirective: + return cxstring::createRef("OMPAtomicDirective"); + case CXCursor_OMPTargetDirective: + return cxstring::createRef("OMPTargetDirective"); + case CXCursor_OMPTargetDataDirective: + return cxstring::createRef("OMPTargetDataDirective"); + case CXCursor_OMPTargetEnterDataDirective: + return cxstring::createRef("OMPTargetEnterDataDirective"); + case CXCursor_OMPTargetExitDataDirective: + return cxstring::createRef("OMPTargetExitDataDirective"); + case CXCursor_OMPTargetParallelDirective: + return cxstring::createRef("OMPTargetParallelDirective"); + case CXCursor_OMPTargetParallelForDirective: + return cxstring::createRef("OMPTargetParallelForDirective"); + case CXCursor_OMPTargetUpdateDirective: + return cxstring::createRef("OMPTargetUpdateDirective"); + case CXCursor_OMPTeamsDirective: + return cxstring::createRef("OMPTeamsDirective"); + case CXCursor_OMPCancellationPointDirective: + return cxstring::createRef("OMPCancellationPointDirective"); + case CXCursor_OMPCancelDirective: + return cxstring::createRef("OMPCancelDirective"); + case CXCursor_OMPTaskLoopDirective: + return cxstring::createRef("OMPTaskLoopDirective"); + case CXCursor_OMPTaskLoopSimdDirective: + return cxstring::createRef("OMPTaskLoopSimdDirective"); + case CXCursor_OMPMasterTaskLoopDirective: + return cxstring::createRef("OMPMasterTaskLoopDirective"); + case CXCursor_OMPMasterTaskLoopSimdDirective: + return cxstring::createRef("OMPMasterTaskLoopSimdDirective"); + case CXCursor_OMPParallelMasterTaskLoopDirective: + return cxstring::createRef("OMPParallelMasterTaskLoopDirective"); + case CXCursor_OMPParallelMasterTaskLoopSimdDirective: + return cxstring::createRef("OMPParallelMasterTaskLoopSimdDirective"); + case CXCursor_OMPDistributeDirective: + return cxstring::createRef("OMPDistributeDirective"); + case CXCursor_OMPDistributeParallelForDirective: + return cxstring::createRef("OMPDistributeParallelForDirective"); + case CXCursor_OMPDistributeParallelForSimdDirective: + return cxstring::createRef("OMPDistributeParallelForSimdDirective"); + case CXCursor_OMPDistributeSimdDirective: + return cxstring::createRef("OMPDistributeSimdDirective"); + case CXCursor_OMPTargetParallelForSimdDirective: + return cxstring::createRef("OMPTargetParallelForSimdDirective"); + case CXCursor_OMPTargetSimdDirective: + return cxstring::createRef("OMPTargetSimdDirective"); + case CXCursor_OMPTeamsDistributeDirective: + return cxstring::createRef("OMPTeamsDistributeDirective"); + case CXCursor_OMPTeamsDistributeSimdDirective: + return cxstring::createRef("OMPTeamsDistributeSimdDirective"); + case CXCursor_OMPTeamsDistributeParallelForSimdDirective: + return cxstring::createRef("OMPTeamsDistributeParallelForSimdDirective"); + case CXCursor_OMPTeamsDistributeParallelForDirective: + return cxstring::createRef("OMPTeamsDistributeParallelForDirective"); + case CXCursor_OMPTargetTeamsDirective: + return cxstring::createRef("OMPTargetTeamsDirective"); + case CXCursor_OMPTargetTeamsDistributeDirective: + return cxstring::createRef("OMPTargetTeamsDistributeDirective"); + case CXCursor_OMPTargetTeamsDistributeParallelForDirective: + return cxstring::createRef("OMPTargetTeamsDistributeParallelForDirective"); + case CXCursor_OMPTargetTeamsDistributeParallelForSimdDirective: + return cxstring::createRef( + "OMPTargetTeamsDistributeParallelForSimdDirective"); + case CXCursor_OMPTargetTeamsDistributeSimdDirective: + return cxstring::createRef("OMPTargetTeamsDistributeSimdDirective"); + case CXCursor_OMPInteropDirective: + return cxstring::createRef("OMPInteropDirective"); + case CXCursor_OMPDispatchDirective: + return cxstring::createRef("OMPDispatchDirective"); + case CXCursor_OMPMaskedDirective: + return cxstring::createRef("OMPMaskedDirective"); + case CXCursor_OMPGenericLoopDirective: + return cxstring::createRef("OMPGenericLoopDirective"); + case CXCursor_OverloadCandidate: + return cxstring::createRef("OverloadCandidate"); + case CXCursor_TypeAliasTemplateDecl: + return cxstring::createRef("TypeAliasTemplateDecl"); + case CXCursor_StaticAssert: + return cxstring::createRef("StaticAssert"); + case CXCursor_FriendDecl: + return cxstring::createRef("FriendDecl"); + case CXCursor_ConvergentAttr: + return cxstring::createRef("attribute(convergent)"); + case CXCursor_WarnUnusedAttr: + return cxstring::createRef("attribute(warn_unused)"); + case CXCursor_WarnUnusedResultAttr: + return cxstring::createRef("attribute(warn_unused_result)"); + case CXCursor_AlignedAttr: + return cxstring::createRef("attribute(aligned)"); + } + + llvm_unreachable("Unhandled CXCursorKind"); +} + +struct GetCursorData { + SourceLocation TokenBeginLoc; + bool PointsAtMacroArgExpansion; + bool VisitedObjCPropertyImplDecl; + SourceLocation VisitedDeclaratorDeclStartLoc; + CXCursor &BestCursor; + + GetCursorData(SourceManager &SM, SourceLocation tokenBegin, + CXCursor &outputCursor) + : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { + PointsAtMacroArgExpansion = SM.isMacroArgExpansion(tokenBegin); + VisitedObjCPropertyImplDecl = false; + } +}; + +static enum CXChildVisitResult +GetCursorVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { + GetCursorData *Data = static_cast<GetCursorData *>(client_data); + CXCursor *BestCursor = &Data->BestCursor; + + // If we point inside a macro argument we should provide info of what the + // token is so use the actual cursor, don't replace it with a macro expansion + // cursor. + if (cursor.kind == CXCursor_MacroExpansion && Data->PointsAtMacroArgExpansion) + return CXChildVisit_Recurse; + + if (clang_isDeclaration(cursor.kind)) { + // Avoid having the implicit methods override the property decls. + if (const ObjCMethodDecl *MD = + dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { + if (MD->isImplicit()) + return CXChildVisit_Break; + + } else if (const ObjCInterfaceDecl *ID = + dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(cursor))) { + // Check that when we have multiple @class references in the same line, + // that later ones do not override the previous ones. + // If we have: + // @class Foo, Bar; + // source ranges for both start at '@', so 'Bar' will end up overriding + // 'Foo' even though the cursor location was at 'Foo'. + if (BestCursor->kind == CXCursor_ObjCInterfaceDecl || + BestCursor->kind == CXCursor_ObjCClassRef) + if (const ObjCInterfaceDecl *PrevID = + dyn_cast_or_null<ObjCInterfaceDecl>( + getCursorDecl(*BestCursor))) { + if (PrevID != ID && !PrevID->isThisDeclarationADefinition() && + !ID->isThisDeclarationADefinition()) + return CXChildVisit_Break; + } + + } else if (const DeclaratorDecl *DD = + dyn_cast_or_null<DeclaratorDecl>(getCursorDecl(cursor))) { + SourceLocation StartLoc = DD->getSourceRange().getBegin(); + // Check that when we have multiple declarators in the same line, + // that later ones do not override the previous ones. + // If we have: + // int Foo, Bar; + // source ranges for both start at 'int', so 'Bar' will end up overriding + // 'Foo' even though the cursor location was at 'Foo'. + if (Data->VisitedDeclaratorDeclStartLoc == StartLoc) + return CXChildVisit_Break; + Data->VisitedDeclaratorDeclStartLoc = StartLoc; + + } else if (const ObjCPropertyImplDecl *PropImp = + dyn_cast_or_null<ObjCPropertyImplDecl>( + getCursorDecl(cursor))) { + (void)PropImp; + // Check that when we have multiple @synthesize in the same line, + // that later ones do not override the previous ones. + // If we have: + // @synthesize Foo, Bar; + // source ranges for both start at '@', so 'Bar' will end up overriding + // 'Foo' even though the cursor location was at 'Foo'. + if (Data->VisitedObjCPropertyImplDecl) + return CXChildVisit_Break; + Data->VisitedObjCPropertyImplDecl = true; + } + } + + if (clang_isExpression(cursor.kind) && + clang_isDeclaration(BestCursor->kind)) { + if (const Decl *D = getCursorDecl(*BestCursor)) { + // Avoid having the cursor of an expression replace the declaration cursor + // when the expression source range overlaps the declaration range. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl + // cursor. + if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() && + D->getLocation() == Data->TokenBeginLoc) + return CXChildVisit_Break; + } + } + + // If our current best cursor is the construction of a temporary object, + // don't replace that cursor with a type reference, because we want + // clang_getCursor() to point at the constructor. + if (clang_isExpression(BestCursor->kind) && + isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) && + cursor.kind == CXCursor_TypeRef) { + // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it + // as having the actual point on the type reference. + *BestCursor = getTypeRefedCallExprCursor(*BestCursor); + return CXChildVisit_Recurse; + } + + // If we already have an Objective-C superclass reference, don't + // update it further. + if (BestCursor->kind == CXCursor_ObjCSuperClassRef) + return CXChildVisit_Break; + + *BestCursor = cursor; + return CXChildVisit_Recurse; +} + +CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullCursor(); + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + SourceLocation SLoc = cxloc::translateSourceLocation(Loc); + CXCursor Result = cxcursor::getCursor(TU, SLoc); + + LOG_FUNC_SECTION { + CXFile SearchFile; + unsigned SearchLine, SearchColumn; + CXFile ResultFile; + unsigned ResultLine, ResultColumn; + CXString SearchFileName, ResultFileName, KindSpelling, USR; + const char *IsDef = clang_isCursorDefinition(Result) ? " (Definition)" : ""; + CXSourceLocation ResultLoc = clang_getCursorLocation(Result); + + clang_getFileLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, + nullptr); + clang_getFileLocation(ResultLoc, &ResultFile, &ResultLine, &ResultColumn, + nullptr); + SearchFileName = clang_getFileName(SearchFile); + ResultFileName = clang_getFileName(ResultFile); + KindSpelling = clang_getCursorKindSpelling(Result.kind); + USR = clang_getCursorUSR(Result); + *Log << llvm::format("(%s:%d:%d) = %s", clang_getCString(SearchFileName), + SearchLine, SearchColumn, + clang_getCString(KindSpelling)) + << llvm::format("(%s:%d:%d):%s%s", clang_getCString(ResultFileName), + ResultLine, ResultColumn, clang_getCString(USR), + IsDef); + clang_disposeString(SearchFileName); + clang_disposeString(ResultFileName); + clang_disposeString(KindSpelling); + clang_disposeString(USR); + + CXCursor Definition = clang_getCursorDefinition(Result); + if (!clang_equalCursors(Definition, clang_getNullCursor())) { + CXSourceLocation DefinitionLoc = clang_getCursorLocation(Definition); + CXString DefinitionKindSpelling = + clang_getCursorKindSpelling(Definition.kind); + CXFile DefinitionFile; + unsigned DefinitionLine, DefinitionColumn; + clang_getFileLocation(DefinitionLoc, &DefinitionFile, &DefinitionLine, + &DefinitionColumn, nullptr); + CXString DefinitionFileName = clang_getFileName(DefinitionFile); + *Log << llvm::format(" -> %s(%s:%d:%d)", + clang_getCString(DefinitionKindSpelling), + clang_getCString(DefinitionFileName), DefinitionLine, + DefinitionColumn); + clang_disposeString(DefinitionFileName); + clang_disposeString(DefinitionKindSpelling); + } + } + + return Result; +} + +CXCursor clang_getNullCursor(void) { + return MakeCXCursorInvalid(CXCursor_InvalidFile); +} + +unsigned clang_equalCursors(CXCursor X, CXCursor Y) { + // Clear out the "FirstInDeclGroup" part in a declaration cursor, since we + // can't set consistently. For example, when visiting a DeclStmt we will set + // it but we don't set it on the result of clang_getCursorDefinition for + // a reference of the same declaration. + // FIXME: Setting "FirstInDeclGroup" in CXCursors is a hack that only works + // when visiting a DeclStmt currently, the AST should be enhanced to be able + // to provide that kind of info. + if (clang_isDeclaration(X.kind)) + X.data[1] = nullptr; + if (clang_isDeclaration(Y.kind)) + Y.data[1] = nullptr; + + return X == Y; +} + +unsigned clang_hashCursor(CXCursor C) { + unsigned Index = 0; + if (clang_isExpression(C.kind) || clang_isStatement(C.kind)) + Index = 1; + + return llvm::DenseMapInfo<std::pair<unsigned, const void *>>::getHashValue( + std::make_pair(C.kind, C.data[Index])); +} + +unsigned clang_isInvalid(enum CXCursorKind K) { + return K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid; +} + +unsigned clang_isDeclaration(enum CXCursorKind K) { + return (K >= CXCursor_FirstDecl && K <= CXCursor_LastDecl) || + (K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl); +} + +unsigned clang_isInvalidDeclaration(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + if (const Decl *D = getCursorDecl(C)) + return D->isInvalidDecl(); + } + + return 0; +} + +unsigned clang_isReference(enum CXCursorKind K) { + return K >= CXCursor_FirstRef && K <= CXCursor_LastRef; +} + +unsigned clang_isExpression(enum CXCursorKind K) { + return K >= CXCursor_FirstExpr && K <= CXCursor_LastExpr; +} + +unsigned clang_isStatement(enum CXCursorKind K) { + return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; +} + +unsigned clang_isAttribute(enum CXCursorKind K) { + return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr; +} + +unsigned clang_isTranslationUnit(enum CXCursorKind K) { + return K == CXCursor_TranslationUnit; +} + +unsigned clang_isPreprocessing(enum CXCursorKind K) { + return K >= CXCursor_FirstPreprocessing && K <= CXCursor_LastPreprocessing; +} + +unsigned clang_isUnexposed(enum CXCursorKind K) { + switch (K) { + case CXCursor_UnexposedDecl: + case CXCursor_UnexposedExpr: + case CXCursor_UnexposedStmt: + case CXCursor_UnexposedAttr: + return true; + default: + return false; + } +} + +CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; } + +CXSourceLocation clang_getCursorLocation(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + std::pair<const ObjCInterfaceDecl *, SourceLocation> P = + getCursorObjCSuperClassRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCProtocolRef: { + std::pair<const ObjCProtocolDecl *, SourceLocation> P = + getCursorObjCProtocolRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_ObjCClassRef: { + std::pair<const ObjCInterfaceDecl *, SourceLocation> P = + getCursorObjCClassRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TypeRef: { + std::pair<const TypeDecl *, SourceLocation> P = getCursorTypeRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_TemplateRef: { + std::pair<const TemplateDecl *, SourceLocation> P = + getCursorTemplateRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_NamespaceRef: { + std::pair<const NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_MemberRef: { + std::pair<const FieldDecl *, SourceLocation> P = getCursorMemberRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_VariableRef: { + std::pair<const VarDecl *, SourceLocation> P = getCursorVariableRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_CXXBaseSpecifier: { + const CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C); + if (!BaseSpec) + return clang_getNullLocation(); + + if (TypeSourceInfo *TSInfo = BaseSpec->getTypeSourceInfo()) + return cxloc::translateSourceLocation( + getCursorContext(C), TSInfo->getTypeLoc().getBeginLoc()); + + return cxloc::translateSourceLocation(getCursorContext(C), + BaseSpec->getBeginLoc()); + } + + case CXCursor_LabelRef: { + std::pair<const LabelStmt *, SourceLocation> P = getCursorLabelRef(C); + return cxloc::translateSourceLocation(getCursorContext(C), P.second); + } + + case CXCursor_OverloadedDeclRef: + return cxloc::translateSourceLocation( + getCursorContext(C), getCursorOverloadedDeclRef(C).second); + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return cxloc::translateSourceLocation( + getCursorContext(C), getLocationFromExpr(getCursorExpr(C))); + + if (clang_isStatement(C.kind)) + return cxloc::translateSourceLocation(getCursorContext(C), + getCursorStmt(C)->getBeginLoc()); + + if (C.kind == CXCursor_PreprocessingDirective) { + SourceLocation L = cxcursor::getCursorPreprocessingDirective(C).getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_MacroExpansion) { + SourceLocation L = + cxcursor::getCursorMacroExpansion(C).getSourceRange().getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_MacroDefinition) { + SourceLocation L = cxcursor::getCursorMacroDefinition(C)->getLocation(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (C.kind == CXCursor_InclusionDirective) { + SourceLocation L = + cxcursor::getCursorInclusionDirective(C)->getSourceRange().getBegin(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (clang_isAttribute(C.kind)) { + SourceLocation L = cxcursor::getCursorAttr(C)->getLocation(); + return cxloc::translateSourceLocation(getCursorContext(C), L); + } + + if (!clang_isDeclaration(C.kind)) + return clang_getNullLocation(); + + const Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullLocation(); + + SourceLocation Loc = D->getLocation(); + // FIXME: Multiple variables declared in a single declaration + // currently lack the information needed to correctly determine their + // ranges when accounting for the type-specifier. We use context + // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, + // and if so, whether it is the first decl. + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + Loc = VD->getLocation(); + } + + // For ObjC methods, give the start location of the method name. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + Loc = MD->getSelectorStartLoc(); + + return cxloc::translateSourceLocation(getCursorContext(C), Loc); +} + +} // end extern "C" + +CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) { + assert(TU); + + // Guard against an invalid SourceLocation, or we may assert in one + // of the following calls. + if (SLoc.isInvalid()) + return clang_getNullCursor(); + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + + // Translate the given source location to make it point at the beginning of + // the token under the cursor. + SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), + CXXUnit->getASTContext().getLangOpts()); + + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); + if (SLoc.isValid()) { + GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result); + CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + SourceLocation(SLoc)); + CursorVis.visitFileRegion(); + } + + return Result; +} + +static SourceRange getRawCursorExtent(CXCursor C) { + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return getCursorObjCSuperClassRef(C).second; + + case CXCursor_ObjCProtocolRef: + return getCursorObjCProtocolRef(C).second; + + case CXCursor_ObjCClassRef: + return getCursorObjCClassRef(C).second; + + case CXCursor_TypeRef: + return getCursorTypeRef(C).second; + + case CXCursor_TemplateRef: + return getCursorTemplateRef(C).second; + + case CXCursor_NamespaceRef: + return getCursorNamespaceRef(C).second; + + case CXCursor_MemberRef: + return getCursorMemberRef(C).second; + + case CXCursor_CXXBaseSpecifier: + return getCursorCXXBaseSpecifier(C)->getSourceRange(); + + case CXCursor_LabelRef: + return getCursorLabelRef(C).second; + + case CXCursor_OverloadedDeclRef: + return getCursorOverloadedDeclRef(C).second; + + case CXCursor_VariableRef: + return getCursorVariableRef(C).second; + + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); + } + } + + if (clang_isExpression(C.kind)) + return getCursorExpr(C)->getSourceRange(); + + if (clang_isStatement(C.kind)) + return getCursorStmt(C)->getSourceRange(); + + if (clang_isAttribute(C.kind)) + return getCursorAttr(C)->getRange(); + + if (C.kind == CXCursor_PreprocessingDirective) + return cxcursor::getCursorPreprocessingDirective(C); + + if (C.kind == CXCursor_MacroExpansion) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = cxcursor::getCursorMacroExpansion(C).getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_MacroDefinition) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_InclusionDirective) { + ASTUnit *TU = getCursorASTUnit(C); + SourceRange Range = + cxcursor::getCursorInclusionDirective(C)->getSourceRange(); + return TU->mapRangeFromPreamble(Range); + } + + if (C.kind == CXCursor_TranslationUnit) { + ASTUnit *TU = getCursorASTUnit(C); + FileID MainID = TU->getSourceManager().getMainFileID(); + SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID); + SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID); + return SourceRange(Start, End); + } + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return SourceRange(); + + SourceRange R = D->getSourceRange(); + // FIXME: Multiple variables declared in a single declaration + // currently lack the information needed to correctly determine their + // ranges when accounting for the type-specifier. We use context + // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, + // and if so, whether it is the first decl. + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + R.setBegin(VD->getLocation()); + } + return R; + } + return SourceRange(); +} + +/// Retrieves the "raw" cursor extent, which is then extended to include +/// the decl-specifier-seq for declarations. +static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) { + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return SourceRange(); + + SourceRange R = D->getSourceRange(); + + // Adjust the start of the location for declarations preceded by + // declaration specifiers. + SourceLocation StartLoc; + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { + if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getBeginLoc(); + } else if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) { + if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo()) + StartLoc = TI->getTypeLoc().getBeginLoc(); + } + + if (StartLoc.isValid() && R.getBegin().isValid() && + SrcMgr.isBeforeInTranslationUnit(StartLoc, R.getBegin())) + R.setBegin(StartLoc); + + // FIXME: Multiple variables declared in a single declaration + // currently lack the information needed to correctly determine their + // ranges when accounting for the type-specifier. We use context + // stored in the CXCursor to determine if the VarDecl is in a DeclGroup, + // and if so, whether it is the first decl. + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!cxcursor::isFirstInDeclGroup(C)) + R.setBegin(VD->getLocation()); + } + + return R; + } + + return getRawCursorExtent(C); +} + +CXSourceRange clang_getCursorExtent(CXCursor C) { + SourceRange R = getRawCursorExtent(C); + if (R.isInvalid()) + return clang_getNullRange(); + + return cxloc::translateSourceRange(getCursorContext(C), R); +} + +CXCursor clang_getCursorReferenced(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); + + CXTranslationUnit tu = getCursorTU(C); + if (clang_isDeclaration(C.kind)) { + const Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + if (const UsingDecl *Using = dyn_cast<UsingDecl>(D)) + return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu); + if (const ObjCPropertyImplDecl *PropImpl = + dyn_cast<ObjCPropertyImplDecl>(D)) + if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) + return MakeCXCursor(Property, tu); + + return C; + } + + if (clang_isExpression(C.kind)) { + const Expr *E = getCursorExpr(C); + const Decl *D = getDeclFromExpr(E); + if (D) { + CXCursor declCursor = MakeCXCursor(D, tu); + declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C), + declCursor); + return declCursor; + } + + if (const OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E)) + return MakeCursorOverloadedDeclRef(Ovl, tu); + + return clang_getNullCursor(); + } + + if (clang_isStatement(C.kind)) { + const Stmt *S = getCursorStmt(C); + if (const GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S)) + if (LabelDecl *label = Goto->getLabel()) + if (LabelStmt *labelS = label->getStmt()) + return MakeCXCursor(labelS, getCursorDecl(C), tu); + + return clang_getNullCursor(); + } + + if (C.kind == CXCursor_MacroExpansion) { + if (const MacroDefinitionRecord *Def = + getCursorMacroExpansion(C).getDefinition()) + return MakeMacroDefinitionCursor(Def, tu); + } + + if (!clang_isReference(C.kind)) + return clang_getNullCursor(); + + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: + return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu); + + case CXCursor_ObjCProtocolRef: { + const ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first; + if (const ObjCProtocolDecl *Def = Prot->getDefinition()) + return MakeCXCursor(Def, tu); + + return MakeCXCursor(Prot, tu); + } + + case CXCursor_ObjCClassRef: { + const ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first; + if (const ObjCInterfaceDecl *Def = Class->getDefinition()) + return MakeCXCursor(Def, tu); + + return MakeCXCursor(Class, tu); + } + + case CXCursor_TypeRef: + return MakeCXCursor(getCursorTypeRef(C).first, tu); + + case CXCursor_TemplateRef: + return MakeCXCursor(getCursorTemplateRef(C).first, tu); + + case CXCursor_NamespaceRef: + return MakeCXCursor(getCursorNamespaceRef(C).first, tu); + + case CXCursor_MemberRef: + return MakeCXCursor(getCursorMemberRef(C).first, tu); + + case CXCursor_CXXBaseSpecifier: { + const CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); + return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), tu)); + } + + case CXCursor_LabelRef: + // FIXME: We end up faking the "parent" declaration here because we + // don't want to make CXCursor larger. + return MakeCXCursor( + getCursorLabelRef(C).first, + cxtu::getASTUnit(tu)->getASTContext().getTranslationUnitDecl(), tu); + + case CXCursor_OverloadedDeclRef: + return C; + + case CXCursor_VariableRef: + return MakeCXCursor(getCursorVariableRef(C).first, tu); + + default: + // We would prefer to enumerate all non-reference cursor kinds here. + llvm_unreachable("Unhandled reference cursor kind"); + } +} + +CXCursor clang_getCursorDefinition(CXCursor C) { + if (clang_isInvalid(C.kind)) + return clang_getNullCursor(); + + CXTranslationUnit TU = getCursorTU(C); + + bool WasReference = false; + if (clang_isReference(C.kind) || clang_isExpression(C.kind)) { + C = clang_getCursorReferenced(C); + WasReference = true; + } + + if (C.kind == CXCursor_MacroExpansion) + return clang_getCursorReferenced(C); + + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + const Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + switch (D->getKind()) { + // Declaration kinds that don't really separate the notions of + // declaration and definition. + case Decl::Namespace: + case Decl::Typedef: + case Decl::TypeAlias: + case Decl::TypeAliasTemplate: + case Decl::TemplateTypeParm: + case Decl::EnumConstant: + case Decl::Field: + case Decl::Binding: + case Decl::MSProperty: + case Decl::MSGuid: + case Decl::TemplateParamObject: + case Decl::IndirectField: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: + case Decl::ImplicitParam: + case Decl::ParmVar: + case Decl::NonTypeTemplateParm: + case Decl::TemplateTemplateParm: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::AccessSpec: + case Decl::LinkageSpec: + case Decl::Export: + case Decl::ObjCPropertyImpl: + case Decl::FileScopeAsm: + case Decl::StaticAssert: + case Decl::Block: + case Decl::Captured: + case Decl::OMPCapturedExpr: + case Decl::Label: // FIXME: Is this right?? + case Decl::ClassScopeFunctionSpecialization: + case Decl::CXXDeductionGuide: + case Decl::Import: + case Decl::OMPThreadPrivate: + case Decl::OMPAllocate: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: + case Decl::OMPRequires: + case Decl::ObjCTypeParam: + case Decl::BuiltinTemplate: + case Decl::PragmaComment: + case Decl::PragmaDetectMismatch: + case Decl::UsingPack: + case Decl::Concept: + case Decl::LifetimeExtendedTemporary: + case Decl::RequiresExprBody: + case Decl::UnresolvedUsingIfExists: + return C; + + // Declaration kinds that don't make any sense here, but are + // nonetheless harmless. + case Decl::Empty: + case Decl::TranslationUnit: + case Decl::ExternCContext: + break; + + // Declaration kinds for which the definition is not resolvable. + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + break; + + case Decl::UsingDirective: + return MakeCXCursor(cast<UsingDirectiveDecl>(D)->getNominatedNamespace(), + TU); + + case Decl::NamespaceAlias: + return MakeCXCursor(cast<NamespaceAliasDecl>(D)->getNamespace(), TU); + + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + if (TagDecl *Def = cast<TagDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + + case Decl::Function: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: { + const FunctionDecl *Def = nullptr; + if (cast<FunctionDecl>(D)->getBody(Def)) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + } + + case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: + case Decl::Decomposition: { + // Ask the variable if it has a definition. + if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + } + + case Decl::FunctionTemplate: { + const FunctionDecl *Def = nullptr; + if (cast<FunctionTemplateDecl>(D)->getTemplatedDecl()->getBody(Def)) + return MakeCXCursor(Def->getDescribedFunctionTemplate(), TU); + return clang_getNullCursor(); + } + + case Decl::ClassTemplate: { + if (RecordDecl *Def = + cast<ClassTemplateDecl>(D)->getTemplatedDecl()->getDefinition()) + return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + TU); + return clang_getNullCursor(); + } + + case Decl::VarTemplate: { + if (VarDecl *Def = + cast<VarTemplateDecl>(D)->getTemplatedDecl()->getDefinition()) + return MakeCXCursor(cast<VarDecl>(Def)->getDescribedVarTemplate(), TU); + return clang_getNullCursor(); + } + + case Decl::Using: + case Decl::UsingEnum: + return MakeCursorOverloadedDeclRef(cast<BaseUsingDecl>(D), D->getLocation(), + TU); + + case Decl::UsingShadow: + case Decl::ConstructorUsingShadow: + return clang_getCursorDefinition( + MakeCXCursor(cast<UsingShadowDecl>(D)->getTargetDecl(), TU)); + + case Decl::ObjCMethod: { + const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D); + if (Method->isThisDeclarationADefinition()) + return C; + + // Dig out the method definition in the associated + // @implementation, if we have it. + // FIXME: The ASTs should make finding the definition easier. + if (const ObjCInterfaceDecl *Class = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) + if (ObjCImplementationDecl *ClassImpl = Class->getImplementation()) + if (ObjCMethodDecl *Def = ClassImpl->getMethod( + Method->getSelector(), Method->isInstanceMethod())) + if (Def->isThisDeclarationADefinition()) + return MakeCXCursor(Def, TU); + + return clang_getNullCursor(); + } + + case Decl::ObjCCategory: + if (ObjCCategoryImplDecl *Impl = + cast<ObjCCategoryDecl>(D)->getImplementation()) + return MakeCXCursor(Impl, TU); + return clang_getNullCursor(); + + case Decl::ObjCProtocol: + if (const ObjCProtocolDecl *Def = + cast<ObjCProtocolDecl>(D)->getDefinition()) + return MakeCXCursor(Def, TU); + return clang_getNullCursor(); + + case Decl::ObjCInterface: { + // There are two notions of a "definition" for an Objective-C + // class: the interface and its implementation. When we resolved a + // reference to an Objective-C class, produce the @interface as + // the definition; when we were provided with the interface, + // produce the @implementation as the definition. + const ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D); + if (WasReference) { + if (const ObjCInterfaceDecl *Def = IFace->getDefinition()) + return MakeCXCursor(Def, TU); + } else if (ObjCImplementationDecl *Impl = IFace->getImplementation()) + return MakeCXCursor(Impl, TU); + return clang_getNullCursor(); + } + + case Decl::ObjCProperty: + // FIXME: We don't really know where to find the + // ObjCPropertyImplDecls that implement this property. + return clang_getNullCursor(); + + case Decl::ObjCCompatibleAlias: + if (const ObjCInterfaceDecl *Class = + cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) + if (const ObjCInterfaceDecl *Def = Class->getDefinition()) + return MakeCXCursor(Def, TU); + + return clang_getNullCursor(); + + case Decl::Friend: + if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); + return clang_getNullCursor(); + + case Decl::FriendTemplate: + if (NamedDecl *Friend = cast<FriendTemplateDecl>(D)->getFriendDecl()) + return clang_getCursorDefinition(MakeCXCursor(Friend, TU)); + return clang_getNullCursor(); + } + + return clang_getNullCursor(); +} + +unsigned clang_isCursorDefinition(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + return clang_getCursorDefinition(C) == C; +} + +CXCursor clang_getCanonicalCursor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return C; + + if (const Decl *D = getCursorDecl(C)) { + if (const ObjCCategoryImplDecl *CatImplD = + dyn_cast<ObjCCategoryImplDecl>(D)) + if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl()) + return MakeCXCursor(CatD, getCursorTU(C)); + + if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) + if (const ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + return MakeCXCursor(IFD, getCursorTU(C)); + + return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C)); + } + + return C; +} + +int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) { + return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first; +} + +unsigned clang_getNumOverloadedDecls(CXCursor C) { + if (C.kind != CXCursor_OverloadedDeclRef) + return 0; + + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first; + if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>()) + return E->getNumDecls(); + + if (OverloadedTemplateStorage *S = + Storage.dyn_cast<OverloadedTemplateStorage *>()) + return S->size(); + + const Decl *D = Storage.get<const Decl *>(); + if (const UsingDecl *Using = dyn_cast<UsingDecl>(D)) + return Using->shadow_size(); + + return 0; +} + +CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) { + if (cursor.kind != CXCursor_OverloadedDeclRef) + return clang_getNullCursor(); + + if (index >= clang_getNumOverloadedDecls(cursor)) + return clang_getNullCursor(); + + CXTranslationUnit TU = getCursorTU(cursor); + OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(cursor).first; + if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>()) + return MakeCXCursor(E->decls_begin()[index], TU); + + if (OverloadedTemplateStorage *S = + Storage.dyn_cast<OverloadedTemplateStorage *>()) + return MakeCXCursor(S->begin()[index], TU); + + const Decl *D = Storage.get<const Decl *>(); + if (const UsingDecl *Using = dyn_cast<UsingDecl>(D)) { + // FIXME: This is, unfortunately, linear time. + UsingDecl::shadow_iterator Pos = Using->shadow_begin(); + std::advance(Pos, index); + return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU); + } + + return clang_getNullCursor(); +} + +void clang_getDefinitionSpellingAndExtent( + CXCursor C, const char **startBuf, const char **endBuf, unsigned *startLine, + unsigned *startColumn, unsigned *endLine, unsigned *endColumn) { + assert(getCursorDecl(C) && "CXCursor has null decl"); + const FunctionDecl *FD = dyn_cast<FunctionDecl>(getCursorDecl(C)); + CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody()); + + SourceManager &SM = FD->getASTContext().getSourceManager(); + *startBuf = SM.getCharacterData(Body->getLBracLoc()); + *endBuf = SM.getCharacterData(Body->getRBracLoc()); + *startLine = SM.getSpellingLineNumber(Body->getLBracLoc()); + *startColumn = SM.getSpellingColumnNumber(Body->getLBracLoc()); + *endLine = SM.getSpellingLineNumber(Body->getRBracLoc()); + *endColumn = SM.getSpellingColumnNumber(Body->getRBracLoc()); +} + +CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags, + unsigned PieceIndex) { + RefNamePieces Pieces; + + switch (C.kind) { + case CXCursor_MemberRefExpr: + if (const MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C))) + Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(), + E->getQualifierLoc().getSourceRange()); + break; + + case CXCursor_DeclRefExpr: + if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) { + SourceRange TemplateArgLoc(E->getLAngleLoc(), E->getRAngleLoc()); + Pieces = + buildPieces(NameFlags, false, E->getNameInfo(), + E->getQualifierLoc().getSourceRange(), &TemplateArgLoc); + } + break; + + case CXCursor_CallExpr: + if (const CXXOperatorCallExpr *OCE = + dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) { + const Expr *Callee = OCE->getCallee(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) + Callee = ICE->getSubExpr(); + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) + Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(), + DRE->getQualifierLoc().getSourceRange()); + } + break; + + default: + break; + } + + if (Pieces.empty()) { + if (PieceIndex == 0) + return clang_getCursorExtent(C); + } else if (PieceIndex < Pieces.size()) { + SourceRange R = Pieces[PieceIndex]; + if (R.isValid()) + return cxloc::translateSourceRange(getCursorContext(C), R); + } + + return clang_getNullRange(); +} + +void clang_enableStackTraces(void) { + // FIXME: Provide an argv0 here so we can find llvm-symbolizer. + llvm::sys::PrintStackTraceOnErrorSignal(StringRef()); +} + +void clang_executeOnThread(void (*fn)(void *), void *user_data, + unsigned stack_size) { + llvm::thread Thread(stack_size == 0 ? clang::DesiredStackSize + : llvm::Optional<unsigned>(stack_size), + fn, user_data); + Thread.join(); +} + +//===----------------------------------------------------------------------===// +// Token-based Operations. +//===----------------------------------------------------------------------===// + +/* CXToken layout: + * int_data[0]: a CXTokenKind + * int_data[1]: starting token location + * int_data[2]: token length + * int_data[3]: reserved + * ptr_data: for identifiers and keywords, an IdentifierInfo*. + * otherwise unused. + */ +CXTokenKind clang_getTokenKind(CXToken CXTok) { + return static_cast<CXTokenKind>(CXTok.int_data[0]); +} + +CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) { + switch (clang_getTokenKind(CXTok)) { + case CXToken_Identifier: + case CXToken_Keyword: + // We know we have an IdentifierInfo*, so use that. + return cxstring::createRef( + static_cast<IdentifierInfo *>(CXTok.ptr_data)->getNameStart()); + + case CXToken_Literal: { + // We have stashed the starting pointer in the ptr_data field. Use it. + const char *Text = static_cast<const char *>(CXTok.ptr_data); + return cxstring::createDup(StringRef(Text, CXTok.int_data[2])); + } + + case CXToken_Punctuation: + case CXToken_Comment: + break; + } + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return cxstring::createEmpty(); + } + + // We have to find the starting buffer pointer the hard way, by + // deconstructing the source location. + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return cxstring::createEmpty(); + + SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]); + std::pair<FileID, unsigned> LocInfo = + CXXUnit->getSourceManager().getDecomposedSpellingLoc(Loc); + bool Invalid = false; + StringRef Buffer = + CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return cxstring::createEmpty(); + + return cxstring::createDup(Buffer.substr(LocInfo.second, CXTok.int_data[2])); +} + +CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullLocation(); + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return clang_getNullLocation(); + + return cxloc::translateSourceLocation( + CXXUnit->getASTContext(), + SourceLocation::getFromRawEncoding(CXTok.int_data[1])); +} + +CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullRange(); + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return clang_getNullRange(); + + return cxloc::translateSourceRange( + CXXUnit->getASTContext(), + SourceLocation::getFromRawEncoding(CXTok.int_data[1])); +} + +static void getTokens(ASTUnit *CXXUnit, SourceRange Range, + SmallVectorImpl<CXToken> &CXTokens) { + SourceManager &SourceMgr = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> BeginLocInfo = + SourceMgr.getDecomposedSpellingLoc(Range.getBegin()); + std::pair<FileID, unsigned> EndLocInfo = + SourceMgr.getDecomposedSpellingLoc(Range.getEnd()); + + // Cannot tokenize across files. + if (BeginLocInfo.first != EndLocInfo.first) + return; + + // Create a lexer + bool Invalid = false; + StringRef Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); + if (Invalid) + return; + + Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), + CXXUnit->getASTContext().getLangOpts(), Buffer.begin(), + Buffer.data() + BeginLocInfo.second, Buffer.end()); + Lex.SetCommentRetentionState(true); + + // Lex tokens until we hit the end of the range. + const char *EffectiveBufferEnd = Buffer.data() + EndLocInfo.second; + Token Tok; + bool previousWasAt = false; + do { + // Lex the next token + Lex.LexFromRawLexer(Tok); + if (Tok.is(tok::eof)) + break; + + // Initialize the CXToken. + CXToken CXTok; + + // - Common fields + CXTok.int_data[1] = Tok.getLocation().getRawEncoding(); + CXTok.int_data[2] = Tok.getLength(); + CXTok.int_data[3] = 0; + + // - Kind-specific fields + if (Tok.isLiteral()) { + CXTok.int_data[0] = CXToken_Literal; + CXTok.ptr_data = const_cast<char *>(Tok.getLiteralData()); + } else if (Tok.is(tok::raw_identifier)) { + // Lookup the identifier to determine whether we have a keyword. + IdentifierInfo *II = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok); + + if ((II->getObjCKeywordID() != tok::objc_not_keyword) && previousWasAt) { + CXTok.int_data[0] = CXToken_Keyword; + } else { + CXTok.int_data[0] = + Tok.is(tok::identifier) ? CXToken_Identifier : CXToken_Keyword; + } + CXTok.ptr_data = II; + } else if (Tok.is(tok::comment)) { + CXTok.int_data[0] = CXToken_Comment; + CXTok.ptr_data = nullptr; + } else { + CXTok.int_data[0] = CXToken_Punctuation; + CXTok.ptr_data = nullptr; + } + CXTokens.push_back(CXTok); + previousWasAt = Tok.is(tok::at); + } while (Lex.getBufferLocation() < EffectiveBufferEnd); +} + +CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) { + LOG_FUNC_SECTION { *Log << TU << ' ' << Location; } + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return nullptr; + + SourceLocation Begin = cxloc::translateSourceLocation(Location); + if (Begin.isInvalid()) + return nullptr; + SourceManager &SM = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> DecomposedEnd = SM.getDecomposedLoc(Begin); + DecomposedEnd.second += + Lexer::MeasureTokenLength(Begin, SM, CXXUnit->getLangOpts()); + + SourceLocation End = + SM.getComposedLoc(DecomposedEnd.first, DecomposedEnd.second); + + SmallVector<CXToken, 32> CXTokens; + getTokens(CXXUnit, SourceRange(Begin, End), CXTokens); + + if (CXTokens.empty()) + return nullptr; + + CXTokens.resize(1); + CXToken *Token = static_cast<CXToken *>(llvm::safe_malloc(sizeof(CXToken))); + + memmove(Token, CXTokens.data(), sizeof(CXToken)); + return Token; +} + +void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, CXToken **Tokens, + unsigned *NumTokens) { + LOG_FUNC_SECTION { *Log << TU << ' ' << Range; } + + if (Tokens) + *Tokens = nullptr; + if (NumTokens) + *NumTokens = 0; + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return; + } + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit || !Tokens || !NumTokens) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + SourceRange R = cxloc::translateCXSourceRange(Range); + if (R.isInvalid()) + return; + + SmallVector<CXToken, 32> CXTokens; + getTokens(CXXUnit, R, CXTokens); + + if (CXTokens.empty()) + return; + + *Tokens = static_cast<CXToken *>( + llvm::safe_malloc(sizeof(CXToken) * CXTokens.size())); + memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size()); + *NumTokens = CXTokens.size(); +} + +void clang_disposeTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens) { + free(Tokens); +} + +//===----------------------------------------------------------------------===// +// Token annotation APIs. +//===----------------------------------------------------------------------===// + +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data); +static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor, + CXClientData client_data); + +namespace { +class AnnotateTokensWorker { + CXToken *Tokens; + CXCursor *Cursors; + unsigned NumTokens; + unsigned TokIdx; + unsigned PreprocessingTokIdx; + CursorVisitor AnnotateVis; + SourceManager &SrcMgr; + bool HasContextSensitiveKeywords; + + struct PostChildrenAction { + CXCursor cursor; + enum Action { Invalid, Ignore, Postpone } action; + }; + using PostChildrenActions = SmallVector<PostChildrenAction, 0>; + + struct PostChildrenInfo { + CXCursor Cursor; + SourceRange CursorRange; + unsigned BeforeReachingCursorIdx; + unsigned BeforeChildrenTokenIdx; + PostChildrenActions ChildActions; + }; + SmallVector<PostChildrenInfo, 8> PostChildrenInfos; + + CXToken &getTok(unsigned Idx) { + assert(Idx < NumTokens); + return Tokens[Idx]; + } + const CXToken &getTok(unsigned Idx) const { + assert(Idx < NumTokens); + return Tokens[Idx]; + } + bool MoreTokens() const { return TokIdx < NumTokens; } + unsigned NextToken() const { return TokIdx; } + void AdvanceToken() { ++TokIdx; } + SourceLocation GetTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(getTok(tokI).int_data[1]); + } + bool isFunctionMacroToken(unsigned tokI) const { + return getTok(tokI).int_data[3] != 0; + } + SourceLocation getFunctionMacroTokenLoc(unsigned tokI) const { + return SourceLocation::getFromRawEncoding(getTok(tokI).int_data[3]); + } + + void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange); + bool annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult, + SourceRange); + +public: + AnnotateTokensWorker(CXToken *tokens, CXCursor *cursors, unsigned numTokens, + CXTranslationUnit TU, SourceRange RegionOfInterest) + : Tokens(tokens), Cursors(cursors), NumTokens(numTokens), TokIdx(0), + PreprocessingTokIdx(0), + AnnotateVis(TU, AnnotateTokensVisitor, this, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, RegionOfInterest, + /*VisitDeclsOnly=*/false, + AnnotateTokensPostChildrenVisitor), + SrcMgr(cxtu::getASTUnit(TU)->getSourceManager()), + HasContextSensitiveKeywords(false) {} + + void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); } + enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent); + bool IsIgnoredChildCursor(CXCursor cursor) const; + PostChildrenActions DetermineChildActions(CXCursor Cursor) const; + + bool postVisitChildren(CXCursor cursor); + void HandlePostPonedChildCursors(const PostChildrenInfo &Info); + void HandlePostPonedChildCursor(CXCursor Cursor, unsigned StartTokenIndex); + + void AnnotateTokens(); + + /// Determine whether the annotator saw any cursors that have + /// context-sensitive keywords. + bool hasContextSensitiveKeywords() const { + return HasContextSensitiveKeywords; + } + + ~AnnotateTokensWorker() { assert(PostChildrenInfos.empty()); } +}; +} // namespace + +void AnnotateTokensWorker::AnnotateTokens() { + // Walk the AST within the region of interest, annotating tokens + // along the way. + AnnotateVis.visitFileRegion(); +} + +bool AnnotateTokensWorker::IsIgnoredChildCursor(CXCursor cursor) const { + if (PostChildrenInfos.empty()) + return false; + + for (const auto &ChildAction : PostChildrenInfos.back().ChildActions) { + if (ChildAction.cursor == cursor && + ChildAction.action == PostChildrenAction::Ignore) { + return true; + } + } + + return false; +} + +const CXXOperatorCallExpr *GetSubscriptOrCallOperator(CXCursor Cursor) { + if (!clang_isExpression(Cursor.kind)) + return nullptr; + + const Expr *E = getCursorExpr(Cursor); + if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(E)) { + const OverloadedOperatorKind Kind = OCE->getOperator(); + if (Kind == OO_Call || Kind == OO_Subscript) + return OCE; + } + + return nullptr; +} + +AnnotateTokensWorker::PostChildrenActions +AnnotateTokensWorker::DetermineChildActions(CXCursor Cursor) const { + PostChildrenActions actions; + + // The DeclRefExpr of CXXOperatorCallExpr refering to the custom operator is + // visited before the arguments to the operator call. For the Call and + // Subscript operator the range of this DeclRefExpr includes the whole call + // expression, so that all tokens in that range would be mapped to the + // operator function, including the tokens of the arguments. To avoid that, + // ensure to visit this DeclRefExpr as last node. + if (const auto *OCE = GetSubscriptOrCallOperator(Cursor)) { + const Expr *Callee = OCE->getCallee(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee)) { + const Expr *SubExpr = ICE->getSubExpr(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + const Decl *parentDecl = getCursorDecl(Cursor); + CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor); + + // Visit the DeclRefExpr as last. + CXCursor cxChild = MakeCXCursor(DRE, parentDecl, TU); + actions.push_back({cxChild, PostChildrenAction::Postpone}); + + // The parent of the DeclRefExpr, an ImplicitCastExpr, has an equally + // wide range as the DeclRefExpr. We can skip visiting this entirely. + cxChild = MakeCXCursor(ICE, parentDecl, TU); + actions.push_back({cxChild, PostChildrenAction::Ignore}); + } + } + } + + return actions; +} + +static inline void updateCursorAnnotation(CXCursor &Cursor, + const CXCursor &updateC) { + if (clang_isInvalid(updateC.kind) || !clang_isInvalid(Cursor.kind)) + return; + Cursor = updateC; +} + +/// It annotates and advances tokens with a cursor until the comparison +//// between the cursor location and the source range is the same as +/// \arg compResult. +/// +/// Pass RangeBefore to annotate tokens with a cursor until a range is reached. +/// Pass RangeOverlap to annotate tokens inside a range. +void AnnotateTokensWorker::annotateAndAdvanceTokens( + CXCursor updateC, RangeComparisonResult compResult, SourceRange range) { + while (MoreTokens()) { + const unsigned I = NextToken(); + if (isFunctionMacroToken(I)) + if (!annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range)) + return; + + SourceLocation TokLoc = GetTokenLoc(I); + if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { + updateCursorAnnotation(Cursors[I], updateC); + AdvanceToken(); + continue; + } + break; + } +} + +/// Special annotation handling for macro argument tokens. +/// \returns true if it advanced beyond all macro tokens, false otherwise. +bool AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens( + CXCursor updateC, RangeComparisonResult compResult, SourceRange range) { + assert(MoreTokens()); + assert(isFunctionMacroToken(NextToken()) && + "Should be called only for macro arg tokens"); + + // This works differently than annotateAndAdvanceTokens; because expanded + // macro arguments can have arbitrary translation-unit source order, we do not + // advance the token index one by one until a token fails the range test. + // We only advance once past all of the macro arg tokens if all of them + // pass the range test. If one of them fails we keep the token index pointing + // at the start of the macro arg tokens so that the failing token will be + // annotated by a subsequent annotation try. + + bool atLeastOneCompFail = false; + + unsigned I = NextToken(); + for (; I < NumTokens && isFunctionMacroToken(I); ++I) { + SourceLocation TokLoc = getFunctionMacroTokenLoc(I); + if (TokLoc.isFileID()) + continue; // not macro arg token, it's parens or comma. + if (LocationCompare(SrcMgr, TokLoc, range) == compResult) { + if (clang_isInvalid(clang_getCursorKind(Cursors[I]))) + Cursors[I] = updateC; + } else + atLeastOneCompFail = true; + } + + if (atLeastOneCompFail) + return false; + + TokIdx = I; // All of the tokens were handled, advance beyond all of them. + return true; +} + +enum CXChildVisitResult AnnotateTokensWorker::Visit(CXCursor cursor, + CXCursor parent) { + SourceRange cursorRange = getRawCursorExtent(cursor); + if (cursorRange.isInvalid()) + return CXChildVisit_Recurse; + + if (IsIgnoredChildCursor(cursor)) + return CXChildVisit_Continue; + + if (!HasContextSensitiveKeywords) { + // Objective-C properties can have context-sensitive keywords. + if (cursor.kind == CXCursor_ObjCPropertyDecl) { + if (const ObjCPropertyDecl *Property = + dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor))) + HasContextSensitiveKeywords = + Property->getPropertyAttributesAsWritten() != 0; + } + // Objective-C methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl || + cursor.kind == CXCursor_ObjCClassMethodDecl) { + if (const ObjCMethodDecl *Method = + dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) { + if (Method->getObjCDeclQualifier()) + HasContextSensitiveKeywords = true; + else { + for (const auto *P : Method->parameters()) { + if (P->getObjCDeclQualifier()) { + HasContextSensitiveKeywords = true; + break; + } + } + } + } + } + // C++ methods can have context-sensitive keywords. + else if (cursor.kind == CXCursor_CXXMethod) { + if (const CXXMethodDecl *Method = + dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) { + if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>()) + HasContextSensitiveKeywords = true; + } + } + // C++ classes can have context-sensitive keywords. + else if (cursor.kind == CXCursor_StructDecl || + cursor.kind == CXCursor_ClassDecl || + cursor.kind == CXCursor_ClassTemplate || + cursor.kind == CXCursor_ClassTemplatePartialSpecialization) { + if (const Decl *D = getCursorDecl(cursor)) + if (D->hasAttr<FinalAttr>()) + HasContextSensitiveKeywords = true; + } + } + + // Don't override a property annotation with its getter/setter method. + if (cursor.kind == CXCursor_ObjCInstanceMethodDecl && + parent.kind == CXCursor_ObjCPropertyDecl) + return CXChildVisit_Continue; + + if (clang_isPreprocessing(cursor.kind)) { + // Items in the preprocessing record are kept separate from items in + // declarations, so we keep a separate token index. + unsigned SavedTokIdx = TokIdx; + TokIdx = PreprocessingTokIdx; + + // Skip tokens up until we catch up to the beginning of the preprocessing + // entry. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + AdvanceToken(); + continue; + case RangeAfter: + case RangeOverlap: + break; + } + break; + } + + // Look at all of the tokens within this range. + while (MoreTokens()) { + const unsigned I = NextToken(); + SourceLocation TokLoc = GetTokenLoc(I); + switch (LocationCompare(SrcMgr, TokLoc, cursorRange)) { + case RangeBefore: + llvm_unreachable("Infeasible"); + case RangeAfter: + break; + case RangeOverlap: + // For macro expansions, just note where the beginning of the macro + // expansion occurs. + if (cursor.kind == CXCursor_MacroExpansion) { + if (TokLoc == cursorRange.getBegin()) + Cursors[I] = cursor; + AdvanceToken(); + break; + } + // We may have already annotated macro names inside macro definitions. + if (Cursors[I].kind != CXCursor_MacroExpansion) + Cursors[I] = cursor; + AdvanceToken(); + continue; + } + break; + } + + // Save the preprocessing token index; restore the non-preprocessing + // token index. + PreprocessingTokIdx = TokIdx; + TokIdx = SavedTokIdx; + return CXChildVisit_Recurse; + } + + if (cursorRange.isInvalid()) + return CXChildVisit_Continue; + + unsigned BeforeReachingCursorIdx = NextToken(); + const enum CXCursorKind cursorK = clang_getCursorKind(cursor); + const enum CXCursorKind K = clang_getCursorKind(parent); + const CXCursor updateC = + (clang_isInvalid(K) || K == CXCursor_TranslationUnit || + // Attributes are annotated out-of-order, skip tokens until we reach it. + clang_isAttribute(cursor.kind)) + ? clang_getNullCursor() + : parent; + + annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange); + + // Avoid having the cursor of an expression "overwrite" the annotation of the + // variable declaration that it belongs to. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor. + if (clang_isExpression(cursorK) && MoreTokens()) { + const Expr *E = getCursorExpr(cursor); + if (const Decl *D = getCursorDecl(cursor)) { + const unsigned I = NextToken(); + if (E->getBeginLoc().isValid() && D->getLocation().isValid() && + E->getBeginLoc() == D->getLocation() && + E->getBeginLoc() == GetTokenLoc(I)) { + updateCursorAnnotation(Cursors[I], updateC); + AdvanceToken(); + } + } + } + + // Before recursing into the children keep some state that we are going + // to use in the AnnotateTokensWorker::postVisitChildren callback to do some + // extra work after the child nodes are visited. + // Note that we don't call VisitChildren here to avoid traversing statements + // code-recursively which can blow the stack. + + PostChildrenInfo Info; + Info.Cursor = cursor; + Info.CursorRange = cursorRange; + Info.BeforeReachingCursorIdx = BeforeReachingCursorIdx; + Info.BeforeChildrenTokenIdx = NextToken(); + Info.ChildActions = DetermineChildActions(cursor); + PostChildrenInfos.push_back(Info); + + return CXChildVisit_Recurse; +} + +bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) { + if (PostChildrenInfos.empty()) + return false; + const PostChildrenInfo &Info = PostChildrenInfos.back(); + if (!clang_equalCursors(Info.Cursor, cursor)) + return false; + + HandlePostPonedChildCursors(Info); + + const unsigned BeforeChildren = Info.BeforeChildrenTokenIdx; + const unsigned AfterChildren = NextToken(); + SourceRange cursorRange = Info.CursorRange; + + // Scan the tokens that are at the end of the cursor, but are not captured + // but the child cursors. + annotateAndAdvanceTokens(cursor, RangeOverlap, cursorRange); + + // Scan the tokens that are at the beginning of the cursor, but are not + // capture by the child cursors. + for (unsigned I = BeforeChildren; I != AfterChildren; ++I) { + if (!clang_isInvalid(clang_getCursorKind(Cursors[I]))) + break; + + Cursors[I] = cursor; + } + + // Attributes are annotated out-of-order, rewind TokIdx to when we first + // encountered the attribute cursor. + if (clang_isAttribute(cursor.kind)) + TokIdx = Info.BeforeReachingCursorIdx; + + PostChildrenInfos.pop_back(); + return false; +} + +void AnnotateTokensWorker::HandlePostPonedChildCursors( + const PostChildrenInfo &Info) { + for (const auto &ChildAction : Info.ChildActions) { + if (ChildAction.action == PostChildrenAction::Postpone) { + HandlePostPonedChildCursor(ChildAction.cursor, + Info.BeforeChildrenTokenIdx); + } + } +} + +void AnnotateTokensWorker::HandlePostPonedChildCursor( + CXCursor Cursor, unsigned StartTokenIndex) { + unsigned I = StartTokenIndex; + + // The bracket tokens of a Call or Subscript operator are mapped to + // CallExpr/CXXOperatorCallExpr because we skipped visiting the corresponding + // DeclRefExpr. Remap these tokens to the DeclRefExpr cursors. + for (unsigned RefNameRangeNr = 0; I < NumTokens; RefNameRangeNr++) { + const CXSourceRange CXRefNameRange = clang_getCursorReferenceNameRange( + Cursor, CXNameRange_WantQualifier, RefNameRangeNr); + if (clang_Range_isNull(CXRefNameRange)) + break; // All ranges handled. + + SourceRange RefNameRange = cxloc::translateCXSourceRange(CXRefNameRange); + while (I < NumTokens) { + const SourceLocation TokenLocation = GetTokenLoc(I); + if (!TokenLocation.isValid()) + break; + + // Adapt the end range, because LocationCompare() reports + // RangeOverlap even for the not-inclusive end location. + const SourceLocation fixedEnd = + RefNameRange.getEnd().getLocWithOffset(-1); + RefNameRange = SourceRange(RefNameRange.getBegin(), fixedEnd); + + const RangeComparisonResult ComparisonResult = + LocationCompare(SrcMgr, TokenLocation, RefNameRange); + + if (ComparisonResult == RangeOverlap) { + Cursors[I++] = Cursor; + } else if (ComparisonResult == RangeBefore) { + ++I; // Not relevant token, check next one. + } else if (ComparisonResult == RangeAfter) { + break; // All tokens updated for current range, check next. + } + } + } +} + +static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + return static_cast<AnnotateTokensWorker *>(client_data) + ->Visit(cursor, parent); +} + +static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor, + CXClientData client_data) { + return static_cast<AnnotateTokensWorker *>(client_data) + ->postVisitChildren(cursor); +} + +namespace { + +/// Uses the macro expansions in the preprocessing record to find +/// and mark tokens that are macro arguments. This info is used by the +/// AnnotateTokensWorker. +class MarkMacroArgTokensVisitor { + SourceManager &SM; + CXToken *Tokens; + unsigned NumTokens; + unsigned CurIdx; + +public: + MarkMacroArgTokensVisitor(SourceManager &SM, CXToken *tokens, + unsigned numTokens) + : SM(SM), Tokens(tokens), NumTokens(numTokens), CurIdx(0) {} + + CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { + if (cursor.kind != CXCursor_MacroExpansion) + return CXChildVisit_Continue; + + SourceRange macroRange = getCursorMacroExpansion(cursor).getSourceRange(); + if (macroRange.getBegin() == macroRange.getEnd()) + return CXChildVisit_Continue; // it's not a function macro. + + for (; CurIdx < NumTokens; ++CurIdx) { + if (!SM.isBeforeInTranslationUnit(getTokenLoc(CurIdx), + macroRange.getBegin())) + break; + } + + if (CurIdx == NumTokens) + return CXChildVisit_Break; + + for (; CurIdx < NumTokens; ++CurIdx) { + SourceLocation tokLoc = getTokenLoc(CurIdx); + if (!SM.isBeforeInTranslationUnit(tokLoc, macroRange.getEnd())) + break; + + setFunctionMacroTokenLoc(CurIdx, SM.getMacroArgExpandedLocation(tokLoc)); + } + + if (CurIdx == NumTokens) + return CXChildVisit_Break; + + return CXChildVisit_Continue; + } + +private: + CXToken &getTok(unsigned Idx) { + assert(Idx < NumTokens); + return Tokens[Idx]; + } + const CXToken &getTok(unsigned Idx) const { + assert(Idx < NumTokens); + return Tokens[Idx]; + } + + SourceLocation getTokenLoc(unsigned tokI) { + return SourceLocation::getFromRawEncoding(getTok(tokI).int_data[1]); + } + + void setFunctionMacroTokenLoc(unsigned tokI, SourceLocation loc) { + // The third field is reserved and currently not used. Use it here + // to mark macro arg expanded tokens with their expanded locations. + getTok(tokI).int_data[3] = loc.getRawEncoding(); + } +}; + +} // end anonymous namespace + +static CXChildVisitResult +MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + return static_cast<MarkMacroArgTokensVisitor *>(client_data) + ->visit(cursor, parent); +} + +/// Used by \c annotatePreprocessorTokens. +/// \returns true if lexing was finished, false otherwise. +static bool lexNext(Lexer &Lex, Token &Tok, unsigned &NextIdx, + unsigned NumTokens) { + if (NextIdx >= NumTokens) + return true; + + ++NextIdx; + Lex.LexFromRawLexer(Tok); + return Tok.is(tok::eof); +} + +static void annotatePreprocessorTokens(CXTranslationUnit TU, + SourceRange RegionOfInterest, + CXCursor *Cursors, CXToken *Tokens, + unsigned NumTokens) { + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + + Preprocessor &PP = CXXUnit->getPreprocessor(); + SourceManager &SourceMgr = CXXUnit->getSourceManager(); + std::pair<FileID, unsigned> BeginLocInfo = + SourceMgr.getDecomposedSpellingLoc(RegionOfInterest.getBegin()); + std::pair<FileID, unsigned> EndLocInfo = + SourceMgr.getDecomposedSpellingLoc(RegionOfInterest.getEnd()); + + if (BeginLocInfo.first != EndLocInfo.first) + return; + + StringRef Buffer; + bool Invalid = false; + Buffer = SourceMgr.getBufferData(BeginLocInfo.first, &Invalid); + if (Buffer.empty() || Invalid) + return; + + Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first), + CXXUnit->getASTContext().getLangOpts(), Buffer.begin(), + Buffer.data() + BeginLocInfo.second, Buffer.end()); + Lex.SetCommentRetentionState(true); + + unsigned NextIdx = 0; + // Lex tokens in raw mode until we hit the end of the range, to avoid + // entering #includes or expanding macros. + while (true) { + Token Tok; + if (lexNext(Lex, Tok, NextIdx, NumTokens)) + break; + unsigned TokIdx = NextIdx - 1; + assert(Tok.getLocation() == + SourceLocation::getFromRawEncoding(Tokens[TokIdx].int_data[1])); + + reprocess: + if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { + // We have found a preprocessing directive. Annotate the tokens + // appropriately. + // + // FIXME: Some simple tests here could identify macro definitions and + // #undefs, to provide specific cursor kinds for those. + + SourceLocation BeginLoc = Tok.getLocation(); + if (lexNext(Lex, Tok, NextIdx, NumTokens)) + break; + + MacroInfo *MI = nullptr; + if (Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "define") { + if (lexNext(Lex, Tok, NextIdx, NumTokens)) + break; + + if (Tok.is(tok::raw_identifier)) { + IdentifierInfo &II = + PP.getIdentifierTable().get(Tok.getRawIdentifier()); + SourceLocation MappedTokLoc = + CXXUnit->mapLocationToPreamble(Tok.getLocation()); + MI = getMacroInfo(II, MappedTokLoc, TU); + } + } + + bool finished = false; + do { + if (lexNext(Lex, Tok, NextIdx, NumTokens)) { + finished = true; + break; + } + // If we are in a macro definition, check if the token was ever a + // macro name and annotate it if that's the case. + if (MI) { + SourceLocation SaveLoc = Tok.getLocation(); + Tok.setLocation(CXXUnit->mapLocationToPreamble(SaveLoc)); + MacroDefinitionRecord *MacroDef = + checkForMacroInMacroDefinition(MI, Tok, TU); + Tok.setLocation(SaveLoc); + if (MacroDef) + Cursors[NextIdx - 1] = + MakeMacroExpansionCursor(MacroDef, Tok.getLocation(), TU); + } + } while (!Tok.isAtStartOfLine()); + + unsigned LastIdx = finished ? NextIdx - 1 : NextIdx - 2; + assert(TokIdx <= LastIdx); + SourceLocation EndLoc = + SourceLocation::getFromRawEncoding(Tokens[LastIdx].int_data[1]); + CXCursor Cursor = + MakePreprocessingDirectiveCursor(SourceRange(BeginLoc, EndLoc), TU); + + for (; TokIdx <= LastIdx; ++TokIdx) + updateCursorAnnotation(Cursors[TokIdx], Cursor); + + if (finished) + break; + goto reprocess; + } + } +} + +// This gets run a separate thread to avoid stack blowout. +static void clang_annotateTokensImpl(CXTranslationUnit TU, ASTUnit *CXXUnit, + CXToken *Tokens, unsigned NumTokens, + CXCursor *Cursors) { + CIndexer *CXXIdx = TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + // Determine the region of interest, which contains all of the tokens. + SourceRange RegionOfInterest; + RegionOfInterest.setBegin( + cxloc::translateSourceLocation(clang_getTokenLocation(TU, Tokens[0]))); + RegionOfInterest.setEnd(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, Tokens[NumTokens - 1]))); + + // Relex the tokens within the source range to look for preprocessing + // directives. + annotatePreprocessorTokens(TU, RegionOfInterest, Cursors, Tokens, NumTokens); + + // If begin location points inside a macro argument, set it to the expansion + // location so we can have the full context when annotating semantically. + { + SourceManager &SM = CXXUnit->getSourceManager(); + SourceLocation Loc = + SM.getMacroArgExpandedLocation(RegionOfInterest.getBegin()); + if (Loc.isMacroID()) + RegionOfInterest.setBegin(SM.getExpansionLoc(Loc)); + } + + if (CXXUnit->getPreprocessor().getPreprocessingRecord()) { + // Search and mark tokens that are macro argument expansions. + MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(), Tokens, + NumTokens); + CursorVisitor MacroArgMarker( + TU, MarkMacroArgTokensVisitorDelegate, &Visitor, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, RegionOfInterest); + MacroArgMarker.visitPreprocessedEntitiesInRegion(); + } + + // Annotate all of the source locations in the region of interest that map to + // a specific cursor. + AnnotateTokensWorker W(Tokens, Cursors, NumTokens, TU, RegionOfInterest); + + // FIXME: We use a ridiculous stack size here because the data-recursion + // algorithm uses a large stack frame than the non-data recursive version, + // and AnnotationTokensWorker currently transforms the data-recursion + // algorithm back into a traditional recursion by explicitly calling + // VisitChildren(). We will need to remove this explicit recursive call. + W.AnnotateTokens(); + + // If we ran into any entities that involve context-sensitive keywords, + // take another pass through the tokens to mark them as such. + if (W.hasContextSensitiveKeywords()) { + for (unsigned I = 0; I != NumTokens; ++I) { + if (clang_getTokenKind(Tokens[I]) != CXToken_Identifier) + continue; + + if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (const ObjCPropertyDecl *Property = + dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) { + if (Property->getPropertyAttributesAsWritten() != 0 && + llvm::StringSwitch<bool>(II->getName()) + .Case("readonly", true) + .Case("assign", true) + .Case("unsafe_unretained", true) + .Case("readwrite", true) + .Case("retain", true) + .Case("copy", true) + .Case("nonatomic", true) + .Case("atomic", true) + .Case("getter", true) + .Case("setter", true) + .Case("strong", true) + .Case("weak", true) + .Case("class", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + } + continue; + } + + if (Cursors[I].kind == CXCursor_ObjCInstanceMethodDecl || + Cursors[I].kind == CXCursor_ObjCClassMethodDecl) { + IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data); + if (llvm::StringSwitch<bool>(II->getName()) + .Case("in", true) + .Case("out", true) + .Case("inout", true) + .Case("oneway", true) + .Case("bycopy", true) + .Case("byref", true) + .Default(false)) + Tokens[I].int_data[0] = CXToken_Keyword; + continue; + } + + if (Cursors[I].kind == CXCursor_CXXFinalAttr || + Cursors[I].kind == CXCursor_CXXOverrideAttr) { + Tokens[I].int_data[0] = CXToken_Keyword; + continue; + } + } + } +} + +void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens, CXCursor *Cursors) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return; + } + if (NumTokens == 0 || !Tokens || !Cursors) { + LOG_FUNC_SECTION { *Log << "<null input>"; } + return; + } + + LOG_FUNC_SECTION { + *Log << TU << ' '; + CXSourceLocation bloc = clang_getTokenLocation(TU, Tokens[0]); + CXSourceLocation eloc = clang_getTokenLocation(TU, Tokens[NumTokens - 1]); + *Log << clang_getRange(bloc, eloc); + } + + // Any token we don't specifically annotate will have a NULL cursor. + CXCursor C = clang_getNullCursor(); + for (unsigned I = 0; I != NumTokens; ++I) + Cursors[I] = C; + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + auto AnnotateTokensImpl = [=]() { + clang_annotateTokensImpl(TU, CXXUnit, Tokens, NumTokens, Cursors); + }; + llvm::CrashRecoveryContext CRC; + if (!RunSafely(CRC, AnnotateTokensImpl, GetSafetyThreadStackSize() * 2)) { + fprintf(stderr, "libclang: crash detected while annotating tokens\n"); + } +} + +//===----------------------------------------------------------------------===// +// Operations for querying linkage of a cursor. +//===----------------------------------------------------------------------===// + +CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { + if (!clang_isDeclaration(cursor.kind)) + return CXLinkage_Invalid; + + const Decl *D = cxcursor::getCursorDecl(cursor); + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) + switch (ND->getLinkageInternal()) { + case NoLinkage: + case VisibleNoLinkage: + return CXLinkage_NoLinkage; + case ModuleInternalLinkage: + case InternalLinkage: + return CXLinkage_Internal; + case UniqueExternalLinkage: + return CXLinkage_UniqueExternal; + case ModuleLinkage: + case ExternalLinkage: + return CXLinkage_External; + }; + + return CXLinkage_Invalid; +} + +//===----------------------------------------------------------------------===// +// Operations for querying visibility of a cursor. +//===----------------------------------------------------------------------===// + +CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) { + if (!clang_isDeclaration(cursor.kind)) + return CXVisibility_Invalid; + + const Decl *D = cxcursor::getCursorDecl(cursor); + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) + switch (ND->getVisibility()) { + case HiddenVisibility: + return CXVisibility_Hidden; + case ProtectedVisibility: + return CXVisibility_Protected; + case DefaultVisibility: + return CXVisibility_Default; + }; + + return CXVisibility_Invalid; +} + +//===----------------------------------------------------------------------===// +// Operations for querying language of a cursor. +//===----------------------------------------------------------------------===// + +static CXLanguageKind getDeclLanguage(const Decl *D) { + if (!D) + return CXLanguage_C; + + switch (D->getKind()) { + default: + break; + case Decl::ImplicitParam: + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCIvar: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + case Decl::ObjCTypeParam: + return CXLanguage_ObjC; + case Decl::CXXConstructor: + case Decl::CXXConversion: + case Decl::CXXDestructor: + case Decl::CXXMethod: + case Decl::CXXRecord: + case Decl::ClassTemplate: + case Decl::ClassTemplatePartialSpecialization: + case Decl::ClassTemplateSpecialization: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::FunctionTemplate: + case Decl::LinkageSpec: + case Decl::Namespace: + case Decl::NamespaceAlias: + case Decl::NonTypeTemplateParm: + case Decl::StaticAssert: + case Decl::TemplateTemplateParm: + case Decl::TemplateTypeParm: + case Decl::UnresolvedUsingTypename: + case Decl::UnresolvedUsingValue: + case Decl::Using: + case Decl::UsingDirective: + case Decl::UsingShadow: + return CXLanguage_CPlusPlus; + } + + return CXLanguage_C; +} + +static CXAvailabilityKind getCursorAvailabilityForDecl(const Decl *D) { + if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()) + return CXAvailability_NotAvailable; + + switch (D->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D)) + return getCursorAvailabilityForDecl( + cast<Decl>(EnumConst->getDeclContext())); + return CXAvailability_Available; + + case AR_Deprecated: + return CXAvailability_Deprecated; + + case AR_Unavailable: + return CXAvailability_NotAvailable; + } + + llvm_unreachable("Unknown availability kind!"); +} + +enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + if (const Decl *D = cxcursor::getCursorDecl(cursor)) + return getCursorAvailabilityForDecl(D); + + return CXAvailability_Available; +} + +static CXVersion convertVersion(VersionTuple In) { + CXVersion Out = {-1, -1, -1}; + if (In.empty()) + return Out; + + Out.Major = In.getMajor(); + + Optional<unsigned> Minor = In.getMinor(); + if (Minor.hasValue()) + Out.Minor = *Minor; + else + return Out; + + Optional<unsigned> Subminor = In.getSubminor(); + if (Subminor.hasValue()) + Out.Subminor = *Subminor; + + return Out; +} + +static void getCursorPlatformAvailabilityForDecl( + const Decl *D, int *always_deprecated, CXString *deprecated_message, + int *always_unavailable, CXString *unavailable_message, + SmallVectorImpl<AvailabilityAttr *> &AvailabilityAttrs) { + bool HadAvailAttr = false; + for (auto A : D->attrs()) { + if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(A)) { + HadAvailAttr = true; + if (always_deprecated) + *always_deprecated = 1; + if (deprecated_message) { + clang_disposeString(*deprecated_message); + *deprecated_message = cxstring::createDup(Deprecated->getMessage()); + } + continue; + } + + if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(A)) { + HadAvailAttr = true; + if (always_unavailable) + *always_unavailable = 1; + if (unavailable_message) { + clang_disposeString(*unavailable_message); + *unavailable_message = cxstring::createDup(Unavailable->getMessage()); + } + continue; + } + + if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(A)) { + AvailabilityAttrs.push_back(Avail); + HadAvailAttr = true; + } + } + + if (!HadAvailAttr) + if (const EnumConstantDecl *EnumConst = dyn_cast<EnumConstantDecl>(D)) + return getCursorPlatformAvailabilityForDecl( + cast<Decl>(EnumConst->getDeclContext()), always_deprecated, + deprecated_message, always_unavailable, unavailable_message, + AvailabilityAttrs); + + if (AvailabilityAttrs.empty()) + return; + + llvm::sort( + AvailabilityAttrs, [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) { + return LHS->getPlatform()->getName() < RHS->getPlatform()->getName(); + }); + ASTContext &Ctx = D->getASTContext(); + auto It = std::unique( + AvailabilityAttrs.begin(), AvailabilityAttrs.end(), + [&Ctx](AvailabilityAttr *LHS, AvailabilityAttr *RHS) { + if (LHS->getPlatform() != RHS->getPlatform()) + return false; + + if (LHS->getIntroduced() == RHS->getIntroduced() && + LHS->getDeprecated() == RHS->getDeprecated() && + LHS->getObsoleted() == RHS->getObsoleted() && + LHS->getMessage() == RHS->getMessage() && + LHS->getReplacement() == RHS->getReplacement()) + return true; + + if ((!LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) || + (!LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) || + (!LHS->getObsoleted().empty() && !RHS->getObsoleted().empty())) + return false; + + if (LHS->getIntroduced().empty() && !RHS->getIntroduced().empty()) + LHS->setIntroduced(Ctx, RHS->getIntroduced()); + + if (LHS->getDeprecated().empty() && !RHS->getDeprecated().empty()) { + LHS->setDeprecated(Ctx, RHS->getDeprecated()); + if (LHS->getMessage().empty()) + LHS->setMessage(Ctx, RHS->getMessage()); + if (LHS->getReplacement().empty()) + LHS->setReplacement(Ctx, RHS->getReplacement()); + } + + if (LHS->getObsoleted().empty() && !RHS->getObsoleted().empty()) { + LHS->setObsoleted(Ctx, RHS->getObsoleted()); + if (LHS->getMessage().empty()) + LHS->setMessage(Ctx, RHS->getMessage()); + if (LHS->getReplacement().empty()) + LHS->setReplacement(Ctx, RHS->getReplacement()); + } + + return true; + }); + AvailabilityAttrs.erase(It, AvailabilityAttrs.end()); +} + +int clang_getCursorPlatformAvailability(CXCursor cursor, int *always_deprecated, + CXString *deprecated_message, + int *always_unavailable, + CXString *unavailable_message, + CXPlatformAvailability *availability, + int availability_size) { + if (always_deprecated) + *always_deprecated = 0; + if (deprecated_message) + *deprecated_message = cxstring::createEmpty(); + if (always_unavailable) + *always_unavailable = 0; + if (unavailable_message) + *unavailable_message = cxstring::createEmpty(); + + if (!clang_isDeclaration(cursor.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(cursor); + if (!D) + return 0; + + SmallVector<AvailabilityAttr *, 8> AvailabilityAttrs; + getCursorPlatformAvailabilityForDecl(D, always_deprecated, deprecated_message, + always_unavailable, unavailable_message, + AvailabilityAttrs); + for (const auto &Avail : + llvm::enumerate(llvm::makeArrayRef(AvailabilityAttrs) + .take_front(availability_size))) { + availability[Avail.index()].Platform = + cxstring::createDup(Avail.value()->getPlatform()->getName()); + availability[Avail.index()].Introduced = + convertVersion(Avail.value()->getIntroduced()); + availability[Avail.index()].Deprecated = + convertVersion(Avail.value()->getDeprecated()); + availability[Avail.index()].Obsoleted = + convertVersion(Avail.value()->getObsoleted()); + availability[Avail.index()].Unavailable = Avail.value()->getUnavailable(); + availability[Avail.index()].Message = + cxstring::createDup(Avail.value()->getMessage()); + } + + return AvailabilityAttrs.size(); +} + +void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) { + clang_disposeString(availability->Platform); + clang_disposeString(availability->Message); +} + +CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + return getDeclLanguage(cxcursor::getCursorDecl(cursor)); + + return CXLanguage_Invalid; +} + +CXTLSKind clang_getCursorTLSKind(CXCursor cursor) { + const Decl *D = cxcursor::getCursorDecl(cursor); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + switch (VD->getTLSKind()) { + case VarDecl::TLS_None: + return CXTLS_None; + case VarDecl::TLS_Dynamic: + return CXTLS_Dynamic; + case VarDecl::TLS_Static: + return CXTLS_Static; + } + } + + return CXTLS_None; +} + +/// If the given cursor is the "templated" declaration +/// describing a class or function template, return the class or +/// function template. +static const Decl *maybeGetTemplateCursor(const Decl *D) { + if (!D) + return nullptr; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FunctionTemplateDecl *FunTmpl = FD->getDescribedFunctionTemplate()) + return FunTmpl; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) + if (ClassTemplateDecl *ClassTmpl = RD->getDescribedClassTemplate()) + return ClassTmpl; + + return D; +} + +enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor C) { + StorageClass sc = SC_None; + const Decl *D = getCursorDecl(C); + if (D) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + sc = FD->getStorageClass(); + } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + sc = VD->getStorageClass(); + } else { + return CX_SC_Invalid; + } + } else { + return CX_SC_Invalid; + } + switch (sc) { + case SC_None: + return CX_SC_None; + case SC_Extern: + return CX_SC_Extern; + case SC_Static: + return CX_SC_Static; + case SC_PrivateExtern: + return CX_SC_PrivateExtern; + case SC_Auto: + return CX_SC_Auto; + case SC_Register: + return CX_SC_Register; + } + llvm_unreachable("Unhandled storage class!"); +} + +CXCursor clang_getCursorSemanticParent(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) { + if (const Decl *D = getCursorDecl(cursor)) { + const DeclContext *DC = D->getDeclContext(); + if (!DC) + return clang_getNullCursor(); + + return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), + getCursorTU(cursor)); + } + } + + if (clang_isStatement(cursor.kind) || clang_isExpression(cursor.kind)) { + if (const Decl *D = getCursorDecl(cursor)) + return MakeCXCursor(D, getCursorTU(cursor)); + } + + return clang_getNullCursor(); +} + +CXCursor clang_getCursorLexicalParent(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) { + if (const Decl *D = getCursorDecl(cursor)) { + const DeclContext *DC = D->getLexicalDeclContext(); + if (!DC) + return clang_getNullCursor(); + + return MakeCXCursor(maybeGetTemplateCursor(cast<Decl>(DC)), + getCursorTU(cursor)); + } + } + + // FIXME: Note that we can't easily compute the lexical context of a + // statement or expression, so we return nothing. + return clang_getNullCursor(); +} + +CXFile clang_getIncludedFile(CXCursor cursor) { + if (cursor.kind != CXCursor_InclusionDirective) + return nullptr; + + const InclusionDirective *ID = getCursorInclusionDirective(cursor); + return const_cast<FileEntry *>(ID->getFile()); +} + +unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved) { + if (C.kind != CXCursor_ObjCPropertyDecl) + return CXObjCPropertyAttr_noattr; + + unsigned Result = CXObjCPropertyAttr_noattr; + const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C)); + ObjCPropertyAttribute::Kind Attr = PD->getPropertyAttributesAsWritten(); + +#define SET_CXOBJCPROP_ATTR(A) \ + if (Attr & ObjCPropertyAttribute::kind_##A) \ + Result |= CXObjCPropertyAttr_##A + SET_CXOBJCPROP_ATTR(readonly); + SET_CXOBJCPROP_ATTR(getter); + SET_CXOBJCPROP_ATTR(assign); + SET_CXOBJCPROP_ATTR(readwrite); + SET_CXOBJCPROP_ATTR(retain); + SET_CXOBJCPROP_ATTR(copy); + SET_CXOBJCPROP_ATTR(nonatomic); + SET_CXOBJCPROP_ATTR(setter); + SET_CXOBJCPROP_ATTR(atomic); + SET_CXOBJCPROP_ATTR(weak); + SET_CXOBJCPROP_ATTR(strong); + SET_CXOBJCPROP_ATTR(unsafe_unretained); + SET_CXOBJCPROP_ATTR(class); +#undef SET_CXOBJCPROP_ATTR + + return Result; +} + +CXString clang_Cursor_getObjCPropertyGetterName(CXCursor C) { + if (C.kind != CXCursor_ObjCPropertyDecl) + return cxstring::createNull(); + + const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C)); + Selector sel = PD->getGetterName(); + if (sel.isNull()) + return cxstring::createNull(); + + return cxstring::createDup(sel.getAsString()); +} + +CXString clang_Cursor_getObjCPropertySetterName(CXCursor C) { + if (C.kind != CXCursor_ObjCPropertyDecl) + return cxstring::createNull(); + + const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(getCursorDecl(C)); + Selector sel = PD->getSetterName(); + if (sel.isNull()) + return cxstring::createNull(); + + return cxstring::createDup(sel.getAsString()); +} + +unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return CXObjCDeclQualifier_None; + + Decl::ObjCDeclQualifier QT = Decl::OBJC_TQ_None; + const Decl *D = getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + QT = MD->getObjCDeclQualifier(); + else if (const ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D)) + QT = PD->getObjCDeclQualifier(); + if (QT == Decl::OBJC_TQ_None) + return CXObjCDeclQualifier_None; + + unsigned Result = CXObjCDeclQualifier_None; + if (QT & Decl::OBJC_TQ_In) + Result |= CXObjCDeclQualifier_In; + if (QT & Decl::OBJC_TQ_Inout) + Result |= CXObjCDeclQualifier_Inout; + if (QT & Decl::OBJC_TQ_Out) + Result |= CXObjCDeclQualifier_Out; + if (QT & Decl::OBJC_TQ_Bycopy) + Result |= CXObjCDeclQualifier_Bycopy; + if (QT & Decl::OBJC_TQ_Byref) + Result |= CXObjCDeclQualifier_Byref; + if (QT & Decl::OBJC_TQ_Oneway) + Result |= CXObjCDeclQualifier_Oneway; + + return Result; +} + +unsigned clang_Cursor_isObjCOptional(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = getCursorDecl(C); + if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) + return PD->getPropertyImplementation() == ObjCPropertyDecl::Optional; + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->getImplementationControl() == ObjCMethodDecl::Optional; + + return 0; +} + +unsigned clang_Cursor_isVariadic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = getCursorDecl(C); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->isVariadic(); + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->isVariadic(); + + return 0; +} + +unsigned clang_Cursor_isExternalSymbol(CXCursor C, CXString *language, + CXString *definedIn, + unsigned *isGenerated) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = getCursorDecl(C); + + if (auto *attr = D->getExternalSourceSymbolAttr()) { + if (language) + *language = cxstring::createDup(attr->getLanguage()); + if (definedIn) + *definedIn = cxstring::createDup(attr->getDefinedIn()); + if (isGenerated) + *isGenerated = attr->getGeneratedDeclaration(); + return 1; + } + return 0; +} + +CXSourceRange clang_Cursor_getCommentRange(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getNullRange(); + + const Decl *D = getCursorDecl(C); + ASTContext &Context = getCursorContext(C); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); + if (!RC) + return clang_getNullRange(); + + return cxloc::translateSourceRange(Context, RC->getSourceRange()); +} + +CXString clang_Cursor_getRawCommentText(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return cxstring::createNull(); + + const Decl *D = getCursorDecl(C); + ASTContext &Context = getCursorContext(C); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); + StringRef RawText = + RC ? RC->getRawText(Context.getSourceManager()) : StringRef(); + + // Don't duplicate the string because RawText points directly into source + // code. + return cxstring::createRef(RawText); +} + +CXString clang_Cursor_getBriefCommentText(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return cxstring::createNull(); + + const Decl *D = getCursorDecl(C); + const ASTContext &Context = getCursorContext(C); + const RawComment *RC = Context.getRawCommentForAnyRedecl(D); + + if (RC) { + StringRef BriefText = RC->getBriefText(Context); + + // Don't duplicate the string because RawComment ensures that this memory + // will not go away. + return cxstring::createRef(BriefText); + } + + return cxstring::createNull(); +} + +CXModule clang_Cursor_getModule(CXCursor C) { + if (C.kind == CXCursor_ModuleImportDecl) { + if (const ImportDecl *ImportD = + dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) + return ImportD->getImportedModule(); + } + + return nullptr; +} + +CXModule clang_getModuleForFile(CXTranslationUnit TU, CXFile File) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + if (!File) + return nullptr; + FileEntry *FE = static_cast<FileEntry *>(File); + + ASTUnit &Unit = *cxtu::getASTUnit(TU); + HeaderSearch &HS = Unit.getPreprocessor().getHeaderSearchInfo(); + ModuleMap::KnownHeader Header = HS.findModuleForHeader(FE); + + return Header.getModule(); +} + +CXFile clang_Module_getASTFile(CXModule CXMod) { + if (!CXMod) + return nullptr; + Module *Mod = static_cast<Module *>(CXMod); + if (auto File = Mod->getASTFile()) + return const_cast<FileEntry *>(&File->getFileEntry()); + return nullptr; +} + +CXModule clang_Module_getParent(CXModule CXMod) { + if (!CXMod) + return nullptr; + Module *Mod = static_cast<Module *>(CXMod); + return Mod->Parent; +} + +CXString clang_Module_getName(CXModule CXMod) { + if (!CXMod) + return cxstring::createEmpty(); + Module *Mod = static_cast<Module *>(CXMod); + return cxstring::createDup(Mod->Name); +} + +CXString clang_Module_getFullName(CXModule CXMod) { + if (!CXMod) + return cxstring::createEmpty(); + Module *Mod = static_cast<Module *>(CXMod); + return cxstring::createDup(Mod->getFullModuleName()); +} + +int clang_Module_isSystem(CXModule CXMod) { + if (!CXMod) + return 0; + Module *Mod = static_cast<Module *>(CXMod); + return Mod->IsSystem; +} + +unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit TU, + CXModule CXMod) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return 0; + } + if (!CXMod) + return 0; + Module *Mod = static_cast<Module *>(CXMod); + FileManager &FileMgr = cxtu::getASTUnit(TU)->getFileManager(); + ArrayRef<const FileEntry *> TopHeaders = Mod->getTopHeaders(FileMgr); + return TopHeaders.size(); +} + +CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU, CXModule CXMod, + unsigned Index) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + if (!CXMod) + return nullptr; + Module *Mod = static_cast<Module *>(CXMod); + FileManager &FileMgr = cxtu::getASTUnit(TU)->getFileManager(); + + ArrayRef<const FileEntry *> TopHeaders = Mod->getTopHeaders(FileMgr); + if (Index < TopHeaders.size()) + return const_cast<FileEntry *>(TopHeaders[Index]); + + return nullptr; +} + +//===----------------------------------------------------------------------===// +// C++ AST instrospection. +//===----------------------------------------------------------------------===// + +unsigned clang_CXXConstructor_isDefaultConstructor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXConstructorDecl *Constructor = + D ? dyn_cast_or_null<CXXConstructorDecl>(D->getAsFunction()) : nullptr; + return (Constructor && Constructor->isDefaultConstructor()) ? 1 : 0; +} + +unsigned clang_CXXConstructor_isCopyConstructor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXConstructorDecl *Constructor = + D ? dyn_cast_or_null<CXXConstructorDecl>(D->getAsFunction()) : nullptr; + return (Constructor && Constructor->isCopyConstructor()) ? 1 : 0; +} + +unsigned clang_CXXConstructor_isMoveConstructor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXConstructorDecl *Constructor = + D ? dyn_cast_or_null<CXXConstructorDecl>(D->getAsFunction()) : nullptr; + return (Constructor && Constructor->isMoveConstructor()) ? 1 : 0; +} + +unsigned clang_CXXConstructor_isConvertingConstructor(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXConstructorDecl *Constructor = + D ? dyn_cast_or_null<CXXConstructorDecl>(D->getAsFunction()) : nullptr; + // Passing 'false' excludes constructors marked 'explicit'. + return (Constructor && Constructor->isConvertingConstructor(false)) ? 1 : 0; +} + +unsigned clang_CXXField_isMutable(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + if (const auto D = cxcursor::getCursorDecl(C)) + if (const auto FD = dyn_cast_or_null<FieldDecl>(D)) + return FD->isMutable() ? 1 : 0; + return 0; +} + +unsigned clang_CXXMethod_isPureVirtual(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->isVirtual() && Method->isPure()) ? 1 : 0; +} + +unsigned clang_CXXMethod_isConst(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->getMethodQualifiers().hasConst()) ? 1 : 0; +} + +unsigned clang_CXXMethod_isDefaulted(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->isDefaulted()) ? 1 : 0; +} + +unsigned clang_CXXMethod_isStatic(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->isStatic()) ? 1 : 0; +} + +unsigned clang_CXXMethod_isVirtual(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + const CXXMethodDecl *Method = + D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr; + return (Method && Method->isVirtual()) ? 1 : 0; +} + +unsigned clang_CXXRecord_isAbstract(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const auto *D = cxcursor::getCursorDecl(C); + const auto *RD = dyn_cast_or_null<CXXRecordDecl>(D); + if (RD) + RD = RD->getDefinition(); + return (RD && RD->isAbstract()) ? 1 : 0; +} + +unsigned clang_EnumDecl_isScoped(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + auto *Enum = dyn_cast_or_null<EnumDecl>(D); + return (Enum && Enum->isScoped()) ? 1 : 0; +} + +//===----------------------------------------------------------------------===// +// Attribute introspection. +//===----------------------------------------------------------------------===// + +CXType clang_getIBOutletCollectionType(CXCursor C) { + if (C.kind != CXCursor_IBOutletCollectionAttr) + return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C)); + + const IBOutletCollectionAttr *A = + cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C)); + + return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C)); +} + +//===----------------------------------------------------------------------===// +// Inspecting memory usage. +//===----------------------------------------------------------------------===// + +typedef std::vector<CXTUResourceUsageEntry> MemUsageEntries; + +static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries, + enum CXTUResourceUsageKind k, + unsigned long amount) { + CXTUResourceUsageEntry entry = {k, amount}; + entries.push_back(entry); +} + +const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) { + const char *str = ""; + switch (kind) { + case CXTUResourceUsage_AST: + str = "ASTContext: expressions, declarations, and types"; + break; + case CXTUResourceUsage_Identifiers: + str = "ASTContext: identifiers"; + break; + case CXTUResourceUsage_Selectors: + str = "ASTContext: selectors"; + break; + case CXTUResourceUsage_GlobalCompletionResults: + str = "Code completion: cached global results"; + break; + case CXTUResourceUsage_SourceManagerContentCache: + str = "SourceManager: content cache allocator"; + break; + case CXTUResourceUsage_AST_SideTables: + str = "ASTContext: side tables"; + break; + case CXTUResourceUsage_SourceManager_Membuffer_Malloc: + str = "SourceManager: malloc'ed memory buffers"; + break; + case CXTUResourceUsage_SourceManager_Membuffer_MMap: + str = "SourceManager: mmap'ed memory buffers"; + break; + case CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc: + str = "ExternalASTSource: malloc'ed memory buffers"; + break; + case CXTUResourceUsage_ExternalASTSource_Membuffer_MMap: + str = "ExternalASTSource: mmap'ed memory buffers"; + break; + case CXTUResourceUsage_Preprocessor: + str = "Preprocessor: malloc'ed memory"; + break; + case CXTUResourceUsage_PreprocessingRecord: + str = "Preprocessor: PreprocessingRecord"; + break; + case CXTUResourceUsage_SourceManager_DataStructures: + str = "SourceManager: data structures and tables"; + break; + case CXTUResourceUsage_Preprocessor_HeaderSearch: + str = "Preprocessor: header search tables"; + break; + } + return str; +} + +CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) { + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + CXTUResourceUsage usage = {(void *)nullptr, 0, nullptr}; + return usage; + } + + ASTUnit *astUnit = cxtu::getASTUnit(TU); + std::unique_ptr<MemUsageEntries> entries(new MemUsageEntries()); + ASTContext &astContext = astUnit->getASTContext(); + + // How much memory is used by AST nodes and types? + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_AST, + (unsigned long)astContext.getASTAllocatedMemory()); + + // How much memory is used by identifiers? + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_Identifiers, + (unsigned long)astContext.Idents.getAllocator().getTotalMemory()); + + // How much memory is used for selectors? + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_Selectors, + (unsigned long)astContext.Selectors.getTotalMemory()); + + // How much memory is used by ASTContext's side tables? + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_AST_SideTables, + (unsigned long)astContext.getSideTableAllocatedMemory()); + + // How much memory is used for caching global code completion results? + unsigned long completionBytes = 0; + if (GlobalCodeCompletionAllocator *completionAllocator = + astUnit->getCachedCompletionAllocator().get()) { + completionBytes = completionAllocator->getTotalMemory(); + } + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_GlobalCompletionResults, completionBytes); + + // How much memory is being used by SourceManager's content cache? + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_SourceManagerContentCache, + (unsigned long)astContext.getSourceManager().getContentCacheSize()); + + // How much memory is being used by the MemoryBuffer's in SourceManager? + const SourceManager::MemoryBufferSizes &srcBufs = + astUnit->getSourceManager().getMemoryBufferSizes(); + + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManager_Membuffer_Malloc, + (unsigned long)srcBufs.malloc_bytes); + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_SourceManager_Membuffer_MMap, + (unsigned long)srcBufs.mmap_bytes); + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_SourceManager_DataStructures, + (unsigned long)astContext.getSourceManager().getDataStructureSizes()); + + // How much memory is being used by the ExternalASTSource? + if (ExternalASTSource *esrc = astContext.getExternalSource()) { + const ExternalASTSource::MemoryBufferSizes &sizes = + esrc->getMemoryBufferSizes(); + + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_ExternalASTSource_Membuffer_Malloc, + (unsigned long)sizes.malloc_bytes); + createCXTUResourceUsageEntry( + *entries, CXTUResourceUsage_ExternalASTSource_Membuffer_MMap, + (unsigned long)sizes.mmap_bytes); + } + + // How much memory is being used by the Preprocessor? + Preprocessor &pp = astUnit->getPreprocessor(); + createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Preprocessor, + pp.getTotalMemory()); + + if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) { + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_PreprocessingRecord, + pRec->getTotalMemory()); + } + + createCXTUResourceUsageEntry(*entries, + CXTUResourceUsage_Preprocessor_HeaderSearch, + pp.getHeaderSearchInfo().getTotalMemory()); + + CXTUResourceUsage usage = {(void *)entries.get(), (unsigned)entries->size(), + !entries->empty() ? &(*entries)[0] : nullptr}; + (void)entries.release(); + return usage; +} + +void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) { + if (usage.data) + delete (MemUsageEntries *)usage.data; +} + +CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) { + CXSourceRangeList *skipped = new CXSourceRangeList; + skipped->count = 0; + skipped->ranges = nullptr; + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return skipped; + } + + if (!file) + return skipped; + + ASTUnit *astUnit = cxtu::getASTUnit(TU); + PreprocessingRecord *ppRec = + astUnit->getPreprocessor().getPreprocessingRecord(); + if (!ppRec) + return skipped; + + ASTContext &Ctx = astUnit->getASTContext(); + SourceManager &sm = Ctx.getSourceManager(); + FileEntry *fileEntry = static_cast<FileEntry *>(file); + FileID wantedFileID = sm.translateFile(fileEntry); + bool isMainFile = wantedFileID == sm.getMainFileID(); + + const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges(); + std::vector<SourceRange> wantedRanges; + for (std::vector<SourceRange>::const_iterator i = SkippedRanges.begin(), + ei = SkippedRanges.end(); + i != ei; ++i) { + if (sm.getFileID(i->getBegin()) == wantedFileID || + sm.getFileID(i->getEnd()) == wantedFileID) + wantedRanges.push_back(*i); + else if (isMainFile && (astUnit->isInPreambleFileID(i->getBegin()) || + astUnit->isInPreambleFileID(i->getEnd()))) + wantedRanges.push_back(*i); + } + + skipped->count = wantedRanges.size(); + skipped->ranges = new CXSourceRange[skipped->count]; + for (unsigned i = 0, ei = skipped->count; i != ei; ++i) + skipped->ranges[i] = cxloc::translateSourceRange(Ctx, wantedRanges[i]); + + return skipped; +} + +CXSourceRangeList *clang_getAllSkippedRanges(CXTranslationUnit TU) { + CXSourceRangeList *skipped = new CXSourceRangeList; + skipped->count = 0; + skipped->ranges = nullptr; + + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return skipped; + } + + ASTUnit *astUnit = cxtu::getASTUnit(TU); + PreprocessingRecord *ppRec = + astUnit->getPreprocessor().getPreprocessingRecord(); + if (!ppRec) + return skipped; + + ASTContext &Ctx = astUnit->getASTContext(); + + const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges(); + + skipped->count = SkippedRanges.size(); + skipped->ranges = new CXSourceRange[skipped->count]; + for (unsigned i = 0, ei = skipped->count; i != ei; ++i) + skipped->ranges[i] = cxloc::translateSourceRange(Ctx, SkippedRanges[i]); + + return skipped; +} + +void clang_disposeSourceRangeList(CXSourceRangeList *ranges) { + if (ranges) { + delete[] ranges->ranges; + delete ranges; + } +} + +void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) { + CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU); + for (unsigned I = 0; I != Usage.numEntries; ++I) + fprintf(stderr, " %s: %lu\n", + clang_getTUResourceUsageName(Usage.entries[I].kind), + Usage.entries[I].amount); + + clang_disposeCXTUResourceUsage(Usage); +} + +CXCursor clang_Cursor_getVarDeclInitializer(CXCursor cursor) { + const Decl *const D = getCursorDecl(cursor); + if (!D) + return clang_getNullCursor(); + const auto *const VD = dyn_cast<VarDecl>(D); + if (!VD) + return clang_getNullCursor(); + const Expr *const Init = VD->getInit(); + if (!Init) + return clang_getNullCursor(); + + return cxcursor::MakeCXCursor(Init, VD, cxcursor::getCursorTU(cursor)); +} + +int clang_Cursor_hasVarDeclGlobalStorage(CXCursor cursor) { + const Decl *const D = getCursorDecl(cursor); + if (!D) + return -1; + const auto *const VD = dyn_cast<VarDecl>(D); + if (!VD) + return -1; + + return VD->hasGlobalStorage(); +} + +int clang_Cursor_hasVarDeclExternalStorage(CXCursor cursor) { + const Decl *const D = getCursorDecl(cursor); + if (!D) + return -1; + const auto *const VD = dyn_cast<VarDecl>(D); + if (!VD) + return -1; + + return VD->hasExternalStorage(); +} + +//===----------------------------------------------------------------------===// +// Misc. utility functions. +//===----------------------------------------------------------------------===// + +/// Default to using our desired 8 MB stack size on "safety" threads. +static unsigned SafetyStackThreadSize = DesiredStackSize; + +namespace clang { + +bool RunSafely(llvm::CrashRecoveryContext &CRC, llvm::function_ref<void()> Fn, + unsigned Size) { + if (!Size) + Size = GetSafetyThreadStackSize(); + if (Size && !getenv("LIBCLANG_NOTHREADS")) + return CRC.RunSafelyOnThread(Fn, Size); + return CRC.RunSafely(Fn); +} + +unsigned GetSafetyThreadStackSize() { return SafetyStackThreadSize; } + +void SetSafetyThreadStackSize(unsigned Value) { SafetyStackThreadSize = Value; } + +} // namespace clang + +void clang::setThreadBackgroundPriority() { + if (getenv("LIBCLANG_BGPRIO_DISABLE")) + return; + +#if LLVM_ENABLE_THREADS + llvm::set_thread_priority(llvm::ThreadPriority::Background); +#endif +} + +void cxindex::printDiagsToStderr(ASTUnit *Unit) { + if (!Unit) + return; + + for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(), + DEnd = Unit->stored_diag_end(); + D != DEnd; ++D) { + CXStoredDiagnostic Diag(*D, Unit->getLangOpts()); + CXString Msg = + clang_formatDiagnostic(&Diag, clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + } +#ifdef _WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif +} + +MacroInfo *cxindex::getMacroInfo(const IdentifierInfo &II, + SourceLocation MacroDefLoc, + CXTranslationUnit TU) { + if (MacroDefLoc.isInvalid() || !TU) + return nullptr; + if (!II.hadMacroDefinition()) + return nullptr; + + ASTUnit *Unit = cxtu::getASTUnit(TU); + Preprocessor &PP = Unit->getPreprocessor(); + MacroDirective *MD = PP.getLocalMacroDirectiveHistory(&II); + if (MD) { + for (MacroDirective::DefInfo Def = MD->getDefinition(); Def; + Def = Def.getPreviousDefinition()) { + if (MacroDefLoc == Def.getMacroInfo()->getDefinitionLoc()) + return Def.getMacroInfo(); + } + } + + return nullptr; +} + +const MacroInfo *cxindex::getMacroInfo(const MacroDefinitionRecord *MacroDef, + CXTranslationUnit TU) { + if (!MacroDef || !TU) + return nullptr; + const IdentifierInfo *II = MacroDef->getName(); + if (!II) + return nullptr; + + return getMacroInfo(*II, MacroDef->getLocation(), TU); +} + +MacroDefinitionRecord * +cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI, const Token &Tok, + CXTranslationUnit TU) { + if (!MI || !TU) + return nullptr; + if (Tok.isNot(tok::raw_identifier)) + return nullptr; + + if (MI->getNumTokens() == 0) + return nullptr; + SourceRange DefRange(MI->getReplacementToken(0).getLocation(), + MI->getDefinitionEndLoc()); + ASTUnit *Unit = cxtu::getASTUnit(TU); + + // Check that the token is inside the definition and not its argument list. + SourceManager &SM = Unit->getSourceManager(); + if (SM.isBeforeInTranslationUnit(Tok.getLocation(), DefRange.getBegin())) + return nullptr; + if (SM.isBeforeInTranslationUnit(DefRange.getEnd(), Tok.getLocation())) + return nullptr; + + Preprocessor &PP = Unit->getPreprocessor(); + PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); + if (!PPRec) + return nullptr; + + IdentifierInfo &II = PP.getIdentifierTable().get(Tok.getRawIdentifier()); + if (!II.hadMacroDefinition()) + return nullptr; + + // Check that the identifier is not one of the macro arguments. + if (llvm::is_contained(MI->params(), &II)) + return nullptr; + + MacroDirective *InnerMD = PP.getLocalMacroDirectiveHistory(&II); + if (!InnerMD) + return nullptr; + + return PPRec->findMacroDefinition(InnerMD->getMacroInfo()); +} + +MacroDefinitionRecord * +cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI, SourceLocation Loc, + CXTranslationUnit TU) { + if (Loc.isInvalid() || !MI || !TU) + return nullptr; + + if (MI->getNumTokens() == 0) + return nullptr; + ASTUnit *Unit = cxtu::getASTUnit(TU); + Preprocessor &PP = Unit->getPreprocessor(); + if (!PP.getPreprocessingRecord()) + return nullptr; + Loc = Unit->getSourceManager().getSpellingLoc(Loc); + Token Tok; + if (PP.getRawToken(Loc, Tok)) + return nullptr; + + return checkForMacroInMacroDefinition(MI, Tok, TU); +} + +CXString clang_getClangVersion() { + return cxstring::createDup(getClangFullVersion()); +} + +Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) { + if (TU) { + if (ASTUnit *Unit = cxtu::getASTUnit(TU)) { + LogOS << '<' << Unit->getMainFileName() << '>'; + if (Unit->isMainFileAST()) + LogOS << " (" << Unit->getASTFileName() << ')'; + return *this; + } + } else { + LogOS << "<NULL TU>"; + } + return *this; +} + +Logger &cxindex::Logger::operator<<(const FileEntry *FE) { + *this << FE->getName(); + return *this; +} + +Logger &cxindex::Logger::operator<<(CXCursor cursor) { + CXString cursorName = clang_getCursorDisplayName(cursor); + *this << cursorName << "@" << clang_getCursorLocation(cursor); + clang_disposeString(cursorName); + return *this; +} + +Logger &cxindex::Logger::operator<<(CXSourceLocation Loc) { + CXFile File; + unsigned Line, Column; + clang_getFileLocation(Loc, &File, &Line, &Column, nullptr); + CXString FileName = clang_getFileName(File); + *this << llvm::format("(%s:%d:%d)", clang_getCString(FileName), Line, Column); + clang_disposeString(FileName); + return *this; +} + +Logger &cxindex::Logger::operator<<(CXSourceRange range) { + CXSourceLocation BLoc = clang_getRangeStart(range); + CXSourceLocation ELoc = clang_getRangeEnd(range); + + CXFile BFile; + unsigned BLine, BColumn; + clang_getFileLocation(BLoc, &BFile, &BLine, &BColumn, nullptr); + + CXFile EFile; + unsigned ELine, EColumn; + clang_getFileLocation(ELoc, &EFile, &ELine, &EColumn, nullptr); + + CXString BFileName = clang_getFileName(BFile); + if (BFile == EFile) { + *this << llvm::format("[%s %d:%d-%d:%d]", clang_getCString(BFileName), + BLine, BColumn, ELine, EColumn); + } else { + CXString EFileName = clang_getFileName(EFile); + *this << llvm::format("[%s:%d:%d - ", clang_getCString(BFileName), BLine, + BColumn) + << llvm::format("%s:%d:%d]", clang_getCString(EFileName), ELine, + EColumn); + clang_disposeString(EFileName); + } + clang_disposeString(BFileName); + return *this; +} + +Logger &cxindex::Logger::operator<<(CXString Str) { + *this << clang_getCString(Str); + return *this; +} + +Logger &cxindex::Logger::operator<<(const llvm::format_object_base &Fmt) { + LogOS << Fmt; + return *this; +} + +static llvm::ManagedStatic<std::mutex> LoggingMutex; + +cxindex::Logger::~Logger() { + std::lock_guard<std::mutex> L(*LoggingMutex); + + static llvm::TimeRecord sBeginTR = llvm::TimeRecord::getCurrentTime(); + + raw_ostream &OS = llvm::errs(); + OS << "[libclang:" << Name << ':'; + +#ifdef USE_DARWIN_THREADS + // TODO: Portability. + mach_port_t tid = pthread_mach_thread_np(pthread_self()); + OS << tid << ':'; +#endif + + llvm::TimeRecord TR = llvm::TimeRecord::getCurrentTime(); + OS << llvm::format("%7.4f] ", TR.getWallTime() - sBeginTR.getWallTime()); + OS << Msg << '\n'; + + if (Trace) { + llvm::sys::PrintStackTrace(OS); + OS << "--------------------------------------------------\n"; + } +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexCXX.cpp b/contrib/libs/clang14/tools/libclang/CIndexCXX.cpp new file mode 100644 index 0000000000..a06fe7ba4a --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexCXX.cpp @@ -0,0 +1,122 @@ +//===- CIndexCXX.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 libclang support for C++ cursors. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace clang::cxcursor; + +unsigned clang_isVirtualBase(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return 0; + + const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return B->isVirtual(); +} + +enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) { + AccessSpecifier spec = AS_none; + + if (C.kind == CXCursor_CXXAccessSpecifier || clang_isDeclaration(C.kind)) + spec = getCursorDecl(C)->getAccess(); + else if (C.kind == CXCursor_CXXBaseSpecifier) + spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier(); + else + return CX_CXXInvalidAccessSpecifier; + + switch (spec) { + case AS_public: return CX_CXXPublic; + case AS_protected: return CX_CXXProtected; + case AS_private: return CX_CXXPrivate; + case AS_none: return CX_CXXInvalidAccessSpecifier; + } + + llvm_unreachable("Invalid AccessSpecifier!"); +} + +enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { + using namespace clang::cxcursor; + + switch (C.kind) { + case CXCursor_ClassTemplate: + case CXCursor_FunctionTemplate: + if (const TemplateDecl *Template + = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C))) + return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind; + break; + + case CXCursor_ClassTemplatePartialSpecialization: + if (const ClassTemplateSpecializationDecl *PartialSpec + = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( + getCursorDecl(C))) { + switch (PartialSpec->getTagKind()) { + case TTK_Interface: + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_NoDeclFound; + } + } + break; + + default: + break; + } + + return CXCursor_NoDeclFound; +} + +CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + const Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + Decl *Template = nullptr; + if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (const ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) + Template = PartialSpec->getSpecializedTemplate(); + else if (const ClassTemplateSpecializationDecl *ClassSpec + = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> Result + = ClassSpec->getSpecializedTemplateOrPartial(); + if (Result.is<ClassTemplateDecl *>()) + Template = Result.get<ClassTemplateDecl *>(); + else + Template = Result.get<ClassTemplatePartialSpecializationDecl *>(); + + } else + Template = CXXRecord->getInstantiatedFromMemberClass(); + } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + Template = Function->getPrimaryTemplate(); + if (!Template) + Template = Function->getInstantiatedFromMemberFunction(); + } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->isStaticDataMember()) + Template = Var->getInstantiatedFromStaticDataMember(); + } else if (const RedeclarableTemplateDecl *Tmpl + = dyn_cast<RedeclarableTemplateDecl>(D)) + Template = Tmpl->getInstantiatedFromMemberTemplate(); + + if (!Template) + return clang_getNullCursor(); + + return MakeCXCursor(Template, getCursorTU(C)); +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexCodeCompletion.cpp b/contrib/libs/clang14/tools/libclang/CIndexCodeCompletion.cpp new file mode 100644 index 0000000000..0d75970f2f --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexCodeCompletion.cpp @@ -0,0 +1,1046 @@ +//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===// +// +// 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 Clang-C Source Indexing library hooks for +// code completion. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CIndexDiagnostic.h" +#include "CLog.h" +#include "CXCursor.h" +#include "CXSourceLocation.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" +#include <atomic> +#include <cstdio> +#include <cstdlib> +#include <string> + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#include "clang/Basic/Version.h" +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#endif + +using namespace clang; +using namespace clang::cxindex; + +enum CXCompletionChunkKind +clang_getCompletionChunkKind(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return CXCompletionChunk_Text; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + return CXCompletionChunk_TypedText; + case CodeCompletionString::CK_Text: + return CXCompletionChunk_Text; + case CodeCompletionString::CK_Optional: + return CXCompletionChunk_Optional; + case CodeCompletionString::CK_Placeholder: + return CXCompletionChunk_Placeholder; + case CodeCompletionString::CK_Informative: + return CXCompletionChunk_Informative; + case CodeCompletionString::CK_ResultType: + return CXCompletionChunk_ResultType; + case CodeCompletionString::CK_CurrentParameter: + return CXCompletionChunk_CurrentParameter; + case CodeCompletionString::CK_LeftParen: + return CXCompletionChunk_LeftParen; + case CodeCompletionString::CK_RightParen: + return CXCompletionChunk_RightParen; + case CodeCompletionString::CK_LeftBracket: + return CXCompletionChunk_LeftBracket; + case CodeCompletionString::CK_RightBracket: + return CXCompletionChunk_RightBracket; + case CodeCompletionString::CK_LeftBrace: + return CXCompletionChunk_LeftBrace; + case CodeCompletionString::CK_RightBrace: + return CXCompletionChunk_RightBrace; + case CodeCompletionString::CK_LeftAngle: + return CXCompletionChunk_LeftAngle; + case CodeCompletionString::CK_RightAngle: + return CXCompletionChunk_RightAngle; + case CodeCompletionString::CK_Comma: + return CXCompletionChunk_Comma; + case CodeCompletionString::CK_Colon: + return CXCompletionChunk_Colon; + case CodeCompletionString::CK_SemiColon: + return CXCompletionChunk_SemiColon; + case CodeCompletionString::CK_Equal: + return CXCompletionChunk_Equal; + case CodeCompletionString::CK_HorizontalSpace: + return CXCompletionChunk_HorizontalSpace; + case CodeCompletionString::CK_VerticalSpace: + return CXCompletionChunk_VerticalSpace; + } + + llvm_unreachable("Invalid CompletionKind!"); +} + +CXString clang_getCompletionChunkText(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return cxstring::createNull(); + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: + return cxstring::createRef((*CCStr)[chunk_number].Text); + + case CodeCompletionString::CK_Optional: + // Note: treated as an empty text block. + return cxstring::createEmpty(); + } + + llvm_unreachable("Invalid CodeCompletionString Kind!"); +} + + +CXCompletionString +clang_getCompletionChunkCompletionString(CXCompletionString completion_string, + unsigned chunk_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr || chunk_number >= CCStr->size()) + return nullptr; + + switch ((*CCStr)[chunk_number].Kind) { + case CodeCompletionString::CK_TypedText: + case CodeCompletionString::CK_Text: + case CodeCompletionString::CK_Placeholder: + case CodeCompletionString::CK_CurrentParameter: + case CodeCompletionString::CK_Informative: + case CodeCompletionString::CK_LeftParen: + case CodeCompletionString::CK_RightParen: + case CodeCompletionString::CK_LeftBracket: + case CodeCompletionString::CK_RightBracket: + case CodeCompletionString::CK_LeftBrace: + case CodeCompletionString::CK_RightBrace: + case CodeCompletionString::CK_LeftAngle: + case CodeCompletionString::CK_RightAngle: + case CodeCompletionString::CK_Comma: + case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: + return nullptr; + + case CodeCompletionString::CK_Optional: + // Note: treated as an empty text block. + return (*CCStr)[chunk_number].Optional; + } + + llvm_unreachable("Invalid CompletionKind!"); +} + +unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? CCStr->size() : 0; +} + +unsigned clang_getCompletionPriority(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); +} + +enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr? static_cast<CXAvailabilityKind>(CCStr->getAvailability()) + : CXAvailability_Available; +} + +unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string) +{ + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? CCStr->getAnnotationCount() : 0; +} + +CXString clang_getCompletionAnnotation(CXCompletionString completion_string, + unsigned annotation_number) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + return CCStr ? cxstring::createRef(CCStr->getAnnotation(annotation_number)) + : cxstring::createNull(); +} + +CXString +clang_getCompletionParent(CXCompletionString completion_string, + CXCursorKind *kind) { + if (kind) + *kind = CXCursor_NotImplemented; + + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + if (!CCStr) + return cxstring::createNull(); + + return cxstring::createRef(CCStr->getParentContextName()); +} + +CXString +clang_getCompletionBriefComment(CXCompletionString completion_string) { + CodeCompletionString *CCStr = (CodeCompletionString *)completion_string; + + if (!CCStr) + return cxstring::createNull(); + + return cxstring::createRef(CCStr->getBriefComment()); +} + +namespace { + +/// The CXCodeCompleteResults structure we allocate internally; +/// the client only sees the initial CXCodeCompleteResults structure. +/// +/// Normally, clients of CXString shouldn't care whether or not a CXString is +/// managed by a pool or by explicitly malloc'ed memory. But +/// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can +/// not rely on the StringPool in the TU. +struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { + AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr); + ~AllocatedCXCodeCompleteResults(); + + /// Diagnostics produced while performing code completion. + SmallVector<StoredDiagnostic, 8> Diagnostics; + + /// Allocated API-exposed wrappters for Diagnostics. + SmallVector<std::unique_ptr<CXStoredDiagnostic>, 8> DiagnosticsWrappers; + + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + + /// Diag object + IntrusiveRefCntPtr<DiagnosticsEngine> Diag; + + /// Language options used to adjust source locations. + LangOptions LangOpts; + + /// File manager, used for diagnostics. + IntrusiveRefCntPtr<FileManager> FileMgr; + + /// Source manager, used for diagnostics. + IntrusiveRefCntPtr<SourceManager> SourceMgr; + + /// Temporary buffers that will be deleted once we have finished with + /// the code-completion results. + SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; + + /// Allocator used to store globally cached code-completion results. + std::shared_ptr<clang::GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + + /// Allocator used to store code completion results. + std::shared_ptr<clang::GlobalCodeCompletionAllocator> CodeCompletionAllocator; + + /// Context under which completion occurred. + enum clang::CodeCompletionContext::Kind ContextKind; + + /// A bitfield representing the acceptable completions for the + /// current context. + unsigned long long Contexts; + + /// The kind of the container for the current context for completions. + enum CXCursorKind ContainerKind; + + /// The USR of the container for the current context for completions. + std::string ContainerUSR; + + /// a boolean value indicating whether there is complete information + /// about the container + unsigned ContainerIsIncomplete; + + /// A string containing the Objective-C selector entered thus far for a + /// message send. + std::string Selector; + + /// Vector of fix-its for each completion result that *must* be applied + /// before that result for the corresponding completion item. + std::vector<std::vector<FixItHint>> FixItsVector; +}; + +} // end anonymous namespace + +unsigned clang_getCompletionNumFixIts(CXCodeCompleteResults *results, + unsigned completion_index) { + AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results; + + if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) + return 0; + + return static_cast<unsigned>(allocated_results->FixItsVector[completion_index].size()); +} + +CXString clang_getCompletionFixIt(CXCodeCompleteResults *results, + unsigned completion_index, + unsigned fixit_index, + CXSourceRange *replacement_range) { + AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results; + + if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) { + if (replacement_range) + *replacement_range = clang_getNullRange(); + return cxstring::createNull(); + } + + ArrayRef<FixItHint> FixIts = allocated_results->FixItsVector[completion_index]; + if (FixIts.size() <= fixit_index) { + if (replacement_range) + *replacement_range = clang_getNullRange(); + return cxstring::createNull(); + } + + const FixItHint &FixIt = FixIts[fixit_index]; + if (replacement_range) { + *replacement_range = cxloc::translateSourceRange( + *allocated_results->SourceMgr, allocated_results->LangOpts, + FixIt.RemoveRange); + } + + return cxstring::createRef(FixIt.CodeToInsert.c_str()); +} + +/// Tracks the number of code-completion result objects that are +/// currently active. +/// +/// Used for debugging purposes only. +static std::atomic<unsigned> CodeCompletionResultObjects; + +AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( + IntrusiveRefCntPtr<FileManager> FileMgr) + : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions), + Diag(new DiagnosticsEngine( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)), + FileMgr(std::move(FileMgr)), + SourceMgr(new SourceManager(*Diag, *this->FileMgr)), + CodeCompletionAllocator( + std::make_shared<clang::GlobalCodeCompletionAllocator>()), + Contexts(CXCompletionContext_Unknown), + ContainerKind(CXCursor_InvalidCode), ContainerIsIncomplete(1) { + if (getenv("LIBCLANG_OBJTRACKING")) + fprintf(stderr, "+++ %u completion results\n", + ++CodeCompletionResultObjects); +} + +AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { + delete [] Results; + + for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) + delete TemporaryBuffers[I]; + + if (getenv("LIBCLANG_OBJTRACKING")) + fprintf(stderr, "--- %u completion results\n", + --CodeCompletionResultObjects); +} + +static unsigned long long getContextsForContextKind( + enum CodeCompletionContext::Kind kind, + Sema &S) { + unsigned long long contexts = 0; + switch (kind) { + case CodeCompletionContext::CCC_OtherWithMacros: { + //We can allow macros here, but we don't know what else is permissible + //So we'll say the only thing permissible are macros + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_TopLevel: + case CodeCompletionContext::CCC_ObjCIvarList: + case CodeCompletionContext::CCC_ClassStructUnion: + case CodeCompletionContext::CCC_Type: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Statement: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Expression: { + contexts = CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCMessageReceiver: { + contexts = CXCompletionContext_ObjCObjectValue | + CXCompletionContext_ObjCSelectorValue | + CXCompletionContext_ObjCInterface; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_CXXClassTypeValue | + CXCompletionContext_AnyType | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_DotMemberAccess: { + contexts = CXCompletionContext_DotMemberAccess; + break; + } + case CodeCompletionContext::CCC_ArrowMemberAccess: { + contexts = CXCompletionContext_ArrowMemberAccess; + break; + } + case CodeCompletionContext::CCC_ObjCPropertyAccess: { + contexts = CXCompletionContext_ObjCPropertyAccess; + break; + } + case CodeCompletionContext::CCC_EnumTag: { + contexts = CXCompletionContext_EnumTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_UnionTag: { + contexts = CXCompletionContext_UnionTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ClassOrStructTag: { + contexts = CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ObjCProtocolName: { + contexts = CXCompletionContext_ObjCProtocol; + break; + } + case CodeCompletionContext::CCC_Namespace: { + contexts = CXCompletionContext_Namespace; + break; + } + case CodeCompletionContext::CCC_SymbolOrNewName: + case CodeCompletionContext::CCC_Symbol: { + contexts = CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_MacroNameUse: { + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_NaturalLanguage: { + contexts = CXCompletionContext_NaturalLanguage; + break; + } + case CodeCompletionContext::CCC_IncludedFile: { + contexts = CXCompletionContext_IncludedFile; + break; + } + case CodeCompletionContext::CCC_SelectorName: { + contexts = CXCompletionContext_ObjCSelectorName; + break; + } + case CodeCompletionContext::CCC_ParenthesizedExpression: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOpts().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCInstanceMessage: { + contexts = CXCompletionContext_ObjCInstanceMessage; + break; + } + case CodeCompletionContext::CCC_ObjCClassMessage: { + contexts = CXCompletionContext_ObjCClassMessage; + break; + } + case CodeCompletionContext::CCC_ObjCInterfaceName: { + contexts = CXCompletionContext_ObjCInterface; + break; + } + case CodeCompletionContext::CCC_ObjCCategoryName: { + contexts = CXCompletionContext_ObjCCategory; + break; + } + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_ObjCInterface: + case CodeCompletionContext::CCC_ObjCImplementation: + case CodeCompletionContext::CCC_NewName: + case CodeCompletionContext::CCC_MacroName: + case CodeCompletionContext::CCC_PreprocessorExpression: + case CodeCompletionContext::CCC_PreprocessorDirective: + case CodeCompletionContext::CCC_Attribute: + case CodeCompletionContext::CCC_TypeQualifiers: { + //Only Clang results should be accepted, so we'll set all of the other + //context bits to 0 (i.e. the empty set) + contexts = CXCompletionContext_Unexposed; + break; + } + case CodeCompletionContext::CCC_Recovery: { + //We don't know what the current context is, so we'll return unknown + //This is the equivalent of setting all of the other context bits + contexts = CXCompletionContext_Unknown; + break; + } + } + return contexts; +} + +namespace { + class CaptureCompletionResults : public CodeCompleteConsumer { + AllocatedCXCodeCompleteResults &AllocatedResults; + CodeCompletionTUInfo CCTUInfo; + SmallVector<CXCompletionResult, 16> StoredResults; + CXTranslationUnit *TU; + public: + CaptureCompletionResults(const CodeCompleteOptions &Opts, + AllocatedCXCodeCompleteResults &Results, + CXTranslationUnit *TranslationUnit) + : CodeCompleteConsumer(Opts), AllocatedResults(Results), + CCTUInfo(Results.CodeCompletionAllocator), TU(TranslationUnit) {} + ~CaptureCompletionResults() override { Finish(); } + + void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) override { + StoredResults.reserve(StoredResults.size() + NumResults); + if (includeFixIts()) + AllocatedResults.FixItsVector.reserve(NumResults); + for (unsigned I = 0; I != NumResults; ++I) { + CodeCompletionString *StoredCompletion + = Results[I].CreateCodeCompletionString(S, Context, getAllocator(), + getCodeCompletionTUInfo(), + includeBriefComments()); + + CXCompletionResult R; + R.CursorKind = Results[I].CursorKind; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); + if (includeFixIts()) + AllocatedResults.FixItsVector.emplace_back(std::move(Results[I].FixIts)); + } + + enum CodeCompletionContext::Kind contextKind = Context.getKind(); + + AllocatedResults.ContextKind = contextKind; + AllocatedResults.Contexts = getContextsForContextKind(contextKind, S); + + AllocatedResults.Selector = ""; + ArrayRef<IdentifierInfo *> SelIdents = Context.getSelIdents(); + for (ArrayRef<IdentifierInfo *>::iterator I = SelIdents.begin(), + E = SelIdents.end(); + I != E; ++I) { + if (IdentifierInfo *selIdent = *I) + AllocatedResults.Selector += selIdent->getName(); + AllocatedResults.Selector += ":"; + } + + QualType baseType = Context.getBaseType(); + NamedDecl *D = nullptr; + + if (!baseType.isNull()) { + // Get the declaration for a class/struct/union/enum type + if (const TagType *Tag = baseType->getAs<TagType>()) + D = Tag->getDecl(); + // Get the @interface declaration for a (possibly-qualified) Objective-C + // object pointer type, e.g., NSString* + else if (const ObjCObjectPointerType *ObjPtr = + baseType->getAs<ObjCObjectPointerType>()) + D = ObjPtr->getInterfaceDecl(); + // Get the @interface declaration for an Objective-C object type + else if (const ObjCObjectType *Obj = baseType->getAs<ObjCObjectType>()) + D = Obj->getInterface(); + // Get the class for a C++ injected-class-name + else if (const InjectedClassNameType *Injected = + baseType->getAs<InjectedClassNameType>()) + D = Injected->getDecl(); + } + + if (D != nullptr) { + CXCursor cursor = cxcursor::MakeCXCursor(D, *TU); + + AllocatedResults.ContainerKind = clang_getCursorKind(cursor); + + CXString CursorUSR = clang_getCursorUSR(cursor); + AllocatedResults.ContainerUSR = clang_getCString(CursorUSR); + clang_disposeString(CursorUSR); + + const Type *type = baseType.getTypePtrOrNull(); + if (type) { + AllocatedResults.ContainerIsIncomplete = type->isIncompleteType(); + } + else { + AllocatedResults.ContainerIsIncomplete = 1; + } + } + else { + AllocatedResults.ContainerKind = CXCursor_InvalidCode; + AllocatedResults.ContainerUSR.clear(); + AllocatedResults.ContainerIsIncomplete = 1; + } + } + + void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates, + SourceLocation OpenParLoc, + bool Braced) override { + StoredResults.reserve(StoredResults.size() + NumCandidates); + for (unsigned I = 0; I != NumCandidates; ++I) { + CodeCompletionString *StoredCompletion = + Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(), + getCodeCompletionTUInfo(), + includeBriefComments(), Braced); + + CXCompletionResult R; + R.CursorKind = CXCursor_OverloadCandidate; + R.CompletionString = StoredCompletion; + StoredResults.push_back(R); + } + } + + CodeCompletionAllocator &getAllocator() override { + return *AllocatedResults.CodeCompletionAllocator; + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo;} + + private: + void Finish() { + AllocatedResults.Results = new CXCompletionResult [StoredResults.size()]; + AllocatedResults.NumResults = StoredResults.size(); + std::memcpy(AllocatedResults.Results, StoredResults.data(), + StoredResults.size() * sizeof(CXCompletionResult)); + StoredResults.clear(); + } + }; +} + +static CXCodeCompleteResults * +clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, + unsigned complete_line, unsigned complete_column, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options) { + bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; + bool SkipPreamble = options & CXCodeComplete_SkipPreamble; + bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts; + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); +#endif +#endif + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr; + + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return nullptr; + } + + ASTUnit *AST = cxtu::getASTUnit(TU); + if (!AST) + return nullptr; + + CIndexer *CXXIdx = TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) + setThreadBackgroundPriority(); + + ASTUnit::ConcurrencyCheck Check(*AST); + + // Perform the remapping of source files. + SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + + for (auto &UF : unsaved_files) { + std::unique_ptr<llvm::MemoryBuffer> MB = + llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); + RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); + } + + if (EnableLogging) { + // FIXME: Add logging. + } + + // Parse the resulting source file to find code-completion results. + AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( + &AST->getFileManager()); + Results->Results = nullptr; + Results->NumResults = 0; + + // Create a code-completion consumer to capture the results. + CodeCompleteOptions Opts; + Opts.IncludeBriefComments = IncludeBriefComments; + Opts.LoadExternal = !SkipPreamble; + Opts.IncludeFixIts = IncludeFixIts; + CaptureCompletionResults Capture(Opts, *Results, &TU); + + // Perform completion. + std::vector<const char *> CArgs; + for (const auto &Arg : TU->Arguments) + CArgs.push_back(Arg.c_str()); + std::string CompletionInvocation = + llvm::formatv("-code-completion-at={0}:{1}:{2}", complete_filename, + complete_line, complete_column) + .str(); + LibclangInvocationReporter InvocationReporter( + *CXXIdx, LibclangInvocationReporter::OperationKind::CompletionOperation, + TU->ParsingOptions, CArgs, CompletionInvocation, unsaved_files); + AST->CodeComplete(complete_filename, complete_line, complete_column, + RemappedFiles, (options & CXCodeComplete_IncludeMacros), + (options & CXCodeComplete_IncludeCodePatterns), + IncludeBriefComments, Capture, + CXXIdx->getPCHContainerOperations(), *Results->Diag, + Results->LangOpts, *Results->SourceMgr, *Results->FileMgr, + Results->Diagnostics, Results->TemporaryBuffers); + + Results->DiagnosticsWrappers.resize(Results->Diagnostics.size()); + + // Keep a reference to the allocator used for cached global completions, so + // that we can be sure that the memory used by our code completion strings + // doesn't get freed due to subsequent reparses (while the code completion + // results are still active). + Results->CachedCompletionAllocator = AST->getCachedCompletionAllocator(); + + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); + SmallString<256> LogResult; + llvm::raw_svector_ostream os(LogResult); + + // Figure out the language and whether or not it uses PCH. + const char *lang = 0; + bool usesPCH = false; + + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I != E; ++I) { + if (*I == 0) + continue; + if (strcmp(*I, "-x") == 0) { + if (I + 1 != E) { + lang = *(++I); + continue; + } + } + else if (strcmp(*I, "-include") == 0) { + if (I+1 != E) { + const char *arg = *(++I); + SmallString<512> pchName; + { + llvm::raw_svector_ostream os(pchName); + os << arg << ".pth"; + } + pchName.push_back('\0'); + llvm::sys::fs::file_status stat_results; + if (!llvm::sys::fs::status(pchName, stat_results)) + usesPCH = true; + continue; + } + } + } + + os << "{ "; + os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); + os << ", \"numRes\": " << Results->NumResults; + os << ", \"diags\": " << Results->Diagnostics.size(); + os << ", \"pch\": " << (usesPCH ? "true" : "false"); + os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; + const char *name = getlogin(); + os << ", \"user\": \"" << (name ? name : "unknown") << '"'; + os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; + os << " }"; + + StringRef res = os.str(); + if (res.size() > 0) { + do { + // Setup the UDP socket. + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); + if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, + &servaddr.sin_addr) <= 0) + break; + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + break; + + sendto(sockfd, res.data(), res.size(), 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + close(sockfd); + } + while (false); + } +#endif +#endif + return Results; +} + +CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + LOG_FUNC_SECTION { + *Log << TU << ' ' + << complete_filename << ':' << complete_line << ':' << complete_column; + } + + if (num_unsaved_files && !unsaved_files) + return nullptr; + + CXCodeCompleteResults *result; + auto CodeCompleteAtImpl = [=, &result]() { + result = clang_codeCompleteAt_Impl( + TU, complete_filename, complete_line, complete_column, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), options); + }; + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, CodeCompleteAtImpl)) { + fprintf(stderr, "libclang: crash detected in code completion\n"); + cxtu::getASTUnit(TU)->setUnsafeToFree(true); + return nullptr; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) + PrintLibclangResourceUsage(TU); + + return result; +} + +unsigned clang_defaultCodeCompleteOptions(void) { + return CXCodeComplete_IncludeMacros; +} + +void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { + if (!ResultsIn) + return; + + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + delete Results; +} + +unsigned +clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results) + return 0; + + return Results->Diagnostics.size(); +} + +CXDiagnostic +clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, + unsigned Index) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results || Index >= Results->Diagnostics.size()) + return nullptr; + + CXStoredDiagnostic *Diag = Results->DiagnosticsWrappers[Index].get(); + if (!Diag) + Diag = (Results->DiagnosticsWrappers[Index] = + std::make_unique<CXStoredDiagnostic>( + Results->Diagnostics[Index], Results->LangOpts)) + .get(); + return Diag; +} + +unsigned long long +clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results) + return 0; + + return Results->Contexts; +} + +enum CXCursorKind clang_codeCompleteGetContainerKind( + CXCodeCompleteResults *ResultsIn, + unsigned *IsIncomplete) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return CXCursor_InvalidCode; + + if (IsIncomplete != nullptr) { + *IsIncomplete = Results->ContainerIsIncomplete; + } + + return Results->ContainerKind; +} + +CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return cxstring::createEmpty(); + + return cxstring::createRef(Results->ContainerUSR.c_str()); +} + + +CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results = + static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn); + if (!Results) + return cxstring::createEmpty(); + + return cxstring::createDup(Results->Selector); +} + +/// Simple utility function that appends a \p New string to the given +/// \p Old string, using the \p Buffer for storage. +/// +/// \param Old The string to which we are appending. This parameter will be +/// updated to reflect the complete string. +/// +/// +/// \param New The string to append to \p Old. +/// +/// \param Buffer A buffer that stores the actual, concatenated string. It will +/// be used if the old string is already-non-empty. +static void AppendToString(StringRef &Old, StringRef New, + SmallString<256> &Buffer) { + if (Old.empty()) { + Old = New; + return; + } + + if (Buffer.empty()) + Buffer.append(Old.begin(), Old.end()); + Buffer.append(New.begin(), New.end()); + Old = Buffer.str(); +} + +/// Get the typed-text blocks from the given code-completion string +/// and return them as a single string. +/// +/// \param String The code-completion string whose typed-text blocks will be +/// concatenated. +/// +/// \param Buffer A buffer used for storage of the completed name. +static StringRef GetTypedName(CodeCompletionString *String, + SmallString<256> &Buffer) { + StringRef Result; + for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end(); + C != CEnd; ++C) { + if (C->Kind == CodeCompletionString::CK_TypedText) + AppendToString(Result, C->Text, Buffer); + } + + return Result; +} + +namespace { + struct OrderCompletionResults { + bool operator()(const CXCompletionResult &XR, + const CXCompletionResult &YR) const { + CodeCompletionString *X + = (CodeCompletionString *)XR.CompletionString; + CodeCompletionString *Y + = (CodeCompletionString *)YR.CompletionString; + + SmallString<256> XBuffer; + StringRef XText = GetTypedName(X, XBuffer); + SmallString<256> YBuffer; + StringRef YText = GetTypedName(Y, YBuffer); + + if (XText.empty() || YText.empty()) + return !XText.empty(); + + int result = XText.compare_insensitive(YText); + if (result < 0) + return true; + if (result > 0) + return false; + + result = XText.compare(YText); + return result < 0; + } + }; +} + +void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults) { + std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.cpp b/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.cpp new file mode 100644 index 0000000000..34792d5bdf --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.cpp @@ -0,0 +1,468 @@ +//===- CIndexDiagnostic.cpp - Diagnostics C Interface ---------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implements the diagnostic functions of the Clang C interface. +// +//===----------------------------------------------------------------------===// + +#include "CIndexDiagnostic.h" +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXSourceLocation.h" +#include "CXString.h" + +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/DiagnosticRenderer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::cxloc; +using namespace clang::cxdiag; +using namespace llvm; + +CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {} + +void +CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) { + Diagnostics.push_back(std::move(D)); +} + +CXDiagnosticImpl::~CXDiagnosticImpl() {} + +namespace { +class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl { + std::string Message; + CXSourceLocation Loc; +public: + CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L) + : CXDiagnosticImpl(CustomNoteDiagnosticKind), Message(std::string(Msg)), + Loc(L) {} + + ~CXDiagnosticCustomNoteImpl() override {} + + CXDiagnosticSeverity getSeverity() const override { + return CXDiagnostic_Note; + } + + CXSourceLocation getLocation() const override { return Loc; } + + CXString getSpelling() const override { + return cxstring::createRef(Message.c_str()); + } + + CXString getDiagnosticOption(CXString *Disable) const override { + if (Disable) + *Disable = cxstring::createEmpty(); + return cxstring::createEmpty(); + } + + unsigned getCategory() const override { return 0; } + CXString getCategoryText() const override { return cxstring::createEmpty(); } + + unsigned getNumRanges() const override { return 0; } + CXSourceRange getRange(unsigned Range) const override { + return clang_getNullRange(); + } + unsigned getNumFixIts() const override { return 0; } + CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const override { + if (ReplacementRange) + *ReplacementRange = clang_getNullRange(); + return cxstring::createEmpty(); + } +}; + +class CXDiagnosticRenderer : public DiagnosticNoteRenderer { +public: + CXDiagnosticRenderer(const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts, + CXDiagnosticSetImpl *mainSet) + : DiagnosticNoteRenderer(LangOpts, DiagOpts), + CurrentSet(mainSet), MainSet(mainSet) {} + + ~CXDiagnosticRenderer() override {} + + void beginDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) override { + + const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>(); + if (!SD) + return; + + if (Level != DiagnosticsEngine::Note) + CurrentSet = MainSet; + + auto Owner = std::make_unique<CXStoredDiagnostic>(*SD, LangOpts); + CXStoredDiagnostic &CD = *Owner; + CurrentSet->appendDiagnostic(std::move(Owner)); + + if (Level != DiagnosticsEngine::Note) + CurrentSet = &CD.getChildDiagnostics(); + } + + void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, StringRef Message, + ArrayRef<CharSourceRange> Ranges, + DiagOrStoredDiag D) override { + if (!D.isNull()) + return; + + CXSourceLocation L; + if (Loc.hasManager()) + L = translateSourceLocation(Loc.getManager(), LangOpts, Loc); + else + L = clang_getNullLocation(); + CurrentSet->appendDiagnostic( + std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L)); + } + + void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges) override {} + + void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints) override {} + + void emitNote(FullSourceLoc Loc, StringRef Message) override { + CXSourceLocation L; + if (Loc.hasManager()) + L = translateSourceLocation(Loc.getManager(), LangOpts, Loc); + else + L = clang_getNullLocation(); + CurrentSet->appendDiagnostic( + std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L)); + } + + CXDiagnosticSetImpl *CurrentSet; + CXDiagnosticSetImpl *MainSet; +}; +} + +CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU, + bool checkIfChanged) { + ASTUnit *AU = cxtu::getASTUnit(TU); + + if (TU->Diagnostics && checkIfChanged) { + // In normal use, ASTUnit's diagnostics should not change unless we reparse. + // Currently they can only change by using the internal testing flag + // '-error-on-deserialized-decl' which will error during deserialization of + // a declaration. What will happen is: + // + // -c-index-test gets a CXTranslationUnit + // -checks the diagnostics, the diagnostics set is lazily created, + // no errors are reported + // -later does an operation, like annotation of tokens, that triggers + // -error-on-deserialized-decl, that will emit a diagnostic error, + // that ASTUnit will catch and add to its stored diagnostics vector. + // -c-index-test wants to check whether an error occurred after performing + // the operation but can only query the lazily created set. + // + // We check here if a new diagnostic was appended since the last time the + // diagnostic set was created, in which case we reset it. + + CXDiagnosticSetImpl * + Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); + if (AU->stored_diag_size() != Set->getNumDiagnostics()) { + // Diagnostics in the ASTUnit were updated, reset the associated + // diagnostics. + delete Set; + TU->Diagnostics = nullptr; + } + } + + if (!TU->Diagnostics) { + CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl(); + TU->Diagnostics = Set; + IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions; + CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(), + &*DOpts, Set); + + for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(), + ei = AU->stored_diag_end(); it != ei; ++it) { + Renderer.emitStoredDiagnostic(*it); + } + } + return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics); +} + +//----------------------------------------------------------------------------- +// C Interface Routines +//----------------------------------------------------------------------------- +unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { + if (cxtu::isNotUsableTU(Unit)) { + LOG_BAD_TU(Unit); + return 0; + } + if (!cxtu::getASTUnit(Unit)) + return 0; + return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics(); +} + +CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) { + if (cxtu::isNotUsableTU(Unit)) { + LOG_BAD_TU(Unit); + return nullptr; + } + + CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit); + if (!D) + return nullptr; + + CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D); + if (Index >= Diags->getNumDiagnostics()) + return nullptr; + + return Diags->getDiagnostic(Index); +} + +CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) { + if (cxtu::isNotUsableTU(Unit)) { + LOG_BAD_TU(Unit); + return nullptr; + } + if (!cxtu::getASTUnit(Unit)) + return nullptr; + return static_cast<CXDiagnostic>(lazyCreateDiags(Unit)); +} + +void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { + // No-op. Kept as a legacy API. CXDiagnostics are now managed + // by the enclosing CXDiagnosticSet. +} + +CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) { + if (!Diagnostic) + return cxstring::createEmpty(); + + CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic); + + SmallString<256> Str; + llvm::raw_svector_ostream Out(Str); + + if (Options & CXDiagnostic_DisplaySourceLocation) { + // Print source location (file:line), along with optional column + // and source ranges. + CXFile File; + unsigned Line, Column; + clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic), + &File, &Line, &Column, nullptr); + if (File) { + CXString FName = clang_getFileName(File); + Out << clang_getCString(FName) << ":" << Line << ":"; + clang_disposeString(FName); + if (Options & CXDiagnostic_DisplayColumn) + Out << Column << ":"; + + if (Options & CXDiagnostic_DisplaySourceRanges) { + unsigned N = clang_getDiagnosticNumRanges(Diagnostic); + bool PrintedRange = false; + for (unsigned I = 0; I != N; ++I) { + CXFile StartFile, EndFile; + CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I); + + unsigned StartLine, StartColumn, EndLine, EndColumn; + clang_getSpellingLocation(clang_getRangeStart(Range), + &StartFile, &StartLine, &StartColumn, + nullptr); + clang_getSpellingLocation(clang_getRangeEnd(Range), + &EndFile, &EndLine, &EndColumn, nullptr); + + if (StartFile != EndFile || StartFile != File) + continue; + + Out << "{" << StartLine << ":" << StartColumn << "-" + << EndLine << ":" << EndColumn << "}"; + PrintedRange = true; + } + if (PrintedRange) + Out << ":"; + } + + Out << " "; + } + } + + /* Print warning/error/etc. */ + switch (Severity) { + case CXDiagnostic_Ignored: llvm_unreachable("impossible"); + case CXDiagnostic_Note: Out << "note: "; break; + case CXDiagnostic_Warning: Out << "warning: "; break; + case CXDiagnostic_Error: Out << "error: "; break; + case CXDiagnostic_Fatal: Out << "fatal error: "; break; + } + + CXString Text = clang_getDiagnosticSpelling(Diagnostic); + if (clang_getCString(Text)) + Out << clang_getCString(Text); + else + Out << "<no diagnostic text>"; + clang_disposeString(Text); + + if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + bool NeedBracket = true; + bool NeedComma = false; + + if (Options & CXDiagnostic_DisplayOption) { + CXString OptionName = clang_getDiagnosticOption(Diagnostic, nullptr); + if (const char *OptionText = clang_getCString(OptionName)) { + if (OptionText[0]) { + Out << " [" << OptionText; + NeedBracket = false; + NeedComma = true; + } + } + clang_disposeString(OptionName); + } + + if (Options & (CXDiagnostic_DisplayCategoryId | + CXDiagnostic_DisplayCategoryName)) { + if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) { + if (Options & CXDiagnostic_DisplayCategoryId) { + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << CategoryID; + NeedBracket = false; + NeedComma = true; + } + + if (Options & CXDiagnostic_DisplayCategoryName) { + CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic); + if (NeedBracket) + Out << " ["; + if (NeedComma) + Out << ", "; + Out << clang_getCString(CategoryName); + NeedBracket = false; + NeedComma = true; + clang_disposeString(CategoryName); + } + } + } + + (void) NeedComma; // Silence dead store warning. + if (!NeedBracket) + Out << "]"; + } + + return cxstring::createDup(Out.str()); +} + +unsigned clang_defaultDiagnosticDisplayOptions() { + return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn | + CXDiagnostic_DisplayOption; +} + +enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) + return D->getSeverity(); + return CXDiagnostic_Ignored; +} + +CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag)) + return D->getLocation(); + return clang_getNullLocation(); +} + +CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getSpelling(); + return cxstring::createEmpty(); +} + +CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { + if (Disable) + *Disable = cxstring::createEmpty(); + + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getDiagnosticOption(Disable); + + return cxstring::createEmpty(); +} + +unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getCategory(); + return 0; +} + +CXString clang_getDiagnosticCategoryName(unsigned Category) { + // Kept for backward compatibility. + return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category)); +} + +CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getCategoryText(); + return cxstring::createEmpty(); +} + +unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getNumRanges(); + return 0; +} + +CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { + CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); + if (!D || Range >= D->getNumRanges()) + return clang_getNullRange(); + return D->getRange(Range); +} + +unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) + return D->getNumFixIts(); + return 0; +} + +CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt, + CXSourceRange *ReplacementRange) { + CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag); + if (!D || FixIt >= D->getNumFixIts()) { + if (ReplacementRange) + *ReplacementRange = clang_getNullRange(); + return cxstring::createEmpty(); + } + return D->getFixIt(FixIt, ReplacementRange); +} + +void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) { + if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(Diags)) { + if (D->isExternallyManaged()) + delete D; + } +} + +CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, + unsigned Index) { + if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) + if (Index < D->getNumDiagnostics()) + return D->getDiagnostic(Index); + return nullptr; +} + +CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) { + CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics(); + return ChildDiags.empty() ? nullptr : (CXDiagnosticSet) &ChildDiags; + } + return nullptr; +} + +unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) { + if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags)) + return D->getNumDiagnostics(); + return 0; +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.h b/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.h new file mode 100644 index 0000000000..25589bb574 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexDiagnostic.h @@ -0,0 +1,165 @@ +/*===-- CIndexDiagnostic.h - Diagnostics C Interface ------------*- C++ -*-===*\ +|* *| +|* 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements the diagnostic functions of the Clang C interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CINDEXDIAGNOSTIC_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CINDEXDIAGNOSTIC_H + +#include "clang-c/Index.h" +#include <memory> +#include <vector> +#include <assert.h> + +namespace clang { + +class LangOptions; +class StoredDiagnostic; +class CXDiagnosticImpl; + +class CXDiagnosticSetImpl { + std::vector<std::unique_ptr<CXDiagnosticImpl>> Diagnostics; + const bool IsExternallyManaged; +public: + CXDiagnosticSetImpl(bool isManaged = false) + : IsExternallyManaged(isManaged) {} + + virtual ~CXDiagnosticSetImpl(); + + size_t getNumDiagnostics() const { + return Diagnostics.size(); + } + + CXDiagnosticImpl *getDiagnostic(unsigned i) const { + assert(i < getNumDiagnostics()); + return Diagnostics[i].get(); + } + + void appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D); + + bool empty() const { + return Diagnostics.empty(); + } + + bool isExternallyManaged() const { return IsExternallyManaged; } +}; + +class CXDiagnosticImpl { +public: + enum Kind { StoredDiagnosticKind, LoadedDiagnosticKind, + CustomNoteDiagnosticKind }; + + virtual ~CXDiagnosticImpl(); + + /// Return the severity of the diagnostic. + virtual CXDiagnosticSeverity getSeverity() const = 0; + + /// Return the location of the diagnostic. + virtual CXSourceLocation getLocation() const = 0; + + /// Return the spelling of the diagnostic. + virtual CXString getSpelling() const = 0; + + /// Return the text for the diagnostic option. + virtual CXString getDiagnosticOption(CXString *Disable) const = 0; + + /// Return the category of the diagnostic. + virtual unsigned getCategory() const = 0; + + /// Return the category string of the diagnostic. + virtual CXString getCategoryText() const = 0; + + /// Return the number of source ranges for the diagnostic. + virtual unsigned getNumRanges() const = 0; + + /// Return the source ranges for the diagnostic. + virtual CXSourceRange getRange(unsigned Range) const = 0; + + /// Return the number of FixIts. + virtual unsigned getNumFixIts() const = 0; + + /// Return the FixIt information (source range and inserted text). + virtual CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const = 0; + + Kind getKind() const { return K; } + + CXDiagnosticSetImpl &getChildDiagnostics() { + return ChildDiags; + } + +protected: + CXDiagnosticImpl(Kind k) : K(k) {} + CXDiagnosticSetImpl ChildDiags; + + void append(std::unique_ptr<CXDiagnosticImpl> D) { + ChildDiags.appendDiagnostic(std::move(D)); + } + +private: + Kind K; +}; + +/// The storage behind a CXDiagnostic +struct CXStoredDiagnostic : public CXDiagnosticImpl { + const StoredDiagnostic &Diag; + const LangOptions &LangOpts; + + CXStoredDiagnostic(const StoredDiagnostic &Diag, + const LangOptions &LangOpts) + : CXDiagnosticImpl(StoredDiagnosticKind), + Diag(Diag), LangOpts(LangOpts) { } + + ~CXStoredDiagnostic() override {} + + /// Return the severity of the diagnostic. + CXDiagnosticSeverity getSeverity() const override; + + /// Return the location of the diagnostic. + CXSourceLocation getLocation() const override; + + /// Return the spelling of the diagnostic. + CXString getSpelling() const override; + + /// Return the text for the diagnostic option. + CXString getDiagnosticOption(CXString *Disable) const override; + + /// Return the category of the diagnostic. + unsigned getCategory() const override; + + /// Return the category string of the diagnostic. + CXString getCategoryText() const override; + + /// Return the number of source ranges for the diagnostic. + unsigned getNumRanges() const override; + + /// Return the source ranges for the diagnostic. + CXSourceRange getRange(unsigned Range) const override; + + /// Return the number of FixIts. + unsigned getNumFixIts() const override; + + /// Return the FixIt information (source range and inserted text). + CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const override; + + static bool classof(const CXDiagnosticImpl *D) { + return D->getKind() == StoredDiagnosticKind; + } +}; + +namespace cxdiag { +CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU, + bool checkIfChanged = false); +} // end namespace cxdiag + +} // end namespace clang + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CIndexHigh.cpp b/contrib/libs/clang14/tools/libclang/CIndexHigh.cpp new file mode 100644 index 0000000000..0b49d1842e --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexHigh.cpp @@ -0,0 +1,534 @@ +//===- CIndexHigh.cpp - Higher level API functions ------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "CursorVisitor.h" +#include "CLog.h" +#include "CXCursor.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/Support/Compiler.h" + +using namespace clang; +using namespace cxcursor; +using namespace cxindex; + +static void getTopOverriddenMethods(CXTranslationUnit TU, + const Decl *D, + SmallVectorImpl<const Decl *> &Methods) { + if (!D) + return; + if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D)) + return; + + SmallVector<CXCursor, 8> Overridden; + cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden); + + if (Overridden.empty()) { + Methods.push_back(D->getCanonicalDecl()); + return; + } + + for (SmallVectorImpl<CXCursor>::iterator + I = Overridden.begin(), E = Overridden.end(); I != E; ++I) + getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods); +} + +namespace { + +struct FindFileIdRefVisitData { + CXTranslationUnit TU; + FileID FID; + const Decl *Dcl; + int SelectorIdIdx; + CXCursorAndRangeVisitor visitor; + + typedef SmallVector<const Decl *, 8> TopMethodsTy; + TopMethodsTy TopMethods; + + FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID, + const Decl *D, int selectorIdIdx, + CXCursorAndRangeVisitor visitor) + : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) { + Dcl = getCanonical(D); + getTopOverriddenMethods(TU, Dcl, TopMethods); + } + + ASTContext &getASTContext() const { + return cxtu::getASTUnit(TU)->getASTContext(); + } + + /// We are looking to find all semantically relevant identifiers, + /// so the definition of "canonical" here is different than in the AST, e.g. + /// + /// \code + /// class C { + /// C() {} + /// }; + /// \endcode + /// + /// we consider the canonical decl of the constructor decl to be the class + /// itself, so both 'C' can be highlighted. + const Decl *getCanonical(const Decl *D) const { + if (!D) + return nullptr; + + D = D->getCanonicalDecl(); + + if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) { + if (ImplD->getClassInterface()) + return getCanonical(ImplD->getClassInterface()); + + } else if (const CXXConstructorDecl *CXXCtorD = + dyn_cast<CXXConstructorDecl>(D)) { + return getCanonical(CXXCtorD->getParent()); + } + + return D; + } + + bool isHit(const Decl *D) const { + if (!D) + return false; + + D = getCanonical(D); + if (D == Dcl) + return true; + + if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D)) + return isOverriddingMethod(D); + + return false; + } + +private: + bool isOverriddingMethod(const Decl *D) const { + if (llvm::is_contained(TopMethods, D)) + return true; + + TopMethodsTy methods; + getTopOverriddenMethods(TU, D, methods); + for (TopMethodsTy::iterator + I = methods.begin(), E = methods.end(); I != E; ++I) { + if (llvm::is_contained(TopMethods, *I)) + return true; + } + + return false; + } +}; + +} // end anonymous namespace. + +/// For a macro \arg Loc, returns the file spelling location and sets +/// to \arg isMacroArg whether the spelling resides inside a macro definition or +/// a macro argument. +static SourceLocation getFileSpellingLoc(SourceManager &SM, + SourceLocation Loc, + bool &isMacroArg) { + assert(Loc.isMacroID()); + SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc); + if (SpellLoc.isMacroID()) + return getFileSpellingLoc(SM, SpellLoc, isMacroArg); + + isMacroArg = SM.isMacroArgExpansion(Loc); + return SpellLoc; +} + +static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + CXCursor declCursor = clang_getCursorReferenced(cursor); + if (!clang_isDeclaration(declCursor.kind)) + return CXChildVisit_Recurse; + + const Decl *D = cxcursor::getCursorDecl(declCursor); + if (!D) + return CXChildVisit_Continue; + + FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data; + if (data->isHit(D)) { + cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor); + + // We are looking for identifiers to highlight so for objc methods (and + // not a parameter) we can only highlight the selector identifiers. + if ((cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) && + cxcursor::getSelectorIdentifierIndex(cursor) == -1) + return CXChildVisit_Recurse; + + if (clang_isExpression(cursor.kind)) { + if (cursor.kind == CXCursor_DeclRefExpr || + cursor.kind == CXCursor_MemberRefExpr) { + // continue.. + + } else if (cursor.kind == CXCursor_ObjCMessageExpr && + cxcursor::getSelectorIdentifierIndex(cursor) != -1) { + // continue.. + + } else + return CXChildVisit_Recurse; + } + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor); + if (SelIdLoc.isValid()) + Loc = SelIdLoc; + + ASTContext &Ctx = data->getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + bool isInMacroDef = false; + if (Loc.isMacroID()) { + bool isMacroArg; + Loc = getFileSpellingLoc(SM, Loc, isMacroArg); + isInMacroDef = !isMacroArg; + } + + // We are looking for identifiers in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first != data->FID) + return CXChildVisit_Recurse; + + if (isInMacroDef) { + // FIXME: For a macro definition make sure that all expansions + // of it expand to the same reference before allowing to point to it. + return CXChildVisit_Recurse; + } + + if (data->visitor.visit(data->visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) + return CXChildVisit_Break; + } + return CXChildVisit_Recurse; +} + +static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor, + const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + assert(clang_isDeclaration(declCursor.kind)); + SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); + + FileID FID = SM.translateFile(File); + const Decl *Dcl = cxcursor::getCursorDecl(declCursor); + if (!Dcl) + return false; + + FindFileIdRefVisitData data(TU, FID, Dcl, + cxcursor::getSelectorIdentifierIndex(declCursor), + Visitor); + + if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) { + return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU), + findFileIdRefVisit, &data); + } + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor FindIdRefsVisitor(TU, + findFileIdRefVisit, &data, + /*VisitPreprocessorLast=*/true, + /*VisitIncludedEntities=*/false, + Range, + /*VisitDeclsOnly=*/true); + return FindIdRefsVisitor.visitFileRegion(); +} + +namespace { + +struct FindFileMacroRefVisitData { + ASTUnit &Unit; + const FileEntry *File; + const IdentifierInfo *Macro; + CXCursorAndRangeVisitor visitor; + + FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File, + const IdentifierInfo *Macro, + CXCursorAndRangeVisitor visitor) + : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { } + + ASTContext &getASTContext() const { + return Unit.getASTContext(); + } +}; + +} // anonymous namespace + +static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor, + CXCursor parent, + CXClientData client_data) { + const IdentifierInfo *Macro = nullptr; + if (cursor.kind == CXCursor_MacroDefinition) + Macro = getCursorMacroDefinition(cursor)->getName(); + else if (cursor.kind == CXCursor_MacroExpansion) + Macro = getCursorMacroExpansion(cursor).getName(); + if (!Macro) + return CXChildVisit_Continue; + + FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data; + if (data->Macro != Macro) + return CXChildVisit_Continue; + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + + ASTContext &Ctx = data->getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + bool isInMacroDef = false; + if (Loc.isMacroID()) { + bool isMacroArg; + Loc = getFileSpellingLoc(SM, Loc, isMacroArg); + isInMacroDef = !isMacroArg; + } + + // We are looking for identifiers in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (SM.getFileEntryForID(LocInfo.first) != data->File) + return CXChildVisit_Continue; + + if (isInMacroDef) { + // FIXME: For a macro definition make sure that all expansions + // of it expand to the same reference before allowing to point to it. + return CXChildVisit_Continue; + } + + if (data->visitor.visit(data->visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) + return CXChildVisit_Break; + return CXChildVisit_Continue; +} + +static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor, + const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + if (Cursor.kind != CXCursor_MacroDefinition && + Cursor.kind != CXCursor_MacroExpansion) + return false; + + ASTUnit *Unit = cxtu::getASTUnit(TU); + SourceManager &SM = Unit->getSourceManager(); + + FileID FID = SM.translateFile(File); + const IdentifierInfo *Macro = nullptr; + if (Cursor.kind == CXCursor_MacroDefinition) + Macro = getCursorMacroDefinition(Cursor)->getName(); + else + Macro = getCursorMacroExpansion(Cursor).getName(); + if (!Macro) + return false; + + FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor); + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor FindMacroRefsVisitor(TU, + findFileMacroRefVisit, &data, + /*VisitPreprocessorLast=*/false, + /*VisitIncludedEntities=*/false, + Range); + return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion(); +} + +namespace { + +struct FindFileIncludesVisitor { + ASTUnit &Unit; + const FileEntry *File; + CXCursorAndRangeVisitor visitor; + + FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File, + CXCursorAndRangeVisitor visitor) + : Unit(Unit), File(File), visitor(visitor) { } + + ASTContext &getASTContext() const { + return Unit.getASTContext(); + } + + enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { + if (cursor.kind != CXCursor_InclusionDirective) + return CXChildVisit_Continue; + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + + ASTContext &Ctx = getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + + // We are looking for includes in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (SM.getFileEntryForID(LocInfo.first) != File) + return CXChildVisit_Continue; + + if (visitor.visit(visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) + return CXChildVisit_Break; + return CXChildVisit_Continue; + } + + static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + return static_cast<FindFileIncludesVisitor*>(client_data)-> + visit(cursor, parent); + } +}; + +} // anonymous namespace + +static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + assert(TU && File && Visitor.visit); + + ASTUnit *Unit = cxtu::getASTUnit(TU); + SourceManager &SM = Unit->getSourceManager(); + + FileID FID = SM.translateFile(File); + + FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor); + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor InclusionCursorsVisitor(TU, + FindFileIncludesVisitor::visit, + &IncludesVisitor, + /*VisitPreprocessorLast=*/false, + /*VisitIncludedEntities=*/false, + Range); + return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion(); +} + + +//===----------------------------------------------------------------------===// +// libclang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file, + CXCursorAndRangeVisitor visitor) { + LogRef Log = Logger::make(__func__); + + if (clang_Cursor_isNull(cursor)) { + if (Log) + *Log << "Null cursor"; + return CXResult_Invalid; + } + if (cursor.kind == CXCursor_NoDeclFound) { + if (Log) + *Log << "Got CXCursor_NoDeclFound"; + return CXResult_Invalid; + } + if (!file) { + if (Log) + *Log << "Null file"; + return CXResult_Invalid; + } + if (!visitor.visit) { + if (Log) + *Log << "Null visitor"; + return CXResult_Invalid; + } + + if (Log) + *Log << cursor << " @" << static_cast<const FileEntry *>(file); + + ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor); + if (!CXXUnit) + return CXResult_Invalid; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + if (cursor.kind == CXCursor_MacroDefinition || + cursor.kind == CXCursor_MacroExpansion) { + if (findMacroRefsInFile(cxcursor::getCursorTU(cursor), + cursor, + static_cast<const FileEntry *>(file), + visitor)) + return CXResult_VisitBreak; + return CXResult_Success; + } + + // We are interested in semantics of identifiers so for C++ constructor exprs + // prefer type references, e.g.: + // + // return MyStruct(); + // + // for 'MyStruct' we'll have a cursor pointing at the constructor decl but + // we are actually interested in the type declaration. + cursor = cxcursor::getTypeRefCursor(cursor); + + CXCursor refCursor = clang_getCursorReferenced(cursor); + + if (!clang_isDeclaration(refCursor.kind)) { + if (Log) + *Log << "cursor is not referencing a declaration"; + return CXResult_Invalid; + } + + if (findIdRefsInFile(cxcursor::getCursorTU(cursor), + refCursor, + static_cast<const FileEntry *>(file), + visitor)) + return CXResult_VisitBreak; + return CXResult_Success; +} + +CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file, + CXCursorAndRangeVisitor visitor) { + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return CXResult_Invalid; + } + + LogRef Log = Logger::make(__func__); + if (!file) { + if (Log) + *Log << "Null file"; + return CXResult_Invalid; + } + if (!visitor.visit) { + if (Log) + *Log << "Null visitor"; + return CXResult_Invalid; + } + + if (Log) + *Log << TU << " @" << static_cast<const FileEntry *>(file); + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return CXResult_Invalid; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor)) + return CXResult_VisitBreak; + return CXResult_Success; +} + +static enum CXVisitorResult _visitCursorAndRange(void *context, + CXCursor cursor, + CXSourceRange range) { + CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context; + return INVOKE_BLOCK2(block, cursor, range); +} + +CXResult clang_findReferencesInFileWithBlock(CXCursor cursor, + CXFile file, + CXCursorAndRangeVisitorBlock block) { + CXCursorAndRangeVisitor visitor = { block, + block ? _visitCursorAndRange : nullptr }; + return clang_findReferencesInFile(cursor, file, visitor); +} + +CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU, + CXFile file, + CXCursorAndRangeVisitorBlock block) { + CXCursorAndRangeVisitor visitor = { block, + block ? _visitCursorAndRange : nullptr }; + return clang_findIncludesInFile(TU, file, visitor); +} + +} // end: extern "C" diff --git a/contrib/libs/clang14/tools/libclang/CIndexInclusionStack.cpp b/contrib/libs/clang14/tools/libclang/CIndexInclusionStack.cpp new file mode 100644 index 0000000000..3e05cff12c --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexInclusionStack.cpp @@ -0,0 +1,94 @@ +//===- CIndexInclusionStack.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 defines a callback mechanism for clients to get the inclusion +// stack from a translation unit. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Frontend/ASTUnit.h" +using namespace clang; + +namespace { +void getInclusions(bool IsLocal, unsigned n, CXTranslationUnit TU, + CXInclusionVisitor CB, CXClientData clientData) { + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + SourceManager &SM = CXXUnit->getSourceManager(); + ASTContext &Ctx = CXXUnit->getASTContext(); + SmallVector<CXSourceLocation, 10> InclusionStack; + const bool HasPreamble = SM.getPreambleFileID().isValid(); + + for (unsigned i = 0 ; i < n ; ++i) { + bool Invalid = false; + const SrcMgr::SLocEntry &SL = + IsLocal ? SM.getLocalSLocEntry(i) : SM.getLoadedSLocEntry(i, &Invalid); + if (!SL.isFile() || Invalid) + continue; + + const SrcMgr::FileInfo &FI = SL.getFile(); + if (!FI.getContentCache().OrigEntry) + continue; + + // If this is the main file, and there is a preamble, skip this SLoc. The + // inclusions of the preamble already showed it. + SourceLocation L = FI.getIncludeLoc(); + if (HasPreamble && CXXUnit->isInMainFileID(L)) + continue; + + // Build the inclusion stack. + InclusionStack.clear(); + while (L.isValid()) { + PresumedLoc PLoc = SM.getPresumedLoc(L); + InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L)); + L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation(); + } + + // If there is a preamble, the last entry is the "inclusion" of that + // preamble into the main file, which has the bogus entry of main.c:1:1 + if (HasPreamble && !InclusionStack.empty()) + InclusionStack.pop_back(); + + // Callback to the client. + // FIXME: We should have a function to construct CXFiles. + CB(static_cast<CXFile>( + const_cast<FileEntry *>(FI.getContentCache().OrigEntry)), + InclusionStack.data(), InclusionStack.size(), clientData); + } +} +} // namespace + +void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, + CXClientData clientData) { + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return; + } + + SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); + const unsigned n = SM.local_sloc_entry_size(); + + // In the case where all the SLocEntries are in an external source, traverse + // those SLocEntries as well. This is the case where we are looking + // at the inclusion stack of an AST/PCH file. Also, if we are not looking at + // a AST/PCH file, but this file has a pre-compiled preamble, we also need + // to look in that file. + if (n == 1 || SM.getPreambleFileID().isValid()) { + getInclusions(/*IsLocal=*/false, SM.loaded_sloc_entry_size(), TU, CB, + clientData); + } + + // Not a PCH/AST file. Note, if there is a preamble, it could still be that + // there are #includes in this file (e.g. for any include after the first + // declaration). + if (n != 1) + getInclusions(/*IsLocal=*/true, n, TU, CB, clientData); +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexUSRs.cpp b/contrib/libs/clang14/tools/libclang/CIndexUSRs.cpp new file mode 100644 index 0000000000..75bb3b0129 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexUSRs.cpp @@ -0,0 +1,139 @@ +//===- CIndexUSRs.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 generation and use of USRs from CXEntities. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Index/USRGeneration.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::index; + +//===----------------------------------------------------------------------===// +// API hooks. +//===----------------------------------------------------------------------===// + +static inline StringRef extractUSRSuffix(StringRef s) { + return s.startswith("c:") ? s.substr(2) : ""; +} + +bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) { + return generateUSRForDecl(D, Buf); +} + +CXString clang_getCursorUSR(CXCursor C) { + const CXCursorKind &K = clang_getCursorKind(C); + + if (clang_isDeclaration(K)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return cxstring::createEmpty(); + + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return cxstring::createEmpty(); + + cxstring::CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return cxstring::createEmpty(); + + bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data); + if (Ignore) { + buf->dispose(); + return cxstring::createEmpty(); + } + + // Return the C-string, but don't make a copy since it is already in + // the string buffer. + buf->Data.push_back('\0'); + return createCXString(buf); + } + + if (K == CXCursor_MacroDefinition) { + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return cxstring::createEmpty(); + + cxstring::CXStringBuf *buf = cxstring::getCXStringBuf(TU); + if (!buf) + return cxstring::createEmpty(); + + bool Ignore = generateUSRForMacro(cxcursor::getCursorMacroDefinition(C), + cxtu::getASTUnit(TU)->getSourceManager(), + buf->Data); + if (Ignore) { + buf->dispose(); + return cxstring::createEmpty(); + } + + // Return the C-string, but don't make a copy since it is already in + // the string buffer. + buf->Data.push_back('\0'); + return createCXString(buf); + } + + return cxstring::createEmpty(); +} + +CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + OS << extractUSRSuffix(clang_getCString(classUSR)); + generateUSRForObjCIvar(name, OS); + return cxstring::createDup(OS.str()); +} + +CXString clang_constructUSR_ObjCMethod(const char *name, + unsigned isInstanceMethod, + CXString classUSR) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + OS << extractUSRSuffix(clang_getCString(classUSR)); + generateUSRForObjCMethod(name, isInstanceMethod, OS); + return cxstring::createDup(OS.str()); +} + +CXString clang_constructUSR_ObjCClass(const char *name) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + generateUSRForObjCClass(name, OS); + return cxstring::createDup(OS.str()); +} + +CXString clang_constructUSR_ObjCProtocol(const char *name) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + generateUSRForObjCProtocol(name, OS); + return cxstring::createDup(OS.str()); +} + +CXString clang_constructUSR_ObjCCategory(const char *class_name, + const char *category_name) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + generateUSRForObjCCategory(class_name, category_name, OS); + return cxstring::createDup(OS.str()); +} + +CXString clang_constructUSR_ObjCProperty(const char *property, + CXString classUSR) { + SmallString<128> Buf(getUSRSpacePrefix()); + llvm::raw_svector_ostream OS(Buf); + OS << extractUSRSuffix(clang_getCString(classUSR)); + generateUSRForObjCProperty(property, /*isClassProp=*/false, OS); + return cxstring::createDup(OS.str()); +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexer.cpp b/contrib/libs/clang14/tools/libclang/CIndexer.cpp new file mode 100644 index 0000000000..8f3d548a1d --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexer.cpp @@ -0,0 +1,222 @@ +//===- CIndexer.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 Clang-C Source Indexing library. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXString.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Driver.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MD5.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/YAMLParser.h" +#include <cstdio> +#include <mutex> + +#ifdef __CYGWIN__ +#include <cygwin/version.h> +#include <sys/cygwin.h> +#define _WIN32 1 +#endif + +#ifdef _WIN32 +#include <windows.h> +#elif defined(_AIX) +#include <errno.h> +#error #include <sys/ldr.h> +#else +#include <dlfcn.h> +#endif + +using namespace clang; + +#ifdef _AIX +namespace clang { +namespace { + +template <typename LibClangPathType> +void getClangResourcesPathImplAIX(LibClangPathType &LibClangPath) { + int PrevErrno = errno; + + size_t BufSize = 2048u; + std::unique_ptr<char[]> Buf; + while (true) { + Buf = std::make_unique<char []>(BufSize); + errno = 0; + int Ret = loadquery(L_GETXINFO, Buf.get(), (unsigned int)BufSize); + if (Ret != -1) + break; // loadquery() was successful. + if (errno != ENOMEM) + llvm_unreachable("Encountered an unexpected loadquery() failure"); + + // errno == ENOMEM; try to allocate more memory. + if ((BufSize & ~((-1u) >> 1u)) != 0u) + llvm::report_fatal_error("BufSize needed for loadquery() too large"); + + Buf.release(); + BufSize <<= 1u; + } + + // Extract the function entry point from the function descriptor. + uint64_t EntryAddr = + reinterpret_cast<uintptr_t &>(clang_createTranslationUnit); + + // Loop to locate the function entry point in the loadquery() results. + ld_xinfo *CurInfo = reinterpret_cast<ld_xinfo *>(Buf.get()); + while (true) { + uint64_t CurTextStart = (uint64_t)CurInfo->ldinfo_textorg; + uint64_t CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize; + if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd) + break; // Successfully located. + + if (CurInfo->ldinfo_next == 0u) + llvm::report_fatal_error("Cannot locate entry point in " + "the loadquery() results"); + CurInfo = reinterpret_cast<ld_xinfo *>(reinterpret_cast<char *>(CurInfo) + + CurInfo->ldinfo_next); + } + + LibClangPath += reinterpret_cast<char *>(CurInfo) + CurInfo->ldinfo_filename; + errno = PrevErrno; +} + +} // end anonymous namespace +} // end namespace clang +#endif + +const std::string &CIndexer::getClangResourcesPath() { + // Did we already compute the path? + if (!ResourcesPath.empty()) + return ResourcesPath; + + SmallString<128> LibClangPath; + + // Find the location where this library lives (libclang.dylib). +#ifdef _WIN32 + MEMORY_BASIC_INFORMATION mbi; + char path[MAX_PATH]; + VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi, + sizeof(mbi)); + GetModuleFileNameA((HINSTANCE)mbi.AllocationBase, path, MAX_PATH); + +#ifdef __CYGWIN__ + char w32path[MAX_PATH]; + strcpy(w32path, path); +#if CYGWIN_VERSION_API_MAJOR > 0 || CYGWIN_VERSION_API_MINOR >= 181 + cygwin_conv_path(CCP_WIN_A_TO_POSIX, w32path, path, MAX_PATH); +#else + cygwin_conv_to_full_posix_path(w32path, path); +#endif +#endif + + LibClangPath += path; +#elif defined(_AIX) + getClangResourcesPathImplAIX(LibClangPath); +#else + // This silly cast below avoids a C++ warning. + Dl_info info; + if (dladdr((void *)(uintptr_t)clang_createTranslationUnit, &info) == 0) + llvm_unreachable("Call to dladdr() failed"); + + // We now have the CIndex directory, locate clang relative to it. + LibClangPath += info.dli_fname; +#endif + + // Cache our result. + ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath); + return ResourcesPath; +} + +StringRef CIndexer::getClangToolchainPath() { + if (!ToolchainPath.empty()) + return ToolchainPath; + StringRef ResourcePath = getClangResourcesPath(); + ToolchainPath = + std::string(llvm::sys::path::parent_path(llvm::sys::path::parent_path( + llvm::sys::path::parent_path(ResourcePath)))); + return ToolchainPath; +} + +LibclangInvocationReporter::LibclangInvocationReporter( + CIndexer &Idx, OperationKind Op, unsigned ParseOptions, + llvm::ArrayRef<const char *> Args, + llvm::ArrayRef<std::string> InvocationArgs, + llvm::ArrayRef<CXUnsavedFile> UnsavedFiles) { + StringRef Path = Idx.getInvocationEmissionPath(); + if (Path.empty()) + return; + + // Create a temporary file for the invocation log. + SmallString<256> TempPath; + TempPath = Path; + llvm::sys::path::append(TempPath, "libclang-%%%%%%%%%%%%"); + int FD; + if (llvm::sys::fs::createUniqueFile(TempPath, FD, TempPath, + llvm::sys::fs::OF_Text)) + return; + File = std::string(TempPath.begin(), TempPath.end()); + llvm::raw_fd_ostream OS(FD, /*ShouldClose=*/true); + + // Write out the information about the invocation to it. + auto WriteStringKey = [&OS](StringRef Key, StringRef Value) { + OS << R"(")" << Key << R"(":")"; + OS << llvm::yaml::escape(Value) << '"'; + }; + OS << '{'; + WriteStringKey("toolchain", Idx.getClangToolchainPath()); + OS << ','; + WriteStringKey("libclang.operation", + Op == OperationKind::ParseOperation ? "parse" : "complete"); + OS << ','; + OS << R"("libclang.opts":)" << ParseOptions; + OS << ','; + OS << R"("args":[)"; + for (const auto &I : llvm::enumerate(Args)) { + if (I.index()) + OS << ','; + OS << '"' << llvm::yaml::escape(I.value()) << '"'; + } + if (!InvocationArgs.empty()) { + OS << R"(],"invocation-args":[)"; + for (const auto &I : llvm::enumerate(InvocationArgs)) { + if (I.index()) + OS << ','; + OS << '"' << llvm::yaml::escape(I.value()) << '"'; + } + } + if (!UnsavedFiles.empty()) { + OS << R"(],"unsaved_file_hashes":[)"; + for (const auto &UF : llvm::enumerate(UnsavedFiles)) { + if (UF.index()) + OS << ','; + OS << '{'; + WriteStringKey("name", UF.value().Filename); + OS << ','; + llvm::MD5 Hash; + Hash.update(getContents(UF.value())); + llvm::MD5::MD5Result Result; + Hash.final(Result); + SmallString<32> Digest = Result.digest(); + WriteStringKey("md5", Digest); + OS << '}'; + } + } + OS << "]}"; +} + +LibclangInvocationReporter::~LibclangInvocationReporter() { + if (!File.empty()) + llvm::sys::fs::remove(File); +} diff --git a/contrib/libs/clang14/tools/libclang/CIndexer.h b/contrib/libs/clang14/tools/libclang/CIndexer.h new file mode 100644 index 0000000000..de15cc34b5 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CIndexer.h @@ -0,0 +1,153 @@ +//===- CIndexer.h - Clang-C Source Indexing Library -------------*- C++ -*-===// +// +// 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 defines CIndexer, a subclass of Indexer that provides extra +// functionality needed by the CIndex library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CINDEXER_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CINDEXER_H + +#include "clang-c/Index.h" +#include "clang/Frontend/PCHContainerOperations.h" +#include "llvm/ADT/STLExtras.h" +#include <utility> + +namespace llvm { + class CrashRecoveryContext; +} + +namespace clang { +class ASTUnit; +class MacroInfo; +class MacroDefinitionRecord; +class SourceLocation; +class Token; +class IdentifierInfo; + +class CIndexer { + bool OnlyLocalDecls; + bool DisplayDiagnostics; + unsigned Options; // CXGlobalOptFlags. + + std::string ResourcesPath; + std::shared_ptr<PCHContainerOperations> PCHContainerOps; + + std::string ToolchainPath; + + std::string InvocationEmissionPath; + +public: + CIndexer(std::shared_ptr<PCHContainerOperations> PCHContainerOps = + std::make_shared<PCHContainerOperations>()) + : OnlyLocalDecls(false), DisplayDiagnostics(false), + Options(CXGlobalOpt_None), PCHContainerOps(std::move(PCHContainerOps)) { + } + + /// Whether we only want to see "local" declarations (that did not + /// come from a previous precompiled header). If false, we want to see all + /// declarations. + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + void setOnlyLocalDecls(bool Local = true) { OnlyLocalDecls = Local; } + + bool getDisplayDiagnostics() const { return DisplayDiagnostics; } + void setDisplayDiagnostics(bool Display = true) { + DisplayDiagnostics = Display; + } + + std::shared_ptr<PCHContainerOperations> getPCHContainerOperations() const { + return PCHContainerOps; + } + + unsigned getCXGlobalOptFlags() const { return Options; } + void setCXGlobalOptFlags(unsigned options) { Options = options; } + + bool isOptEnabled(CXGlobalOptFlags opt) const { + return Options & opt; + } + + /// Get the path of the clang resource files. + const std::string &getClangResourcesPath(); + + StringRef getClangToolchainPath(); + + void setInvocationEmissionPath(StringRef Str) { + InvocationEmissionPath = std::string(Str); + } + + StringRef getInvocationEmissionPath() const { return InvocationEmissionPath; } +}; + +/// Logs information about a particular libclang operation like parsing to +/// a new file in the invocation emission path. +class LibclangInvocationReporter { +public: + enum class OperationKind { ParseOperation, CompletionOperation }; + + LibclangInvocationReporter(CIndexer &Idx, OperationKind Op, + unsigned ParseOptions, + llvm::ArrayRef<const char *> Args, + llvm::ArrayRef<std::string> InvocationArgs, + llvm::ArrayRef<CXUnsavedFile> UnsavedFiles); + ~LibclangInvocationReporter(); + +private: + std::string File; +}; + + /// Return the current size to request for "safety". + unsigned GetSafetyThreadStackSize(); + + /// Set the current size to request for "safety" (or 0, if safety + /// threads should not be used). + void SetSafetyThreadStackSize(unsigned Value); + + /// Execution the given code "safely", using crash recovery or safety + /// threads when possible. + /// + /// \return False if a crash was detected. + bool RunSafely(llvm::CrashRecoveryContext &CRC, llvm::function_ref<void()> Fn, + unsigned Size = 0); + + /// Set the thread priority to background. + /// FIXME: Move to llvm/Support. + void setThreadBackgroundPriority(); + + /// Print libclang's resource usage to standard error. + void PrintLibclangResourceUsage(CXTranslationUnit TU); + + namespace cxindex { + void printDiagsToStderr(ASTUnit *Unit); + + /// If \c MacroDefLoc points at a macro definition with \c II as + /// its name, this retrieves its MacroInfo. + MacroInfo *getMacroInfo(const IdentifierInfo &II, + SourceLocation MacroDefLoc, CXTranslationUnit TU); + + /// Retrieves the corresponding MacroInfo of a MacroDefinitionRecord. + const MacroInfo *getMacroInfo(const MacroDefinitionRecord *MacroDef, + CXTranslationUnit TU); + + /// If \c Loc resides inside the definition of \c MI and it points at + /// an identifier that has ever been a macro name, this returns the latest + /// MacroDefinitionRecord for that name, otherwise it returns NULL. + MacroDefinitionRecord *checkForMacroInMacroDefinition(const MacroInfo *MI, + SourceLocation Loc, + CXTranslationUnit TU); + + /// If \c Tok resides inside the definition of \c MI and it points at + /// an identifier that has ever been a macro name, this returns the latest + /// MacroDefinitionRecord for that name, otherwise it returns NULL. + MacroDefinitionRecord *checkForMacroInMacroDefinition(const MacroInfo *MI, + const Token &Tok, + CXTranslationUnit TU); + } + } + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CLog.h b/contrib/libs/clang14/tools/libclang/CLog.h new file mode 100644 index 0000000000..ffd0940e7a --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CLog.h @@ -0,0 +1,102 @@ +//===- CLog.h - Logging Interface -------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CLOG_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CLOG_H + +#include "clang-c/Index.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace llvm { +class format_object_base; +} + +namespace clang { + class FileEntry; + +namespace cxindex { + +class Logger; +typedef IntrusiveRefCntPtr<Logger> LogRef; + +/// Collects logging output and writes it to stderr when it's destructed. +/// Common use case: +/// \code +/// if (LogRef Log = Logger::make(__func__)) { +/// *Log << "stuff"; +/// } +/// \endcode +class Logger : public RefCountedBase<Logger> { + std::string Name; + bool Trace; + SmallString<64> Msg; + llvm::raw_svector_ostream LogOS; +public: + static const char *getEnvVar() { + static const char *sCachedVar = ::getenv("LIBCLANG_LOGGING"); + return sCachedVar; + } + static bool isLoggingEnabled() { return getEnvVar() != nullptr; } + static bool isStackTracingEnabled() { + if (const char *EnvOpt = Logger::getEnvVar()) + return llvm::StringRef(EnvOpt) == "2"; + return false; + } + static LogRef make(llvm::StringRef name, + bool trace = isStackTracingEnabled()) { + if (isLoggingEnabled()) + return new Logger(name, trace); + return nullptr; + } + + explicit Logger(llvm::StringRef name, bool trace) + : Name(std::string(name)), Trace(trace), LogOS(Msg) {} + ~Logger(); + + Logger &operator<<(CXTranslationUnit); + Logger &operator<<(const FileEntry *FE); + Logger &operator<<(CXCursor cursor); + Logger &operator<<(CXSourceLocation); + Logger &operator<<(CXSourceRange); + Logger &operator<<(CXString); + Logger &operator<<(llvm::StringRef Str) { LogOS << Str; return *this; } + Logger &operator<<(const char *Str) { + if (Str) + LogOS << Str; + return *this; + } + Logger &operator<<(unsigned long N) { LogOS << N; return *this; } + Logger &operator<<(long N) { LogOS << N ; return *this; } + Logger &operator<<(unsigned int N) { LogOS << N; return *this; } + Logger &operator<<(int N) { LogOS << N; return *this; } + Logger &operator<<(char C) { LogOS << C; return *this; } + Logger &operator<<(unsigned char C) { LogOS << C; return *this; } + Logger &operator<<(signed char C) { LogOS << C; return *this; } + Logger &operator<<(const llvm::format_object_base &Fmt); +}; + +} +} + +/// Macros to automate common uses of Logger. Like this: +/// \code +/// LOG_FUNC_SECTION { +/// *Log << "blah"; +/// } +/// \endcode +#define LOG_SECTION(NAME) \ + if (clang::cxindex::LogRef Log = clang::cxindex::Logger::make(NAME)) +#define LOG_FUNC_SECTION LOG_SECTION(__func__) + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXComment.cpp b/contrib/libs/clang14/tools/libclang/CXComment.cpp new file mode 100644 index 0000000000..bafaeb0fd0 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXComment.cpp @@ -0,0 +1,408 @@ +//===- CXComment.cpp - libclang APIs for manipulating CXComments ----------===// +// +// 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 defines all libclang APIs related to walking comment AST. +// +//===----------------------------------------------------------------------===// + +#include "CXComment.h" +#include "CXCursor.h" +#include "CXString.h" +#include "clang-c/Documentation.h" +#include "clang-c/Index.h" +#include "clang/AST/Decl.h" +#include "clang/Index/CommentToXML.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include <climits> + +using namespace clang; +using namespace clang::comments; +using namespace clang::cxcomment; + +CXComment clang_Cursor_getParsedComment(CXCursor C) { + using namespace clang::cxcursor; + + if (!clang_isDeclaration(C.kind)) + return createCXComment(nullptr, nullptr); + + const Decl *D = getCursorDecl(C); + const ASTContext &Context = getCursorContext(C); + const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/nullptr); + + return createCXComment(FC, getCursorTU(C)); +} + +enum CXCommentKind clang_Comment_getKind(CXComment CXC) { + const Comment *C = getASTNode(CXC); + if (!C) + return CXComment_Null; + + switch (C->getCommentKind()) { + case Comment::NoCommentKind: + return CXComment_Null; + + case Comment::TextCommentKind: + return CXComment_Text; + + case Comment::InlineCommandCommentKind: + return CXComment_InlineCommand; + + case Comment::HTMLStartTagCommentKind: + return CXComment_HTMLStartTag; + + case Comment::HTMLEndTagCommentKind: + return CXComment_HTMLEndTag; + + case Comment::ParagraphCommentKind: + return CXComment_Paragraph; + + case Comment::BlockCommandCommentKind: + return CXComment_BlockCommand; + + case Comment::ParamCommandCommentKind: + return CXComment_ParamCommand; + + case Comment::TParamCommandCommentKind: + return CXComment_TParamCommand; + + case Comment::VerbatimBlockCommentKind: + return CXComment_VerbatimBlockCommand; + + case Comment::VerbatimBlockLineCommentKind: + return CXComment_VerbatimBlockLine; + + case Comment::VerbatimLineCommentKind: + return CXComment_VerbatimLine; + + case Comment::FullCommentKind: + return CXComment_FullComment; + } + llvm_unreachable("unknown CommentKind"); +} + +unsigned clang_Comment_getNumChildren(CXComment CXC) { + const Comment *C = getASTNode(CXC); + if (!C) + return 0; + + return C->child_count(); +} + +CXComment clang_Comment_getChild(CXComment CXC, unsigned ChildIdx) { + const Comment *C = getASTNode(CXC); + if (!C || ChildIdx >= C->child_count()) + return createCXComment(nullptr, nullptr); + + return createCXComment(*(C->child_begin() + ChildIdx), CXC.TranslationUnit); +} + +unsigned clang_Comment_isWhitespace(CXComment CXC) { + const Comment *C = getASTNode(CXC); + if (!C) + return false; + + if (const TextComment *TC = dyn_cast<TextComment>(C)) + return TC->isWhitespace(); + + if (const ParagraphComment *PC = dyn_cast<ParagraphComment>(C)) + return PC->isWhitespace(); + + return false; +} + +unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) { + const InlineContentComment *ICC = getASTNodeAs<InlineContentComment>(CXC); + if (!ICC) + return false; + + return ICC->hasTrailingNewline(); +} + +CXString clang_TextComment_getText(CXComment CXC) { + const TextComment *TC = getASTNodeAs<TextComment>(CXC); + if (!TC) + return cxstring::createNull(); + + return cxstring::createRef(TC->getText()); +} + +CXString clang_InlineCommandComment_getCommandName(CXComment CXC) { + const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); + if (!ICC) + return cxstring::createNull(); + + const CommandTraits &Traits = getCommandTraits(CXC); + return cxstring::createRef(ICC->getCommandName(Traits)); +} + +enum CXCommentInlineCommandRenderKind +clang_InlineCommandComment_getRenderKind(CXComment CXC) { + const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); + if (!ICC) + return CXCommentInlineCommandRenderKind_Normal; + + switch (ICC->getRenderKind()) { + case InlineCommandComment::RenderNormal: + return CXCommentInlineCommandRenderKind_Normal; + + case InlineCommandComment::RenderBold: + return CXCommentInlineCommandRenderKind_Bold; + + case InlineCommandComment::RenderMonospaced: + return CXCommentInlineCommandRenderKind_Monospaced; + + case InlineCommandComment::RenderEmphasized: + return CXCommentInlineCommandRenderKind_Emphasized; + + case InlineCommandComment::RenderAnchor: + return CXCommentInlineCommandRenderKind_Anchor; + } + llvm_unreachable("unknown InlineCommandComment::RenderKind"); +} + +unsigned clang_InlineCommandComment_getNumArgs(CXComment CXC) { + const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); + if (!ICC) + return 0; + + return ICC->getNumArgs(); +} + +CXString clang_InlineCommandComment_getArgText(CXComment CXC, + unsigned ArgIdx) { + const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC); + if (!ICC || ArgIdx >= ICC->getNumArgs()) + return cxstring::createNull(); + + return cxstring::createRef(ICC->getArgText(ArgIdx)); +} + +CXString clang_HTMLTagComment_getTagName(CXComment CXC) { + const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); + if (!HTC) + return cxstring::createNull(); + + return cxstring::createRef(HTC->getTagName()); +} + +unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) { + const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); + if (!HST) + return false; + + return HST->isSelfClosing(); +} + +unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) { + const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); + if (!HST) + return 0; + + return HST->getNumAttrs(); +} + +CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) { + const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); + if (!HST || AttrIdx >= HST->getNumAttrs()) + return cxstring::createNull(); + + return cxstring::createRef(HST->getAttr(AttrIdx).Name); +} + +CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) { + const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC); + if (!HST || AttrIdx >= HST->getNumAttrs()) + return cxstring::createNull(); + + return cxstring::createRef(HST->getAttr(AttrIdx).Value); +} + +CXString clang_BlockCommandComment_getCommandName(CXComment CXC) { + const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); + if (!BCC) + return cxstring::createNull(); + + const CommandTraits &Traits = getCommandTraits(CXC); + return cxstring::createRef(BCC->getCommandName(Traits)); +} + +unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) { + const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); + if (!BCC) + return 0; + + return BCC->getNumArgs(); +} + +CXString clang_BlockCommandComment_getArgText(CXComment CXC, + unsigned ArgIdx) { + const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); + if (!BCC || ArgIdx >= BCC->getNumArgs()) + return cxstring::createNull(); + + return cxstring::createRef(BCC->getArgText(ArgIdx)); +} + +CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) { + const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC); + if (!BCC) + return createCXComment(nullptr, nullptr); + + return createCXComment(BCC->getParagraph(), CXC.TranslationUnit); +} + +CXString clang_ParamCommandComment_getParamName(CXComment CXC) { + const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); + if (!PCC || !PCC->hasParamName()) + return cxstring::createNull(); + + return cxstring::createRef(PCC->getParamNameAsWritten()); +} + +unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) { + const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); + if (!PCC) + return false; + + return PCC->isParamIndexValid(); +} + +unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) { + const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); + if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam()) + return ParamCommandComment::InvalidParamIndex; + + return PCC->getParamIndex(); +} + +unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) { + const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); + if (!PCC) + return false; + + return PCC->isDirectionExplicit(); +} + +enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection( + CXComment CXC) { + const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC); + if (!PCC) + return CXCommentParamPassDirection_In; + + switch (PCC->getDirection()) { + case ParamCommandComment::In: + return CXCommentParamPassDirection_In; + + case ParamCommandComment::Out: + return CXCommentParamPassDirection_Out; + + case ParamCommandComment::InOut: + return CXCommentParamPassDirection_InOut; + } + llvm_unreachable("unknown ParamCommandComment::PassDirection"); +} + +CXString clang_TParamCommandComment_getParamName(CXComment CXC) { + const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); + if (!TPCC || !TPCC->hasParamName()) + return cxstring::createNull(); + + return cxstring::createRef(TPCC->getParamNameAsWritten()); +} + +unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) { + const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); + if (!TPCC) + return false; + + return TPCC->isPositionValid(); +} + +unsigned clang_TParamCommandComment_getDepth(CXComment CXC) { + const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); + if (!TPCC || !TPCC->isPositionValid()) + return 0; + + return TPCC->getDepth(); +} + +unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) { + const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC); + if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth()) + return 0; + + return TPCC->getIndex(Depth); +} + +CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) { + const VerbatimBlockLineComment *VBL = + getASTNodeAs<VerbatimBlockLineComment>(CXC); + if (!VBL) + return cxstring::createNull(); + + return cxstring::createRef(VBL->getText()); +} + +CXString clang_VerbatimLineComment_getText(CXComment CXC) { + const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC); + if (!VLC) + return cxstring::createNull(); + + return cxstring::createRef(VLC->getText()); +} + +//===----------------------------------------------------------------------===// +// Converting comments to XML. +//===----------------------------------------------------------------------===// + +CXString clang_HTMLTagComment_getAsString(CXComment CXC) { + const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC); + if (!HTC) + return cxstring::createNull(); + + CXTranslationUnit TU = CXC.TranslationUnit; + if (!TU->CommentToXML) + TU->CommentToXML = new clang::index::CommentToXMLConverter(); + + SmallString<128> Text; + TU->CommentToXML->convertHTMLTagNodeToText( + HTC, Text, cxtu::getASTUnit(TU)->getASTContext()); + return cxstring::createDup(Text.str()); +} + +CXString clang_FullComment_getAsHTML(CXComment CXC) { + const FullComment *FC = getASTNodeAs<FullComment>(CXC); + if (!FC) + return cxstring::createNull(); + + CXTranslationUnit TU = CXC.TranslationUnit; + if (!TU->CommentToXML) + TU->CommentToXML = new clang::index::CommentToXMLConverter(); + + SmallString<1024> HTML; + TU->CommentToXML + ->convertCommentToHTML(FC, HTML, cxtu::getASTUnit(TU)->getASTContext()); + return cxstring::createDup(HTML.str()); +} + +CXString clang_FullComment_getAsXML(CXComment CXC) { + const FullComment *FC = getASTNodeAs<FullComment>(CXC); + if (!FC) + return cxstring::createNull(); + + CXTranslationUnit TU = CXC.TranslationUnit; + if (!TU->CommentToXML) + TU->CommentToXML = new clang::index::CommentToXMLConverter(); + + SmallString<1024> XML; + TU->CommentToXML + ->convertCommentToXML(FC, XML, cxtu::getASTUnit(TU)->getASTContext()); + return cxstring::createDup(XML.str()); +} + diff --git a/contrib/libs/clang14/tools/libclang/CXComment.h b/contrib/libs/clang14/tools/libclang/CXComment.h new file mode 100644 index 0000000000..30be06419c --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXComment.h @@ -0,0 +1,63 @@ +//===- CXComment.h - Routines for manipulating CXComments -----------------===// +// +// 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 defines routines for manipulating CXComments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXCOMMENT_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXCOMMENT_H + +#include "CXTranslationUnit.h" +#include "clang-c/Documentation.h" +#include "clang-c/Index.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Comment.h" +#include "clang/Frontend/ASTUnit.h" + +namespace clang { +namespace comments { + class CommandTraits; +} + +namespace cxcomment { + +static inline CXComment createCXComment(const comments::Comment *C, + CXTranslationUnit TU) { + CXComment Result; + Result.ASTNode = C; + Result.TranslationUnit = TU; + return Result; +} + +static inline const comments::Comment *getASTNode(CXComment CXC) { + return static_cast<const comments::Comment *>(CXC.ASTNode); +} + +template<typename T> +static inline const T *getASTNodeAs(CXComment CXC) { + const comments::Comment *C = getASTNode(CXC); + if (!C) + return nullptr; + + return dyn_cast<T>(C); +} + +static inline ASTContext &getASTContext(CXComment CXC) { + return cxtu::getASTUnit(CXC.TranslationUnit)->getASTContext(); +} + +static inline comments::CommandTraits &getCommandTraits(CXComment CXC) { + return getASTContext(CXC).getCommentCommandTraits(); +} + +} // end namespace cxcomment +} // end namespace clang + +#endif + diff --git a/contrib/libs/clang14/tools/libclang/CXCompilationDatabase.cpp b/contrib/libs/clang14/tools/libclang/CXCompilationDatabase.cpp new file mode 100644 index 0000000000..2ca532659d --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXCompilationDatabase.cpp @@ -0,0 +1,167 @@ +#include "clang-c/CXCompilationDatabase.h" +#include "CXString.h" +#include "clang/Tooling/CompilationDatabase.h" +#include <cstdio> + +using namespace clang; +using namespace clang::tooling; + +// FIXME: do something more useful with the error message +CXCompilationDatabase +clang_CompilationDatabase_fromDirectory(const char *BuildDir, + CXCompilationDatabase_Error *ErrorCode) +{ + std::string ErrorMsg; + CXCompilationDatabase_Error Err = CXCompilationDatabase_NoError; + + std::unique_ptr<CompilationDatabase> db = + CompilationDatabase::loadFromDirectory(BuildDir, ErrorMsg); + + if (!db) { + fprintf(stderr, "LIBCLANG TOOLING ERROR: %s\n", ErrorMsg.c_str()); + Err = CXCompilationDatabase_CanNotLoadDatabase; + } + + if (ErrorCode) + *ErrorCode = Err; + + return db.release(); +} + +void +clang_CompilationDatabase_dispose(CXCompilationDatabase CDb) +{ + delete static_cast<CompilationDatabase *>(CDb); +} + +struct AllocatedCXCompileCommands +{ + std::vector<CompileCommand> CCmd; + + AllocatedCXCompileCommands(std::vector<CompileCommand> Cmd) + : CCmd(std::move(Cmd)) {} +}; + +CXCompileCommands +clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase CDb, + const char *CompleteFileName) +{ + if (CompilationDatabase *db = static_cast<CompilationDatabase *>(CDb)) { + std::vector<CompileCommand> CCmd(db->getCompileCommands(CompleteFileName)); + if (!CCmd.empty()) + return new AllocatedCXCompileCommands(std::move(CCmd)); + } + + return nullptr; +} + +CXCompileCommands +clang_CompilationDatabase_getAllCompileCommands(CXCompilationDatabase CDb) { + if (CompilationDatabase *db = static_cast<CompilationDatabase *>(CDb)) { + std::vector<CompileCommand> CCmd(db->getAllCompileCommands()); + if (!CCmd.empty()) + return new AllocatedCXCompileCommands(std::move(CCmd)); + } + + return nullptr; +} + +void +clang_CompileCommands_dispose(CXCompileCommands Cmds) +{ + delete static_cast<AllocatedCXCompileCommands *>(Cmds); +} + +unsigned +clang_CompileCommands_getSize(CXCompileCommands Cmds) +{ + if (!Cmds) + return 0; + + AllocatedCXCompileCommands *ACC = + static_cast<AllocatedCXCompileCommands *>(Cmds); + + return ACC->CCmd.size(); +} + +CXCompileCommand +clang_CompileCommands_getCommand(CXCompileCommands Cmds, unsigned I) +{ + if (!Cmds) + return nullptr; + + AllocatedCXCompileCommands *ACC = + static_cast<AllocatedCXCompileCommands *>(Cmds); + + if (I >= ACC->CCmd.size()) + return nullptr; + + return &ACC->CCmd[I]; +} + +CXString +clang_CompileCommand_getDirectory(CXCompileCommand CCmd) +{ + if (!CCmd) + return cxstring::createNull(); + + CompileCommand *cmd = static_cast<CompileCommand *>(CCmd); + return cxstring::createRef(cmd->Directory.c_str()); +} + +CXString +clang_CompileCommand_getFilename(CXCompileCommand CCmd) +{ + if (!CCmd) + return cxstring::createNull(); + + CompileCommand *cmd = static_cast<CompileCommand *>(CCmd); + return cxstring::createRef(cmd->Filename.c_str()); +} + +unsigned +clang_CompileCommand_getNumArgs(CXCompileCommand CCmd) +{ + if (!CCmd) + return 0; + + return static_cast<CompileCommand *>(CCmd)->CommandLine.size(); +} + +CXString +clang_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg) +{ + if (!CCmd) + return cxstring::createNull(); + + CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd); + + if (Arg >= Cmd->CommandLine.size()) + return cxstring::createNull(); + + return cxstring::createRef(Cmd->CommandLine[Arg].c_str()); +} + +unsigned +clang_CompileCommand_getNumMappedSources(CXCompileCommand CCmd) +{ + // Left here for backward compatibility. No mapped sources exists in the C++ + // backend anymore. + return 0; +} + +CXString +clang_CompileCommand_getMappedSourcePath(CXCompileCommand CCmd, unsigned I) +{ + // Left here for backward compatibility. No mapped sources exists in the C++ + // backend anymore. + return cxstring::createNull(); +} + +CXString +clang_CompileCommand_getMappedSourceContent(CXCompileCommand CCmd, unsigned I) +{ + // Left here for backward compatibility. No mapped sources exists in the C++ + // backend anymore. + return cxstring::createNull(); +} diff --git a/contrib/libs/clang14/tools/libclang/CXCursor.cpp b/contrib/libs/clang14/tools/libclang/CXCursor.cpp new file mode 100644 index 0000000000..db02e0c71c --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXCursor.cpp @@ -0,0 +1,1721 @@ +//===- CXCursor.cpp - Routines for manipulating CXCursors -----------------===// +// +// 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 defines routines for manipulating CXCursors. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXCursor. +// +//===----------------------------------------------------------------------===// + +#include "CXCursor.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "CXType.h" +#include "clang-c/Index.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; +using namespace cxcursor; + +CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU) { + assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid); + CXCursor C = {K, 0, {nullptr, nullptr, TU}}; + return C; +} + +static CXCursorKind GetCursorKind(const Attr *A) { + assert(A && "Invalid arguments!"); + switch (A->getKind()) { + default: + break; + case attr::IBAction: + return CXCursor_IBActionAttr; + case attr::IBOutlet: + return CXCursor_IBOutletAttr; + case attr::IBOutletCollection: + return CXCursor_IBOutletCollectionAttr; + case attr::Final: + return CXCursor_CXXFinalAttr; + case attr::Override: + return CXCursor_CXXOverrideAttr; + case attr::Annotate: + return CXCursor_AnnotateAttr; + case attr::AsmLabel: + return CXCursor_AsmLabelAttr; + case attr::Packed: + return CXCursor_PackedAttr; + case attr::Pure: + return CXCursor_PureAttr; + case attr::Const: + return CXCursor_ConstAttr; + case attr::NoDuplicate: + return CXCursor_NoDuplicateAttr; + case attr::CUDAConstant: + return CXCursor_CUDAConstantAttr; + case attr::CUDADevice: + return CXCursor_CUDADeviceAttr; + case attr::CUDAGlobal: + return CXCursor_CUDAGlobalAttr; + case attr::CUDAHost: + return CXCursor_CUDAHostAttr; + case attr::CUDAShared: + return CXCursor_CUDASharedAttr; + case attr::Visibility: + return CXCursor_VisibilityAttr; + case attr::DLLExport: + return CXCursor_DLLExport; + case attr::DLLImport: + return CXCursor_DLLImport; + case attr::NSReturnsRetained: + return CXCursor_NSReturnsRetained; + case attr::NSReturnsNotRetained: + return CXCursor_NSReturnsNotRetained; + case attr::NSReturnsAutoreleased: + return CXCursor_NSReturnsAutoreleased; + case attr::NSConsumesSelf: + return CXCursor_NSConsumesSelf; + case attr::NSConsumed: + return CXCursor_NSConsumed; + case attr::ObjCException: + return CXCursor_ObjCException; + case attr::ObjCNSObject: + return CXCursor_ObjCNSObject; + case attr::ObjCIndependentClass: + return CXCursor_ObjCIndependentClass; + case attr::ObjCPreciseLifetime: + return CXCursor_ObjCPreciseLifetime; + case attr::ObjCReturnsInnerPointer: + return CXCursor_ObjCReturnsInnerPointer; + case attr::ObjCRequiresSuper: + return CXCursor_ObjCRequiresSuper; + case attr::ObjCRootClass: + return CXCursor_ObjCRootClass; + case attr::ObjCSubclassingRestricted: + return CXCursor_ObjCSubclassingRestricted; + case attr::ObjCExplicitProtocolImpl: + return CXCursor_ObjCExplicitProtocolImpl; + case attr::ObjCDesignatedInitializer: + return CXCursor_ObjCDesignatedInitializer; + case attr::ObjCRuntimeVisible: + return CXCursor_ObjCRuntimeVisible; + case attr::ObjCBoxable: + return CXCursor_ObjCBoxable; + case attr::FlagEnum: + return CXCursor_FlagEnum; + case attr::Convergent: + return CXCursor_ConvergentAttr; + case attr::WarnUnused: + return CXCursor_WarnUnusedAttr; + case attr::WarnUnusedResult: + return CXCursor_WarnUnusedResultAttr; + case attr::Aligned: + return CXCursor_AlignedAttr; + } + + return CXCursor_UnexposedAttr; +} + +CXCursor cxcursor::MakeCXCursor(const Attr *A, const Decl *Parent, + CXTranslationUnit TU) { + assert(A && Parent && TU && "Invalid arguments!"); + CXCursor C = {GetCursorKind(A), 0, {Parent, A, TU}}; + return C; +} + +CXCursor cxcursor::MakeCXCursor(const Decl *D, CXTranslationUnit TU, + SourceRange RegionOfInterest, + bool FirstInDeclGroup) { + assert(D && TU && "Invalid arguments!"); + + CXCursorKind K = getCursorKindForDecl(D); + + if (K == CXCursor_ObjCClassMethodDecl || + K == CXCursor_ObjCInstanceMethodDecl) { + int SelectorIdIndex = -1; + // Check if cursor points to a selector id. + if (RegionOfInterest.isValid() && + RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { + SmallVector<SourceLocation, 16> SelLocs; + cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs); + SmallVectorImpl<SourceLocation>::iterator I = + llvm::find(SelLocs, RegionOfInterest.getBegin()); + if (I != SelLocs.end()) + SelectorIdIndex = I - SelLocs.begin(); + } + CXCursor C = {K, + SelectorIdIndex, + {D, (void *)(intptr_t)(FirstInDeclGroup ? 1 : 0), TU}}; + return C; + } + + CXCursor C = {K, 0, {D, (void *)(intptr_t)(FirstInDeclGroup ? 1 : 0), TU}}; + return C; +} + +CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, + CXTranslationUnit TU, + SourceRange RegionOfInterest) { + assert(S && TU && "Invalid arguments!"); + CXCursorKind K = CXCursor_NotImplemented; + + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: + break; + + case Stmt::CaseStmtClass: + K = CXCursor_CaseStmt; + break; + + case Stmt::DefaultStmtClass: + K = CXCursor_DefaultStmt; + break; + + case Stmt::IfStmtClass: + K = CXCursor_IfStmt; + break; + + case Stmt::SwitchStmtClass: + K = CXCursor_SwitchStmt; + break; + + case Stmt::WhileStmtClass: + K = CXCursor_WhileStmt; + break; + + case Stmt::DoStmtClass: + K = CXCursor_DoStmt; + break; + + case Stmt::ForStmtClass: + K = CXCursor_ForStmt; + break; + + case Stmt::GotoStmtClass: + K = CXCursor_GotoStmt; + break; + + case Stmt::IndirectGotoStmtClass: + K = CXCursor_IndirectGotoStmt; + break; + + case Stmt::ContinueStmtClass: + K = CXCursor_ContinueStmt; + break; + + case Stmt::BreakStmtClass: + K = CXCursor_BreakStmt; + break; + + case Stmt::ReturnStmtClass: + K = CXCursor_ReturnStmt; + break; + + case Stmt::GCCAsmStmtClass: + K = CXCursor_GCCAsmStmt; + break; + + case Stmt::MSAsmStmtClass: + K = CXCursor_MSAsmStmt; + break; + + case Stmt::ObjCAtTryStmtClass: + K = CXCursor_ObjCAtTryStmt; + break; + + case Stmt::ObjCAtCatchStmtClass: + K = CXCursor_ObjCAtCatchStmt; + break; + + case Stmt::ObjCAtFinallyStmtClass: + K = CXCursor_ObjCAtFinallyStmt; + break; + + case Stmt::ObjCAtThrowStmtClass: + K = CXCursor_ObjCAtThrowStmt; + break; + + case Stmt::ObjCAtSynchronizedStmtClass: + K = CXCursor_ObjCAtSynchronizedStmt; + break; + + case Stmt::ObjCAutoreleasePoolStmtClass: + K = CXCursor_ObjCAutoreleasePoolStmt; + break; + + case Stmt::ObjCForCollectionStmtClass: + K = CXCursor_ObjCForCollectionStmt; + break; + + case Stmt::CXXCatchStmtClass: + K = CXCursor_CXXCatchStmt; + break; + + case Stmt::CXXTryStmtClass: + K = CXCursor_CXXTryStmt; + break; + + case Stmt::CXXForRangeStmtClass: + K = CXCursor_CXXForRangeStmt; + break; + + case Stmt::SEHTryStmtClass: + K = CXCursor_SEHTryStmt; + break; + + case Stmt::SEHExceptStmtClass: + K = CXCursor_SEHExceptStmt; + break; + + case Stmt::SEHFinallyStmtClass: + K = CXCursor_SEHFinallyStmt; + break; + + case Stmt::SEHLeaveStmtClass: + K = CXCursor_SEHLeaveStmt; + break; + + case Stmt::CoroutineBodyStmtClass: + case Stmt::CoreturnStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::ArrayTypeTraitExprClass: + case Stmt::AsTypeExprClass: + case Stmt::AtomicExprClass: + case Stmt::BinaryConditionalOperatorClass: + case Stmt::TypeTraitExprClass: + case Stmt::CoawaitExprClass: + case Stmt::ConceptSpecializationExprClass: + case Stmt::RequiresExprClass: + case Stmt::DependentCoawaitExprClass: + case Stmt::CoyieldExprClass: + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDefaultInitExprClass: + case Stmt::CXXFoldExprClass: + case Stmt::CXXRewrittenBinaryOperatorClass: + case Stmt::CXXStdInitializerListExprClass: + case Stmt::CXXScalarValueInitExprClass: + case Stmt::CXXUuidofExprClass: + case Stmt::ChooseExprClass: + case Stmt::DesignatedInitExprClass: + case Stmt::DesignatedInitUpdateExprClass: + case Stmt::ArrayInitLoopExprClass: + case Stmt::ArrayInitIndexExprClass: + case Stmt::ExprWithCleanupsClass: + case Stmt::ExpressionTraitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::ImplicitCastExprClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::NoInitExprClass: + case Stmt::MaterializeTemporaryExprClass: + case Stmt::ObjCIndirectCopyRestoreExprClass: + case Stmt::OffsetOfExprClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::SourceLocExprClass: + case Stmt::ConvertVectorExprClass: + case Stmt::VAArgExprClass: + case Stmt::ObjCArrayLiteralClass: + case Stmt::ObjCDictionaryLiteralClass: + case Stmt::ObjCBoxedExprClass: + case Stmt::ObjCSubscriptRefExprClass: + case Stmt::RecoveryExprClass: + case Stmt::SYCLUniqueStableNameExprClass: + K = CXCursor_UnexposedExpr; + break; + + case Stmt::OpaqueValueExprClass: + if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr()) + return MakeCXCursor(Src, Parent, TU, RegionOfInterest); + K = CXCursor_UnexposedExpr; + break; + + case Stmt::PseudoObjectExprClass: + return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(), Parent, + TU, RegionOfInterest); + + case Stmt::CompoundStmtClass: + K = CXCursor_CompoundStmt; + break; + + case Stmt::NullStmtClass: + K = CXCursor_NullStmt; + break; + + case Stmt::LabelStmtClass: + K = CXCursor_LabelStmt; + break; + + case Stmt::AttributedStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::DeclStmtClass: + K = CXCursor_DeclStmt; + break; + + case Stmt::CapturedStmtClass: + K = CXCursor_UnexposedStmt; + break; + + case Stmt::IntegerLiteralClass: + K = CXCursor_IntegerLiteral; + break; + + case Stmt::FixedPointLiteralClass: + K = CXCursor_FixedPointLiteral; + break; + + case Stmt::FloatingLiteralClass: + K = CXCursor_FloatingLiteral; + break; + + case Stmt::ImaginaryLiteralClass: + K = CXCursor_ImaginaryLiteral; + break; + + case Stmt::StringLiteralClass: + K = CXCursor_StringLiteral; + break; + + case Stmt::CharacterLiteralClass: + K = CXCursor_CharacterLiteral; + break; + + case Stmt::ConstantExprClass: + return MakeCXCursor(cast<ConstantExpr>(S)->getSubExpr(), Parent, TU, + RegionOfInterest); + + case Stmt::ParenExprClass: + K = CXCursor_ParenExpr; + break; + + case Stmt::UnaryOperatorClass: + K = CXCursor_UnaryOperator; + break; + + case Stmt::UnaryExprOrTypeTraitExprClass: + case Stmt::CXXNoexceptExprClass: + K = CXCursor_UnaryExpr; + break; + + case Stmt::MSPropertySubscriptExprClass: + case Stmt::ArraySubscriptExprClass: + K = CXCursor_ArraySubscriptExpr; + break; + + case Stmt::MatrixSubscriptExprClass: + // TODO: add support for MatrixSubscriptExpr. + K = CXCursor_UnexposedExpr; + break; + + case Stmt::OMPArraySectionExprClass: + K = CXCursor_OMPArraySectionExpr; + break; + + case Stmt::OMPArrayShapingExprClass: + K = CXCursor_OMPArrayShapingExpr; + break; + + case Stmt::OMPIteratorExprClass: + K = CXCursor_OMPIteratorExpr; + break; + + case Stmt::BinaryOperatorClass: + K = CXCursor_BinaryOperator; + break; + + case Stmt::CompoundAssignOperatorClass: + K = CXCursor_CompoundAssignOperator; + break; + + case Stmt::ConditionalOperatorClass: + K = CXCursor_ConditionalOperator; + break; + + case Stmt::CStyleCastExprClass: + K = CXCursor_CStyleCastExpr; + break; + + case Stmt::CompoundLiteralExprClass: + K = CXCursor_CompoundLiteralExpr; + break; + + case Stmt::InitListExprClass: + K = CXCursor_InitListExpr; + break; + + case Stmt::AddrLabelExprClass: + K = CXCursor_AddrLabelExpr; + break; + + case Stmt::StmtExprClass: + K = CXCursor_StmtExpr; + break; + + case Stmt::GenericSelectionExprClass: + K = CXCursor_GenericSelectionExpr; + break; + + case Stmt::GNUNullExprClass: + K = CXCursor_GNUNullExpr; + break; + + case Stmt::CXXStaticCastExprClass: + K = CXCursor_CXXStaticCastExpr; + break; + + case Stmt::CXXDynamicCastExprClass: + K = CXCursor_CXXDynamicCastExpr; + break; + + case Stmt::CXXReinterpretCastExprClass: + K = CXCursor_CXXReinterpretCastExpr; + break; + + case Stmt::CXXConstCastExprClass: + K = CXCursor_CXXConstCastExpr; + break; + + case Stmt::CXXFunctionalCastExprClass: + K = CXCursor_CXXFunctionalCastExpr; + break; + + case Stmt::CXXAddrspaceCastExprClass: + K = CXCursor_CXXAddrspaceCastExpr; + break; + + case Stmt::CXXTypeidExprClass: + K = CXCursor_CXXTypeidExpr; + break; + + case Stmt::CXXBoolLiteralExprClass: + K = CXCursor_CXXBoolLiteralExpr; + break; + + case Stmt::CXXNullPtrLiteralExprClass: + K = CXCursor_CXXNullPtrLiteralExpr; + break; + + case Stmt::CXXThisExprClass: + K = CXCursor_CXXThisExpr; + break; + + case Stmt::CXXThrowExprClass: + K = CXCursor_CXXThrowExpr; + break; + + case Stmt::CXXNewExprClass: + K = CXCursor_CXXNewExpr; + break; + + case Stmt::CXXDeleteExprClass: + K = CXCursor_CXXDeleteExpr; + break; + + case Stmt::ObjCStringLiteralClass: + K = CXCursor_ObjCStringLiteral; + break; + + case Stmt::ObjCEncodeExprClass: + K = CXCursor_ObjCEncodeExpr; + break; + + case Stmt::ObjCSelectorExprClass: + K = CXCursor_ObjCSelectorExpr; + break; + + case Stmt::ObjCProtocolExprClass: + K = CXCursor_ObjCProtocolExpr; + break; + + case Stmt::ObjCBoolLiteralExprClass: + K = CXCursor_ObjCBoolLiteralExpr; + break; + + case Stmt::ObjCAvailabilityCheckExprClass: + K = CXCursor_ObjCAvailabilityCheckExpr; + break; + + case Stmt::ObjCBridgedCastExprClass: + K = CXCursor_ObjCBridgedCastExpr; + break; + + case Stmt::BlockExprClass: + K = CXCursor_BlockExpr; + break; + + case Stmt::PackExpansionExprClass: + K = CXCursor_PackExpansionExpr; + break; + + case Stmt::SizeOfPackExprClass: + K = CXCursor_SizeOfPackExpr; + break; + + case Stmt::DeclRefExprClass: + if (const ImplicitParamDecl *IPD = dyn_cast_or_null<ImplicitParamDecl>( + cast<DeclRefExpr>(S)->getDecl())) { + if (const ObjCMethodDecl *MD = + dyn_cast<ObjCMethodDecl>(IPD->getDeclContext())) { + if (MD->getSelfDecl() == IPD) { + K = CXCursor_ObjCSelfExpr; + break; + } + } + } + + K = CXCursor_DeclRefExpr; + break; + + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::SubstNonTypeTemplateParmExprClass: + case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::FunctionParmPackExprClass: + case Stmt::UnresolvedLookupExprClass: + case Stmt::TypoExprClass: // A typo could actually be a DeclRef or a MemberRef + K = CXCursor_DeclRefExpr; + break; + + case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXPseudoDestructorExprClass: + case Stmt::MemberExprClass: + case Stmt::MSPropertyRefExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCIvarRefExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::UnresolvedMemberExprClass: + K = CXCursor_MemberRefExpr; + break; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CUDAKernelCallExprClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXInheritedCtorInitExprClass: + case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXUnresolvedConstructExprClass: + case Stmt::UserDefinedLiteralClass: + K = CXCursor_CallExpr; + break; + + case Stmt::LambdaExprClass: + K = CXCursor_LambdaExpr; + break; + + case Stmt::ObjCMessageExprClass: { + K = CXCursor_ObjCMessageExpr; + int SelectorIdIndex = -1; + // Check if cursor points to a selector id. + if (RegionOfInterest.isValid() && + RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) { + SmallVector<SourceLocation, 16> SelLocs; + cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs); + SmallVectorImpl<SourceLocation>::iterator I = + llvm::find(SelLocs, RegionOfInterest.getBegin()); + if (I != SelLocs.end()) + SelectorIdIndex = I - SelLocs.begin(); + } + CXCursor C = {K, 0, {Parent, S, TU}}; + return getSelectorIdentifierCursor(SelectorIdIndex, C); + } + + case Stmt::MSDependentExistsStmtClass: + K = CXCursor_UnexposedStmt; + break; + case Stmt::OMPCanonicalLoopClass: + K = CXCursor_OMPCanonicalLoop; + break; + case Stmt::OMPMetaDirectiveClass: + K = CXCursor_OMPMetaDirective; + break; + case Stmt::OMPParallelDirectiveClass: + K = CXCursor_OMPParallelDirective; + break; + case Stmt::OMPSimdDirectiveClass: + K = CXCursor_OMPSimdDirective; + break; + case Stmt::OMPTileDirectiveClass: + K = CXCursor_OMPTileDirective; + break; + case Stmt::OMPUnrollDirectiveClass: + K = CXCursor_OMPUnrollDirective; + break; + case Stmt::OMPForDirectiveClass: + K = CXCursor_OMPForDirective; + break; + case Stmt::OMPForSimdDirectiveClass: + K = CXCursor_OMPForSimdDirective; + break; + case Stmt::OMPSectionsDirectiveClass: + K = CXCursor_OMPSectionsDirective; + break; + case Stmt::OMPSectionDirectiveClass: + K = CXCursor_OMPSectionDirective; + break; + case Stmt::OMPSingleDirectiveClass: + K = CXCursor_OMPSingleDirective; + break; + case Stmt::OMPMasterDirectiveClass: + K = CXCursor_OMPMasterDirective; + break; + case Stmt::OMPCriticalDirectiveClass: + K = CXCursor_OMPCriticalDirective; + break; + case Stmt::OMPParallelForDirectiveClass: + K = CXCursor_OMPParallelForDirective; + break; + case Stmt::OMPParallelForSimdDirectiveClass: + K = CXCursor_OMPParallelForSimdDirective; + break; + case Stmt::OMPParallelMasterDirectiveClass: + K = CXCursor_OMPParallelMasterDirective; + break; + case Stmt::OMPParallelSectionsDirectiveClass: + K = CXCursor_OMPParallelSectionsDirective; + break; + case Stmt::OMPTaskDirectiveClass: + K = CXCursor_OMPTaskDirective; + break; + case Stmt::OMPTaskyieldDirectiveClass: + K = CXCursor_OMPTaskyieldDirective; + break; + case Stmt::OMPBarrierDirectiveClass: + K = CXCursor_OMPBarrierDirective; + break; + case Stmt::OMPTaskwaitDirectiveClass: + K = CXCursor_OMPTaskwaitDirective; + break; + case Stmt::OMPTaskgroupDirectiveClass: + K = CXCursor_OMPTaskgroupDirective; + break; + case Stmt::OMPFlushDirectiveClass: + K = CXCursor_OMPFlushDirective; + break; + case Stmt::OMPDepobjDirectiveClass: + K = CXCursor_OMPDepobjDirective; + break; + case Stmt::OMPScanDirectiveClass: + K = CXCursor_OMPScanDirective; + break; + case Stmt::OMPOrderedDirectiveClass: + K = CXCursor_OMPOrderedDirective; + break; + case Stmt::OMPAtomicDirectiveClass: + K = CXCursor_OMPAtomicDirective; + break; + case Stmt::OMPTargetDirectiveClass: + K = CXCursor_OMPTargetDirective; + break; + case Stmt::OMPTargetDataDirectiveClass: + K = CXCursor_OMPTargetDataDirective; + break; + case Stmt::OMPTargetEnterDataDirectiveClass: + K = CXCursor_OMPTargetEnterDataDirective; + break; + case Stmt::OMPTargetExitDataDirectiveClass: + K = CXCursor_OMPTargetExitDataDirective; + break; + case Stmt::OMPTargetParallelDirectiveClass: + K = CXCursor_OMPTargetParallelDirective; + break; + case Stmt::OMPTargetParallelForDirectiveClass: + K = CXCursor_OMPTargetParallelForDirective; + break; + case Stmt::OMPTargetUpdateDirectiveClass: + K = CXCursor_OMPTargetUpdateDirective; + break; + case Stmt::OMPTeamsDirectiveClass: + K = CXCursor_OMPTeamsDirective; + break; + case Stmt::OMPCancellationPointDirectiveClass: + K = CXCursor_OMPCancellationPointDirective; + break; + case Stmt::OMPCancelDirectiveClass: + K = CXCursor_OMPCancelDirective; + break; + case Stmt::OMPTaskLoopDirectiveClass: + K = CXCursor_OMPTaskLoopDirective; + break; + case Stmt::OMPTaskLoopSimdDirectiveClass: + K = CXCursor_OMPTaskLoopSimdDirective; + break; + case Stmt::OMPMasterTaskLoopDirectiveClass: + K = CXCursor_OMPMasterTaskLoopDirective; + break; + case Stmt::OMPMasterTaskLoopSimdDirectiveClass: + K = CXCursor_OMPMasterTaskLoopSimdDirective; + break; + case Stmt::OMPParallelMasterTaskLoopDirectiveClass: + K = CXCursor_OMPParallelMasterTaskLoopDirective; + break; + case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: + K = CXCursor_OMPParallelMasterTaskLoopSimdDirective; + break; + case Stmt::OMPDistributeDirectiveClass: + K = CXCursor_OMPDistributeDirective; + break; + case Stmt::OMPDistributeParallelForDirectiveClass: + K = CXCursor_OMPDistributeParallelForDirective; + break; + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + K = CXCursor_OMPDistributeParallelForSimdDirective; + break; + case Stmt::OMPDistributeSimdDirectiveClass: + K = CXCursor_OMPDistributeSimdDirective; + break; + case Stmt::OMPTargetParallelForSimdDirectiveClass: + K = CXCursor_OMPTargetParallelForSimdDirective; + break; + case Stmt::OMPTargetSimdDirectiveClass: + K = CXCursor_OMPTargetSimdDirective; + break; + case Stmt::OMPTeamsDistributeDirectiveClass: + K = CXCursor_OMPTeamsDistributeDirective; + break; + case Stmt::OMPTeamsDistributeSimdDirectiveClass: + K = CXCursor_OMPTeamsDistributeSimdDirective; + break; + case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: + K = CXCursor_OMPTeamsDistributeParallelForSimdDirective; + break; + case Stmt::OMPTeamsDistributeParallelForDirectiveClass: + K = CXCursor_OMPTeamsDistributeParallelForDirective; + break; + case Stmt::OMPTargetTeamsDirectiveClass: + K = CXCursor_OMPTargetTeamsDirective; + break; + case Stmt::OMPTargetTeamsDistributeDirectiveClass: + K = CXCursor_OMPTargetTeamsDistributeDirective; + break; + case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: + K = CXCursor_OMPTargetTeamsDistributeParallelForDirective; + break; + case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: + K = CXCursor_OMPTargetTeamsDistributeParallelForSimdDirective; + break; + case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: + K = CXCursor_OMPTargetTeamsDistributeSimdDirective; + break; + case Stmt::OMPInteropDirectiveClass: + K = CXCursor_OMPInteropDirective; + break; + case Stmt::OMPDispatchDirectiveClass: + K = CXCursor_OMPDispatchDirective; + break; + case Stmt::OMPMaskedDirectiveClass: + K = CXCursor_OMPMaskedDirective; + break; + case Stmt::OMPGenericLoopDirectiveClass: + K = CXCursor_OMPGenericLoopDirective; + break; + case Stmt::BuiltinBitCastExprClass: + K = CXCursor_BuiltinBitCastExpr; + } + + CXCursor C = {K, 0, {Parent, S, TU}}; + return C; +} + +CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Super && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_ObjCSuperClassRef, 0, {Super, RawLoc, TU}}; + return C; +} + +std::pair<const ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCSuperClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCSuperClassRef); + return std::make_pair(static_cast<const ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Proto && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_ObjCProtocolRef, 0, {Proto, RawLoc, TU}}; + return C; +} + +std::pair<const ObjCProtocolDecl *, SourceLocation> +cxcursor::getCursorObjCProtocolRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCProtocolRef); + return std::make_pair(static_cast<const ObjCProtocolDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, + SourceLocation Loc, + CXTranslationUnit TU) { + // 'Class' can be null for invalid code. + if (!Class) + return MakeCXCursorInvalid(CXCursor_InvalidCode); + assert(TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_ObjCClassRef, 0, {Class, RawLoc, TU}}; + return C; +} + +std::pair<const ObjCInterfaceDecl *, SourceLocation> +cxcursor::getCursorObjCClassRef(CXCursor C) { + assert(C.kind == CXCursor_ObjCClassRef); + return std::make_pair(static_cast<const ObjCInterfaceDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, + CXTranslationUnit TU) { + assert(Type && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_TypeRef, 0, {Type, RawLoc, TU}}; + return C; +} + +std::pair<const TypeDecl *, SourceLocation> +cxcursor::getCursorTypeRef(CXCursor C) { + assert(C.kind == CXCursor_TypeRef); + return std::make_pair(static_cast<const TypeDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorTemplateRef(const TemplateDecl *Template, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Template && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_TemplateRef, 0, {Template, RawLoc, TU}}; + return C; +} + +std::pair<const TemplateDecl *, SourceLocation> +cxcursor::getCursorTemplateRef(CXCursor C) { + assert(C.kind == CXCursor_TemplateRef); + return std::make_pair(static_cast<const TemplateDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS, + SourceLocation Loc, + CXTranslationUnit TU) { + + assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU && + "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_NamespaceRef, 0, {NS, RawLoc, TU}}; + return C; +} + +std::pair<const NamedDecl *, SourceLocation> +cxcursor::getCursorNamespaceRef(CXCursor C) { + assert(C.kind == CXCursor_NamespaceRef); + return std::make_pair(static_cast<const NamedDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Var && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_VariableRef, 0, {Var, RawLoc, TU}}; + return C; +} + +std::pair<const VarDecl *, SourceLocation> +cxcursor::getCursorVariableRef(CXCursor C) { + assert(C.kind == CXCursor_VariableRef); + return std::make_pair(static_cast<const VarDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, + SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Field && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_MemberRef, 0, {Field, RawLoc, TU}}; + return C; +} + +std::pair<const FieldDecl *, SourceLocation> +cxcursor::getCursorMemberRef(CXCursor C) { + assert(C.kind == CXCursor_MemberRef); + return std::make_pair(static_cast<const FieldDecl *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B, + CXTranslationUnit TU) { + CXCursor C = {CXCursor_CXXBaseSpecifier, 0, {B, nullptr, TU}}; + return C; +} + +const CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) { + assert(C.kind == CXCursor_CXXBaseSpecifier); + return static_cast<const CXXBaseSpecifier *>(C.data[0]); +} + +CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, + CXTranslationUnit TU) { + CXCursor C = { + CXCursor_PreprocessingDirective, + 0, + {Range.getBegin().getPtrEncoding(), Range.getEnd().getPtrEncoding(), TU}}; + return C; +} + +SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) { + assert(C.kind == CXCursor_PreprocessingDirective); + SourceRange Range(SourceLocation::getFromPtrEncoding(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); + ASTUnit *TU = getCursorASTUnit(C); + return TU->mapRangeFromPreamble(Range); +} + +CXCursor cxcursor::MakeMacroDefinitionCursor(const MacroDefinitionRecord *MI, + CXTranslationUnit TU) { + CXCursor C = {CXCursor_MacroDefinition, 0, {MI, nullptr, TU}}; + return C; +} + +const MacroDefinitionRecord *cxcursor::getCursorMacroDefinition(CXCursor C) { + assert(C.kind == CXCursor_MacroDefinition); + return static_cast<const MacroDefinitionRecord *>(C.data[0]); +} + +CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI, + CXTranslationUnit TU) { + CXCursor C = {CXCursor_MacroExpansion, 0, {MI, nullptr, TU}}; + return C; +} + +CXCursor cxcursor::MakeMacroExpansionCursor(MacroDefinitionRecord *MI, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Loc.isValid()); + CXCursor C = {CXCursor_MacroExpansion, 0, {MI, Loc.getPtrEncoding(), TU}}; + return C; +} + +const IdentifierInfo *cxcursor::MacroExpansionCursor::getName() const { + if (isPseudo()) + return getAsMacroDefinition()->getName(); + return getAsMacroExpansion()->getName(); +} +const MacroDefinitionRecord * +cxcursor::MacroExpansionCursor::getDefinition() const { + if (isPseudo()) + return getAsMacroDefinition(); + return getAsMacroExpansion()->getDefinition(); +} +SourceRange cxcursor::MacroExpansionCursor::getSourceRange() const { + if (isPseudo()) + return getPseudoLoc(); + return getAsMacroExpansion()->getSourceRange(); +} + +CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID, + CXTranslationUnit TU) { + CXCursor C = {CXCursor_InclusionDirective, 0, {ID, nullptr, TU}}; + return C; +} + +const InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) { + assert(C.kind == CXCursor_InclusionDirective); + return static_cast<const InclusionDirective *>(C.data[0]); +} + +CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, + CXTranslationUnit TU) { + + assert(Label && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + CXCursor C = {CXCursor_LabelRef, 0, {Label, RawLoc, TU}}; + return C; +} + +std::pair<const LabelStmt *, SourceLocation> +cxcursor::getCursorLabelRef(CXCursor C) { + assert(C.kind == CXCursor_LabelRef); + return std::make_pair(static_cast<const LabelStmt *>(C.data[0]), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(const OverloadExpr *E, + CXTranslationUnit TU) { + assert(E && TU && "Invalid arguments!"); + OverloadedDeclRefStorage Storage(E); + void *RawLoc = E->getNameLoc().getPtrEncoding(); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, {Storage.getOpaqueValue(), RawLoc, TU}}; + return C; +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(const Decl *D, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(D && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + OverloadedDeclRefStorage Storage(D); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, {Storage.getOpaqueValue(), RawLoc, TU}}; + return C; +} + +CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name, + SourceLocation Loc, + CXTranslationUnit TU) { + assert(Name.getAsOverloadedTemplate() && TU && "Invalid arguments!"); + void *RawLoc = Loc.getPtrEncoding(); + OverloadedDeclRefStorage Storage(Name.getAsOverloadedTemplate()); + CXCursor C = { + CXCursor_OverloadedDeclRef, 0, {Storage.getOpaqueValue(), RawLoc, TU}}; + return C; +} + +std::pair<cxcursor::OverloadedDeclRefStorage, SourceLocation> +cxcursor::getCursorOverloadedDeclRef(CXCursor C) { + assert(C.kind == CXCursor_OverloadedDeclRef); + return std::make_pair(OverloadedDeclRefStorage::getFromOpaqueValue( + const_cast<void *>(C.data[0])), + SourceLocation::getFromPtrEncoding(C.data[1])); +} + +const Decl *cxcursor::getCursorDecl(CXCursor Cursor) { + return static_cast<const Decl *>(Cursor.data[0]); +} + +const Expr *cxcursor::getCursorExpr(CXCursor Cursor) { + return dyn_cast_or_null<Expr>(getCursorStmt(Cursor)); +} + +const Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { + if (Cursor.kind == CXCursor_ObjCSuperClassRef || + Cursor.kind == CXCursor_ObjCProtocolRef || + Cursor.kind == CXCursor_ObjCClassRef) + return nullptr; + + return static_cast<const Stmt *>(Cursor.data[1]); +} + +const Attr *cxcursor::getCursorAttr(CXCursor Cursor) { + return static_cast<const Attr *>(Cursor.data[1]); +} + +ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { + return getCursorASTUnit(Cursor)->getASTContext(); +} + +ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) { + CXTranslationUnit TU = getCursorTU(Cursor); + if (!TU) + return nullptr; + return cxtu::getASTUnit(TU); +} + +CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) { + return static_cast<CXTranslationUnit>(const_cast<void *>(Cursor.data[2])); +} + +void cxcursor::getOverriddenCursors(CXCursor cursor, + SmallVectorImpl<CXCursor> &overridden) { + assert(clang_isDeclaration(cursor.kind)); + const NamedDecl *D = dyn_cast_or_null<NamedDecl>(getCursorDecl(cursor)); + if (!D) + return; + + CXTranslationUnit TU = getCursorTU(cursor); + SmallVector<const NamedDecl *, 8> OverDecls; + D->getASTContext().getOverriddenMethods(D, OverDecls); + + for (SmallVectorImpl<const NamedDecl *>::iterator I = OverDecls.begin(), + E = OverDecls.end(); + I != E; ++I) { + overridden.push_back(MakeCXCursor(*I, TU)); + } +} + +std::pair<int, SourceLocation> +cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) { + if (cursor.kind == CXCursor_ObjCMessageExpr) { + if (cursor.xdata != -1) + return std::make_pair(cursor.xdata, + cast<ObjCMessageExpr>(getCursorExpr(cursor)) + ->getSelectorLoc(cursor.xdata)); + } else if (cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) { + if (cursor.xdata != -1) + return std::make_pair(cursor.xdata, + cast<ObjCMethodDecl>(getCursorDecl(cursor)) + ->getSelectorLoc(cursor.xdata)); + } + + return std::make_pair(-1, SourceLocation()); +} + +CXCursor cxcursor::getSelectorIdentifierCursor(int SelIdx, CXCursor cursor) { + CXCursor newCursor = cursor; + + if (cursor.kind == CXCursor_ObjCMessageExpr) { + if (SelIdx == -1 || + unsigned(SelIdx) >= + cast<ObjCMessageExpr>(getCursorExpr(cursor))->getNumSelectorLocs()) + newCursor.xdata = -1; + else + newCursor.xdata = SelIdx; + } else if (cursor.kind == CXCursor_ObjCClassMethodDecl || + cursor.kind == CXCursor_ObjCInstanceMethodDecl) { + if (SelIdx == -1 || + unsigned(SelIdx) >= + cast<ObjCMethodDecl>(getCursorDecl(cursor))->getNumSelectorLocs()) + newCursor.xdata = -1; + else + newCursor.xdata = SelIdx; + } + + return newCursor; +} + +CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) { + if (cursor.kind != CXCursor_CallExpr) + return cursor; + + if (cursor.xdata == 0) + return cursor; + + const Expr *E = getCursorExpr(cursor); + TypeSourceInfo *Type = nullptr; + if (const CXXUnresolvedConstructExpr *UnCtor = + dyn_cast<CXXUnresolvedConstructExpr>(E)) { + Type = UnCtor->getTypeSourceInfo(); + } else if (const CXXTemporaryObjectExpr *Tmp = + dyn_cast<CXXTemporaryObjectExpr>(E)) { + Type = Tmp->getTypeSourceInfo(); + } + + if (!Type) + return cursor; + + CXTranslationUnit TU = getCursorTU(cursor); + QualType Ty = Type->getType(); + TypeLoc TL = Type->getTypeLoc(); + SourceLocation Loc = TL.getBeginLoc(); + + if (const ElaboratedType *ElabT = Ty->getAs<ElaboratedType>()) { + Ty = ElabT->getNamedType(); + ElaboratedTypeLoc ElabTL = TL.castAs<ElaboratedTypeLoc>(); + Loc = ElabTL.getNamedTypeLoc().getBeginLoc(); + } + + if (const TypedefType *Typedef = Ty->getAs<TypedefType>()) + return MakeCursorTypeRef(Typedef->getDecl(), Loc, TU); + if (const TagType *Tag = Ty->getAs<TagType>()) + return MakeCursorTypeRef(Tag->getDecl(), Loc, TU); + if (const TemplateTypeParmType *TemplP = Ty->getAs<TemplateTypeParmType>()) + return MakeCursorTypeRef(TemplP->getDecl(), Loc, TU); + + return cursor; +} + +bool cxcursor::operator==(CXCursor X, CXCursor Y) { + return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] && + X.data[2] == Y.data[2]; +} + +// FIXME: Remove once we can model DeclGroups and their appropriate ranges +// properly in the ASTs. +bool cxcursor::isFirstInDeclGroup(CXCursor C) { + assert(clang_isDeclaration(C.kind)); + return ((uintptr_t)(C.data[1])) != 0; +} + +//===----------------------------------------------------------------------===// +// libclang CXCursor APIs +//===----------------------------------------------------------------------===// + +int clang_Cursor_isNull(CXCursor cursor) { + return clang_equalCursors(cursor, clang_getNullCursor()); +} + +CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) { + return getCursorTU(cursor); +} + +int clang_Cursor_getNumArguments(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) + return MD->param_size(); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) + return FD->param_size(); + } + + if (clang_isExpression(C.kind)) { + const Expr *E = cxcursor::getCursorExpr(C); + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + return CE->getNumArgs(); + } + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { + return CE->getNumArgs(); + } + } + + return -1; +} + +CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) { + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) { + if (i < MD->param_size()) + return cxcursor::MakeCXCursor(MD->parameters()[i], + cxcursor::getCursorTU(C)); + } else if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) { + if (i < FD->param_size()) + return cxcursor::MakeCXCursor(FD->parameters()[i], + cxcursor::getCursorTU(C)); + } + } + + if (clang_isExpression(C.kind)) { + const Expr *E = cxcursor::getCursorExpr(C); + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + if (i < CE->getNumArgs()) { + return cxcursor::MakeCXCursor(CE->getArg(i), getCursorDecl(C), + cxcursor::getCursorTU(C)); + } + } + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { + if (i < CE->getNumArgs()) { + return cxcursor::MakeCXCursor(CE->getArg(i), getCursorDecl(C), + cxcursor::getCursorTU(C)); + } + } + } + + return clang_getNullCursor(); +} + +int clang_Cursor_getNumTemplateArguments(CXCursor C) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + return -1; + } + + const FunctionDecl *FD = + llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C)); + if (!FD) { + return -1; + } + + const FunctionTemplateSpecializationInfo *SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + return -1; + } + + return SpecInfo->TemplateArguments->size(); +} + +enum CXGetTemplateArgumentStatus { + /** The operation completed successfully */ + CXGetTemplateArgumentStatus_Success = 0, + + /** The specified cursor did not represent a FunctionDecl. */ + CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1, + + /** The specified cursor was not castable to a FunctionDecl. */ + CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2, + + /** A NULL FunctionTemplateSpecializationInfo was retrieved. */ + CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3, + + /** An invalid (OOB) argument index was specified */ + CXGetTemplateArgumentStatus_InvalidIndex = -4 +}; + +static int clang_Cursor_getTemplateArgument(CXCursor C, unsigned I, + TemplateArgument *TA) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + return CXGetTemplateArgumentStatus_CursorNotFunctionDecl; + } + + const FunctionDecl *FD = + llvm::dyn_cast_or_null<clang::FunctionDecl>(getCursorDecl(C)); + if (!FD) { + return CXGetTemplateArgumentStatus_BadFunctionDeclCast; + } + + const FunctionTemplateSpecializationInfo *SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + return CXGetTemplateArgumentStatus_NullTemplSpecInfo; + } + + if (I >= SpecInfo->TemplateArguments->size()) { + return CXGetTemplateArgumentStatus_InvalidIndex; + } + + *TA = SpecInfo->TemplateArguments->get(I); + return 0; +} + +enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C, + unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA)) { + return CXTemplateArgumentKind_Invalid; + } + + switch (TA.getKind()) { + case TemplateArgument::Null: + return CXTemplateArgumentKind_Null; + case TemplateArgument::Type: + return CXTemplateArgumentKind_Type; + case TemplateArgument::Declaration: + return CXTemplateArgumentKind_Declaration; + case TemplateArgument::NullPtr: + return CXTemplateArgumentKind_NullPtr; + case TemplateArgument::Integral: + return CXTemplateArgumentKind_Integral; + case TemplateArgument::Template: + return CXTemplateArgumentKind_Template; + case TemplateArgument::TemplateExpansion: + return CXTemplateArgumentKind_TemplateExpansion; + case TemplateArgument::Expression: + return CXTemplateArgumentKind_Expression; + case TemplateArgument::Pack: + return CXTemplateArgumentKind_Pack; + } + + return CXTemplateArgumentKind_Invalid; +} + +CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + if (TA.getKind() != TemplateArgument::Type) { + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C)); +} + +long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + assert(0 && "Unable to retrieve TemplateArgument"); + return 0; + } + + if (TA.getKind() != TemplateArgument::Integral) { + assert(0 && "Passed template argument is not Integral"); + return 0; + } + + return TA.getAsIntegral().getSExtValue(); +} + +unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, + unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + assert(0 && "Unable to retrieve TemplateArgument"); + return 0; + } + + if (TA.getKind() != TemplateArgument::Integral) { + assert(0 && "Passed template argument is not Integral"); + return 0; + } + + return TA.getAsIntegral().getZExtValue(); +} + +//===----------------------------------------------------------------------===// +// CXCursorSet. +//===----------------------------------------------------------------------===// + +typedef llvm::DenseMap<CXCursor, unsigned> CXCursorSet_Impl; + +static inline CXCursorSet packCXCursorSet(CXCursorSet_Impl *setImpl) { + return (CXCursorSet)setImpl; +} +static inline CXCursorSet_Impl *unpackCXCursorSet(CXCursorSet set) { + return (CXCursorSet_Impl *)set; +} +namespace llvm { +template <> struct DenseMapInfo<CXCursor> { +public: + static inline CXCursor getEmptyKey() { + return MakeCXCursorInvalid(CXCursor_InvalidFile); + } + static inline CXCursor getTombstoneKey() { + return MakeCXCursorInvalid(CXCursor_NoDeclFound); + } + static inline unsigned getHashValue(const CXCursor &cursor) { + return llvm::DenseMapInfo<std::pair<const void *, const void *>>:: + getHashValue(std::make_pair(cursor.data[0], cursor.data[1])); + } + static inline bool isEqual(const CXCursor &x, const CXCursor &y) { + return x.kind == y.kind && x.data[0] == y.data[0] && x.data[1] == y.data[1]; + } +}; +} // namespace llvm + +CXCursorSet clang_createCXCursorSet() { + return packCXCursorSet(new CXCursorSet_Impl()); +} + +void clang_disposeCXCursorSet(CXCursorSet set) { + delete unpackCXCursorSet(set); +} + +unsigned clang_CXCursorSet_contains(CXCursorSet set, CXCursor cursor) { + CXCursorSet_Impl *setImpl = unpackCXCursorSet(set); + if (!setImpl) + return 0; + return setImpl->find(cursor) != setImpl->end(); +} + +unsigned clang_CXCursorSet_insert(CXCursorSet set, CXCursor cursor) { + // Do not insert invalid cursors into the set. + if (cursor.kind >= CXCursor_FirstInvalid && + cursor.kind <= CXCursor_LastInvalid) + return 1; + + CXCursorSet_Impl *setImpl = unpackCXCursorSet(set); + if (!setImpl) + return 1; + unsigned &entry = (*setImpl)[cursor]; + unsigned flag = entry == 0 ? 1 : 0; + entry = 1; + return flag; +} + +CXCompletionString clang_getCursorCompletionString(CXCursor cursor) { + enum CXCursorKind kind = clang_getCursorKind(cursor); + if (clang_isDeclaration(kind)) { + const Decl *decl = getCursorDecl(cursor); + if (const NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) { + ASTUnit *unit = getCursorASTUnit(cursor); + CodeCompletionResult Result(namedDecl, CCP_Declaration); + CodeCompletionString *String = Result.CreateCodeCompletionString( + unit->getASTContext(), unit->getPreprocessor(), + CodeCompletionContext::CCC_Other, + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo(), true); + return String; + } + } else if (kind == CXCursor_MacroDefinition) { + const MacroDefinitionRecord *definition = getCursorMacroDefinition(cursor); + const IdentifierInfo *Macro = definition->getName(); + ASTUnit *unit = getCursorASTUnit(cursor); + CodeCompletionResult Result( + Macro, + unit->getPreprocessor().getMacroDefinition(Macro).getMacroInfo()); + CodeCompletionString *String = Result.CreateCodeCompletionString( + unit->getASTContext(), unit->getPreprocessor(), + CodeCompletionContext::CCC_Other, + unit->getCodeCompletionTUInfo().getAllocator(), + unit->getCodeCompletionTUInfo(), false); + return String; + } + return nullptr; +} + +namespace { +struct OverridenCursorsPool { + typedef SmallVector<CXCursor, 2> CursorVec; + std::vector<CursorVec *> AllCursors; + std::vector<CursorVec *> AvailableCursors; + + ~OverridenCursorsPool() { + for (std::vector<CursorVec *>::iterator I = AllCursors.begin(), + E = AllCursors.end(); + I != E; ++I) { + delete *I; + } + } +}; +} // namespace + +void *cxcursor::createOverridenCXCursorsPool() { + return new OverridenCursorsPool(); +} + +void cxcursor::disposeOverridenCXCursorsPool(void *pool) { + delete static_cast<OverridenCursorsPool *>(pool); +} + +void clang_getOverriddenCursors(CXCursor cursor, CXCursor **overridden, + unsigned *num_overridden) { + if (overridden) + *overridden = nullptr; + if (num_overridden) + *num_overridden = 0; + + CXTranslationUnit TU = cxcursor::getCursorTU(cursor); + + if (!overridden || !num_overridden || !TU) + return; + + if (!clang_isDeclaration(cursor.kind)) + return; + + OverridenCursorsPool &pool = + *static_cast<OverridenCursorsPool *>(TU->OverridenCursorsPool); + + OverridenCursorsPool::CursorVec *Vec = nullptr; + + if (!pool.AvailableCursors.empty()) { + Vec = pool.AvailableCursors.back(); + pool.AvailableCursors.pop_back(); + } else { + Vec = new OverridenCursorsPool::CursorVec(); + pool.AllCursors.push_back(Vec); + } + + // Clear out the vector, but don't free the memory contents. This + // reduces malloc() traffic. + Vec->clear(); + + // Use the first entry to contain a back reference to the vector. + // This is a complete hack. + CXCursor backRefCursor = MakeCXCursorInvalid(CXCursor_InvalidFile, TU); + backRefCursor.data[0] = Vec; + assert(cxcursor::getCursorTU(backRefCursor) == TU); + Vec->push_back(backRefCursor); + + // Get the overridden cursors. + cxcursor::getOverriddenCursors(cursor, *Vec); + + // Did we get any overridden cursors? If not, return Vec to the pool + // of available cursor vectors. + if (Vec->size() == 1) { + pool.AvailableCursors.push_back(Vec); + return; + } + + // Now tell the caller about the overridden cursors. + assert(Vec->size() > 1); + *overridden = &((*Vec)[1]); + *num_overridden = Vec->size() - 1; +} + +void clang_disposeOverriddenCursors(CXCursor *overridden) { + if (!overridden) + return; + + // Use pointer arithmetic to get back the first faux entry + // which has a back-reference to the TU and the vector. + --overridden; + OverridenCursorsPool::CursorVec *Vec = + static_cast<OverridenCursorsPool::CursorVec *>( + const_cast<void *>(overridden->data[0])); + CXTranslationUnit TU = getCursorTU(*overridden); + + assert(Vec && TU); + + OverridenCursorsPool &pool = + *static_cast<OverridenCursorsPool *>(TU->OverridenCursorsPool); + + pool.AvailableCursors.push_back(Vec); +} + +int clang_Cursor_isDynamicCall(CXCursor C) { + const Expr *E = nullptr; + if (clang_isExpression(C.kind)) + E = getCursorExpr(C); + if (!E) + return 0; + + if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) { + if (MsgE->getReceiverKind() != ObjCMessageExpr::Instance) + return false; + if (auto *RecE = dyn_cast<ObjCMessageExpr>( + MsgE->getInstanceReceiver()->IgnoreParenCasts())) { + if (RecE->getMethodFamily() == OMF_alloc) + return false; + } + return true; + } + + if (auto *PropRefE = dyn_cast<ObjCPropertyRefExpr>(E)) { + return !PropRefE->isSuperReceiver(); + } + + const MemberExpr *ME = nullptr; + if (isa<MemberExpr>(E)) + ME = cast<MemberExpr>(E); + else if (const CallExpr *CE = dyn_cast<CallExpr>(E)) + ME = dyn_cast_or_null<MemberExpr>(CE->getCallee()); + + if (ME) { + if (const CXXMethodDecl *MD = + dyn_cast_or_null<CXXMethodDecl>(ME->getMemberDecl())) + return MD->isVirtual() && + ME->performsVirtualDispatch( + cxcursor::getCursorContext(C).getLangOpts()); + } + + return 0; +} + +CXType clang_Cursor_getReceiverType(CXCursor C) { + CXTranslationUnit TU = cxcursor::getCursorTU(C); + const Expr *E = nullptr; + if (clang_isExpression(C.kind)) + E = getCursorExpr(C); + + if (const ObjCMessageExpr *MsgE = dyn_cast_or_null<ObjCMessageExpr>(E)) + return cxtype::MakeCXType(MsgE->getReceiverType(), TU); + + if (auto *PropRefE = dyn_cast<ObjCPropertyRefExpr>(E)) { + return cxtype::MakeCXType( + PropRefE->getReceiverType(cxcursor::getCursorContext(C)), TU); + } + + const MemberExpr *ME = nullptr; + if (isa<MemberExpr>(E)) + ME = cast<MemberExpr>(E); + else if (const CallExpr *CE = dyn_cast<CallExpr>(E)) + ME = dyn_cast_or_null<MemberExpr>(CE->getCallee()); + + if (ME) { + if (isa_and_nonnull<CXXMethodDecl>(ME->getMemberDecl())) { + auto receiverTy = ME->getBase()->IgnoreImpCasts()->getType(); + return cxtype::MakeCXType(receiverTy, TU); + } + } + + return cxtype::MakeCXType(QualType(), TU); +} diff --git a/contrib/libs/clang14/tools/libclang/CXCursor.h b/contrib/libs/clang14/tools/libclang/CXCursor.h new file mode 100644 index 0000000000..1e4c0a05c9 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXCursor.h @@ -0,0 +1,293 @@ +//===- CXCursor.h - Routines for manipulating CXCursors -------------------===// +// +// 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 defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXCURSOR_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXCURSOR_H + +#include "clang-c/Index.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" +#include <utility> + +namespace clang { + +class ASTContext; +class ASTUnit; +class Attr; +class CXXBaseSpecifier; +class Decl; +class Expr; +class FieldDecl; +class InclusionDirective; +class LabelStmt; +class MacroDefinitionRecord; +class MacroExpansion; +class NamedDecl; +class ObjCInterfaceDecl; +class ObjCProtocolDecl; +class OverloadedTemplateStorage; +class OverloadExpr; +class Stmt; +class TemplateDecl; +class TemplateName; +class TypeDecl; +class VarDecl; +class IdentifierInfo; + +namespace cxcursor { + +CXCursor getCursor(CXTranslationUnit, SourceLocation); + +CXCursor MakeCXCursor(const clang::Attr *A, const clang::Decl *Parent, + CXTranslationUnit TU); +CXCursor MakeCXCursor(const clang::Decl *D, CXTranslationUnit TU, + SourceRange RegionOfInterest = SourceRange(), + bool FirstInDeclGroup = true); +CXCursor MakeCXCursor(const clang::Stmt *S, const clang::Decl *Parent, + CXTranslationUnit TU, + SourceRange RegionOfInterest = SourceRange()); +CXCursor MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU = nullptr); + +/// Create an Objective-C superclass reference at the given location. +CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super, + SourceLocation Loc, CXTranslationUnit TU); + +/// Unpack an ObjCSuperClassRef cursor into the interface it references +/// and optionally the location where the reference occurred. +std::pair<const ObjCInterfaceDecl *, SourceLocation> +getCursorObjCSuperClassRef(CXCursor C); + +/// Create an Objective-C protocol reference at the given location. +CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, + SourceLocation Loc, CXTranslationUnit TU); + +/// Unpack an ObjCProtocolRef cursor into the protocol it references +/// and optionally the location where the reference occurred. +std::pair<const ObjCProtocolDecl *, SourceLocation> +getCursorObjCProtocolRef(CXCursor C); + +/// Create an Objective-C class reference at the given location. +CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, + SourceLocation Loc, CXTranslationUnit TU); + +/// Unpack an ObjCClassRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<const ObjCInterfaceDecl *, SourceLocation> +getCursorObjCClassRef(CXCursor C); + +/// Create a type reference at the given location. +CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a TypeRef cursor into the class it references +/// and optionally the location where the reference occurred. +std::pair<const TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); + +/// Create a reference to a template at the given location. +CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a TemplateRef cursor into the template it references and +/// the location where the reference occurred. +std::pair<const TemplateDecl *, SourceLocation> +getCursorTemplateRef(CXCursor C); + +/// Create a reference to a namespace or namespace alias at the given +/// location. +CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a NamespaceRef cursor into the namespace or namespace alias +/// it references and the location where the reference occurred. +std::pair<const NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C); + +/// Create a reference to a variable at the given location. +CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a VariableRef cursor into the variable it references and the +/// location where the where the reference occurred. +std::pair<const VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C); + +/// Create a reference to a field at the given location. +CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a MemberRef cursor into the field it references and the +/// location where the reference occurred. +std::pair<const FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C); + +/// Create a CXX base specifier cursor. +CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B, + CXTranslationUnit TU); + +/// Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier. +const CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C); + +/// Create a preprocessing directive cursor. +CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, + CXTranslationUnit TU); + +/// Unpack a given preprocessing directive to retrieve its source range. +SourceRange getCursorPreprocessingDirective(CXCursor C); + +/// Create a macro definition cursor. +CXCursor MakeMacroDefinitionCursor(const MacroDefinitionRecord *, + CXTranslationUnit TU); + +/// Unpack a given macro definition cursor to retrieve its +/// source range. +const MacroDefinitionRecord *getCursorMacroDefinition(CXCursor C); + +/// Create a macro expansion cursor. +CXCursor MakeMacroExpansionCursor(MacroExpansion *, CXTranslationUnit TU); + +/// Create a "pseudo" macro expansion cursor, using a macro definition +/// and a source location. +CXCursor MakeMacroExpansionCursor(MacroDefinitionRecord *, SourceLocation Loc, + CXTranslationUnit TU); + +/// Wraps a macro expansion cursor and provides a common interface +/// for a normal macro expansion cursor or a "pseudo" one. +/// +/// "Pseudo" macro expansion cursors (essentially a macro definition along with +/// a source location) are created in special cases, for example they can be +/// created for identifiers inside macro definitions, if these identifiers are +/// macro names. +class MacroExpansionCursor { + CXCursor C; + + bool isPseudo() const { return C.data[1] != nullptr; } + const MacroDefinitionRecord *getAsMacroDefinition() const { + assert(isPseudo()); + return static_cast<const MacroDefinitionRecord *>(C.data[0]); + } + const MacroExpansion *getAsMacroExpansion() const { + assert(!isPseudo()); + return static_cast<const MacroExpansion *>(C.data[0]); + } + SourceLocation getPseudoLoc() const { + assert(isPseudo()); + return SourceLocation::getFromPtrEncoding(C.data[1]); + } + +public: + MacroExpansionCursor(CXCursor C) : C(C) { + assert(C.kind == CXCursor_MacroExpansion); + } + + const IdentifierInfo *getName() const; + const MacroDefinitionRecord *getDefinition() const; + SourceRange getSourceRange() const; +}; + +/// Unpack a given macro expansion cursor to retrieve its info. +static inline MacroExpansionCursor getCursorMacroExpansion(CXCursor C) { + return C; +} + +/// Create an inclusion directive cursor. +CXCursor MakeInclusionDirectiveCursor(InclusionDirective *, + CXTranslationUnit TU); + +/// Unpack a given inclusion directive cursor to retrieve its +/// source range. +const InclusionDirective *getCursorInclusionDirective(CXCursor C); + +/// Create a label reference at the given location. +CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc, + CXTranslationUnit TU); + +/// Unpack a label reference into the label statement it refers to and +/// the location of the reference. +std::pair<const LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C); + +/// Create a overloaded declaration reference cursor for an expression. +CXCursor MakeCursorOverloadedDeclRef(const OverloadExpr *E, + CXTranslationUnit TU); + +/// Create a overloaded declaration reference cursor for a declaration. +CXCursor MakeCursorOverloadedDeclRef(const Decl *D, SourceLocation Location, + CXTranslationUnit TU); + +/// Create a overloaded declaration reference cursor for a template name. +CXCursor MakeCursorOverloadedDeclRef(TemplateName Template, + SourceLocation Location, + CXTranslationUnit TU); + +/// Internal storage for an overloaded declaration reference cursor; +typedef llvm::PointerUnion<const OverloadExpr *, const Decl *, + OverloadedTemplateStorage *> + OverloadedDeclRefStorage; + +/// Unpack an overloaded declaration reference into an expression, +/// declaration, or template name along with the source location. +std::pair<OverloadedDeclRefStorage, SourceLocation> +getCursorOverloadedDeclRef(CXCursor C); + +const Decl *getCursorDecl(CXCursor Cursor); +const Expr *getCursorExpr(CXCursor Cursor); +const Stmt *getCursorStmt(CXCursor Cursor); +const Attr *getCursorAttr(CXCursor Cursor); + +ASTContext &getCursorContext(CXCursor Cursor); +ASTUnit *getCursorASTUnit(CXCursor Cursor); +CXTranslationUnit getCursorTU(CXCursor Cursor); + +void getOverriddenCursors(CXCursor cursor, + SmallVectorImpl<CXCursor> &overridden); + +/// Create an opaque pool used for fast generation of overridden +/// CXCursor arrays. +void *createOverridenCXCursorsPool(); + +/// Dispose of the overridden CXCursors pool. +void disposeOverridenCXCursorsPool(void *pool); + +/// Returns a index/location pair for a selector identifier if the cursor +/// points to one. +std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor); +static inline int getSelectorIdentifierIndex(CXCursor cursor) { + return getSelectorIdentifierIndexAndLoc(cursor).first; +} +static inline SourceLocation getSelectorIdentifierLoc(CXCursor cursor) { + return getSelectorIdentifierIndexAndLoc(cursor).second; +} + +CXCursor getSelectorIdentifierCursor(int SelIdx, CXCursor cursor); + +static inline CXCursor getTypeRefedCallExprCursor(CXCursor cursor) { + CXCursor newCursor = cursor; + if (cursor.kind == CXCursor_CallExpr) + newCursor.xdata = 1; + return newCursor; +} + +CXCursor getTypeRefCursor(CXCursor cursor); + +/// Generate a USR for \arg D and put it in \arg Buf. +/// \returns true if no USR was computed or the result should be ignored, +/// false otherwise. +bool getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf); + +bool operator==(CXCursor X, CXCursor Y); + +inline bool operator!=(CXCursor X, CXCursor Y) { return !(X == Y); } + +/// Return true if the cursor represents a declaration that is the +/// first in a declaration group. +bool isFirstInDeclGroup(CXCursor C); + +} // namespace cxcursor +} // namespace clang + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.cpp b/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.cpp new file mode 100644 index 0000000000..2f892fd1a4 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.cpp @@ -0,0 +1,1312 @@ +//===- CXIndexDataConsumer.cpp - Index data consumer for libclang----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "CXIndexDataConsumer.h" +#include "CIndexDiagnostic.h" +#include "CXTranslationUnit.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; +using namespace clang::index; +using namespace cxindex; +using namespace cxcursor; + +namespace { +class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { + CXIndexDataConsumer &DataConsumer; + SourceLocation DeclLoc; + const DeclContext *LexicalDC; + +public: + IndexingDeclVisitor(CXIndexDataConsumer &dataConsumer, SourceLocation Loc, + const DeclContext *lexicalDC) + : DataConsumer(dataConsumer), DeclLoc(Loc), LexicalDC(lexicalDC) { } + + bool VisitFunctionDecl(const FunctionDecl *D) { + DataConsumer.handleFunction(D); + return true; + } + + bool VisitVarDecl(const VarDecl *D) { + DataConsumer.handleVar(D); + return true; + } + + bool VisitFieldDecl(const FieldDecl *D) { + DataConsumer.handleField(D); + return true; + } + + bool VisitMSPropertyDecl(const MSPropertyDecl *D) { + return true; + } + + bool VisitEnumConstantDecl(const EnumConstantDecl *D) { + DataConsumer.handleEnumerator(D); + return true; + } + + bool VisitTypedefNameDecl(const TypedefNameDecl *D) { + DataConsumer.handleTypedefName(D); + return true; + } + + bool VisitTagDecl(const TagDecl *D) { + DataConsumer.handleTagDecl(D); + return true; + } + + bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { + DataConsumer.handleObjCInterface(D); + return true; + } + + bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { + DataConsumer.handleObjCProtocol(D); + return true; + } + + bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { + DataConsumer.handleObjCImplementation(D); + return true; + } + + bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { + DataConsumer.handleObjCCategory(D); + return true; + } + + bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { + DataConsumer.handleObjCCategoryImpl(D); + return true; + } + + bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { + if (isa<ObjCImplDecl>(LexicalDC) && !D->isThisDeclarationADefinition()) + DataConsumer.handleSynthesizedObjCMethod(D, DeclLoc, LexicalDC); + else + DataConsumer.handleObjCMethod(D, DeclLoc); + return true; + } + + bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { + DataConsumer.handleObjCProperty(D); + return true; + } + + bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { + DataConsumer.handleSynthesizedObjCProperty(D); + return true; + } + + bool VisitNamespaceDecl(const NamespaceDecl *D) { + DataConsumer.handleNamespace(D); + return true; + } + + bool VisitUsingDecl(const UsingDecl *D) { + return true; + } + + bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { + return true; + } + + bool VisitClassTemplateDecl(const ClassTemplateDecl *D) { + DataConsumer.handleClassTemplate(D); + return true; + } + + bool VisitClassTemplateSpecializationDecl(const + ClassTemplateSpecializationDecl *D) { + DataConsumer.handleTagDecl(D); + return true; + } + + bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { + DataConsumer.handleFunctionTemplate(D); + return true; + } + + bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { + DataConsumer.handleTypeAliasTemplate(D); + return true; + } + + bool VisitImportDecl(const ImportDecl *D) { + DataConsumer.importedModule(D); + return true; + } +}; + +CXSymbolRole getSymbolRole(SymbolRoleSet Role) { + // CXSymbolRole mirrors low 9 bits of clang::index::SymbolRole. + return CXSymbolRole(static_cast<uint32_t>(Role) & ((1 << 9) - 1)); +} +} + +bool CXIndexDataConsumer::handleDeclOccurrence( + const Decl *D, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations, + SourceLocation Loc, ASTNodeInfo ASTNode) { + Loc = getASTContext().getSourceManager().getFileLoc(Loc); + + if (Roles & (unsigned)SymbolRole::Reference) { + const NamedDecl *ND = dyn_cast<NamedDecl>(D); + if (!ND) + return true; + + if (auto *ObjCID = dyn_cast_or_null<ObjCInterfaceDecl>(ASTNode.OrigD)) { + if (!ObjCID->isThisDeclarationADefinition() && + ObjCID->getLocation() == Loc) { + // The libclang API treats this as ObjCClassRef declaration. + IndexingDeclVisitor(*this, Loc, nullptr).Visit(ObjCID); + return true; + } + } + if (auto *ObjCPD = dyn_cast_or_null<ObjCProtocolDecl>(ASTNode.OrigD)) { + if (!ObjCPD->isThisDeclarationADefinition() && + ObjCPD->getLocation() == Loc) { + // The libclang API treats this as ObjCProtocolRef declaration. + IndexingDeclVisitor(*this, Loc, nullptr).Visit(ObjCPD); + return true; + } + } + + CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct; + if (Roles & (unsigned)SymbolRole::Implicit) { + Kind = CXIdxEntityRef_Implicit; + } + CXSymbolRole CXRole = getSymbolRole(Roles); + + CXCursor Cursor; + if (ASTNode.OrigE) { + Cursor = cxcursor::MakeCXCursor(ASTNode.OrigE, + cast<Decl>(ASTNode.ContainerDC), + getCXTU()); + } else { + if (ASTNode.OrigD) { + if (auto *OrigND = dyn_cast<NamedDecl>(ASTNode.OrigD)) + Cursor = getRefCursor(OrigND, Loc); + else + Cursor = MakeCXCursor(ASTNode.OrigD, CXTU); + } else { + Cursor = getRefCursor(ND, Loc); + } + } + handleReference(ND, Loc, Cursor, + dyn_cast_or_null<NamedDecl>(ASTNode.Parent), + ASTNode.ContainerDC, ASTNode.OrigE, Kind, CXRole); + + } else { + const DeclContext *LexicalDC = ASTNode.ContainerDC; + if (!LexicalDC) { + for (const auto &SymRel : Relations) { + if (SymRel.Roles & (unsigned)SymbolRole::RelationChildOf) + LexicalDC = dyn_cast<DeclContext>(SymRel.RelatedSymbol); + } + } + IndexingDeclVisitor(*this, Loc, LexicalDC).Visit(ASTNode.OrigD); + } + + return !shouldAbort(); +} + +bool CXIndexDataConsumer::handleModuleOccurrence(const ImportDecl *ImportD, + const Module *Mod, + SymbolRoleSet Roles, + SourceLocation Loc) { + if (Roles & (SymbolRoleSet)SymbolRole::Declaration) + IndexingDeclVisitor(*this, SourceLocation(), nullptr).Visit(ImportD); + return !shouldAbort(); +} + +void CXIndexDataConsumer::finish() { + indexDiagnostics(); +} + + +CXIndexDataConsumer::ObjCProtocolListInfo::ObjCProtocolListInfo( + const ObjCProtocolList &ProtList, + CXIndexDataConsumer &IdxCtx, + ScratchAlloc &SA) { + ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator + I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) { + SourceLocation Loc = *LI; + ObjCProtocolDecl *PD = *I; + ProtEntities.push_back(EntityInfo()); + IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA); + CXIdxObjCProtocolRefInfo ProtInfo = { nullptr, + MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU), + IdxCtx.getIndexLoc(Loc) }; + ProtInfos.push_back(ProtInfo); + + if (IdxCtx.shouldSuppressRefs()) + IdxCtx.markEntityOccurrenceInFile(PD, Loc); + } + + for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) + ProtInfos[i].protocol = &ProtEntities[i]; + + for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i) + Prots.push_back(&ProtInfos[i]); +} + + +IBOutletCollectionInfo::IBOutletCollectionInfo( + const IBOutletCollectionInfo &other) + : AttrInfo(CXIdxAttr_IBOutletCollection, other.cursor, other.loc, other.A) { + + IBCollInfo.attrInfo = this; + IBCollInfo.classCursor = other.IBCollInfo.classCursor; + IBCollInfo.classLoc = other.IBCollInfo.classLoc; + if (other.IBCollInfo.objcClass) { + ClassInfo = other.ClassInfo; + IBCollInfo.objcClass = &ClassInfo; + } else + IBCollInfo.objcClass = nullptr; +} + +AttrListInfo::AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx) + : SA(IdxCtx), ref_cnt(0) { + + if (!D->hasAttrs()) + return; + + for (const auto *A : D->attrs()) { + CXCursor C = MakeCXCursor(A, D, IdxCtx.CXTU); + CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation()); + switch (C.kind) { + default: + Attrs.push_back(AttrInfo(CXIdxAttr_Unexposed, C, Loc, A)); + break; + case CXCursor_IBActionAttr: + Attrs.push_back(AttrInfo(CXIdxAttr_IBAction, C, Loc, A)); + break; + case CXCursor_IBOutletAttr: + Attrs.push_back(AttrInfo(CXIdxAttr_IBOutlet, C, Loc, A)); + break; + case CXCursor_IBOutletCollectionAttr: + IBCollAttrs.push_back(IBOutletCollectionInfo(C, Loc, A)); + break; + } + } + + for (unsigned i = 0, e = IBCollAttrs.size(); i != e; ++i) { + IBOutletCollectionInfo &IBInfo = IBCollAttrs[i]; + CXAttrs.push_back(&IBInfo); + + const IBOutletCollectionAttr * + IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A); + SourceLocation InterfaceLocStart = + IBAttr->getInterfaceLoc()->getTypeLoc().getBeginLoc(); + IBInfo.IBCollInfo.attrInfo = &IBInfo; + IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(InterfaceLocStart); + IBInfo.IBCollInfo.objcClass = nullptr; + IBInfo.IBCollInfo.classCursor = clang_getNullCursor(); + QualType Ty = IBAttr->getInterface(); + if (const ObjCObjectType *ObjectTy = Ty->getAs<ObjCObjectType>()) { + if (const ObjCInterfaceDecl *InterD = ObjectTy->getInterface()) { + IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA); + IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo; + IBInfo.IBCollInfo.classCursor = + MakeCursorObjCClassRef(InterD, InterfaceLocStart, IdxCtx.CXTU); + } + } + } + + for (unsigned i = 0, e = Attrs.size(); i != e; ++i) + CXAttrs.push_back(&Attrs[i]); +} + +IntrusiveRefCntPtr<AttrListInfo> +AttrListInfo::create(const Decl *D, CXIndexDataConsumer &IdxCtx) { + ScratchAlloc SA(IdxCtx); + AttrListInfo *attrs = SA.allocate<AttrListInfo>(); + return new (attrs) AttrListInfo(D, IdxCtx); +} + +CXIndexDataConsumer::CXXBasesListInfo::CXXBasesListInfo(const CXXRecordDecl *D, + CXIndexDataConsumer &IdxCtx, + ScratchAlloc &SA) { + for (const auto &Base : D->bases()) { + BaseEntities.push_back(EntityInfo()); + const NamedDecl *BaseD = nullptr; + QualType T = Base.getType(); + SourceLocation Loc = getBaseLoc(Base); + + if (const TypedefType *TDT = T->getAs<TypedefType>()) { + BaseD = TDT->getDecl(); + } else if (const TemplateSpecializationType * + TST = T->getAs<TemplateSpecializationType>()) { + BaseD = TST->getTemplateName().getAsTemplateDecl(); + } else if (const RecordType *RT = T->getAs<RecordType>()) { + BaseD = RT->getDecl(); + } + + if (BaseD) + IdxCtx.getEntityInfo(BaseD, BaseEntities.back(), SA); + CXIdxBaseClassInfo BaseInfo = { nullptr, + MakeCursorCXXBaseSpecifier(&Base, IdxCtx.CXTU), + IdxCtx.getIndexLoc(Loc) }; + BaseInfos.push_back(BaseInfo); + } + + for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) { + if (BaseEntities[i].name && BaseEntities[i].USR) + BaseInfos[i].base = &BaseEntities[i]; + } + + for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) + CXBases.push_back(&BaseInfos[i]); +} + +SourceLocation CXIndexDataConsumer::CXXBasesListInfo::getBaseLoc( + const CXXBaseSpecifier &Base) const { + SourceLocation Loc = Base.getSourceRange().getBegin(); + TypeLoc TL; + if (Base.getTypeSourceInfo()) + TL = Base.getTypeSourceInfo()->getTypeLoc(); + if (TL.isNull()) + return Loc; + + if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) + TL = QL.getUnqualifiedLoc(); + + if (ElaboratedTypeLoc EL = TL.getAs<ElaboratedTypeLoc>()) + return EL.getNamedTypeLoc().getBeginLoc(); + if (DependentNameTypeLoc DL = TL.getAs<DependentNameTypeLoc>()) + return DL.getNameLoc(); + if (DependentTemplateSpecializationTypeLoc DTL = + TL.getAs<DependentTemplateSpecializationTypeLoc>()) + return DTL.getTemplateNameLoc(); + + return Loc; +} + +const char *ScratchAlloc::toCStr(StringRef Str) { + if (Str.empty()) + return ""; + if (Str.data()[Str.size()] == '\0') + return Str.data(); + return copyCStr(Str); +} + +const char *ScratchAlloc::copyCStr(StringRef Str) { + char *buf = IdxCtx.StrScratch.Allocate<char>(Str.size() + 1); + std::uninitialized_copy(Str.begin(), Str.end(), buf); + buf[Str.size()] = '\0'; + return buf; +} + +void CXIndexDataConsumer::setASTContext(ASTContext &ctx) { + Ctx = &ctx; + cxtu::getASTUnit(CXTU)->setASTContext(&ctx); +} + +void CXIndexDataConsumer::setPreprocessor(std::shared_ptr<Preprocessor> PP) { + cxtu::getASTUnit(CXTU)->setPreprocessor(std::move(PP)); +} + +bool CXIndexDataConsumer::isFunctionLocalDecl(const Decl *D) { + assert(D); + + if (!D->getParentFunctionOrMethod()) + return false; + + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { + switch (ND->getFormalLinkage()) { + case NoLinkage: + case InternalLinkage: + return true; + case VisibleNoLinkage: + case ModuleInternalLinkage: + case UniqueExternalLinkage: + llvm_unreachable("Not a sema linkage"); + case ModuleLinkage: + case ExternalLinkage: + return false; + } + } + + return true; +} + +bool CXIndexDataConsumer::shouldAbort() { + if (!CB.abortQuery) + return false; + return CB.abortQuery(ClientData, nullptr); +} + +void CXIndexDataConsumer::enteredMainFile(const FileEntry *File) { + if (File && CB.enteredMainFile) { + CXIdxClientFile idxFile = + CB.enteredMainFile(ClientData, + static_cast<CXFile>(const_cast<FileEntry *>(File)), + nullptr); + FileMap[File] = idxFile; + } +} + +void CXIndexDataConsumer::ppIncludedFile(SourceLocation hashLoc, + StringRef filename, + const FileEntry *File, + bool isImport, bool isAngled, + bool isModuleImport) { + if (!CB.ppIncludedFile) + return; + + ScratchAlloc SA(*this); + CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc), + SA.toCStr(filename), + static_cast<CXFile>( + const_cast<FileEntry *>(File)), + isImport, isAngled, isModuleImport }; + CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info); + FileMap[File] = idxFile; +} + +void CXIndexDataConsumer::importedModule(const ImportDecl *ImportD) { + if (!CB.importedASTFile) + return; + + Module *Mod = ImportD->getImportedModule(); + if (!Mod) + return; + + // If the imported module is part of the top-level module that we're + // indexing, it doesn't correspond to an imported AST file. + // FIXME: This assumes that AST files and top-level modules directly + // correspond, which is unlikely to remain true forever. + if (Module *SrcMod = ImportD->getImportedOwningModule()) + if (SrcMod->getTopLevelModule() == Mod->getTopLevelModule()) + return; + + FileEntry *FE = nullptr; + if (auto File = Mod->getASTFile()) + FE = const_cast<FileEntry *>(&File->getFileEntry()); + CXIdxImportedASTFileInfo Info = {static_cast<CXFile>(FE), Mod, + getIndexLoc(ImportD->getLocation()), + ImportD->isImplicit()}; + CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info); + (void)astFile; +} + +void CXIndexDataConsumer::importedPCH(const FileEntry *File) { + if (!CB.importedASTFile) + return; + + CXIdxImportedASTFileInfo Info = { + static_cast<CXFile>( + const_cast<FileEntry *>(File)), + /*module=*/nullptr, + getIndexLoc(SourceLocation()), + /*isImplicit=*/false + }; + CXIdxClientASTFile astFile = CB.importedASTFile(ClientData, &Info); + (void)astFile; +} + +void CXIndexDataConsumer::startedTranslationUnit() { + CXIdxClientContainer idxCont = nullptr; + if (CB.startedTranslationUnit) + idxCont = CB.startedTranslationUnit(ClientData, nullptr); + addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); +} + +void CXIndexDataConsumer::indexDiagnostics() { + if (!hasDiagnosticCallback()) + return; + + CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(getCXTU()); + handleDiagnosticSet(DiagSet); +} + +void CXIndexDataConsumer::handleDiagnosticSet(CXDiagnostic CXDiagSet) { + if (!CB.diagnostic) + return; + + CB.diagnostic(ClientData, CXDiagSet, nullptr); +} + +bool CXIndexDataConsumer::handleDecl(const NamedDecl *D, + SourceLocation Loc, CXCursor Cursor, + DeclInfo &DInfo, + const DeclContext *LexicalDC, + const DeclContext *SemaDC) { + if (!CB.indexDeclaration || !D) + return false; + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return false; + + ScratchAlloc SA(*this); + getEntityInfo(D, DInfo.EntInfo, SA); + if ((!shouldIndexFunctionLocalSymbols() && !DInfo.EntInfo.USR) + || Loc.isInvalid()) + return false; + + if (!LexicalDC) + LexicalDC = D->getLexicalDeclContext(); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(D, Loc); + + DInfo.entityInfo = &DInfo.EntInfo; + DInfo.cursor = Cursor; + DInfo.loc = getIndexLoc(Loc); + DInfo.isImplicit = D->isImplicit(); + + DInfo.attributes = DInfo.EntInfo.attributes; + DInfo.numAttributes = DInfo.EntInfo.numAttributes; + + if (!SemaDC) + SemaDC = D->getDeclContext(); + getContainerInfo(SemaDC, DInfo.SemanticContainer); + DInfo.semanticContainer = &DInfo.SemanticContainer; + + if (LexicalDC == SemaDC) { + DInfo.lexicalContainer = &DInfo.SemanticContainer; + } else if (isTemplateImplicitInstantiation(D)) { + // Implicit instantiations have the lexical context of where they were + // instantiated first. We choose instead the semantic context because: + // 1) at the time that we see the instantiation we have not seen the + // function where it occurred yet. + // 2) the lexical context of the first instantiation is not useful + // information anyway. + DInfo.lexicalContainer = &DInfo.SemanticContainer; + } else { + getContainerInfo(LexicalDC, DInfo.LexicalContainer); + DInfo.lexicalContainer = &DInfo.LexicalContainer; + } + + if (DInfo.isContainer) { + getContainerInfo(getEntityContainer(D), DInfo.DeclAsContainer); + DInfo.declAsContainer = &DInfo.DeclAsContainer; + } + + CB.indexDeclaration(ClientData, &DInfo); + return true; +} + +bool CXIndexDataConsumer::handleObjCContainer(const ObjCContainerDecl *D, + SourceLocation Loc, CXCursor Cursor, + ObjCContainerDeclInfo &ContDInfo) { + ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo; + return handleDecl(D, Loc, Cursor, ContDInfo); +} + +bool CXIndexDataConsumer::handleFunction(const FunctionDecl *D) { + bool isDef = D->isThisDeclarationADefinition(); + bool isContainer = isDef; + bool isSkipped = false; + if (D->hasSkippedBody()) { + isSkipped = true; + isDef = true; + isContainer = false; + } + + DeclInfo DInfo(!D->isFirstDecl(), isDef, isContainer); + if (isSkipped) + DInfo.flags |= CXIdxDeclFlag_Skipped; + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleVar(const VarDecl *D) { + DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(), + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleField(const FieldDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleEnumerator(const EnumConstantDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleTagDecl(const TagDecl *D) { + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(D)) + return handleCXXRecordDecl(CXXRD, D); + + DeclInfo DInfo(!D->isFirstDecl(), D->isThisDeclarationADefinition(), + D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleTypedefName(const TypedefNameDecl *D) { + DeclInfo DInfo(!D->isFirstDecl(), /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleObjCInterface(const ObjCInterfaceDecl *D) { + // For @class forward declarations, suppress them the same way as references. + if (!D->isThisDeclarationADefinition()) { + if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation())) + return false; // already occurred. + + // FIXME: This seems like the wrong definition for redeclaration. + bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration, + /*isImplementation=*/false); + return handleObjCContainer(D, D->getLocation(), + MakeCursorObjCClassRef(D, D->getLocation(), + CXTU), + ContDInfo); + } + + ScratchAlloc SA(*this); + + CXIdxBaseClassInfo BaseClass; + EntityInfo BaseEntity; + BaseClass.cursor = clang_getNullCursor(); + if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) { + getEntityInfo(SuperD, BaseEntity, SA); + SourceLocation SuperLoc = D->getSuperClassLoc(); + BaseClass.base = &BaseEntity; + BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU); + BaseClass.loc = getIndexLoc(SuperLoc); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(SuperD, SuperLoc); + } + + ObjCProtocolList EmptyProtoList; + ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition() + ? D->getReferencedProtocols() + : EmptyProtoList, + *this, SA); + + ObjCInterfaceDeclInfo InterInfo(D); + InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); + InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo; + InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass + : nullptr; + InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo; + + return handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo); +} + +bool CXIndexDataConsumer::handleObjCImplementation( + const ObjCImplementationDecl *D) { + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false, + /*isRedeclaration=*/true, + /*isImplementation=*/true); + return handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo); +} + +bool CXIndexDataConsumer::handleObjCProtocol(const ObjCProtocolDecl *D) { + if (!D->isThisDeclarationADefinition()) { + if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation())) + return false; // already occurred. + + // FIXME: This seems like the wrong definition for redeclaration. + bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl(); + ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, + isRedeclaration, + /*isImplementation=*/false); + return handleObjCContainer(D, D->getLocation(), + MakeCursorObjCProtocolRef(D, D->getLocation(), + CXTU), + ContDInfo); + } + + ScratchAlloc SA(*this); + ObjCProtocolList EmptyProtoList; + ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition() + ? D->getReferencedProtocols() + : EmptyProtoList, + *this, SA); + + ObjCProtocolDeclInfo ProtInfo(D); + ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo(); + + return handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo); +} + +bool CXIndexDataConsumer::handleObjCCategory(const ObjCCategoryDecl *D) { + ScratchAlloc SA(*this); + + ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false); + EntityInfo ClassEntity; + const ObjCInterfaceDecl *IFaceD = D->getClassInterface(); + SourceLocation ClassLoc = D->getLocation(); + SourceLocation CategoryLoc = D->IsClassExtension() ? ClassLoc + : D->getCategoryNameLoc(); + getEntityInfo(IFaceD, ClassEntity, SA); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(IFaceD, ClassLoc); + + ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA); + + CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; + if (IFaceD) { + CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; + CatDInfo.ObjCCatDeclInfo.classCursor = + MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); + } else { + CatDInfo.ObjCCatDeclInfo.objcClass = nullptr; + CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); + } + CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); + CatDInfo.ObjCProtoListInfo = ProtInfo.getListInfo(); + CatDInfo.ObjCCatDeclInfo.protocols = &CatDInfo.ObjCProtoListInfo; + + return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); +} + +bool CXIndexDataConsumer::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) { + ScratchAlloc SA(*this); + + const ObjCCategoryDecl *CatD = D->getCategoryDecl(); + ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true); + EntityInfo ClassEntity; + const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface(); + SourceLocation ClassLoc = D->getLocation(); + SourceLocation CategoryLoc = D->getCategoryNameLoc(); + getEntityInfo(IFaceD, ClassEntity, SA); + + if (shouldSuppressRefs()) + markEntityOccurrenceInFile(IFaceD, ClassLoc); + + CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo; + if (IFaceD) { + CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity; + CatDInfo.ObjCCatDeclInfo.classCursor = + MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU); + } else { + CatDInfo.ObjCCatDeclInfo.objcClass = nullptr; + CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor(); + } + CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc); + CatDInfo.ObjCCatDeclInfo.protocols = nullptr; + + return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo); +} + +bool CXIndexDataConsumer::handleObjCMethod(const ObjCMethodDecl *D, + SourceLocation Loc) { + bool isDef = D->isThisDeclarationADefinition(); + bool isContainer = isDef; + bool isSkipped = false; + if (D->hasSkippedBody()) { + isSkipped = true; + isDef = true; + isContainer = false; + } + + DeclInfo DInfo(!D->isCanonicalDecl(), isDef, isContainer); + if (isSkipped) + DInfo.flags |= CXIdxDeclFlag_Skipped; + return handleDecl(D, Loc, getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleSynthesizedObjCProperty( + const ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *PD = D->getPropertyDecl(); + auto *DC = D->getDeclContext(); + return handleReference(PD, D->getLocation(), getCursor(D), + dyn_cast<NamedDecl>(DC), DC); +} + +bool CXIndexDataConsumer::handleSynthesizedObjCMethod(const ObjCMethodDecl *D, + SourceLocation Loc, + const DeclContext *LexicalDC) { + DeclInfo DInfo(/*isRedeclaration=*/true, /*isDefinition=*/true, + /*isContainer=*/false); + return handleDecl(D, Loc, getCursor(D), DInfo, LexicalDC, D->getDeclContext()); +} + +bool CXIndexDataConsumer::handleObjCProperty(const ObjCPropertyDecl *D) { + ScratchAlloc SA(*this); + + ObjCPropertyDeclInfo DInfo; + EntityInfo GetterEntity; + EntityInfo SetterEntity; + + DInfo.ObjCPropDeclInfo.declInfo = &DInfo; + + if (ObjCMethodDecl *Getter = D->getGetterMethodDecl()) { + getEntityInfo(Getter, GetterEntity, SA); + DInfo.ObjCPropDeclInfo.getter = &GetterEntity; + } else { + DInfo.ObjCPropDeclInfo.getter = nullptr; + } + if (ObjCMethodDecl *Setter = D->getSetterMethodDecl()) { + getEntityInfo(Setter, SetterEntity, SA); + DInfo.ObjCPropDeclInfo.setter = &SetterEntity; + } else { + DInfo.ObjCPropDeclInfo.setter = nullptr; + } + + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleNamespace(const NamespaceDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isOriginalNamespace(), + /*isDefinition=*/true, + /*isContainer=*/true); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleClassTemplate(const ClassTemplateDecl *D) { + return handleCXXRecordDecl(D->getTemplatedDecl(), D); +} + +bool CXIndexDataConsumer::handleFunctionTemplate(const FunctionTemplateDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), + /*isDefinition=*/D->isThisDeclarationADefinition(), + /*isContainer=*/D->isThisDeclarationADefinition()); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D) { + DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(), + /*isDefinition=*/true, /*isContainer=*/false); + return handleDecl(D, D->getLocation(), getCursor(D), DInfo); +} + +bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc, + CXCursor Cursor, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E, + CXIdxEntityRefKind Kind, + CXSymbolRole Role) { + if (!CB.indexEntityReference) + return false; + + if (!D || !DC) + return false; + if (Loc.isInvalid()) + return false; + if (!shouldIndexFunctionLocalSymbols() && isFunctionLocalDecl(D)) + return false; + if (isNotFromSourceFile(D->getLocation())) + return false; + if (D->isImplicit() && shouldIgnoreIfImplicit(D)) + return false; + + if (shouldSuppressRefs()) { + if (markEntityOccurrenceInFile(D, Loc)) + return false; // already occurred. + } + + ScratchAlloc SA(*this); + EntityInfo RefEntity, ParentEntity; + getEntityInfo(D, RefEntity, SA); + if (!RefEntity.USR) + return false; + + getEntityInfo(Parent, ParentEntity, SA); + + ContainerInfo Container; + getContainerInfo(DC, Container); + + CXIdxEntityRefInfo Info = { Kind, + Cursor, + getIndexLoc(Loc), + &RefEntity, + Parent ? &ParentEntity : nullptr, + &Container, + Role }; + CB.indexEntityReference(ClientData, &Info); + return true; +} + +bool CXIndexDataConsumer::isNotFromSourceFile(SourceLocation Loc) const { + if (Loc.isInvalid()) + return true; + SourceManager &SM = Ctx->getSourceManager(); + SourceLocation FileLoc = SM.getFileLoc(Loc); + FileID FID = SM.getFileID(FileLoc); + return SM.getFileEntryForID(FID) == nullptr; +} + +void CXIndexDataConsumer::addContainerInMap(const DeclContext *DC, + CXIdxClientContainer container) { + if (!DC) + return; + + ContainerMapTy::iterator I = ContainerMap.find(DC); + if (I == ContainerMap.end()) { + if (container) + ContainerMap[DC] = container; + return; + } + // Allow changing the container of a previously seen DeclContext so we + // can handle invalid user code, like a function re-definition. + if (container) + I->second = container; + else + ContainerMap.erase(I); +} + +CXIdxClientEntity CXIndexDataConsumer::getClientEntity(const Decl *D) const { + if (!D) + return nullptr; + EntityMapTy::const_iterator I = EntityMap.find(D); + if (I == EntityMap.end()) + return nullptr; + return I->second; +} + +void CXIndexDataConsumer::setClientEntity(const Decl *D, CXIdxClientEntity client) { + if (!D) + return; + EntityMap[D] = client; +} + +bool CXIndexDataConsumer::handleCXXRecordDecl(const CXXRecordDecl *RD, + const NamedDecl *OrigD) { + if (RD->isThisDeclarationADefinition()) { + ScratchAlloc SA(*this); + CXXClassDeclInfo CXXDInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), + /*isDefinition=*/RD->isThisDeclarationADefinition()); + CXXBasesListInfo BaseList(RD, *this, SA); + CXXDInfo.CXXClassInfo.declInfo = &CXXDInfo; + CXXDInfo.CXXClassInfo.bases = BaseList.getBases(); + CXXDInfo.CXXClassInfo.numBases = BaseList.getNumBases(); + + if (shouldSuppressRefs()) { + // Go through bases and mark them as referenced. + for (unsigned i = 0, e = BaseList.getNumBases(); i != e; ++i) { + const CXIdxBaseClassInfo *baseInfo = BaseList.getBases()[i]; + if (baseInfo->base) { + const NamedDecl *BaseD = BaseList.BaseEntities[i].Dcl; + SourceLocation + Loc = SourceLocation::getFromRawEncoding(baseInfo->loc.int_data); + markEntityOccurrenceInFile(BaseD, Loc); + } + } + } + + return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), CXXDInfo); + } + + DeclInfo DInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(), + /*isDefinition=*/RD->isThisDeclarationADefinition(), + /*isContainer=*/RD->isThisDeclarationADefinition()); + return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), DInfo); +} + +bool CXIndexDataConsumer::markEntityOccurrenceInFile(const NamedDecl *D, + SourceLocation Loc) { + if (!D || Loc.isInvalid()) + return true; + + SourceManager &SM = Ctx->getSourceManager(); + D = getEntityDecl(D); + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc)); + FileID FID = LocInfo.first; + if (FID.isInvalid()) + return true; + + const FileEntry *FE = SM.getFileEntryForID(FID); + if (!FE) + return true; + RefFileOccurrence RefOccur(FE, D); + std::pair<llvm::DenseSet<RefFileOccurrence>::iterator, bool> + res = RefFileOccurrences.insert(RefOccur); + return !res.second; // already in map +} + +const NamedDecl *CXIndexDataConsumer::getEntityDecl(const NamedDecl *D) const { + assert(D); + D = cast<NamedDecl>(D->getCanonicalDecl()); + + if (const ObjCImplementationDecl * + ImplD = dyn_cast<ObjCImplementationDecl>(D)) { + return getEntityDecl(ImplD->getClassInterface()); + + } else if (const ObjCCategoryImplDecl * + CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) { + return getEntityDecl(CatImplD->getCategoryDecl()); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate()) + return getEntityDecl(TemplD); + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate()) + return getEntityDecl(TemplD); + } + + return D; +} + +const DeclContext * +CXIndexDataConsumer::getEntityContainer(const Decl *D) const { + const DeclContext *DC = dyn_cast<DeclContext>(D); + if (DC) + return DC; + + if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(D)) { + DC = ClassTempl->getTemplatedDecl(); + } else if (const FunctionTemplateDecl * + FuncTempl = dyn_cast<FunctionTemplateDecl>(D)) { + DC = FuncTempl->getTemplatedDecl(); + } + + return DC; +} + +CXIdxClientContainer +CXIndexDataConsumer::getClientContainerForDC(const DeclContext *DC) const { + if (!DC) + return nullptr; + + ContainerMapTy::const_iterator I = ContainerMap.find(DC); + if (I == ContainerMap.end()) + return nullptr; + + return I->second; +} + +CXIdxClientFile CXIndexDataConsumer::getIndexFile(const FileEntry *File) { + if (!File) + return nullptr; + + FileMapTy::iterator FI = FileMap.find(File); + if (FI != FileMap.end()) + return FI->second; + + return nullptr; +} + +CXIdxLoc CXIndexDataConsumer::getIndexLoc(SourceLocation Loc) const { + CXIdxLoc idxLoc = { {nullptr, nullptr}, 0 }; + if (Loc.isInvalid()) + return idxLoc; + + idxLoc.ptr_data[0] = const_cast<CXIndexDataConsumer *>(this); + idxLoc.int_data = Loc.getRawEncoding(); + return idxLoc; +} + +void CXIndexDataConsumer::translateLoc(SourceLocation Loc, + CXIdxClientFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, + unsigned *offset) { + if (Loc.isInvalid()) + return; + + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return; + + const FileEntry *FE = SM.getFileEntryForID(FID); + if (indexFile) + *indexFile = getIndexFile(FE); + if (file) + *file = const_cast<FileEntry *>(FE); + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} + +static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage L); +static CXIdxEntityCXXTemplateKind +getEntityKindFromSymbolProperties(SymbolPropertySet K); +static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L); + +void CXIndexDataConsumer::getEntityInfo(const NamedDecl *D, + EntityInfo &EntityInfo, + ScratchAlloc &SA) { + if (!D) + return; + + D = getEntityDecl(D); + EntityInfo.cursor = getCursor(D); + EntityInfo.Dcl = D; + EntityInfo.IndexCtx = this; + + SymbolInfo SymInfo = getSymbolInfo(D); + EntityInfo.kind = getEntityKindFromSymbolKind(SymInfo.Kind, SymInfo.Lang); + EntityInfo.templateKind = getEntityKindFromSymbolProperties(SymInfo.Properties); + EntityInfo.lang = getEntityLangFromSymbolLang(SymInfo.Lang); + + if (D->hasAttrs()) { + EntityInfo.AttrList = AttrListInfo::create(D, *this); + EntityInfo.attributes = EntityInfo.AttrList->getAttrs(); + EntityInfo.numAttributes = EntityInfo.AttrList->getNumAttrs(); + } + + if (EntityInfo.kind == CXIdxEntity_Unexposed) + return; + + if (IdentifierInfo *II = D->getIdentifier()) { + EntityInfo.name = SA.toCStr(II->getName()); + + } else if (isa<TagDecl>(D) || isa<FieldDecl>(D) || isa<NamespaceDecl>(D)) { + EntityInfo.name = nullptr; // anonymous tag/field/namespace. + + } else { + SmallString<256> StrBuf; + { + llvm::raw_svector_ostream OS(StrBuf); + D->printName(OS); + } + EntityInfo.name = SA.copyCStr(StrBuf.str()); + } + + { + SmallString<512> StrBuf; + bool Ignore = getDeclCursorUSR(D, StrBuf); + if (Ignore) { + EntityInfo.USR = nullptr; + } else { + EntityInfo.USR = SA.copyCStr(StrBuf.str()); + } + } +} + +void CXIndexDataConsumer::getContainerInfo(const DeclContext *DC, + ContainerInfo &ContInfo) { + ContInfo.cursor = getCursor(cast<Decl>(DC)); + ContInfo.DC = DC; + ContInfo.IndexCtx = this; +} + +CXCursor CXIndexDataConsumer::getRefCursor(const NamedDecl *D, SourceLocation Loc) { + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCursorTypeRef(TD, Loc, CXTU); + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCursorObjCClassRef(ID, Loc, CXTU); + if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) + return MakeCursorObjCProtocolRef(PD, Loc, CXTU); + if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) + return MakeCursorTemplateRef(Template, Loc, CXTU); + if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const NamespaceAliasDecl *Namespace = dyn_cast<NamespaceAliasDecl>(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) + return MakeCursorMemberRef(Field, Loc, CXTU); + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) + return MakeCursorVariableRef(Var, Loc, CXTU); + + return clang_getNullCursor(); +} + +bool CXIndexDataConsumer::shouldIgnoreIfImplicit(const Decl *D) { + if (isa<ObjCInterfaceDecl>(D)) + return false; + if (isa<ObjCCategoryDecl>(D)) + return false; + if (isa<ObjCIvarDecl>(D)) + return false; + if (isa<ObjCMethodDecl>(D)) + return false; + if (isa<ImportDecl>(D)) + return false; + return true; +} + +bool CXIndexDataConsumer::isTemplateImplicitInstantiation(const Decl *D) { + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + return SD->getSpecializationKind() == TSK_ImplicitInstantiation; + } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + } + return false; +} + +static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage Lang) { + switch (K) { + case SymbolKind::Unknown: + case SymbolKind::Module: + case SymbolKind::Macro: + case SymbolKind::ClassProperty: + case SymbolKind::Using: + case SymbolKind::TemplateTypeParm: + case SymbolKind::TemplateTemplateParm: + case SymbolKind::NonTypeTemplateParm: + return CXIdxEntity_Unexposed; + + case SymbolKind::Enum: return CXIdxEntity_Enum; + case SymbolKind::Struct: return CXIdxEntity_Struct; + case SymbolKind::Union: return CXIdxEntity_Union; + case SymbolKind::TypeAlias: + if (Lang == SymbolLanguage::CXX) + return CXIdxEntity_CXXTypeAlias; + return CXIdxEntity_Typedef; + case SymbolKind::Function: return CXIdxEntity_Function; + case SymbolKind::Variable: return CXIdxEntity_Variable; + case SymbolKind::Field: + if (Lang == SymbolLanguage::ObjC) + return CXIdxEntity_ObjCIvar; + return CXIdxEntity_Field; + case SymbolKind::EnumConstant: return CXIdxEntity_EnumConstant; + case SymbolKind::Class: + if (Lang == SymbolLanguage::ObjC) + return CXIdxEntity_ObjCClass; + return CXIdxEntity_CXXClass; + case SymbolKind::Protocol: + if (Lang == SymbolLanguage::ObjC) + return CXIdxEntity_ObjCProtocol; + return CXIdxEntity_CXXInterface; + case SymbolKind::Extension: return CXIdxEntity_ObjCCategory; + case SymbolKind::InstanceMethod: + if (Lang == SymbolLanguage::ObjC) + return CXIdxEntity_ObjCInstanceMethod; + return CXIdxEntity_CXXInstanceMethod; + case SymbolKind::ClassMethod: return CXIdxEntity_ObjCClassMethod; + case SymbolKind::StaticMethod: return CXIdxEntity_CXXStaticMethod; + case SymbolKind::InstanceProperty: return CXIdxEntity_ObjCProperty; + case SymbolKind::StaticProperty: return CXIdxEntity_CXXStaticVariable; + case SymbolKind::Namespace: return CXIdxEntity_CXXNamespace; + case SymbolKind::NamespaceAlias: return CXIdxEntity_CXXNamespaceAlias; + case SymbolKind::Constructor: return CXIdxEntity_CXXConstructor; + case SymbolKind::Destructor: return CXIdxEntity_CXXDestructor; + case SymbolKind::ConversionFunction: return CXIdxEntity_CXXConversionFunction; + case SymbolKind::Parameter: return CXIdxEntity_Variable; + } + llvm_unreachable("invalid symbol kind"); +} + +static CXIdxEntityCXXTemplateKind +getEntityKindFromSymbolProperties(SymbolPropertySet K) { + if (K & (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization) + return CXIdxEntity_TemplatePartialSpecialization; + if (K & (SymbolPropertySet)SymbolProperty::TemplateSpecialization) + return CXIdxEntity_TemplateSpecialization; + if (K & (SymbolPropertySet)SymbolProperty::Generic) + return CXIdxEntity_Template; + return CXIdxEntity_NonTemplate; +} + +static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L) { + switch (L) { + case SymbolLanguage::C: return CXIdxEntityLang_C; + case SymbolLanguage::ObjC: return CXIdxEntityLang_ObjC; + case SymbolLanguage::CXX: return CXIdxEntityLang_CXX; + case SymbolLanguage::Swift: return CXIdxEntityLang_Swift; + } + llvm_unreachable("invalid symbol language"); +} diff --git a/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.h b/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.h new file mode 100644 index 0000000000..8e6045dbf6 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXIndexDataConsumer.h @@ -0,0 +1,500 @@ +//===- CXIndexDataConsumer.h - Index data consumer for libclang--*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXINDEXDATACONSUMER_H + +#include "CXCursor.h" +#include "Index_Internal.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclObjC.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + class FileEntry; + class MSPropertyDecl; + class ObjCPropertyDecl; + class ClassTemplateDecl; + class FunctionTemplateDecl; + class TypeAliasTemplateDecl; + class ClassTemplateSpecializationDecl; + +namespace cxindex { + class CXIndexDataConsumer; + class AttrListInfo; + +class ScratchAlloc { + CXIndexDataConsumer &IdxCtx; + +public: + explicit ScratchAlloc(CXIndexDataConsumer &indexCtx); + ScratchAlloc(const ScratchAlloc &SA); + + ~ScratchAlloc(); + + const char *toCStr(StringRef Str); + const char *copyCStr(StringRef Str); + + template <typename T> + T *allocate(); +}; + +struct EntityInfo : public CXIdxEntityInfo { + const NamedDecl *Dcl; + CXIndexDataConsumer *IndexCtx; + IntrusiveRefCntPtr<AttrListInfo> AttrList; + + EntityInfo() { + name = USR = nullptr; + attributes = nullptr; + numAttributes = 0; + } +}; + +struct ContainerInfo : public CXIdxContainerInfo { + const DeclContext *DC; + CXIndexDataConsumer *IndexCtx; +}; + +struct DeclInfo : public CXIdxDeclInfo { + enum DInfoKind { + Info_Decl, + + Info_ObjCContainer, + Info_ObjCInterface, + Info_ObjCProtocol, + Info_ObjCCategory, + + Info_ObjCProperty, + + Info_CXXClass + }; + + DInfoKind Kind; + + EntityInfo EntInfo; + ContainerInfo SemanticContainer; + ContainerInfo LexicalContainer; + ContainerInfo DeclAsContainer; + + DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer) + : Kind(Info_Decl) { + this->isRedeclaration = isRedeclaration; + this->isDefinition = isDefinition; + this->isContainer = isContainer; + attributes = nullptr; + numAttributes = 0; + declAsContainer = semanticContainer = lexicalContainer = nullptr; + flags = 0; + } + DeclInfo(DInfoKind K, + bool isRedeclaration, bool isDefinition, bool isContainer) + : Kind(K) { + this->isRedeclaration = isRedeclaration; + this->isDefinition = isDefinition; + this->isContainer = isContainer; + attributes = nullptr; + numAttributes = 0; + declAsContainer = semanticContainer = lexicalContainer = nullptr; + flags = 0; + } +}; + +struct ObjCContainerDeclInfo : public DeclInfo { + CXIdxObjCContainerDeclInfo ObjCContDeclInfo; + + ObjCContainerDeclInfo(bool isForwardRef, + bool isRedeclaration, + bool isImplementation) + : DeclInfo(Info_ObjCContainer, isRedeclaration, + /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) { + init(isForwardRef, isImplementation); + } + ObjCContainerDeclInfo(DInfoKind K, + bool isForwardRef, + bool isRedeclaration, + bool isImplementation) + : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef, + /*isContainer=*/!isForwardRef) { + init(isForwardRef, isImplementation); + } + + static bool classof(const DeclInfo *D) { + return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory; + } + +private: + void init(bool isForwardRef, bool isImplementation) { + if (isForwardRef) + ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef; + else if (isImplementation) + ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation; + else + ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface; + } +}; + +struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo; + CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; + + ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D) + : ObjCContainerDeclInfo(Info_ObjCInterface, + /*isForwardRef=*/false, + /*isRedeclaration=*/D->getPreviousDecl() != nullptr, + /*isImplementation=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCInterface; + } +}; + +struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo; + + ObjCProtocolDeclInfo(const ObjCProtocolDecl *D) + : ObjCContainerDeclInfo(Info_ObjCProtocol, + /*isForwardRef=*/false, + /*isRedeclaration=*/D->getPreviousDecl(), + /*isImplementation=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCProtocol; + } +}; + +struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo { + CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo; + CXIdxObjCProtocolRefListInfo ObjCProtoListInfo; + + explicit ObjCCategoryDeclInfo(bool isImplementation) + : ObjCContainerDeclInfo(Info_ObjCCategory, + /*isForwardRef=*/false, + /*isRedeclaration=*/isImplementation, + /*isImplementation=*/isImplementation) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCCategory; + } +}; + +struct ObjCPropertyDeclInfo : public DeclInfo { + CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo; + + ObjCPropertyDeclInfo() + : DeclInfo(Info_ObjCProperty, + /*isRedeclaration=*/false, /*isDefinition=*/false, + /*isContainer=*/false) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_ObjCProperty; + } +}; + +struct CXXClassDeclInfo : public DeclInfo { + CXIdxCXXClassDeclInfo CXXClassInfo; + + CXXClassDeclInfo(bool isRedeclaration, bool isDefinition) + : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { } + + static bool classof(const DeclInfo *D) { + return D->Kind == Info_CXXClass; + } +}; + +struct AttrInfo : public CXIdxAttrInfo { + const Attr *A; + + AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) { + kind = Kind; + cursor = C; + loc = Loc; + this->A = A; + } +}; + +struct IBOutletCollectionInfo : public AttrInfo { + EntityInfo ClassInfo; + CXIdxIBOutletCollectionAttrInfo IBCollInfo; + + IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) : + AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) { + assert(C.kind == CXCursor_IBOutletCollectionAttr); + IBCollInfo.objcClass = nullptr; + } + + IBOutletCollectionInfo(const IBOutletCollectionInfo &other); + + static bool classof(const AttrInfo *A) { + return A->kind == CXIdxAttr_IBOutletCollection; + } +}; + +class AttrListInfo { + ScratchAlloc SA; + + SmallVector<AttrInfo, 2> Attrs; + SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs; + SmallVector<CXIdxAttrInfo *, 2> CXAttrs; + unsigned ref_cnt; + + AttrListInfo(const AttrListInfo &) = delete; + void operator=(const AttrListInfo &) = delete; +public: + AttrListInfo(const Decl *D, CXIndexDataConsumer &IdxCtx); + + static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D, + CXIndexDataConsumer &IdxCtx); + + const CXIdxAttrInfo *const *getAttrs() const { + if (CXAttrs.empty()) + return nullptr; + return CXAttrs.data(); + } + unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); } + + /// Retain/Release only useful when we allocate a AttrListInfo from the + /// BumpPtrAllocator, and not from the stack; so that we keep a pointer + // in the EntityInfo + void Retain() { ++ref_cnt; } + void Release() { + assert (ref_cnt > 0 && "Reference count is already zero."); + if (--ref_cnt == 0) { + // Memory is allocated from a BumpPtrAllocator, no need to delete it. + this->~AttrListInfo(); + } + } +}; + +class CXIndexDataConsumer : public index::IndexDataConsumer { + ASTContext *Ctx; + CXClientData ClientData; + IndexerCallbacks &CB; + unsigned IndexOptions; + CXTranslationUnit CXTU; + + typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy; + typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer> + ContainerMapTy; + typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy; + + FileMapTy FileMap; + ContainerMapTy ContainerMap; + EntityMapTy EntityMap; + + typedef std::pair<const FileEntry *, const Decl *> RefFileOccurrence; + llvm::DenseSet<RefFileOccurrence> RefFileOccurrences; + + llvm::BumpPtrAllocator StrScratch; + unsigned StrAdapterCount; + friend class ScratchAlloc; + + struct ObjCProtocolListInfo { + SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos; + SmallVector<EntityInfo, 4> ProtEntities; + SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots; + + CXIdxObjCProtocolRefListInfo getListInfo() const { + CXIdxObjCProtocolRefListInfo Info = { Prots.data(), + (unsigned)Prots.size() }; + return Info; + } + + ObjCProtocolListInfo(const ObjCProtocolList &ProtList, + CXIndexDataConsumer &IdxCtx, + ScratchAlloc &SA); + }; + + struct CXXBasesListInfo { + SmallVector<CXIdxBaseClassInfo, 4> BaseInfos; + SmallVector<EntityInfo, 4> BaseEntities; + SmallVector<CXIdxBaseClassInfo *, 4> CXBases; + + const CXIdxBaseClassInfo *const *getBases() const { + return CXBases.data(); + } + unsigned getNumBases() const { return (unsigned)CXBases.size(); } + + CXXBasesListInfo(const CXXRecordDecl *D, + CXIndexDataConsumer &IdxCtx, ScratchAlloc &SA); + + private: + SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const; + }; + + friend class AttrListInfo; + +public: + CXIndexDataConsumer(CXClientData clientData, IndexerCallbacks &indexCallbacks, + unsigned indexOptions, CXTranslationUnit cxTU) + : Ctx(nullptr), ClientData(clientData), CB(indexCallbacks), + IndexOptions(indexOptions), CXTU(cxTU), StrAdapterCount(0) {} + + ASTContext &getASTContext() const { return *Ctx; } + CXTranslationUnit getCXTU() const { return CXTU; } + + void setASTContext(ASTContext &ctx); + void setPreprocessor(std::shared_ptr<Preprocessor> PP) override; + + bool shouldSuppressRefs() const { + return IndexOptions & CXIndexOpt_SuppressRedundantRefs; + } + + bool shouldIndexFunctionLocalSymbols() const { + return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols; + } + + bool shouldIndexImplicitTemplateInsts() const { + return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations; + } + + static bool isFunctionLocalDecl(const Decl *D); + + bool shouldAbort(); + + bool hasDiagnosticCallback() const { return CB.diagnostic; } + + void enteredMainFile(const FileEntry *File); + + void ppIncludedFile(SourceLocation hashLoc, + StringRef filename, const FileEntry *File, + bool isImport, bool isAngled, bool isModuleImport); + + void importedModule(const ImportDecl *ImportD); + void importedPCH(const FileEntry *File); + + void startedTranslationUnit(); + + void indexDiagnostics(); + + void handleDiagnosticSet(CXDiagnosticSet CXDiagSet); + + bool handleFunction(const FunctionDecl *FD); + + bool handleVar(const VarDecl *D); + + bool handleField(const FieldDecl *D); + + bool handleEnumerator(const EnumConstantDecl *D); + + bool handleTagDecl(const TagDecl *D); + + bool handleTypedefName(const TypedefNameDecl *D); + + bool handleObjCInterface(const ObjCInterfaceDecl *D); + bool handleObjCImplementation(const ObjCImplementationDecl *D); + + bool handleObjCProtocol(const ObjCProtocolDecl *D); + + bool handleObjCCategory(const ObjCCategoryDecl *D); + bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D); + + bool handleObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc); + + bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D); + bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc, + const DeclContext *LexicalDC); + + bool handleObjCProperty(const ObjCPropertyDecl *D); + + bool handleNamespace(const NamespaceDecl *D); + + bool handleClassTemplate(const ClassTemplateDecl *D); + bool handleFunctionTemplate(const FunctionTemplateDecl *D); + bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E = nullptr, + CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct, + CXSymbolRole Role = CXSymbolRole_None); + + bool isNotFromSourceFile(SourceLocation Loc) const; + + void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, unsigned *offset); + + CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const; + void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container); + + CXIdxClientEntity getClientEntity(const Decl *D) const; + void setClientEntity(const Decl *D, CXIdxClientEntity client); + + static bool isTemplateImplicitInstantiation(const Decl *D); + +private: + bool handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles, + ArrayRef<index::SymbolRelation> Relations, + SourceLocation Loc, ASTNodeInfo ASTNode) override; + + bool handleModuleOccurrence(const ImportDecl *ImportD, const Module *Mod, + index::SymbolRoleSet Roles, + SourceLocation Loc) override; + + void finish() override; + + bool handleDecl(const NamedDecl *D, + SourceLocation Loc, CXCursor Cursor, + DeclInfo &DInfo, + const DeclContext *LexicalDC = nullptr, + const DeclContext *SemaDC = nullptr); + + bool handleObjCContainer(const ObjCContainerDecl *D, + SourceLocation Loc, CXCursor Cursor, + ObjCContainerDeclInfo &ContDInfo); + + bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD); + + bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc); + + const NamedDecl *getEntityDecl(const NamedDecl *D) const; + + const DeclContext *getEntityContainer(const Decl *D) const; + + CXIdxClientFile getIndexFile(const FileEntry *File); + + CXIdxLoc getIndexLoc(SourceLocation Loc) const; + + void getEntityInfo(const NamedDecl *D, + EntityInfo &EntityInfo, + ScratchAlloc &SA); + + void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo); + + CXCursor getCursor(const Decl *D) { + return cxcursor::MakeCXCursor(D, CXTU); + } + + CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc); + + static bool shouldIgnoreIfImplicit(const Decl *D); +}; + +inline ScratchAlloc::ScratchAlloc(CXIndexDataConsumer &idxCtx) : IdxCtx(idxCtx) { + ++IdxCtx.StrAdapterCount; +} +inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) { + ++IdxCtx.StrAdapterCount; +} + +inline ScratchAlloc::~ScratchAlloc() { + --IdxCtx.StrAdapterCount; + if (IdxCtx.StrAdapterCount == 0) + IdxCtx.StrScratch.Reset(); +} + +template <typename T> +inline T *ScratchAlloc::allocate() { + return IdxCtx.StrScratch.Allocate<T>(); +} + +}} // end clang::cxindex + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.cpp b/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.cpp new file mode 100644 index 0000000000..bb6942a45f --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.cpp @@ -0,0 +1,394 @@ +//===-- CXLoadedDiagnostic.cpp - Handling of persisent diags ----*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implements handling of persisent diagnostics. +// +//===----------------------------------------------------------------------===// + +#include "CXLoadedDiagnostic.h" +#include "CXString.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Frontend/SerializedDiagnosticReader.h" +#include "clang/Frontend/SerializedDiagnostics.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Bitstream/BitstreamReader.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Extend CXDiagnosticSetImpl which contains strings for diagnostics. +//===----------------------------------------------------------------------===// + +typedef llvm::DenseMap<unsigned, const char *> Strings; + +namespace { +class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl { +public: + CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {} + ~CXLoadedDiagnosticSetImpl() override {} + + llvm::BumpPtrAllocator Alloc; + Strings Categories; + Strings WarningFlags; + Strings FileNames; + + FileSystemOptions FO; + FileManager FakeFiles; + llvm::DenseMap<unsigned, const FileEntry *> Files; + + /// Copy the string into our own allocator. + const char *copyString(StringRef Blob) { + char *mem = Alloc.Allocate<char>(Blob.size() + 1); + memcpy(mem, Blob.data(), Blob.size()); + mem[Blob.size()] = '\0'; + return mem; + } +}; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Cleanup. +//===----------------------------------------------------------------------===// + +CXLoadedDiagnostic::~CXLoadedDiagnostic() {} + +//===----------------------------------------------------------------------===// +// Public CXLoadedDiagnostic methods. +//===----------------------------------------------------------------------===// + +CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const { + // FIXME: Fail more softly if the diagnostic level is unknown? + auto severityAsLevel = static_cast<serialized_diags::Level>(severity); + assert(severity == static_cast<unsigned>(severityAsLevel) && + "unknown serialized diagnostic level"); + + switch (severityAsLevel) { +#define CASE(X) case serialized_diags::X: return CXDiagnostic_##X; + CASE(Ignored) + CASE(Note) + CASE(Warning) + CASE(Error) + CASE(Fatal) +#undef CASE + // The 'Remark' level isn't represented in the stable API. + case serialized_diags::Remark: return CXDiagnostic_Warning; + } + + llvm_unreachable("Invalid diagnostic level"); +} + +static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) { + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + uintptr_t V = (uintptr_t) DLoc; + V |= 0x1; + CXSourceLocation Loc = { { (void*) V, nullptr }, 0 }; + return Loc; +} + +CXSourceLocation CXLoadedDiagnostic::getLocation() const { + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + return makeLocation(&DiagLoc); +} + +CXString CXLoadedDiagnostic::getSpelling() const { + return cxstring::createRef(Spelling); +} + +CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const { + if (DiagOption.empty()) + return cxstring::createEmpty(); + + // FIXME: possibly refactor with logic in CXStoredDiagnostic. + if (Disable) + *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str()); + return cxstring::createDup((Twine("-W") + DiagOption).str()); +} + +unsigned CXLoadedDiagnostic::getCategory() const { + return category; +} + +CXString CXLoadedDiagnostic::getCategoryText() const { + return cxstring::createDup(CategoryText); +} + +unsigned CXLoadedDiagnostic::getNumRanges() const { + return Ranges.size(); +} + +CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const { + assert(Range < Ranges.size()); + return Ranges[Range]; +} + +unsigned CXLoadedDiagnostic::getNumFixIts() const { + return FixIts.size(); +} + +CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const { + assert(FixIt < FixIts.size()); + if (ReplacementRange) + *ReplacementRange = FixIts[FixIt].first; + return cxstring::createRef(FixIts[FixIt].second); +} + +void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location, + CXFile *file, + unsigned int *line, + unsigned int *column, + unsigned int *offset) { + + + // CXSourceLocation consists of the following fields: + // + // void *ptr_data[2]; + // unsigned int_data; + // + // The lowest bit of ptr_data[0] is always set to 1 to indicate this + // is a persistent diagnostic. + // + // For now, do the unoptimized approach and store the data in a side + // data structure. We can optimize this case later. + + uintptr_t V = (uintptr_t) location.ptr_data[0]; + assert((V & 0x1) == 1); + V &= ~(uintptr_t)1; + + const Location &Loc = *((Location*)V); + + if (file) + *file = Loc.file; + if (line) + *line = Loc.line; + if (column) + *column = Loc.column; + if (offset) + *offset = Loc.offset; +} + +//===----------------------------------------------------------------------===// +// Deserialize diagnostics. +//===----------------------------------------------------------------------===// + +namespace { +class DiagLoader : serialized_diags::SerializedDiagnosticReader { + enum CXLoadDiag_Error *error; + CXString *errorString; + std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags; + SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags; + + std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) { + if (error) + *error = code; + if (errorString) + *errorString = cxstring::createDup(err); + return serialized_diags::SDError::HandlerFailed; + } + + std::error_code reportInvalidFile(llvm::StringRef err) { + return reportBad(CXLoadDiag_InvalidFile, err); + } + + std::error_code readRange(const serialized_diags::Location &SDStart, + const serialized_diags::Location &SDEnd, + CXSourceRange &SR); + + std::error_code readLocation(const serialized_diags::Location &SDLoc, + CXLoadedDiagnostic::Location &LoadedLoc); + +protected: + std::error_code visitStartOfDiagnostic() override; + std::error_code visitEndOfDiagnostic() override; + + std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override; + + std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override; + + std::error_code visitDiagnosticRecord( + unsigned Severity, const serialized_diags::Location &Location, + unsigned Category, unsigned Flag, StringRef Message) override; + + std::error_code visitFilenameRecord(unsigned ID, unsigned Size, + unsigned Timestamp, + StringRef Name) override; + + std::error_code visitFixitRecord(const serialized_diags::Location &Start, + const serialized_diags::Location &End, + StringRef CodeToInsert) override; + + std::error_code + visitSourceRangeRecord(const serialized_diags::Location &Start, + const serialized_diags::Location &End) override; + +public: + DiagLoader(enum CXLoadDiag_Error *e, CXString *es) + : error(e), errorString(es) { + if (error) + *error = CXLoadDiag_None; + if (errorString) + *errorString = cxstring::createEmpty(); + } + + CXDiagnosticSet load(const char *file); +}; +} // end anonymous namespace + +CXDiagnosticSet DiagLoader::load(const char *file) { + TopDiags = std::make_unique<CXLoadedDiagnosticSetImpl>(); + + std::error_code EC = readDiagnostics(file); + if (EC) { + switch (EC.value()) { + case static_cast<int>(serialized_diags::SDError::HandlerFailed): + // We've already reported the problem. + break; + case static_cast<int>(serialized_diags::SDError::CouldNotLoad): + reportBad(CXLoadDiag_CannotLoad, EC.message()); + break; + default: + reportInvalidFile(EC.message()); + break; + } + return nullptr; + } + + return (CXDiagnosticSet)TopDiags.release(); +} + +std::error_code +DiagLoader::readLocation(const serialized_diags::Location &SDLoc, + CXLoadedDiagnostic::Location &LoadedLoc) { + unsigned FileID = SDLoc.FileID; + if (FileID == 0) + LoadedLoc.file = nullptr; + else { + LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]); + if (!LoadedLoc.file) + return reportInvalidFile("Corrupted file entry in source location"); + } + LoadedLoc.line = SDLoc.Line; + LoadedLoc.column = SDLoc.Col; + LoadedLoc.offset = SDLoc.Offset; + return std::error_code(); +} + +std::error_code +DiagLoader::readRange(const serialized_diags::Location &SDStart, + const serialized_diags::Location &SDEnd, + CXSourceRange &SR) { + CXLoadedDiagnostic::Location *Start, *End; + Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>(); + End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>(); + + std::error_code EC; + if ((EC = readLocation(SDStart, *Start))) + return EC; + if ((EC = readLocation(SDEnd, *End))) + return EC; + + CXSourceLocation startLoc = makeLocation(Start); + CXSourceLocation endLoc = makeLocation(End); + SR = clang_getRange(startLoc, endLoc); + return std::error_code(); +} + +std::error_code DiagLoader::visitStartOfDiagnostic() { + CurrentDiags.push_back(std::make_unique<CXLoadedDiagnostic>()); + return std::error_code(); +} + +std::error_code DiagLoader::visitEndOfDiagnostic() { + auto D = CurrentDiags.pop_back_val(); + if (CurrentDiags.empty()) + TopDiags->appendDiagnostic(std::move(D)); + else + CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D)); + return std::error_code(); +} + +std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) { + // FIXME: Why do we care about long strings? + if (Name.size() > 65536) + return reportInvalidFile("Out-of-bounds string in category"); + TopDiags->Categories[ID] = TopDiags->copyString(Name); + return std::error_code(); +} + +std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) { + // FIXME: Why do we care about long strings? + if (Name.size() > 65536) + return reportInvalidFile("Out-of-bounds string in warning flag"); + TopDiags->WarningFlags[ID] = TopDiags->copyString(Name); + return std::error_code(); +} + +std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size, + unsigned Timestamp, + StringRef Name) { + // FIXME: Why do we care about long strings? + if (Name.size() > 65536) + return reportInvalidFile("Out-of-bounds string in filename"); + TopDiags->FileNames[ID] = TopDiags->copyString(Name); + TopDiags->Files[ID] = + TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp); + return std::error_code(); +} + +std::error_code +DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start, + const serialized_diags::Location &End) { + CXSourceRange SR; + if (std::error_code EC = readRange(Start, End, SR)) + return EC; + CurrentDiags.back()->Ranges.push_back(SR); + return std::error_code(); +} + +std::error_code +DiagLoader::visitFixitRecord(const serialized_diags::Location &Start, + const serialized_diags::Location &End, + StringRef CodeToInsert) { + CXSourceRange SR; + if (std::error_code EC = readRange(Start, End, SR)) + return EC; + // FIXME: Why do we care about long strings? + if (CodeToInsert.size() > 65536) + return reportInvalidFile("Out-of-bounds string in FIXIT"); + CurrentDiags.back()->FixIts.push_back( + std::make_pair(SR, TopDiags->copyString(CodeToInsert))); + return std::error_code(); +} + +std::error_code DiagLoader::visitDiagnosticRecord( + unsigned Severity, const serialized_diags::Location &Location, + unsigned Category, unsigned Flag, StringRef Message) { + CXLoadedDiagnostic &D = *CurrentDiags.back(); + D.severity = Severity; + if (std::error_code EC = readLocation(Location, D.DiagLoc)) + return EC; + D.category = Category; + D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : ""; + D.CategoryText = Category ? TopDiags->Categories[Category] : ""; + D.Spelling = TopDiags->copyString(Message); + return std::error_code(); +} + +CXDiagnosticSet clang_loadDiagnostics(const char *file, + enum CXLoadDiag_Error *error, + CXString *errorString) { + DiagLoader L(error, errorString); + return L.load(file); +} diff --git a/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.h b/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.h new file mode 100644 index 0000000000..93995d7bb7 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXLoadedDiagnostic.h @@ -0,0 +1,93 @@ +/*===-- CXLoadedDiagnostic.h - Handling of persisent diags ------*- C++ -*-===*\ +|* *| +|* 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 *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Implements handling of persisent diagnostics. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXLOADEDDIAGNOSTIC_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXLOADEDDIAGNOSTIC_H + +#include "CIndexDiagnostic.h" +#include "llvm/ADT/StringRef.h" +#include "clang/Basic/LLVM.h" +#include <vector> + +namespace clang { +class CXLoadedDiagnostic : public CXDiagnosticImpl { +public: + CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind), + severity(0), category(0) {} + + ~CXLoadedDiagnostic() override; + + /// Return the severity of the diagnostic. + CXDiagnosticSeverity getSeverity() const override; + + /// Return the location of the diagnostic. + CXSourceLocation getLocation() const override; + + /// Return the spelling of the diagnostic. + CXString getSpelling() const override; + + /// Return the text for the diagnostic option. + CXString getDiagnosticOption(CXString *Disable) const override; + + /// Return the category of the diagnostic. + unsigned getCategory() const override; + + /// Return the category string of the diagnostic. + CXString getCategoryText() const override; + + /// Return the number of source ranges for the diagnostic. + unsigned getNumRanges() const override; + + /// Return the source ranges for the diagnostic. + CXSourceRange getRange(unsigned Range) const override; + + /// Return the number of FixIts. + unsigned getNumFixIts() const override; + + /// Return the FixIt information (source range and inserted text). + CXString getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const override; + + static bool classof(const CXDiagnosticImpl *D) { + return D->getKind() == LoadedDiagnosticKind; + } + + /// Decode the CXSourceLocation into file, line, column, and offset. + static void decodeLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + + struct Location { + CXFile file; + unsigned line; + unsigned column; + unsigned offset; + + Location() : line(0), column(0), offset(0) {} + }; + + Location DiagLoc; + + std::vector<CXSourceRange> Ranges; + std::vector<std::pair<CXSourceRange, const char *> > FixIts; + const char *Spelling; + llvm::StringRef DiagOption; + llvm::StringRef CategoryText; + unsigned severity; + unsigned category; +}; +} + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXSourceLocation.cpp b/contrib/libs/clang14/tools/libclang/CXSourceLocation.cpp new file mode 100644 index 0000000000..39c2194f7d --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXSourceLocation.cpp @@ -0,0 +1,374 @@ +//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===// +// +// 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 defines routines for manipulating CXSourceLocations. +// +//===----------------------------------------------------------------------===// + +#include "CXSourceLocation.h" +#include "CIndexer.h" +#include "CLog.h" +#include "CXLoadedDiagnostic.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang/Basic/FileManager.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" + +using namespace clang; +using namespace clang::cxindex; + +//===----------------------------------------------------------------------===// +// Internal predicates on CXSourceLocations. +//===----------------------------------------------------------------------===// + +static bool isASTUnitSourceLocation(const CXSourceLocation &L) { + // If the lowest bit is clear then the first ptr_data entry is a SourceManager + // pointer, or the CXSourceLocation is a null location. + return ((uintptr_t)L.ptr_data[0] & 0x1) == 0; +} + +//===----------------------------------------------------------------------===// +// Basic construction and comparison of CXSourceLocations and CXSourceRanges. +//===----------------------------------------------------------------------===// + +CXSourceLocation clang_getNullLocation() { + CXSourceLocation Result = { { nullptr, nullptr }, 0 }; + return Result; +} + +unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { + return (loc1.ptr_data[0] == loc2.ptr_data[0] && + loc1.ptr_data[1] == loc2.ptr_data[1] && + loc1.int_data == loc2.int_data); +} + +CXSourceRange clang_getNullRange() { + CXSourceRange Result = { { nullptr, nullptr }, 0, 0 }; + return Result; +} + +CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) { + if (!isASTUnitSourceLocation(begin)) { + if (isASTUnitSourceLocation(end)) + return clang_getNullRange(); + CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 }; + return Result; + } + + if (begin.ptr_data[0] != end.ptr_data[0] || + begin.ptr_data[1] != end.ptr_data[1]) + return clang_getNullRange(); + + CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] }, + begin.int_data, end.int_data }; + + return Result; +} + +unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) { + return range1.ptr_data[0] == range2.ptr_data[0] + && range1.ptr_data[1] == range2.ptr_data[1] + && range1.begin_int_data == range2.begin_int_data + && range1.end_int_data == range2.end_int_data; +} + +int clang_Range_isNull(CXSourceRange range) { + return clang_equalRanges(range, clang_getNullRange()); +} + + +CXSourceLocation clang_getRangeStart(CXSourceRange range) { + // Special decoding for CXSourceLocations for CXLoadedDiagnostics. + if ((uintptr_t)range.ptr_data[0] & 0x1) { + CXSourceLocation Result = { { range.ptr_data[0], nullptr }, 0 }; + return Result; + } + + CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, + range.begin_int_data }; + return Result; +} + +CXSourceLocation clang_getRangeEnd(CXSourceRange range) { + // Special decoding for CXSourceLocations for CXLoadedDiagnostics. + if ((uintptr_t)range.ptr_data[0] & 0x1) { + CXSourceLocation Result = { { range.ptr_data[1], nullptr }, 0 }; + return Result; + } + + CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] }, + range.end_int_data }; + return Result; +} + +//===----------------------------------------------------------------------===// +// Getting CXSourceLocations and CXSourceRanges from a translation unit. +//===----------------------------------------------------------------------===// + +CXSourceLocation clang_getLocation(CXTranslationUnit TU, + CXFile file, + unsigned line, + unsigned column) { + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullLocation(); + } + if (!file) + return clang_getNullLocation(); + if (line == 0 || column == 0) + return clang_getNullLocation(); + + LogRef Log = Logger::make(__func__); + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + const FileEntry *File = static_cast<const FileEntry *>(file); + SourceLocation SLoc = CXXUnit->getLocation(File, line, column); + if (SLoc.isInvalid()) { + if (Log) + *Log << llvm::format("(\"%s\", %d, %d) = invalid", + File->getName().str().c_str(), line, column); + return clang_getNullLocation(); + } + + CXSourceLocation CXLoc = + cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); + if (Log) + *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(), + line, column) + << CXLoc; + + return CXLoc; +} + +CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU, + CXFile file, + unsigned offset) { + if (cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return clang_getNullLocation(); + } + if (!file) + return clang_getNullLocation(); + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + + SourceLocation SLoc + = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset); + + if (SLoc.isInvalid()) + return clang_getNullLocation(); + + return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); +} + +//===----------------------------------------------------------------------===// +// Routines for expanding and manipulating CXSourceLocations, regardless +// of their origin. +//===----------------------------------------------------------------------===// + +static void createNullLocation(CXFile *file, unsigned *line, + unsigned *column, unsigned *offset) { + if (file) + *file = nullptr; + if (line) + *line = 0; + if (column) + *column = 0; + if (offset) + *offset = 0; +} + +static void createNullLocation(CXString *filename, unsigned *line, + unsigned *column, unsigned *offset = nullptr) { + if (filename) + *filename = cxstring::createEmpty(); + if (line) + *line = 0; + if (column) + *column = 0; + if (offset) + *offset = 0; +} + +int clang_Location_isInSystemHeader(CXSourceLocation location) { + const SourceLocation Loc = + SourceLocation::getFromRawEncoding(location.int_data); + if (Loc.isInvalid()) + return 0; + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + return SM.isInSystemHeader(Loc); +} + +int clang_Location_isFromMainFile(CXSourceLocation location) { + const SourceLocation Loc = + SourceLocation::getFromRawEncoding(location.int_data); + if (Loc.isInvalid()) + return 0; + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + return SM.isWrittenInMainFile(Loc); +} + +void clang_getExpansionLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (!isASTUnitSourceLocation(location)) { + CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) { + createNullLocation(file, line, column, offset); + return; + } + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc); + + // Check that the FileID is invalid on the expansion location. + // This can manifest in invalid code. + FileID fileID = SM.getFileID(ExpansionLoc); + bool Invalid = false; + const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid); + if (Invalid || !sloc.isFile()) { + createNullLocation(file, line, column, offset); + return; + } + + if (file) + *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc)); + if (line) + *line = SM.getExpansionLineNumber(ExpansionLoc); + if (column) + *column = SM.getExpansionColumnNumber(ExpansionLoc); + if (offset) + *offset = SM.getDecomposedLoc(ExpansionLoc).second; +} + +void clang_getPresumedLocation(CXSourceLocation location, + CXString *filename, + unsigned *line, + unsigned *column) { + if (!isASTUnitSourceLocation(location)) { + // Other SourceLocation implementations do not support presumed locations + // at this time. + createNullLocation(filename, line, column); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) { + createNullLocation(filename, line, column); + return; + } + + const SourceManager &SM = + *static_cast<const SourceManager *>(location.ptr_data[0]); + PresumedLoc PreLoc = SM.getPresumedLoc(Loc); + if (PreLoc.isInvalid()) { + createNullLocation(filename, line, column); + return; + } + + if (filename) *filename = cxstring::createRef(PreLoc.getFilename()); + if (line) *line = PreLoc.getLine(); + if (column) *column = PreLoc.getColumn(); +} + +void clang_getInstantiationLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + // Redirect to new API. + clang_getExpansionLocation(location, file, line, column, offset); +} + +void clang_getSpellingLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (!isASTUnitSourceLocation(location)) { + CXLoadedDiagnostic::decodeLocation(location, file, line, + column, offset); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) + return createNullLocation(file, line, column, offset); + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + // FIXME: This should call SourceManager::getSpellingLoc(). + SourceLocation SpellLoc = SM.getFileLoc(Loc); + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return createNullLocation(file, line, column, offset); + + if (file) + *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} + +void clang_getFileLocation(CXSourceLocation location, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (!isASTUnitSourceLocation(location)) { + CXLoadedDiagnostic::decodeLocation(location, file, line, + column, offset); + return; + } + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + + if (!location.ptr_data[0] || Loc.isInvalid()) + return createNullLocation(file, line, column, offset); + + const SourceManager &SM = + *static_cast<const SourceManager*>(location.ptr_data[0]); + SourceLocation FileLoc = SM.getFileLoc(Loc); + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return createNullLocation(file, line, column, offset); + + if (file) + *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID)); + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} diff --git a/contrib/libs/clang14/tools/libclang/CXSourceLocation.h b/contrib/libs/clang14/tools/libclang/CXSourceLocation.h new file mode 100644 index 0000000000..c86f685037 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXSourceLocation.h @@ -0,0 +1,81 @@ +//===- CXSourceLocation.h - CXSourceLocations Utilities ---------*- C++ -*-===// +// +// 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 defines routines for manipulating CXSourceLocations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXSOURCELOCATION_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXSOURCELOCATION_H + +#include "clang-c/Index.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class SourceManager; + +namespace cxloc { + +/// Translate a Clang source location into a CIndex source location. +static inline CXSourceLocation +translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts, + SourceLocation Loc) { + if (Loc.isInvalid()) + return clang_getNullLocation(); + + CXSourceLocation Result = { { &SM, &LangOpts, }, + Loc.getRawEncoding() }; + return Result; +} + +/// Translate a Clang source location into a CIndex source location. +static inline CXSourceLocation translateSourceLocation(ASTContext &Context, + SourceLocation Loc) { + return translateSourceLocation(Context.getSourceManager(), + Context.getLangOpts(), + Loc); +} + +/// Translate a Clang source range into a CIndex source range. +/// +/// Clang internally represents ranges where the end location points to the +/// start of the token at the end. However, for external clients it is more +/// useful to have a CXSourceRange be a proper half-open interval. This routine +/// does the appropriate translation. +CXSourceRange translateSourceRange(const SourceManager &SM, + const LangOptions &LangOpts, + const CharSourceRange &R); + +/// Translate a Clang source range into a CIndex source range. +static inline CXSourceRange translateSourceRange(ASTContext &Context, + SourceRange R) { + return translateSourceRange(Context.getSourceManager(), + Context.getLangOpts(), + CharSourceRange::getTokenRange(R)); +} + +static inline SourceLocation translateSourceLocation(CXSourceLocation L) { + return SourceLocation::getFromRawEncoding(L.int_data); +} + +static inline SourceRange translateCXSourceRange(CXSourceRange R) { + return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data), + SourceLocation::getFromRawEncoding(R.end_int_data)); +} + +/// Translates CXSourceRange to CharSourceRange. +/// The semantics of \p R are: +/// R.begin_int_data is first character of the range. +/// R.end_int_data is one character past the end of the range. +CharSourceRange translateCXRangeToCharRange(CXSourceRange R); +}} // end namespace: clang::cxloc + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXStoredDiagnostic.cpp b/contrib/libs/clang14/tools/libclang/CXStoredDiagnostic.cpp new file mode 100644 index 0000000000..c4c24876e7 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXStoredDiagnostic.cpp @@ -0,0 +1,111 @@ +//===- CXStoredDiagnostic.cpp - Diagnostics C Interface -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implements part of the diagnostic functions of the Clang C interface. +// +//===----------------------------------------------------------------------===// + +#include "CIndexDiagnostic.h" +#include "CIndexer.h" +#include "CXTranslationUnit.h" +#include "CXSourceLocation.h" +#include "CXString.h" + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/ADT/Twine.h" + +using namespace clang; +using namespace clang::cxloc; + +CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const { + switch (Diag.getLevel()) { + case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored; + case DiagnosticsEngine::Note: return CXDiagnostic_Note; + case DiagnosticsEngine::Remark: + // The 'Remark' level isn't represented in the stable API. + case DiagnosticsEngine::Warning: return CXDiagnostic_Warning; + case DiagnosticsEngine::Error: return CXDiagnostic_Error; + case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal; + } + + llvm_unreachable("Invalid diagnostic level"); +} + +CXSourceLocation CXStoredDiagnostic::getLocation() const { + if (Diag.getLocation().isInvalid()) + return clang_getNullLocation(); + + return translateSourceLocation(Diag.getLocation().getManager(), + LangOpts, Diag.getLocation()); +} + +CXString CXStoredDiagnostic::getSpelling() const { + return cxstring::createRef(Diag.getMessage()); +} + +CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const { + unsigned ID = Diag.getID(); + StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID); + if (!Option.empty()) { + if (Disable) + *Disable = cxstring::createDup((Twine("-Wno-") + Option).str()); + return cxstring::createDup((Twine("-W") + Option).str()); + } + + if (ID == diag::fatal_too_many_errors) { + if (Disable) + *Disable = cxstring::createRef("-ferror-limit=0"); + return cxstring::createRef("-ferror-limit="); + } + + return cxstring::createEmpty(); +} + +unsigned CXStoredDiagnostic::getCategory() const { + return DiagnosticIDs::getCategoryNumberForDiag(Diag.getID()); +} + +CXString CXStoredDiagnostic::getCategoryText() const { + unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID()); + return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(catID)); +} + +unsigned CXStoredDiagnostic::getNumRanges() const { + if (Diag.getLocation().isInvalid()) + return 0; + + return Diag.range_size(); +} + +CXSourceRange CXStoredDiagnostic::getRange(unsigned int Range) const { + assert(Diag.getLocation().isValid()); + return translateSourceRange(Diag.getLocation().getManager(), + LangOpts, + Diag.range_begin()[Range]); +} + +unsigned CXStoredDiagnostic::getNumFixIts() const { + if (Diag.getLocation().isInvalid()) + return 0; + return Diag.fixit_size(); +} + +CXString CXStoredDiagnostic::getFixIt(unsigned FixIt, + CXSourceRange *ReplacementRange) const { + const FixItHint &Hint = Diag.fixit_begin()[FixIt]; + if (ReplacementRange) { + // Create a range that covers the entire replacement (or + // removal) range, adjusting the end of the range to point to + // the end of the token. + *ReplacementRange = translateSourceRange(Diag.getLocation().getManager(), + LangOpts, Hint.RemoveRange); + } + return cxstring::createDup(Hint.CodeToInsert); +} + diff --git a/contrib/libs/clang14/tools/libclang/CXString.cpp b/contrib/libs/clang14/tools/libclang/CXString.cpp new file mode 100644 index 0000000000..2754795f4a --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXString.cpp @@ -0,0 +1,191 @@ +//===- CXString.cpp - Routines for manipulating CXStrings -----------------===// +// +// 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 defines routines for manipulating CXStrings. It should be the +// only file that has internal knowledge of the encoding of the data in +// CXStrings. +// +//===----------------------------------------------------------------------===// + +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang-c/Index.h" +#include "clang/Frontend/ASTUnit.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +/// Describes the kind of underlying data in CXString. +enum CXStringFlag { + /// CXString contains a 'const char *' that it doesn't own. + CXS_Unmanaged, + + /// CXString contains a 'const char *' that it allocated with malloc(). + CXS_Malloc, + + /// CXString contains a CXStringBuf that needs to be returned to the + /// CXStringPool. + CXS_StringBuf +}; + +namespace clang { +namespace cxstring { + +//===----------------------------------------------------------------------===// +// Basic generation of CXStrings. +//===----------------------------------------------------------------------===// + +CXString createEmpty() { + CXString Str; + Str.data = ""; + Str.private_flags = CXS_Unmanaged; + return Str; +} + +CXString createNull() { + CXString Str; + Str.data = nullptr; + Str.private_flags = CXS_Unmanaged; + return Str; +} + +CXString createRef(const char *String) { + if (String && String[0] == '\0') + return createEmpty(); + + CXString Str; + Str.data = String; + Str.private_flags = CXS_Unmanaged; + return Str; +} + +CXString createDup(const char *String) { + if (!String) + return createNull(); + + if (String[0] == '\0') + return createEmpty(); + + CXString Str; + Str.data = strdup(String); + Str.private_flags = CXS_Malloc; + return Str; +} + +CXString createRef(StringRef String) { + // If the string is not nul-terminated, we have to make a copy. + + // FIXME: This is doing a one past end read, and should be removed! For memory + // we don't manage, the API string can become unterminated at any time outside + // our control. + + if (!String.empty() && String.data()[String.size()] != 0) + return createDup(String); + + CXString Result; + Result.data = String.data(); + Result.private_flags = (unsigned) CXS_Unmanaged; + return Result; +} + +CXString createDup(StringRef String) { + CXString Result; + char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1)); + memmove(Spelling, String.data(), String.size()); + Spelling[String.size()] = 0; + Result.data = Spelling; + Result.private_flags = (unsigned) CXS_Malloc; + return Result; +} + +CXString createCXString(CXStringBuf *buf) { + CXString Str; + Str.data = buf; + Str.private_flags = (unsigned) CXS_StringBuf; + return Str; +} + +CXStringSet *createSet(const std::vector<std::string> &Strings) { + CXStringSet *Set = new CXStringSet; + Set->Count = Strings.size(); + Set->Strings = new CXString[Set->Count]; + for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI) + Set->Strings[SI] = createDup(Strings[SI]); + return Set; +} + + +//===----------------------------------------------------------------------===// +// String pools. +//===----------------------------------------------------------------------===// + +CXStringPool::~CXStringPool() { + for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end(); + I != E; ++I) { + delete *I; + } +} + +CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) { + if (Pool.empty()) + return new CXStringBuf(TU); + + CXStringBuf *Buf = Pool.back(); + Buf->Data.clear(); + Pool.pop_back(); + return Buf; +} + +CXStringBuf *getCXStringBuf(CXTranslationUnit TU) { + return TU->StringPool->getCXStringBuf(TU); +} + +void CXStringBuf::dispose() { + TU->StringPool->Pool.push_back(this); +} + +bool isManagedByPool(CXString str) { + return ((CXStringFlag) str.private_flags) == CXS_StringBuf; +} + +} // end namespace cxstring +} // end namespace clang + +//===----------------------------------------------------------------------===// +// libClang public APIs. +//===----------------------------------------------------------------------===// + +const char *clang_getCString(CXString string) { + if (string.private_flags == (unsigned) CXS_StringBuf) { + return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data(); + } + return static_cast<const char *>(string.data); +} + +void clang_disposeString(CXString string) { + switch ((CXStringFlag) string.private_flags) { + case CXS_Unmanaged: + break; + case CXS_Malloc: + if (string.data) + free(const_cast<void *>(string.data)); + break; + case CXS_StringBuf: + static_cast<cxstring::CXStringBuf *>( + const_cast<void *>(string.data))->dispose(); + break; + } +} + +void clang_disposeStringSet(CXStringSet *set) { + for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI) + clang_disposeString(set->Strings[SI]); + delete[] set->Strings; + delete set; +} + diff --git a/contrib/libs/clang14/tools/libclang/CXString.h b/contrib/libs/clang14/tools/libclang/CXString.h new file mode 100644 index 0000000000..809bdec3d6 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXString.h @@ -0,0 +1,108 @@ +//===- CXString.h - Routines for manipulating CXStrings -------------------===// +// +// 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 defines routines for manipulating CXStrings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXSTRING_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXSTRING_H + +#include "clang-c/Index.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include <string> +#include <vector> + +namespace clang { +namespace cxstring { + +struct CXStringBuf; + +/// Create a CXString object for an empty "" string. +CXString createEmpty(); + +/// Create a CXString object for an NULL string. +/// +/// A NULL string should be used as an "invalid" value in case of errors. +CXString createNull(); + +/// Create a CXString object from a nul-terminated C string. New +/// CXString may contain a pointer to \p String. +/// +/// \p String should not be changed by the caller afterwards. +CXString createRef(const char *String); + +/// Create a CXString object from a nul-terminated C string. New +/// CXString will contain a copy of \p String. +/// +/// \p String can be changed or freed by the caller. +CXString createDup(const char *String); + +/// Create a CXString object from a StringRef. New CXString may +/// contain a pointer to the undrelying data of \p String. +/// +/// \p String should not be changed by the caller afterwards. +CXString createRef(StringRef String); + +/// Create a CXString object from a StringRef. New CXString will +/// contain a copy of \p String. +/// +/// \p String can be changed or freed by the caller. +CXString createDup(StringRef String); + +// Usually std::string is intended to be used as backing storage for CXString. +// In this case, call \c createRef(String.c_str()). +// +// If you need to make a copy, call \c createDup(StringRef(String)). +CXString createRef(std::string String) = delete; + +/// Create a CXString object that is backed by a string buffer. +CXString createCXString(CXStringBuf *buf); + +CXStringSet *createSet(const std::vector<std::string> &Strings); + +/// A string pool used for fast allocation/deallocation of strings. +class CXStringPool { +public: + ~CXStringPool(); + + CXStringBuf *getCXStringBuf(CXTranslationUnit TU); + +private: + std::vector<CXStringBuf *> Pool; + + friend struct CXStringBuf; +}; + +struct CXStringBuf { + SmallString<128> Data; + CXTranslationUnit TU; + + CXStringBuf(CXTranslationUnit TU) : TU(TU) {} + + /// Return this buffer to the pool. + void dispose(); +}; + +CXStringBuf *getCXStringBuf(CXTranslationUnit TU); + +/// Returns true if the CXString data is managed by a pool. +bool isManagedByPool(CXString str); + +} + +static inline StringRef getContents(const CXUnsavedFile &UF) { + return StringRef(UF.Contents, UF.Length); +} +} + +#endif + diff --git a/contrib/libs/clang14/tools/libclang/CXTranslationUnit.h b/contrib/libs/clang14/tools/libclang/CXTranslationUnit.h new file mode 100644 index 0000000000..3424bf2997 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXTranslationUnit.h @@ -0,0 +1,89 @@ +//===- CXTranslationUnit.h - Routines for manipulating CXTranslationUnits -===// +// +// 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 defines routines for manipulating CXTranslationUnits. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXTRANSLATIONUNIT_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXTRANSLATIONUNIT_H + +#include "CLog.h" +#include "CXString.h" +#include "clang-c/Index.h" + +namespace clang { + class ASTUnit; + class CIndexer; +namespace index { +class CommentToXMLConverter; +} // namespace index +} // namespace clang + +struct CXTranslationUnitImpl { + clang::CIndexer *CIdx; + clang::ASTUnit *TheASTUnit; + clang::cxstring::CXStringPool *StringPool; + void *Diagnostics; + void *OverridenCursorsPool; + clang::index::CommentToXMLConverter *CommentToXML; + unsigned ParsingOptions; + std::vector<std::string> Arguments; +}; + +struct CXTargetInfoImpl { + CXTranslationUnit TranslationUnit; +}; + +namespace clang { +namespace cxtu { + +CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, + std::unique_ptr<ASTUnit> AU); + +static inline ASTUnit *getASTUnit(CXTranslationUnit TU) { + if (!TU) + return nullptr; + return TU->TheASTUnit; +} + +/// \returns true if the ASTUnit has a diagnostic about the AST file being +/// corrupted. +bool isASTReadError(ASTUnit *AU); + +static inline bool isNotUsableTU(CXTranslationUnit TU) { + return !TU; +} + +#define LOG_BAD_TU(TU) \ + do { \ + LOG_FUNC_SECTION { \ + *Log << "called with a bad TU: " << TU; \ + } \ + } while(false) + +class CXTUOwner { + CXTranslationUnitImpl *TU; + +public: + CXTUOwner(CXTranslationUnitImpl *tu) : TU(tu) { } + ~CXTUOwner(); + + CXTranslationUnitImpl *getTU() const { return TU; } + + CXTranslationUnitImpl *takeTU() { + CXTranslationUnitImpl *retTU = TU; + TU = nullptr; + return retTU; + } +}; + + +}} // end namespace clang::cxtu + +#endif diff --git a/contrib/libs/clang14/tools/libclang/CXType.cpp b/contrib/libs/clang14/tools/libclang/CXType.cpp new file mode 100644 index 0000000000..822ab3bb64 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXType.cpp @@ -0,0 +1,1338 @@ +//===- CXType.cpp - Implements 'CXTypes' aspect of libclang ---------------===// +// +// 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 'CXTypes' API hooks in the Clang-C library. +// +//===--------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "CXType.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; + +static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { +#define BTCASE(K) case BuiltinType::K: return CXType_##K + switch (BT->getKind()) { + BTCASE(Void); + BTCASE(Bool); + BTCASE(Char_U); + BTCASE(UChar); + BTCASE(Char16); + BTCASE(Char32); + BTCASE(UShort); + BTCASE(UInt); + BTCASE(ULong); + BTCASE(ULongLong); + BTCASE(UInt128); + BTCASE(Char_S); + BTCASE(SChar); + case BuiltinType::WChar_S: return CXType_WChar; + case BuiltinType::WChar_U: return CXType_WChar; + BTCASE(Short); + BTCASE(Int); + BTCASE(Long); + BTCASE(LongLong); + BTCASE(Int128); + BTCASE(Half); + BTCASE(Float); + BTCASE(Double); + BTCASE(LongDouble); + BTCASE(ShortAccum); + BTCASE(Accum); + BTCASE(LongAccum); + BTCASE(UShortAccum); + BTCASE(UAccum); + BTCASE(ULongAccum); + BTCASE(Float16); + BTCASE(Float128); + BTCASE(Ibm128); + BTCASE(NullPtr); + BTCASE(Overload); + BTCASE(Dependent); + BTCASE(ObjCId); + BTCASE(ObjCClass); + BTCASE(ObjCSel); +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) BTCASE(Id); +#include "clang/Basic/OpenCLImageTypes.def" +#undef IMAGE_TYPE +#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) BTCASE(Id); +#include "clang/Basic/OpenCLExtensionTypes.def" + BTCASE(OCLSampler); + BTCASE(OCLEvent); + BTCASE(OCLQueue); + BTCASE(OCLReserveID); + default: + return CXType_Unexposed; + } +#undef BTCASE +} + +static CXTypeKind GetTypeKind(QualType T) { + const Type *TP = T.getTypePtrOrNull(); + if (!TP) + return CXType_Invalid; + +#define TKCASE(K) case Type::K: return CXType_##K + switch (TP->getTypeClass()) { + case Type::Builtin: + return GetBuiltinTypeKind(cast<BuiltinType>(TP)); + TKCASE(Complex); + TKCASE(Pointer); + TKCASE(BlockPointer); + TKCASE(LValueReference); + TKCASE(RValueReference); + TKCASE(Record); + TKCASE(Enum); + TKCASE(Typedef); + TKCASE(ObjCInterface); + TKCASE(ObjCObject); + TKCASE(ObjCObjectPointer); + TKCASE(ObjCTypeParam); + TKCASE(FunctionNoProto); + TKCASE(FunctionProto); + TKCASE(ConstantArray); + TKCASE(IncompleteArray); + TKCASE(VariableArray); + TKCASE(DependentSizedArray); + TKCASE(Vector); + TKCASE(ExtVector); + TKCASE(MemberPointer); + TKCASE(Auto); + TKCASE(Elaborated); + TKCASE(Pipe); + TKCASE(Attributed); + TKCASE(Atomic); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + + +CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { + CXTypeKind TK = CXType_Invalid; + + if (TU && !T.isNull()) { + // Handle attributed types as the original type + if (auto *ATT = T->getAs<AttributedType>()) { + if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes)) { + // Return the equivalent type which represents the canonically + // equivalent type. + return MakeCXType(ATT->getEquivalentType(), TU); + } + } + // Handle paren types as the original type + if (auto *PTT = T->getAs<ParenType>()) { + return MakeCXType(PTT->getInnerType(), TU); + } + + ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); + if (Ctx.getLangOpts().ObjC) { + QualType UnqualT = T.getUnqualifiedType(); + if (Ctx.isObjCIdType(UnqualT)) + TK = CXType_ObjCId; + else if (Ctx.isObjCClassType(UnqualT)) + TK = CXType_ObjCClass; + else if (Ctx.isObjCSelType(UnqualT)) + TK = CXType_ObjCSel; + } + + /* Handle decayed types as the original type */ + if (const DecayedType *DT = T->getAs<DecayedType>()) { + return MakeCXType(DT->getOriginalType(), TU); + } + } + if (TK == CXType_Invalid) + TK = GetTypeKind(T); + + CXType CT = { TK, { TK == CXType_Invalid ? nullptr + : T.getAsOpaquePtr(), TU } }; + return CT; +} + +using cxtype::MakeCXType; + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline CXTranslationUnit GetTU(CXType CT) { + return static_cast<CXTranslationUnit>(CT.data[1]); +} + +static Optional<ArrayRef<TemplateArgument>> +GetTemplateArguments(QualType Type) { + assert(!Type.isNull()); + if (const auto *Specialization = Type->getAs<TemplateSpecializationType>()) + return Specialization->template_arguments(); + + if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) { + const auto *TemplateDecl = + dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl); + if (TemplateDecl) + return TemplateDecl->getTemplateArgs().asArray(); + } + + return None; +} + +static Optional<QualType> TemplateArgumentToQualType(const TemplateArgument &A) { + if (A.getKind() == TemplateArgument::Type) + return A.getAsType(); + return None; +} + +static Optional<QualType> +FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) { + unsigned current = 0; + for (const auto &A : TA) { + if (A.getKind() == TemplateArgument::Pack) { + if (index < current + A.pack_size()) + return TemplateArgumentToQualType(A.getPackAsArray()[index - current]); + current += A.pack_size(); + continue; + } + if (current == index) + return TemplateArgumentToQualType(A); + current++; + } + return None; +} + +CXType clang_getCursorType(CXCursor C) { + using namespace cxcursor; + + CXTranslationUnit TU = cxcursor::getCursorTU(C); + if (!TU) + return MakeCXType(QualType(), TU); + + ASTContext &Context = cxtu::getASTUnit(TU)->getASTContext(); + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, TU); + } + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (!D) + return MakeCXType(QualType(), TU); + + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCXType(Context.getTypeDeclType(TD), TU); + if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCXType(Context.getObjCInterfaceType(ID), TU); + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) + return MakeCXType(DD->getType(), TU); + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) + return MakeCXType(VD->getType(), TU); + if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) + return MakeCXType(PD->getType(), TU); + if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) + return MakeCXType(FTD->getTemplatedDecl()->getType(), TU); + return MakeCXType(QualType(), TU); + } + + if (clang_isReference(C.kind)) { + switch (C.kind) { + case CXCursor_ObjCSuperClassRef: { + QualType T + = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_ObjCClassRef: { + QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first); + return MakeCXType(T, TU); + } + + case CXCursor_TypeRef: { + QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first); + return MakeCXType(T, TU); + + } + + case CXCursor_CXXBaseSpecifier: + return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU); + + case CXCursor_MemberRef: + return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU); + + case CXCursor_VariableRef: + return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU); + + case CXCursor_ObjCProtocolRef: + case CXCursor_TemplateRef: + case CXCursor_NamespaceRef: + case CXCursor_OverloadedDeclRef: + default: + break; + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +CXString clang_getTypeSpelling(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return cxstring::createEmpty(); + + CXTranslationUnit TU = GetTU(CT); + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts()); + + T.print(OS, PP); + + return cxstring::createDup(OS.str()); +} + +CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { + using namespace cxcursor; + CXTranslationUnit TU = cxcursor::getCursorTU(C); + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + + if (const TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) { + QualType T = TD->getUnderlyingType(); + return MakeCXType(T, TU); + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +CXType clang_getEnumDeclIntegerType(CXCursor C) { + using namespace cxcursor; + CXTranslationUnit TU = cxcursor::getCursorTU(C); + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + + if (const EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) { + QualType T = TD->getIntegerType(); + return MakeCXType(T, TU); + } + + return MakeCXType(QualType(), TU); + } + + return MakeCXType(QualType(), TU); +} + +long long clang_getEnumConstantDeclValue(CXCursor C) { + using namespace cxcursor; + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + + if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { + return TD->getInitVal().getSExtValue(); + } + + return LLONG_MIN; + } + + return LLONG_MIN; +} + +unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) { + using namespace cxcursor; + + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + + if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { + return TD->getInitVal().getZExtValue(); + } + + return ULLONG_MAX; + } + + return ULLONG_MAX; +} + +int clang_getFieldDeclBitWidth(CXCursor C) { + using namespace cxcursor; + + if (clang_isDeclaration(C.kind)) { + const Decl *D = getCursorDecl(C); + + if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) { + if (FD->isBitField()) + return FD->getBitWidthValue(getCursorContext(C)); + } + } + + return -1; +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + CXTranslationUnit TU = GetTU(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + return MakeCXType(cxtu::getASTUnit(TU)->getASTContext() + .getCanonicalType(T), + TU); +} + +unsigned clang_isConstQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalConstQualified(); +} + +unsigned clang_isVolatileQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalVolatileQualified(); +} + +unsigned clang_isRestrictQualifiedType(CXType CT) { + QualType T = GetQualType(CT); + return T.isLocalRestrictQualified(); +} + +unsigned clang_getAddressSpace(CXType CT) { + QualType T = GetQualType(CT); + + // For non language-specific address space, use separate helper function. + if (T.getAddressSpace() >= LangAS::FirstTargetAddressSpace) { + return T.getQualifiers().getAddressSpaceAttributePrintValue(); + } + // FIXME: this function returns either a LangAS or a target AS + // Those values can overlap which makes this function rather unpredictable + // for any caller + return (unsigned)T.getAddressSpace(); +} + +CXString clang_getTypedefName(CXType CT) { + QualType T = GetQualType(CT); + const TypedefType *TT = T->getAs<TypedefType>(); + if (TT) { + TypedefNameDecl *TD = TT->getDecl(); + if (TD) + return cxstring::createDup(TD->getNameAsString().c_str()); + } + return cxstring::createEmpty(); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (!TP) + return MakeCXType(QualType(), GetTU(CT)); + +try_again: + switch (TP->getTypeClass()) { + case Type::Pointer: + T = cast<PointerType>(TP)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast<BlockPointerType>(TP)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast<ReferenceType>(TP)->getPointeeType(); + break; + case Type::ObjCObjectPointer: + T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); + break; + case Type::MemberPointer: + T = cast<MemberPointerType>(TP)->getPointeeType(); + break; + case Type::Auto: + case Type::DeducedTemplateSpecialization: + TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); + if (TP) + goto try_again; + break; + default: + T = QualType(); + break; + } + return MakeCXType(T, GetTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + if (CT.kind == CXType_Invalid) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (!TP) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + Decl *D = nullptr; + +try_again: + switch (TP->getTypeClass()) { + case Type::Typedef: + D = cast<TypedefType>(TP)->getDecl(); + break; + case Type::ObjCObject: + D = cast<ObjCObjectType>(TP)->getInterface(); + break; + case Type::ObjCInterface: + D = cast<ObjCInterfaceType>(TP)->getDecl(); + break; + case Type::Record: + case Type::Enum: + D = cast<TagType>(TP)->getDecl(); + break; + case Type::TemplateSpecialization: + if (const RecordType *Record = TP->getAs<RecordType>()) + D = Record->getDecl(); + else + D = cast<TemplateSpecializationType>(TP)->getTemplateName() + .getAsTemplateDecl(); + break; + + case Type::Auto: + case Type::DeducedTemplateSpecialization: + TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); + if (TP) + goto try_again; + break; + + case Type::InjectedClassName: + D = cast<InjectedClassNameType>(TP)->getDecl(); + break; + + // FIXME: Template type parameters! + + case Type::Elaborated: + TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); + goto try_again; + + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetTU(CT)); +} + +CXString clang_getTypeKindSpelling(enum CXTypeKind K) { + const char *s = nullptr; +#define TKIND(X) case CXType_##X: s = "" #X ""; break + switch (K) { + TKIND(Invalid); + TKIND(Unexposed); + TKIND(Void); + TKIND(Bool); + TKIND(Char_U); + TKIND(UChar); + TKIND(Char16); + TKIND(Char32); + TKIND(UShort); + TKIND(UInt); + TKIND(ULong); + TKIND(ULongLong); + TKIND(UInt128); + TKIND(Char_S); + TKIND(SChar); + case CXType_WChar: s = "WChar"; break; + TKIND(Short); + TKIND(Int); + TKIND(Long); + TKIND(LongLong); + TKIND(Int128); + TKIND(Half); + TKIND(Float); + TKIND(Double); + TKIND(LongDouble); + TKIND(ShortAccum); + TKIND(Accum); + TKIND(LongAccum); + TKIND(UShortAccum); + TKIND(UAccum); + TKIND(ULongAccum); + TKIND(Float16); + TKIND(Float128); + TKIND(Ibm128); + TKIND(NullPtr); + TKIND(Overload); + TKIND(Dependent); + TKIND(ObjCId); + TKIND(ObjCClass); + TKIND(ObjCSel); + TKIND(Complex); + TKIND(Pointer); + TKIND(BlockPointer); + TKIND(LValueReference); + TKIND(RValueReference); + TKIND(Record); + TKIND(Enum); + TKIND(Typedef); + TKIND(ObjCInterface); + TKIND(ObjCObject); + TKIND(ObjCObjectPointer); + TKIND(ObjCTypeParam); + TKIND(FunctionNoProto); + TKIND(FunctionProto); + TKIND(ConstantArray); + TKIND(IncompleteArray); + TKIND(VariableArray); + TKIND(DependentSizedArray); + TKIND(Vector); + TKIND(ExtVector); + TKIND(MemberPointer); + TKIND(Auto); + TKIND(Elaborated); + TKIND(Pipe); + TKIND(Attributed); + TKIND(BFloat16); +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id); +#include "clang/Basic/OpenCLImageTypes.def" +#undef IMAGE_TYPE +#define EXT_OPAQUE_TYPE(ExtTYpe, Id, Ext) TKIND(Id); +#include "clang/Basic/OpenCLExtensionTypes.def" + TKIND(OCLSampler); + TKIND(OCLEvent); + TKIND(OCLQueue); + TKIND(OCLReserveID); + TKIND(Atomic); + } +#undef TKIND + return cxstring::createRef(s); +} + +unsigned clang_equalTypes(CXType A, CXType B) { + return A.data[0] == B.data[0] && A.data[1] == B.data[1]; +} + +unsigned clang_isFunctionTypeVariadic(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return 0; + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) + return (unsigned)FD->isVariadic(); + + if (T->getAs<FunctionNoProtoType>()) + return 1; + + return 0; +} + +CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return CXCallingConv_Invalid; + + if (const FunctionType *FD = T->getAs<FunctionType>()) { +#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X + switch (FD->getCallConv()) { + TCALLINGCONV(C); + TCALLINGCONV(X86StdCall); + TCALLINGCONV(X86FastCall); + TCALLINGCONV(X86ThisCall); + TCALLINGCONV(X86Pascal); + TCALLINGCONV(X86RegCall); + TCALLINGCONV(X86VectorCall); + TCALLINGCONV(AArch64VectorCall); + TCALLINGCONV(Win64); + TCALLINGCONV(X86_64SysV); + TCALLINGCONV(AAPCS); + TCALLINGCONV(AAPCS_VFP); + TCALLINGCONV(IntelOclBicc); + TCALLINGCONV(Swift); + TCALLINGCONV(SwiftAsync); + TCALLINGCONV(PreserveMost); + TCALLINGCONV(PreserveAll); + case CC_SpirFunction: return CXCallingConv_Unexposed; + case CC_OpenCLKernel: return CXCallingConv_Unexposed; + break; + } +#undef TCALLINGCONV + } + + return CXCallingConv_Invalid; +} + +int clang_getNumArgTypes(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return -1; + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { + return FD->getNumParams(); + } + + if (T->getAs<FunctionNoProtoType>()) { + return 0; + } + + return -1; +} + +CXType clang_getArgType(CXType X, unsigned i) { + QualType T = GetQualType(X); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(X)); + + if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { + unsigned numParams = FD->getNumParams(); + if (i >= numParams) + return MakeCXType(QualType(), GetTU(X)); + + return MakeCXType(FD->getParamType(i), GetTU(X)); + } + + return MakeCXType(QualType(), GetTU(X)); +} + +CXType clang_getResultType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(X)); + + if (const FunctionType *FD = T->getAs<FunctionType>()) + return MakeCXType(FD->getReturnType(), GetTU(X)); + + return MakeCXType(QualType(), GetTU(X)); +} + +CXType clang_getCursorResultType(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + const Decl *D = cxcursor::getCursorDecl(C); + if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) + return MakeCXType(MD->getReturnType(), cxcursor::getCursorTU(C)); + + return clang_getResultType(clang_getCursorType(C)); + } + + return MakeCXType(QualType(), cxcursor::getCursorTU(C)); +} + +// FIXME: We should expose the canThrow(...) result instead of the EST. +static CXCursor_ExceptionSpecificationKind +getExternalExceptionSpecificationKind(ExceptionSpecificationType EST) { + switch (EST) { + case EST_None: + return CXCursor_ExceptionSpecificationKind_None; + case EST_DynamicNone: + return CXCursor_ExceptionSpecificationKind_DynamicNone; + case EST_Dynamic: + return CXCursor_ExceptionSpecificationKind_Dynamic; + case EST_MSAny: + return CXCursor_ExceptionSpecificationKind_MSAny; + case EST_BasicNoexcept: + return CXCursor_ExceptionSpecificationKind_BasicNoexcept; + case EST_NoThrow: + return CXCursor_ExceptionSpecificationKind_NoThrow; + case EST_NoexceptFalse: + case EST_NoexceptTrue: + case EST_DependentNoexcept: + return CXCursor_ExceptionSpecificationKind_ComputedNoexcept; + case EST_Unevaluated: + return CXCursor_ExceptionSpecificationKind_Unevaluated; + case EST_Uninstantiated: + return CXCursor_ExceptionSpecificationKind_Uninstantiated; + case EST_Unparsed: + return CXCursor_ExceptionSpecificationKind_Unparsed; + } + llvm_unreachable("invalid EST value"); +} + +int clang_getExceptionSpecificationType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return -1; + + if (const auto *FD = T->getAs<FunctionProtoType>()) + return getExternalExceptionSpecificationKind(FD->getExceptionSpecType()); + + return -1; +} + +int clang_getCursorExceptionSpecificationType(CXCursor C) { + if (clang_isDeclaration(C.kind)) + return clang_getExceptionSpecificationType(clang_getCursorType(C)); + + return -1; +} + +unsigned clang_isPODType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return 0; + + CXTranslationUnit TU = GetTU(X); + + return T.isPODType(cxtu::getASTUnit(TU)->getASTContext()) ? 1 : 0; +} + +CXType clang_getElementType(CXType CT) { + QualType ET = QualType(); + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + ET = cast<ConstantArrayType> (TP)->getElementType(); + break; + case Type::IncompleteArray: + ET = cast<IncompleteArrayType> (TP)->getElementType(); + break; + case Type::VariableArray: + ET = cast<VariableArrayType> (TP)->getElementType(); + break; + case Type::DependentSizedArray: + ET = cast<DependentSizedArrayType> (TP)->getElementType(); + break; + case Type::Vector: + ET = cast<VectorType> (TP)->getElementType(); + break; + case Type::ExtVector: + ET = cast<ExtVectorType>(TP)->getElementType(); + break; + case Type::Complex: + ET = cast<ComplexType> (TP)->getElementType(); + break; + default: + break; + } + } + return MakeCXType(ET, GetTU(CT)); +} + +long long clang_getNumElements(CXType CT) { + long long result = -1; + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); + break; + case Type::Vector: + result = cast<VectorType> (TP)->getNumElements(); + break; + case Type::ExtVector: + result = cast<ExtVectorType>(TP)->getNumElements(); + break; + default: + break; + } + } + return result; +} + +CXType clang_getArrayElementType(CXType CT) { + QualType ET = QualType(); + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + ET = cast<ConstantArrayType> (TP)->getElementType(); + break; + case Type::IncompleteArray: + ET = cast<IncompleteArrayType> (TP)->getElementType(); + break; + case Type::VariableArray: + ET = cast<VariableArrayType> (TP)->getElementType(); + break; + case Type::DependentSizedArray: + ET = cast<DependentSizedArrayType> (TP)->getElementType(); + break; + default: + break; + } + } + return MakeCXType(ET, GetTU(CT)); +} + +long long clang_getArraySize(CXType CT) { + long long result = -1; + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP) { + switch (TP->getTypeClass()) { + case Type::ConstantArray: + result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); + break; + default: + break; + } + } + return result; +} + +static bool isIncompleteTypeWithAlignment(QualType QT) { + return QT->isIncompleteArrayType() || !QT->isIncompleteType(); +} + +long long clang_Type_getAlignOf(CXType T) { + if (T.kind == CXType_Invalid) + return CXTypeLayoutError_Invalid; + ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); + QualType QT = GetQualType(T); + // [expr.alignof] p1: return size_t value for complete object type, reference + // or array. + // [expr.alignof] p3: if reference type, return size of referenced type + if (QT->isReferenceType()) + QT = QT.getNonReferenceType(); + if (!isIncompleteTypeWithAlignment(QT)) + return CXTypeLayoutError_Incomplete; + if (QT->isDependentType()) + return CXTypeLayoutError_Dependent; + if (const auto *Deduced = dyn_cast<DeducedType>(QT)) + if (Deduced->getDeducedType().isNull()) + return CXTypeLayoutError_Undeduced; + // Exceptions by GCC extension - see ASTContext.cpp:1313 getTypeInfoImpl + // if (QT->isFunctionType()) return 4; // Bug #15511 - should be 1 + // if (QT->isVoidType()) return 1; + return Ctx.getTypeAlignInChars(QT).getQuantity(); +} + +CXType clang_Type_getClassType(CXType CT) { + QualType ET = QualType(); + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP && TP->getTypeClass() == Type::MemberPointer) { + ET = QualType(cast<MemberPointerType> (TP)->getClass(), 0); + } + return MakeCXType(ET, GetTU(CT)); +} + +long long clang_Type_getSizeOf(CXType T) { + if (T.kind == CXType_Invalid) + return CXTypeLayoutError_Invalid; + ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); + QualType QT = GetQualType(T); + // [expr.sizeof] p2: if reference type, return size of referenced type + if (QT->isReferenceType()) + QT = QT.getNonReferenceType(); + // [expr.sizeof] p1: return -1 on: func, incomplete, bitfield, incomplete + // enumeration + // Note: We get the cxtype, not the cxcursor, so we can't call + // FieldDecl->isBitField() + // [expr.sizeof] p3: pointer ok, function not ok. + // [gcc extension] lib/AST/ExprConstant.cpp:1372 HandleSizeof : vla == error + if (QT->isIncompleteType()) + return CXTypeLayoutError_Incomplete; + if (QT->isDependentType()) + return CXTypeLayoutError_Dependent; + if (!QT->isConstantSizeType()) + return CXTypeLayoutError_NotConstantSize; + if (const auto *Deduced = dyn_cast<DeducedType>(QT)) + if (Deduced->getDeducedType().isNull()) + return CXTypeLayoutError_Undeduced; + // [gcc extension] lib/AST/ExprConstant.cpp:1372 + // HandleSizeof : {voidtype,functype} == 1 + // not handled by ASTContext.cpp:1313 getTypeInfoImpl + if (QT->isVoidType() || QT->isFunctionType()) + return 1; + return Ctx.getTypeSizeInChars(QT).getQuantity(); +} + +static bool isTypeIncompleteForLayout(QualType QT) { + return QT->isIncompleteType() && !QT->isIncompleteArrayType(); +} + +static long long visitRecordForValidation(const RecordDecl *RD) { + for (const auto *I : RD->fields()){ + QualType FQT = I->getType(); + if (isTypeIncompleteForLayout(FQT)) + return CXTypeLayoutError_Incomplete; + if (FQT->isDependentType()) + return CXTypeLayoutError_Dependent; + // recurse + if (const RecordType *ChildType = I->getType()->getAs<RecordType>()) { + if (const RecordDecl *Child = ChildType->getDecl()) { + long long ret = visitRecordForValidation(Child); + if (ret < 0) + return ret; + } + } + // else try next field + } + return 0; +} + +static long long validateFieldParentType(CXCursor PC, CXType PT){ + if (clang_isInvalid(PC.kind)) + return CXTypeLayoutError_Invalid; + const RecordDecl *RD = + dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); + // validate parent declaration + if (!RD || RD->isInvalidDecl()) + return CXTypeLayoutError_Invalid; + RD = RD->getDefinition(); + if (!RD) + return CXTypeLayoutError_Incomplete; + if (RD->isInvalidDecl()) + return CXTypeLayoutError_Invalid; + // validate parent type + QualType RT = GetQualType(PT); + if (RT->isIncompleteType()) + return CXTypeLayoutError_Incomplete; + if (RT->isDependentType()) + return CXTypeLayoutError_Dependent; + // We recurse into all record fields to detect incomplete and dependent types. + long long Error = visitRecordForValidation(RD); + if (Error < 0) + return Error; + return 0; +} + +long long clang_Type_getOffsetOf(CXType PT, const char *S) { + // check that PT is not incomplete/dependent + CXCursor PC = clang_getTypeDeclaration(PT); + long long Error = validateFieldParentType(PC,PT); + if (Error < 0) + return Error; + if (!S) + return CXTypeLayoutError_InvalidFieldName; + // lookup field + ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext(); + IdentifierInfo *II = &Ctx.Idents.get(S); + DeclarationName FieldName(II); + const RecordDecl *RD = + dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); + // verified in validateFieldParentType + RD = RD->getDefinition(); + RecordDecl::lookup_result Res = RD->lookup(FieldName); + // If a field of the parent record is incomplete, lookup will fail. + // and we would return InvalidFieldName instead of Incomplete. + // But this erroneous results does protects again a hidden assertion failure + // in the RecordLayoutBuilder + if (!Res.isSingleResult()) + return CXTypeLayoutError_InvalidFieldName; + if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front())) + return Ctx.getFieldOffset(FD); + if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(Res.front())) + return Ctx.getFieldOffset(IFD); + // we don't want any other Decl Type. + return CXTypeLayoutError_InvalidFieldName; +} + +CXType clang_Type_getModifiedType(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + if (auto *ATT = T->getAs<AttributedType>()) + return MakeCXType(ATT->getModifiedType(), GetTU(CT)); + + return MakeCXType(QualType(), GetTU(CT)); +} + +long long clang_Cursor_getOffsetOfField(CXCursor C) { + if (clang_isDeclaration(C.kind)) { + // we need to validate the parent type + CXCursor PC = clang_getCursorSemanticParent(C); + CXType PT = clang_getCursorType(PC); + long long Error = validateFieldParentType(PC,PT); + if (Error < 0) + return Error; + // proceed with the offset calculation + const Decl *D = cxcursor::getCursorDecl(C); + ASTContext &Ctx = cxcursor::getCursorContext(C); + if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) + return Ctx.getFieldOffset(FD); + if (const IndirectFieldDecl *IFD = dyn_cast_or_null<IndirectFieldDecl>(D)) + return Ctx.getFieldOffset(IFD); + } + return -1; +} + +enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T) { + QualType QT = GetQualType(T); + if (QT.isNull()) + return CXRefQualifier_None; + const FunctionProtoType *FD = QT->getAs<FunctionProtoType>(); + if (!FD) + return CXRefQualifier_None; + switch (FD->getRefQualifier()) { + case RQ_None: + return CXRefQualifier_None; + case RQ_LValue: + return CXRefQualifier_LValue; + case RQ_RValue: + return CXRefQualifier_RValue; + } + return CXRefQualifier_None; +} + +unsigned clang_Cursor_isBitField(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(cxcursor::getCursorDecl(C)); + if (!FD) + return 0; + return FD->isBitField(); +} + +CXString clang_getDeclObjCTypeEncoding(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return cxstring::createEmpty(); + + const Decl *D = cxcursor::getCursorDecl(C); + ASTContext &Ctx = cxcursor::getCursorContext(C); + std::string encoding; + + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { + encoding = Ctx.getObjCEncodingForMethodDecl(OMD); + } else if (const ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D)) + encoding = Ctx.getObjCEncodingForPropertyDecl(OPD, nullptr); + else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + encoding = Ctx.getObjCEncodingForFunctionDecl(FD); + else { + QualType Ty; + if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) + Ty = Ctx.getTypeDeclType(TD); + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) + Ty = VD->getType(); + else return cxstring::createRef("?"); + Ctx.getObjCEncodingForType(Ty, encoding); + } + + return cxstring::createDup(encoding); +} + +static unsigned GetTemplateArgumentArraySize(ArrayRef<TemplateArgument> TA) { + unsigned size = TA.size(); + for (const auto &Arg : TA) + if (Arg.getKind() == TemplateArgument::Pack) + size += Arg.pack_size() - 1; + return size; +} + +int clang_Type_getNumTemplateArguments(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return -1; + + auto TA = GetTemplateArguments(T); + if (!TA) + return -1; + + return GetTemplateArgumentArraySize(TA.getValue()); +} + +CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + auto TA = GetTemplateArguments(T); + if (!TA) + return MakeCXType(QualType(), GetTU(CT)); + + Optional<QualType> QT = FindTemplateArgumentTypeAt(TA.getValue(), index); + return MakeCXType(QT.getValueOr(QualType()), GetTU(CT)); +} + +CXType clang_Type_getObjCObjectBaseType(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return MakeCXType(QualType(), GetTU(CT)); + + return MakeCXType(OT->getBaseType(), GetTU(CT)); +} + +unsigned clang_Type_getNumObjCProtocolRefs(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return 0; + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return 0; + + return OT->getNumProtocols(); +} + +CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) { + QualType T = GetQualType(CT); + if (T.isNull()) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + const ObjCProtocolDecl *PD = OT->getProtocol(i); + if (!PD) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(PD, GetTU(CT)); +} + +unsigned clang_Type_getNumObjCTypeArgs(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return 0; + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return 0; + + return OT->getTypeArgs().size(); +} + +CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) { + QualType T = GetQualType(CT); + if (T.isNull()) + return MakeCXType(QualType(), GetTU(CT)); + + const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); + if (!OT) + return MakeCXType(QualType(), GetTU(CT)); + + const ArrayRef<QualType> TA = OT->getTypeArgs(); + if ((size_t)i >= TA.size()) + return MakeCXType(QualType(), GetTU(CT)); + + return MakeCXType(TA[i], GetTU(CT)); +} + +unsigned clang_Type_visitFields(CXType PT, + CXFieldVisitor visitor, + CXClientData client_data){ + CXCursor PC = clang_getTypeDeclaration(PT); + if (clang_isInvalid(PC.kind)) + return false; + const RecordDecl *RD = + dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); + if (!RD || RD->isInvalidDecl()) + return false; + RD = RD->getDefinition(); + if (!RD || RD->isInvalidDecl()) + return false; + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I){ + const FieldDecl *FD = dyn_cast_or_null<FieldDecl>((*I)); + // Callback to the client. + switch (visitor(cxcursor::MakeCXCursor(FD, GetTU(PT)), client_data)){ + case CXVisit_Break: + return true; + case CXVisit_Continue: + break; + } + } + return true; +} + +unsigned clang_Cursor_isAnonymous(CXCursor C){ + if (!clang_isDeclaration(C.kind)) + return 0; + const Decl *D = cxcursor::getCursorDecl(C); + if (const NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(D)) { + return ND->isAnonymousNamespace(); + } else if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(D)) { + return TD->getTypedefNameForAnonDecl() == nullptr && + TD->getIdentifier() == nullptr; + } + + return 0; +} + +unsigned clang_Cursor_isAnonymousRecordDecl(CXCursor C){ + if (!clang_isDeclaration(C.kind)) + return 0; + const Decl *D = cxcursor::getCursorDecl(C); + if (const RecordDecl *FD = dyn_cast_or_null<RecordDecl>(D)) + return FD->isAnonymousStructOrUnion(); + return 0; +} + +unsigned clang_Cursor_isInlineNamespace(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + const Decl *D = cxcursor::getCursorDecl(C); + const NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(D); + return ND ? ND->isInline() : 0; +} + +CXType clang_Type_getNamedType(CXType CT){ + QualType T = GetQualType(CT); + const Type *TP = T.getTypePtrOrNull(); + + if (TP && TP->getTypeClass() == Type::Elaborated) + return MakeCXType(cast<ElaboratedType>(TP)->getNamedType(), GetTU(CT)); + + return MakeCXType(QualType(), GetTU(CT)); +} + +unsigned clang_Type_isTransparentTagTypedef(CXType TT){ + QualType T = GetQualType(TT); + if (auto *TT = dyn_cast_or_null<TypedefType>(T.getTypePtrOrNull())) { + if (auto *D = TT->getDecl()) + return D->isTransparentTag(); + } + return false; +} + +enum CXTypeNullabilityKind clang_Type_getNullability(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return CXTypeNullability_Invalid; + + ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext(); + if (auto nullability = T->getNullability(Ctx)) { + switch (*nullability) { + case NullabilityKind::NonNull: + return CXTypeNullability_NonNull; + case NullabilityKind::Nullable: + return CXTypeNullability_Nullable; + case NullabilityKind::NullableResult: + return CXTypeNullability_NullableResult; + case NullabilityKind::Unspecified: + return CXTypeNullability_Unspecified; + } + } + return CXTypeNullability_Invalid; +} + +CXType clang_Type_getValueType(CXType CT) { + QualType T = GetQualType(CT); + + if (T.isNull() || !T->isAtomicType()) + return MakeCXType(QualType(), GetTU(CT)); + + const auto *AT = T->castAs<AtomicType>(); + return MakeCXType(AT->getValueType(), GetTU(CT)); +} diff --git a/contrib/libs/clang14/tools/libclang/CXType.h b/contrib/libs/clang14/tools/libclang/CXType.h new file mode 100644 index 0000000000..ffe70a9b1c --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CXType.h @@ -0,0 +1,25 @@ +//===- CXTypes.h - Routines for manipulating CXTypes ----------------------===// +// +// 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 defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CXTYPE_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CXTYPE_H + +#include "clang-c/Index.h" +#include "clang/AST/Type.h" + +namespace clang { +namespace cxtype { + +CXType MakeCXType(QualType T, CXTranslationUnit TU); + +}} // end namespace clang::cxtype +#endif diff --git a/contrib/libs/clang14/tools/libclang/CursorVisitor.h b/contrib/libs/clang14/tools/libclang/CursorVisitor.h new file mode 100644 index 0000000000..364d9fdebd --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/CursorVisitor.h @@ -0,0 +1,278 @@ +//===- CursorVisitor.h - CursorVisitor interface ----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H +#define LLVM_CLANG_TOOLS_LIBCLANG_CURSORVISITOR_H + +#include "CXCursor.h" +#include "CXTranslationUnit.h" +#include "Index_Internal.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeLocVisitor.h" + +namespace clang { +class PreprocessingRecord; +class ASTUnit; + +namespace cxcursor { + +class VisitorJob { +public: + enum Kind { + DeclVisitKind, + StmtVisitKind, + MemberExprPartsKind, + TypeLocVisitKind, + OverloadExprPartsKind, + DeclRefExprPartsKind, + LabelRefVisitKind, + ExplicitTemplateArgsVisitKind, + NestedNameSpecifierLocVisitKind, + DeclarationNameInfoVisitKind, + MemberRefVisitKind, + SizeOfPackExprPartsKind, + LambdaExprPartsKind, + PostChildrenVisitKind + }; + +protected: + const void *data[3]; + CXCursor parent; + Kind K; + VisitorJob(CXCursor C, Kind k, const void *d1, const void *d2 = nullptr, + const void *d3 = nullptr) + : parent(C), K(k) { + data[0] = d1; + data[1] = d2; + data[2] = d3; + } + +public: + Kind getKind() const { return K; } + const CXCursor &getParent() const { return parent; } +}; + +typedef SmallVector<VisitorJob, 10> VisitorWorkList; + +// Cursor visitor. +class CursorVisitor : public DeclVisitor<CursorVisitor, bool>, + public TypeLocVisitor<CursorVisitor, bool> { +public: + /// Callback called after child nodes of a cursor have been visited. + /// Return true to break visitation or false to continue. + typedef bool (*PostChildrenVisitorTy)(CXCursor cursor, + CXClientData client_data); + +private: + /// The translation unit we are traversing. + CXTranslationUnit TU; + ASTUnit *AU; + + /// The parent cursor whose children we are traversing. + CXCursor Parent; + + /// The declaration that serves at the parent of any statement or + /// expression nodes. + const Decl *StmtParent; + + /// The visitor function. + CXCursorVisitor Visitor; + + PostChildrenVisitorTy PostChildrenVisitor; + + /// The opaque client data, to be passed along to the visitor. + CXClientData ClientData; + + /// Whether we should visit the preprocessing record entries last, + /// after visiting other declarations. + bool VisitPreprocessorLast; + + /// Whether we should visit declarations or preprocessing record + /// entries that are #included inside the \arg RegionOfInterest. + bool VisitIncludedEntities; + + /// When valid, a source range to which the cursor should restrict + /// its search. + SourceRange RegionOfInterest; + + /// Whether we should only visit declarations and not preprocessing + /// record entries. + bool VisitDeclsOnly; + + // FIXME: Eventually remove. This part of a hack to support proper + // iteration over all Decls contained lexically within an ObjC container. + DeclContext::decl_iterator *DI_current; + DeclContext::decl_iterator DE_current; + SmallVectorImpl<Decl *>::iterator *FileDI_current; + SmallVectorImpl<Decl *>::iterator FileDE_current; + + // Cache of pre-allocated worklists for data-recursion walk of Stmts. + SmallVector<VisitorWorkList *, 5> WorkListFreeList; + SmallVector<VisitorWorkList *, 5> WorkListCache; + + using DeclVisitor<CursorVisitor, bool>::Visit; + using TypeLocVisitor<CursorVisitor, bool>::Visit; + + /// Determine whether this particular source range comes before, comes + /// after, or overlaps the region of interest. + /// + /// \param R a half-open source range retrieved from the abstract syntax tree. + RangeComparisonResult CompareRegionOfInterest(SourceRange R); + + bool visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length); + + class SetParentRAII { + CXCursor &Parent; + const Decl *&StmtParent; + CXCursor OldParent; + + public: + SetParentRAII(CXCursor &Parent, const Decl *&StmtParent, CXCursor NewParent) + : Parent(Parent), StmtParent(StmtParent), OldParent(Parent) { + Parent = NewParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + + ~SetParentRAII() { + Parent = OldParent; + if (clang_isDeclaration(Parent.kind)) + StmtParent = getCursorDecl(Parent); + } + }; + +public: + CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor, + CXClientData ClientData, bool VisitPreprocessorLast, + bool VisitIncludedPreprocessingEntries = false, + SourceRange RegionOfInterest = SourceRange(), + bool VisitDeclsOnly = false, + PostChildrenVisitorTy PostChildrenVisitor = nullptr) + : TU(TU), AU(cxtu::getASTUnit(TU)), Visitor(Visitor), + PostChildrenVisitor(PostChildrenVisitor), ClientData(ClientData), + VisitPreprocessorLast(VisitPreprocessorLast), + VisitIncludedEntities(VisitIncludedPreprocessingEntries), + RegionOfInterest(RegionOfInterest), VisitDeclsOnly(VisitDeclsOnly), + DI_current(nullptr), FileDI_current(nullptr) { + Parent.kind = CXCursor_NoDeclFound; + Parent.data[0] = nullptr; + Parent.data[1] = nullptr; + Parent.data[2] = nullptr; + StmtParent = nullptr; + } + + ~CursorVisitor() { + // Free the pre-allocated worklists for data-recursion. + for (SmallVectorImpl<VisitorWorkList *>::iterator I = WorkListCache.begin(), + E = WorkListCache.end(); + I != E; ++I) { + delete *I; + } + } + + ASTUnit *getASTUnit() const { return AU; } + CXTranslationUnit getTU() const { return TU; } + + bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); + + /// Visit declarations and preprocessed entities for the file region + /// designated by \see RegionOfInterest. + bool visitFileRegion(); + + bool visitPreprocessedEntitiesInRegion(); + + bool shouldVisitIncludedEntities() const { return VisitIncludedEntities; } + + template <typename InputIterator> + bool visitPreprocessedEntities(InputIterator First, InputIterator Last, + PreprocessingRecord &PPRec, + FileID FID = FileID()); + + bool VisitChildren(CXCursor Parent); + + // Declaration visitors + bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); + bool VisitTypeAliasDecl(TypeAliasDecl *D); + bool VisitAttributes(Decl *D); + bool VisitBlockDecl(BlockDecl *B); + bool VisitCXXRecordDecl(CXXRecordDecl *D); + Optional<bool> shouldVisitCursor(CXCursor C); + bool VisitDeclContext(DeclContext *DC); + bool VisitTranslationUnitDecl(TranslationUnitDecl *D); + bool VisitTypedefDecl(TypedefDecl *D); + bool VisitTagDecl(TagDecl *D); + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); + bool VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + bool VisitEnumConstantDecl(EnumConstantDecl *D); + bool VisitDeclaratorDecl(DeclaratorDecl *DD); + bool VisitFunctionDecl(FunctionDecl *ND); + bool VisitFieldDecl(FieldDecl *D); + bool VisitVarDecl(VarDecl *); + bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + bool VisitClassTemplateDecl(ClassTemplateDecl *D); + bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); + bool VisitObjCMethodDecl(ObjCMethodDecl *ND); + bool VisitObjCContainerDecl(ObjCContainerDecl *D); + bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); + bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); + bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); + bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + bool VisitObjCImplDecl(ObjCImplDecl *D); + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D); + // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations. + bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD); + bool VisitLinkageSpecDecl(LinkageSpecDecl *D); + bool VisitNamespaceDecl(NamespaceDecl *D); + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + bool VisitStaticAssertDecl(StaticAssertDecl *D); + bool VisitFriendDecl(FriendDecl *D); + bool VisitDecompositionDecl(DecompositionDecl *D); + + // Name visitor + bool VisitDeclarationNameInfo(DeclarationNameInfo Name); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); + bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + // Template visitors + bool VisitTemplateParameters(const TemplateParameterList *Params); + bool VisitTemplateName(TemplateName Name, SourceLocation Loc); + bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); + + // Type visitors +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); +#include "clang/AST/TypeLocNodes.def" + + bool VisitTagTypeLoc(TagTypeLoc TL); + bool VisitArrayTypeLoc(ArrayTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); + + // Data-recursive visitor functions. + bool IsInRegionOfInterest(CXCursor C); + bool RunVisitorWorkList(VisitorWorkList &WL); + void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S); + LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S); + +private: + Optional<bool> handleDeclForVisitation(const Decl *D); +}; + +} // namespace cxcursor +} // namespace clang + +#endif diff --git a/contrib/libs/clang14/tools/libclang/FatalErrorHandler.cpp b/contrib/libs/clang14/tools/libclang/FatalErrorHandler.cpp new file mode 100644 index 0000000000..506b047c1b --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/FatalErrorHandler.cpp @@ -0,0 +1,32 @@ +/*===-- clang-c/FatalErrorHandler.cpp - Fatal Error Handling ------*- C -*-===*\ +|* *| +|* 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 *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "clang-c/FatalErrorHandler.h" +#include "llvm/Support/ErrorHandling.h" +#include <stdio.h> +#include <stdlib.h> + +static void aborting_fatal_error_handler(void *, const char *reason, + bool) { + // Write the result out to stderr avoiding errs() because raw_ostreams can + // call report_fatal_error. + fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason); + ::abort(); +} + +extern "C" { +void clang_install_aborting_llvm_fatal_error_handler(void) { + llvm::remove_fatal_error_handler(); + llvm::install_fatal_error_handler(aborting_fatal_error_handler, nullptr); +} + +void clang_uninstall_llvm_fatal_error_handler(void) { + llvm::remove_fatal_error_handler(); +} +} diff --git a/contrib/libs/clang14/tools/libclang/Index_Internal.h b/contrib/libs/clang14/tools/libclang/Index_Internal.h new file mode 100644 index 0000000000..d28438770e --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/Index_Internal.h @@ -0,0 +1,54 @@ +//===- CXString.h - Routines for manipulating CXStrings -------------------===// +// +// 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 defines routines for manipulating CXStrings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_LIBCLANG_INDEX_INTERNAL_H +#define LLVM_CLANG_TOOLS_LIBCLANG_INDEX_INTERNAL_H + +#include "clang-c/Index.h" + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_feature(blocks) + +#define INVOKE_BLOCK2(block, arg1, arg2) block(arg1, arg2) + +#else +// If we are compiled with a compiler that doesn't have native blocks support, +// define and call the block manually. + +#define INVOKE_BLOCK2(block, arg1, arg2) block->invoke(block, arg1, arg2) + +typedef struct _CXCursorAndRangeVisitorBlock { + void *isa; + int flags; + int reserved; + enum CXVisitorResult (*invoke)(_CXCursorAndRangeVisitorBlock *, + CXCursor, CXSourceRange); +} *CXCursorAndRangeVisitorBlock; + +#endif // !__has_feature(blocks) + +/// The result of comparing two source ranges. +enum RangeComparisonResult { + /// Either the ranges overlap or one of the ranges is invalid. + RangeOverlap, + + /// The first range ends before the second range starts. + RangeBefore, + + /// The first range starts after the second range ends. + RangeAfter +}; + +#endif diff --git a/contrib/libs/clang14/tools/libclang/Indexing.cpp b/contrib/libs/clang14/tools/libclang/Indexing.cpp new file mode 100644 index 0000000000..0e83ec6ca7 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/Indexing.cpp @@ -0,0 +1,997 @@ +//===- Indexing.cpp - Higher level API functions --------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "CIndexDiagnostic.h" +#include "CIndexer.h" +#include "CLog.h" +#include "CXCursor.h" +#include "CXIndexDataConsumer.h" +#include "CXSourceLocation.h" +#include "CXString.h" +#include "CXTranslationUnit.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Frontend/Utils.h" +#include "clang/Index/IndexingAction.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/PPConditionalDirectiveRecord.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cstdio> +#include <mutex> +#include <utility> + +using namespace clang; +using namespace clang::index; +using namespace cxtu; +using namespace cxindex; + +namespace { + +//===----------------------------------------------------------------------===// +// Skip Parsed Bodies +//===----------------------------------------------------------------------===// + +/// A "region" in source code identified by the file/offset of the +/// preprocessor conditional directive that it belongs to. +/// Multiple, non-consecutive ranges can be parts of the same region. +/// +/// As an example of different regions separated by preprocessor directives: +/// +/// \code +/// #1 +/// #ifdef BLAH +/// #2 +/// #ifdef CAKE +/// #3 +/// #endif +/// #2 +/// #endif +/// #1 +/// \endcode +/// +/// There are 3 regions, with non-consecutive parts: +/// #1 is identified as the beginning of the file +/// #2 is identified as the location of "#ifdef BLAH" +/// #3 is identified as the location of "#ifdef CAKE" +/// +class PPRegion { + llvm::sys::fs::UniqueID UniqueID; + time_t ModTime; + unsigned Offset; +public: + PPRegion() : UniqueID(0, 0), ModTime(), Offset() {} + PPRegion(llvm::sys::fs::UniqueID UniqueID, unsigned offset, time_t modTime) + : UniqueID(UniqueID), ModTime(modTime), Offset(offset) {} + + const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } + unsigned getOffset() const { return Offset; } + time_t getModTime() const { return ModTime; } + + bool isInvalid() const { return *this == PPRegion(); } + + friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) { + return lhs.UniqueID == rhs.UniqueID && lhs.Offset == rhs.Offset && + lhs.ModTime == rhs.ModTime; + } +}; + +} // end anonymous namespace + +namespace llvm { + + template <> + struct DenseMapInfo<PPRegion> { + static inline PPRegion getEmptyKey() { + return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-1), 0); + } + static inline PPRegion getTombstoneKey() { + return PPRegion(llvm::sys::fs::UniqueID(0, 0), unsigned(-2), 0); + } + + static unsigned getHashValue(const PPRegion &S) { + llvm::FoldingSetNodeID ID; + const llvm::sys::fs::UniqueID &UniqueID = S.getUniqueID(); + ID.AddInteger(UniqueID.getFile()); + ID.AddInteger(UniqueID.getDevice()); + ID.AddInteger(S.getOffset()); + ID.AddInteger(S.getModTime()); + return ID.ComputeHash(); + } + + static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) { + return LHS == RHS; + } + }; +} + +namespace { + +/// Keeps track of function bodies that have already been parsed. +/// +/// Is thread-safe. +class ThreadSafeParsedRegions { + mutable std::mutex Mutex; + llvm::DenseSet<PPRegion> ParsedRegions; + +public: + ~ThreadSafeParsedRegions() = default; + + llvm::DenseSet<PPRegion> getParsedRegions() const { + std::lock_guard<std::mutex> MG(Mutex); + return ParsedRegions; + } + + void addParsedRegions(ArrayRef<PPRegion> Regions) { + std::lock_guard<std::mutex> MG(Mutex); + ParsedRegions.insert(Regions.begin(), Regions.end()); + } +}; + +/// Provides information whether source locations have already been parsed in +/// another FrontendAction. +/// +/// Is NOT thread-safe. +class ParsedSrcLocationsTracker { + ThreadSafeParsedRegions &ParsedRegionsStorage; + PPConditionalDirectiveRecord &PPRec; + Preprocessor &PP; + + /// Snapshot of the shared state at the point when this instance was + /// constructed. + llvm::DenseSet<PPRegion> ParsedRegionsSnapshot; + /// Regions that were queried during this instance lifetime. + SmallVector<PPRegion, 32> NewParsedRegions; + + /// Caching the last queried region. + PPRegion LastRegion; + bool LastIsParsed; + +public: + /// Creates snapshot of \p ParsedRegionsStorage. + ParsedSrcLocationsTracker(ThreadSafeParsedRegions &ParsedRegionsStorage, + PPConditionalDirectiveRecord &ppRec, + Preprocessor &pp) + : ParsedRegionsStorage(ParsedRegionsStorage), PPRec(ppRec), PP(pp), + ParsedRegionsSnapshot(ParsedRegionsStorage.getParsedRegions()) {} + + /// \returns true iff \p Loc has already been parsed. + /// + /// Can provide false-negative in case the location was parsed after this + /// instance had been constructed. + bool hasAlredyBeenParsed(SourceLocation Loc, FileID FID, + const FileEntry *FE) { + assert(FE); + PPRegion region = getRegion(Loc, FID, FE); + if (region.isInvalid()) + return false; + + // Check common case, consecutive functions in the same region. + if (LastRegion == region) + return LastIsParsed; + + LastRegion = region; + // Source locations can't be revisited during single TU parsing. + // That means if we hit the same region again, it's a different location in + // the same region and so the "is parsed" value from the snapshot is still + // correct. + LastIsParsed = ParsedRegionsSnapshot.count(region); + if (!LastIsParsed) + NewParsedRegions.emplace_back(std::move(region)); + return LastIsParsed; + } + + /// Updates ParsedRegionsStorage with newly parsed regions. + void syncWithStorage() { + ParsedRegionsStorage.addParsedRegions(NewParsedRegions); + } + +private: + PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) { + assert(FE); + auto Bail = [this, FE]() { + if (isParsedOnceInclude(FE)) { + const llvm::sys::fs::UniqueID &ID = FE->getUniqueID(); + return PPRegion(ID, 0, FE->getModificationTime()); + } + return PPRegion(); + }; + + SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc); + assert(RegionLoc.isFileID()); + if (RegionLoc.isInvalid()) + return Bail(); + + FileID RegionFID; + unsigned RegionOffset; + std::tie(RegionFID, RegionOffset) = + PPRec.getSourceManager().getDecomposedLoc(RegionLoc); + + if (RegionFID != FID) + return Bail(); + + const llvm::sys::fs::UniqueID &ID = FE->getUniqueID(); + return PPRegion(ID, RegionOffset, FE->getModificationTime()); + } + + bool isParsedOnceInclude(const FileEntry *FE) { + return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) || + PP.getHeaderSearchInfo().hasFileBeenImported(FE); + } +}; + +//===----------------------------------------------------------------------===// +// IndexPPCallbacks +//===----------------------------------------------------------------------===// + +class IndexPPCallbacks : public PPCallbacks { + Preprocessor &PP; + CXIndexDataConsumer &DataConsumer; + bool IsMainFileEntered; + +public: + IndexPPCallbacks(Preprocessor &PP, CXIndexDataConsumer &dataConsumer) + : PP(PP), DataConsumer(dataConsumer), IsMainFileEntered(false) { } + + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, FileID PrevFID) override { + if (IsMainFileEntered) + return; + + SourceManager &SM = PP.getSourceManager(); + SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID()); + + if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) { + IsMainFileEntered = true; + DataConsumer.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID())); + } + } + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) override { + bool isImport = (IncludeTok.is(tok::identifier) && + IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import); + DataConsumer.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled, + Imported); + } + + /// MacroDefined - This hook is called whenever a macro definition is seen. + void MacroDefined(const Token &Id, const MacroDirective *MD) override {} + + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + /// MI is released immediately following this callback. + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD, + const MacroDirective *UD) override {} + + /// MacroExpands - This is called by when a macro invocation is found. + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override {} + + /// SourceRangeSkipped - This hook is called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// #if/#else directive and ends after the #endif/#else directive. + void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override { + } +}; + +//===----------------------------------------------------------------------===// +// IndexingConsumer +//===----------------------------------------------------------------------===// + +class IndexingConsumer : public ASTConsumer { + CXIndexDataConsumer &DataConsumer; + +public: + IndexingConsumer(CXIndexDataConsumer &dataConsumer, + ParsedSrcLocationsTracker *parsedLocsTracker) + : DataConsumer(dataConsumer) {} + + void Initialize(ASTContext &Context) override { + DataConsumer.setASTContext(Context); + DataConsumer.startedTranslationUnit(); + } + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + return !DataConsumer.shouldAbort(); + } +}; + +//===----------------------------------------------------------------------===// +// CaptureDiagnosticConsumer +//===----------------------------------------------------------------------===// + +class CaptureDiagnosticConsumer : public DiagnosticConsumer { + SmallVector<StoredDiagnostic, 4> Errors; +public: + + void HandleDiagnostic(DiagnosticsEngine::Level level, + const Diagnostic &Info) override { + if (level >= DiagnosticsEngine::Error) + Errors.push_back(StoredDiagnostic(level, Info)); + } +}; + +//===----------------------------------------------------------------------===// +// IndexingFrontendAction +//===----------------------------------------------------------------------===// + +class IndexingFrontendAction : public ASTFrontendAction { + std::shared_ptr<CXIndexDataConsumer> DataConsumer; + IndexingOptions Opts; + + ThreadSafeParsedRegions *SKData; + std::unique_ptr<ParsedSrcLocationsTracker> ParsedLocsTracker; + +public: + IndexingFrontendAction(std::shared_ptr<CXIndexDataConsumer> dataConsumer, + const IndexingOptions &Opts, + ThreadSafeParsedRegions *skData) + : DataConsumer(std::move(dataConsumer)), Opts(Opts), SKData(skData) {} + + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + + if (!PPOpts.ImplicitPCHInclude.empty()) { + auto File = CI.getFileManager().getFile(PPOpts.ImplicitPCHInclude); + if (File) + DataConsumer->importedPCH(*File); + } + + DataConsumer->setASTContext(CI.getASTContext()); + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks(std::make_unique<IndexPPCallbacks>(PP, *DataConsumer)); + DataConsumer->setPreprocessor(CI.getPreprocessorPtr()); + + if (SKData) { + auto *PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager()); + PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); + ParsedLocsTracker = + std::make_unique<ParsedSrcLocationsTracker>(*SKData, *PPRec, PP); + } + + std::vector<std::unique_ptr<ASTConsumer>> Consumers; + Consumers.push_back(std::make_unique<IndexingConsumer>( + *DataConsumer, ParsedLocsTracker.get())); + Consumers.push_back(createIndexingASTConsumer( + DataConsumer, Opts, CI.getPreprocessorPtr(), + [this](const Decl *D) { return this->shouldSkipFunctionBody(D); })); + return std::make_unique<MultiplexConsumer>(std::move(Consumers)); + } + + bool shouldSkipFunctionBody(const Decl *D) { + if (!ParsedLocsTracker) { + // Always skip bodies. + return true; + } + + const SourceManager &SM = D->getASTContext().getSourceManager(); + SourceLocation Loc = D->getLocation(); + if (Loc.isMacroID()) + return false; + if (SM.isInSystemHeader(Loc)) + return true; // always skip bodies from system headers. + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + // Don't skip bodies from main files; this may be revisited. + if (SM.getMainFileID() == FID) + return false; + const FileEntry *FE = SM.getFileEntryForID(FID); + if (!FE) + return false; + + return ParsedLocsTracker->hasAlredyBeenParsed(Loc, FID, FE); + } + + TranslationUnitKind getTranslationUnitKind() override { + if (DataConsumer->shouldIndexImplicitTemplateInsts()) + return TU_Complete; + else + return TU_Prefix; + } + bool hasCodeCompletionSupport() const override { return false; } + + void EndSourceFileAction() override { + if (ParsedLocsTracker) + ParsedLocsTracker->syncWithStorage(); + } +}; + +//===----------------------------------------------------------------------===// +// clang_indexSourceFileUnit Implementation +//===----------------------------------------------------------------------===// + +static IndexingOptions getIndexingOptionsFromCXOptions(unsigned index_options) { + IndexingOptions IdxOpts; + if (index_options & CXIndexOpt_IndexFunctionLocalSymbols) + IdxOpts.IndexFunctionLocals = true; + if (index_options & CXIndexOpt_IndexImplicitTemplateInstantiations) + IdxOpts.IndexImplicitInstantiation = true; + return IdxOpts; +} + +struct IndexSessionData { + CXIndex CIdx; + std::unique_ptr<ThreadSafeParsedRegions> SkipBodyData = + std::make_unique<ThreadSafeParsedRegions>(); + + explicit IndexSessionData(CXIndex cIdx) : CIdx(cIdx) {} +}; + +} // anonymous namespace + +static CXErrorCode clang_indexSourceFile_Impl( + CXIndexAction cxIdxAction, CXClientData client_data, + IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, + unsigned index_options, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU, + unsigned TU_options) { + if (out_TU) + *out_TU = nullptr; + bool requestedToGetTU = (out_TU != nullptr); + + if (!cxIdxAction) { + return CXError_InvalidArguments; + } + if (!client_index_callbacks || index_callbacks_size == 0) { + return CXError_InvalidArguments; + } + + IndexerCallbacks CB; + memset(&CB, 0, sizeof(CB)); + unsigned ClientCBSize = index_callbacks_size < sizeof(CB) + ? index_callbacks_size : sizeof(CB); + memcpy(&CB, client_index_callbacks, ClientCBSize); + + IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction); + CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx); + + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::All; + if (TU_options & CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles) + CaptureDiagnostics = CaptureDiagsKind::AllWithoutNonErrorsFromIncludes; + if (Logger::isLoggingEnabled()) + CaptureDiagnostics = CaptureDiagsKind::None; + + CaptureDiagnosticConsumer *CaptureDiag = nullptr; + if (CaptureDiagnostics != CaptureDiagsKind::None) + CaptureDiag = new CaptureDiagnosticConsumer(); + + // Configure the diagnostics. + IntrusiveRefCntPtr<DiagnosticsEngine> + Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions, + CaptureDiag, + /*ShouldOwnClient=*/true)); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine, + llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > + DiagCleanup(Diags.get()); + + std::unique_ptr<std::vector<const char *>> Args( + new std::vector<const char *>()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> > + ArgsCleanup(Args.get()); + + Args->insert(Args->end(), command_line_args, + command_line_args + num_command_line_args); + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + // Put the source file after command_line_args otherwise if '-x' flag is + // present it will be unused. + if (source_filename) + Args->push_back(source_filename); + + std::shared_ptr<CompilerInvocation> CInvok = + createInvocationFromCommandLine(*Args, Diags); + + if (!CInvok) + return CXError_Failure; + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar< + std::shared_ptr<CompilerInvocation>, + llvm::CrashRecoveryContextDestructorCleanup< + std::shared_ptr<CompilerInvocation>>> + CInvokCleanup(&CInvok); + + if (CInvok->getFrontendOpts().Inputs.empty()) + return CXError_Failure; + + typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner; + std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup( + BufOwner.get()); + + for (auto &UF : unsaved_files) { + std::unique_ptr<llvm::MemoryBuffer> MB = + llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); + CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get()); + BufOwner->push_back(std::move(MB)); + } + + // Since libclang is primarily used by batch tools dealing with + // (often very broken) source code, where spell-checking can have a + // significant negative impact on performance (particularly when + // precompiled headers are involved), we disable it. + CInvok->getLangOpts()->SpellChecking = false; + + if (index_options & CXIndexOpt_SuppressWarnings) + CInvok->getDiagnosticOpts().IgnoreWarnings = true; + + // Make sure to use the raw module format. + CInvok->getHeaderSearchOpts().ModuleFormat = std::string( + CXXIdx->getPCHContainerOperations()->getRawReader().getFormat()); + + auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics, + /*UserFilesAreVolatile=*/true); + if (!Unit) + return CXError_InvalidArguments; + + auto *UPtr = Unit.get(); + std::unique_ptr<CXTUOwner> CXTU( + new CXTUOwner(MakeCXTranslationUnit(CXXIdx, std::move(Unit)))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner> + CXTUCleanup(CXTU.get()); + + // Enable the skip-parsed-bodies optimization only for C++; this may be + // revisited. + bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) && + CInvok->getLangOpts()->CPlusPlus; + if (SkipBodies) + CInvok->getFrontendOpts().SkipFunctionBodies = true; + + auto DataConsumer = + std::make_shared<CXIndexDataConsumer>(client_data, CB, index_options, + CXTU->getTU()); + auto IndexAction = std::make_unique<IndexingFrontendAction>( + DataConsumer, getIndexingOptionsFromCXOptions(index_options), + SkipBodies ? IdxSession->SkipBodyData.get() : nullptr); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<FrontendAction> + IndexActionCleanup(IndexAction.get()); + + bool Persistent = requestedToGetTU; + bool OnlyLocalDecls = false; + bool PrecompilePreamble = false; + bool CreatePreambleOnFirstParse = false; + bool CacheCodeCompletionResults = false; + PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); + PPOpts.AllowPCHWithCompilerErrors = true; + + if (requestedToGetTU) { + OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); + PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; + CreatePreambleOnFirstParse = + TU_options & CXTranslationUnit_CreatePreambleOnFirstParse; + // FIXME: Add a flag for modules. + CacheCodeCompletionResults + = TU_options & CXTranslationUnit_CacheCompletionResults; + } + + if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) { + PPOpts.DetailedRecord = true; + } + + if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) + PPOpts.DetailedRecord = false; + + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; + DiagnosticErrorTrap DiagTrap(*Diags); + bool Success = ASTUnit::LoadFromCompilerInvocationAction( + std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags, + IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(), + OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses, + CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true); + if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(UPtr); + + if (isASTReadError(UPtr)) + return CXError_ASTReadError; + + if (!Success) + return CXError_Failure; + + if (out_TU) + *out_TU = CXTU->takeTU(); + + return CXError_Success; +} + +//===----------------------------------------------------------------------===// +// clang_indexTranslationUnit Implementation +//===----------------------------------------------------------------------===// + +static void indexPreprocessingRecord(ASTUnit &Unit, CXIndexDataConsumer &IdxCtx) { + Preprocessor &PP = Unit.getPreprocessor(); + if (!PP.getPreprocessingRecord()) + return; + + // FIXME: Only deserialize inclusion directives. + + bool isModuleFile = Unit.isModuleFile(); + for (PreprocessedEntity *PPE : Unit.getLocalPreprocessingEntities()) { + if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) { + SourceLocation Loc = ID->getSourceRange().getBegin(); + // Modules have synthetic main files as input, give an invalid location + // if the location points to such a file. + if (isModuleFile && Unit.isInMainFileID(Loc)) + Loc = SourceLocation(); + IdxCtx.ppIncludedFile(Loc, ID->getFileName(), + ID->getFile(), + ID->getKind() == InclusionDirective::Import, + !ID->wasInQuotes(), ID->importedModule()); + } + } +} + +static CXErrorCode clang_indexTranslationUnit_Impl( + CXIndexAction idxAction, CXClientData client_data, + IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, + unsigned index_options, CXTranslationUnit TU) { + // Check arguments. + if (isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return CXError_InvalidArguments; + } + if (!client_index_callbacks || index_callbacks_size == 0) { + return CXError_InvalidArguments; + } + + CIndexer *CXXIdx = TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + IndexerCallbacks CB; + memset(&CB, 0, sizeof(CB)); + unsigned ClientCBSize = index_callbacks_size < sizeof(CB) + ? index_callbacks_size : sizeof(CB); + memcpy(&CB, client_index_callbacks, ClientCBSize); + + CXIndexDataConsumer DataConsumer(client_data, CB, index_options, TU); + + ASTUnit *Unit = cxtu::getASTUnit(TU); + if (!Unit) + return CXError_Failure; + + ASTUnit::ConcurrencyCheck Check(*Unit); + + if (const FileEntry *PCHFile = Unit->getPCHFile()) + DataConsumer.importedPCH(PCHFile); + + FileManager &FileMgr = Unit->getFileManager(); + + if (Unit->getOriginalSourceFileName().empty()) + DataConsumer.enteredMainFile(nullptr); + else if (auto MainFile = FileMgr.getFile(Unit->getOriginalSourceFileName())) + DataConsumer.enteredMainFile(*MainFile); + else + DataConsumer.enteredMainFile(nullptr); + + DataConsumer.setASTContext(Unit->getASTContext()); + DataConsumer.startedTranslationUnit(); + + indexPreprocessingRecord(*Unit, DataConsumer); + indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options)); + DataConsumer.indexDiagnostics(); + + return CXError_Success; +} + +//===----------------------------------------------------------------------===// +// libclang public APIs. +//===----------------------------------------------------------------------===// + +int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) { + return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory; +} + +const CXIdxObjCContainerDeclInfo * +clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCContainerDeclInfo * + ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI)) + return &ContInfo->ObjCContDeclInfo; + + return nullptr; +} + +const CXIdxObjCInterfaceDeclInfo * +clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) + return &InterInfo->ObjCInterDeclInfo; + + return nullptr; +} + +const CXIdxObjCCategoryDeclInfo * +clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){ + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCCategoryDeclInfo * + CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) + return &CatInfo->ObjCCatDeclInfo; + + return nullptr; +} + +const CXIdxObjCProtocolRefListInfo * +clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI)) + return InterInfo->ObjCInterDeclInfo.protocols; + + if (const ObjCProtocolDeclInfo * + ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI)) + return &ProtInfo->ObjCProtoRefListInfo; + + if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI)) + return CatInfo->ObjCCatDeclInfo.protocols; + + return nullptr; +} + +const CXIdxObjCPropertyDeclInfo * +clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI)) + return &PropInfo->ObjCPropDeclInfo; + + return nullptr; +} + +const CXIdxIBOutletCollectionAttrInfo * +clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) { + if (!AInfo) + return nullptr; + + const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo); + if (const IBOutletCollectionInfo * + IBInfo = dyn_cast<IBOutletCollectionInfo>(DI)) + return &IBInfo->IBCollInfo; + + return nullptr; +} + +const CXIdxCXXClassDeclInfo * +clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return nullptr; + + const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo); + if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI)) + return &ClassInfo->CXXClassInfo; + + return nullptr; +} + +CXIdxClientContainer +clang_index_getClientContainer(const CXIdxContainerInfo *info) { + if (!info) + return nullptr; + const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); + return Container->IndexCtx->getClientContainerForDC(Container->DC); +} + +void clang_index_setClientContainer(const CXIdxContainerInfo *info, + CXIdxClientContainer client) { + if (!info) + return; + const ContainerInfo *Container = static_cast<const ContainerInfo *>(info); + Container->IndexCtx->addContainerInMap(Container->DC, client); +} + +CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) { + if (!info) + return nullptr; + const EntityInfo *Entity = static_cast<const EntityInfo *>(info); + return Entity->IndexCtx->getClientEntity(Entity->Dcl); +} + +void clang_index_setClientEntity(const CXIdxEntityInfo *info, + CXIdxClientEntity client) { + if (!info) + return; + const EntityInfo *Entity = static_cast<const EntityInfo *>(info); + Entity->IndexCtx->setClientEntity(Entity->Dcl, client); +} + +CXIndexAction clang_IndexAction_create(CXIndex CIdx) { + return new IndexSessionData(CIdx); +} + +void clang_IndexAction_dispose(CXIndexAction idxAction) { + if (idxAction) + delete static_cast<IndexSessionData *>(idxAction); +} + +int clang_indexSourceFile(CXIndexAction idxAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + CXTranslationUnit *out_TU, + unsigned TU_options) { + SmallVector<const char *, 4> Args; + Args.push_back("clang"); + Args.append(command_line_args, command_line_args + num_command_line_args); + return clang_indexSourceFileFullArgv( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, source_filename, Args.data(), Args.size(), unsaved_files, + num_unsaved_files, out_TU, TU_options); +} + +int clang_indexSourceFileFullArgv( + CXIndexAction idxAction, CXClientData client_data, + IndexerCallbacks *index_callbacks, unsigned index_callbacks_size, + unsigned index_options, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + CXTranslationUnit *out_TU, unsigned TU_options) { + LOG_FUNC_SECTION { + *Log << source_filename << ": "; + for (int i = 0; i != num_command_line_args; ++i) + *Log << command_line_args[i] << " "; + } + + if (num_unsaved_files && !unsaved_files) + return CXError_InvalidArguments; + + CXErrorCode result = CXError_Failure; + auto IndexSourceFileImpl = [=, &result]() { + result = clang_indexSourceFile_Impl( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, source_filename, command_line_args, + num_command_line_args, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), out_TU, + TU_options); + }; + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, IndexSourceFileImpl)) { + fprintf(stderr, "libclang: crash detected during indexing source file: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", TU_options); + fprintf(stderr, "}\n"); + + return 1; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + if (out_TU) + PrintLibclangResourceUsage(*out_TU); + } + + return result; +} + +int clang_indexTranslationUnit(CXIndexAction idxAction, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + CXTranslationUnit TU) { + LOG_FUNC_SECTION { + *Log << TU; + } + + CXErrorCode result; + auto IndexTranslationUnitImpl = [=, &result]() { + result = clang_indexTranslationUnit_Impl( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, TU); + }; + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, IndexTranslationUnitImpl)) { + fprintf(stderr, "libclang: crash detected during indexing TU\n"); + + return 1; + } + + return result; +} + +void clang_indexLoc_getFileLocation(CXIdxLoc location, + CXIdxClientFile *indexFile, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (indexFile) *indexFile = nullptr; + if (file) *file = nullptr; + if (line) *line = 0; + if (column) *column = 0; + if (offset) *offset = 0; + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return; + + CXIndexDataConsumer &DataConsumer = + *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]); + DataConsumer.translateLoc(Loc, indexFile, file, line, column, offset); +} + +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return clang_getNullLocation(); + + CXIndexDataConsumer &DataConsumer = + *static_cast<CXIndexDataConsumer*>(location.ptr_data[0]); + return cxloc::translateSourceLocation(DataConsumer.getASTContext(), Loc); +} diff --git a/contrib/libs/clang14/tools/libclang/Rewrite.cpp b/contrib/libs/clang14/tools/libclang/Rewrite.cpp new file mode 100644 index 0000000000..389232d97a --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/Rewrite.cpp @@ -0,0 +1,63 @@ +//===- Rewrite.cpp --------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "clang-c/Rewrite.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Rewrite/Core/Rewriter.h" + +CXRewriter clang_CXRewriter_create(CXTranslationUnit TU) { + if (clang::cxtu::isNotUsableTU(TU)) { + LOG_BAD_TU(TU); + return {}; + } + clang::ASTUnit *AU = clang::cxtu::getASTUnit(TU); + assert(AU); + return reinterpret_cast<CXRewriter>( + new clang::Rewriter(AU->getSourceManager(), AU->getLangOpts())); +} + +void clang_CXRewriter_insertTextBefore(CXRewriter Rew, CXSourceLocation Loc, + const char *Insert) { + assert(Rew); + clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew); + R.InsertTextBefore(clang::cxloc::translateSourceLocation(Loc), Insert); +} + +void clang_CXRewriter_replaceText(CXRewriter Rew, CXSourceRange ToBeReplaced, + const char *Replacement) { + assert(Rew); + clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew); + R.ReplaceText(clang::cxloc::translateCXRangeToCharRange(ToBeReplaced), + Replacement); +} + +void clang_CXRewriter_removeText(CXRewriter Rew, CXSourceRange ToBeRemoved) { + assert(Rew); + clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew); + R.RemoveText(clang::cxloc::translateCXRangeToCharRange(ToBeRemoved)); +} + +int clang_CXRewriter_overwriteChangedFiles(CXRewriter Rew) { + assert(Rew); + clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew); + return R.overwriteChangedFiles(); +} + +void clang_CXRewriter_writeMainFileToStdOut(CXRewriter Rew) { + assert(Rew); + clang::Rewriter &R = *reinterpret_cast<clang::Rewriter *>(Rew); + R.getEditBuffer(R.getSourceMgr().getMainFileID()).write(llvm::outs()); +} + +void clang_CXRewriter_dispose(CXRewriter Rew) { + if (Rew) + delete reinterpret_cast<clang::Rewriter *>(Rew); +} diff --git a/contrib/libs/clang14/tools/libclang/dynamic/ya.make b/contrib/libs/clang14/tools/libclang/dynamic/ya.make new file mode 100644 index 0000000000..04a7fdf688 --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/dynamic/ya.make @@ -0,0 +1,3 @@ +# Generated by devtools/yamaker. + +DLL_FOR(contrib/libs/clang14/tools/libclang clang EXPORTS ../libclang-generic.exports) diff --git a/contrib/libs/clang14/tools/libclang/libclang-generic.exports b/contrib/libs/clang14/tools/libclang/libclang-generic.exports new file mode 100644 index 0000000000..639d13d21d --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/libclang-generic.exports @@ -0,0 +1,395 @@ +clang_BlockCommandComment_getArgText +clang_BlockCommandComment_getCommandName +clang_BlockCommandComment_getNumArgs +clang_BlockCommandComment_getParagraph +clang_CXCursorSet_contains +clang_CXCursorSet_insert +clang_CXIndex_getGlobalOptions +clang_CXIndex_setGlobalOptions +clang_CXIndex_setInvocationEmissionPathOption +clang_CXRewriter_create +clang_CXRewriter_dispose +clang_CXRewriter_insertTextBefore +clang_CXRewriter_overwriteChangedFiles +clang_CXRewriter_removeText +clang_CXRewriter_replaceText +clang_CXRewriter_writeMainFileToStdOut +clang_CXXConstructor_isConvertingConstructor +clang_CXXConstructor_isCopyConstructor +clang_CXXConstructor_isDefaultConstructor +clang_CXXConstructor_isMoveConstructor +clang_CXXField_isMutable +clang_CXXMethod_isConst +clang_CXXMethod_isDefaulted +clang_CXXMethod_isPureVirtual +clang_CXXMethod_isStatic +clang_CXXMethod_isVirtual +clang_CXXRecord_isAbstract +clang_Comment_getChild +clang_Comment_getKind +clang_Comment_getNumChildren +clang_Comment_isWhitespace +clang_CompilationDatabase_dispose +clang_CompilationDatabase_fromDirectory +clang_CompilationDatabase_getAllCompileCommands +clang_CompilationDatabase_getCompileCommands +clang_CompileCommand_getArg +clang_CompileCommand_getDirectory +clang_CompileCommand_getFilename +clang_CompileCommand_getMappedSourceContent +clang_CompileCommand_getMappedSourcePath +clang_CompileCommand_getNumArgs +clang_CompileCommand_getNumMappedSources +clang_CompileCommands_dispose +clang_CompileCommands_getCommand +clang_CompileCommands_getSize +clang_Cursor_Evaluate +clang_Cursor_getArgument +clang_Cursor_getBriefCommentText +clang_Cursor_getCXXManglings +clang_Cursor_getCommentRange +clang_Cursor_getMangling +clang_Cursor_getModule +clang_Cursor_getNumArguments +clang_Cursor_getNumTemplateArguments +clang_Cursor_getObjCDeclQualifiers +clang_Cursor_getObjCManglings +clang_Cursor_getObjCPropertyAttributes +clang_Cursor_getObjCPropertyGetterName +clang_Cursor_getObjCPropertySetterName +clang_Cursor_getObjCSelectorIndex +clang_Cursor_getOffsetOfField +clang_Cursor_getParsedComment +clang_Cursor_getRawCommentText +clang_Cursor_getReceiverType +clang_Cursor_getSpellingNameRange +clang_Cursor_getStorageClass +clang_Cursor_getTemplateArgumentKind +clang_Cursor_getTemplateArgumentType +clang_Cursor_getTemplateArgumentUnsignedValue +clang_Cursor_getTemplateArgumentValue +clang_Cursor_getTranslationUnit +clang_Cursor_getVarDeclInitializer +clang_Cursor_hasAttrs +clang_Cursor_hasVarDeclExternalStorage +clang_Cursor_hasVarDeclGlobalStorage +clang_Cursor_isAnonymous +clang_Cursor_isAnonymousRecordDecl +clang_Cursor_isBitField +clang_Cursor_isDynamicCall +clang_Cursor_isExternalSymbol +clang_Cursor_isFunctionInlined +clang_Cursor_isInlineNamespace +clang_Cursor_isMacroBuiltin +clang_Cursor_isMacroFunctionLike +clang_Cursor_isNull +clang_Cursor_isObjCOptional +clang_Cursor_isVariadic +clang_EnumDecl_isScoped +clang_EvalResult_dispose +clang_EvalResult_getAsDouble +clang_EvalResult_getAsInt +clang_EvalResult_getAsLongLong +clang_EvalResult_getAsStr +clang_EvalResult_getAsUnsigned +clang_EvalResult_getKind +clang_EvalResult_isUnsignedInt +clang_File_isEqual +clang_File_tryGetRealPathName +clang_FullComment_getAsHTML +clang_FullComment_getAsXML +clang_HTMLStartTagComment_isSelfClosing +clang_HTMLStartTag_getAttrName +clang_HTMLStartTag_getAttrValue +clang_HTMLStartTag_getNumAttrs +clang_HTMLTagComment_getAsString +clang_HTMLTagComment_getTagName +clang_IndexAction_create +clang_IndexAction_dispose +clang_InlineCommandComment_getArgText +clang_InlineCommandComment_getCommandName +clang_InlineCommandComment_getNumArgs +clang_InlineCommandComment_getRenderKind +clang_InlineContentComment_hasTrailingNewline +clang_Location_isFromMainFile +clang_Location_isInSystemHeader +clang_ModuleMapDescriptor_create +clang_ModuleMapDescriptor_dispose +clang_ModuleMapDescriptor_setFrameworkModuleName +clang_ModuleMapDescriptor_setUmbrellaHeader +clang_ModuleMapDescriptor_writeToBuffer +clang_Module_getASTFile +clang_Module_getFullName +clang_Module_getName +clang_Module_getNumTopLevelHeaders +clang_Module_getParent +clang_Module_getTopLevelHeader +clang_Module_isSystem +clang_ParamCommandComment_getDirection +clang_ParamCommandComment_getParamIndex +clang_ParamCommandComment_getParamName +clang_ParamCommandComment_isDirectionExplicit +clang_ParamCommandComment_isParamIndexValid +clang_PrintingPolicy_dispose +clang_PrintingPolicy_getProperty +clang_PrintingPolicy_setProperty +clang_Range_isNull +clang_TParamCommandComment_getDepth +clang_TParamCommandComment_getIndex +clang_TParamCommandComment_getParamName +clang_TParamCommandComment_isParamPositionValid +clang_TargetInfo_dispose +clang_TargetInfo_getPointerWidth +clang_TargetInfo_getTriple +clang_TextComment_getText +clang_Type_getAlignOf +clang_Type_getCXXRefQualifier +clang_Type_getClassType +clang_Type_getModifiedType +clang_Type_getNamedType +clang_Type_getNullability +clang_Type_getNumObjCProtocolRefs +clang_Type_getNumObjCTypeArgs +clang_Type_getNumTemplateArguments +clang_Type_getObjCEncoding +clang_Type_getObjCObjectBaseType +clang_Type_getObjCProtocolDecl +clang_Type_getObjCTypeArg +clang_Type_getOffsetOf +clang_Type_getSizeOf +clang_Type_getTemplateArgumentAsType +clang_Type_getValueType +clang_Type_isTransparentTagTypedef +clang_Type_visitFields +clang_VerbatimBlockLineComment_getText +clang_VerbatimLineComment_getText +clang_VirtualFileOverlay_addFileMapping +clang_VirtualFileOverlay_create +clang_VirtualFileOverlay_dispose +clang_VirtualFileOverlay_setCaseSensitivity +clang_VirtualFileOverlay_writeToBuffer +clang_annotateTokens +clang_codeCompleteAt +clang_codeCompleteGetContainerKind +clang_codeCompleteGetContainerUSR +clang_codeCompleteGetContexts +clang_codeCompleteGetDiagnostic +clang_codeCompleteGetNumDiagnostics +clang_codeCompleteGetObjCSelector +clang_constructUSR_ObjCCategory +clang_constructUSR_ObjCClass +clang_constructUSR_ObjCIvar +clang_constructUSR_ObjCMethod +clang_constructUSR_ObjCProperty +clang_constructUSR_ObjCProtocol +clang_createCXCursorSet +clang_createIndex +clang_createTranslationUnit +clang_createTranslationUnit2 +clang_createTranslationUnitFromSourceFile +clang_defaultCodeCompleteOptions +clang_defaultDiagnosticDisplayOptions +clang_defaultEditingTranslationUnitOptions +clang_defaultReparseOptions +clang_defaultSaveOptions +clang_disposeCXCursorSet +clang_disposeCXPlatformAvailability +clang_disposeCXTUResourceUsage +clang_disposeCodeCompleteResults +clang_disposeDiagnostic +clang_disposeDiagnosticSet +clang_disposeIndex +clang_disposeOverriddenCursors +clang_disposeSourceRangeList +clang_disposeString +clang_disposeStringSet +clang_disposeTokens +clang_disposeTranslationUnit +clang_enableStackTraces +clang_equalCursors +clang_equalLocations +clang_equalRanges +clang_equalTypes +clang_executeOnThread +clang_findIncludesInFile +clang_findIncludesInFileWithBlock +clang_findReferencesInFile +clang_findReferencesInFileWithBlock +clang_formatDiagnostic +clang_free +clang_getAddressSpace +clang_getAllSkippedRanges +clang_getArgType +clang_getArrayElementType +clang_getArraySize +clang_getBuildSessionTimestamp +clang_getCString +clang_getCXTUResourceUsage +clang_getCXXAccessSpecifier +clang_getCanonicalCursor +clang_getCanonicalType +clang_getChildDiagnostics +clang_getClangVersion +clang_getCompletionAnnotation +clang_getCompletionAvailability +clang_getCompletionBriefComment +clang_getCompletionChunkCompletionString +clang_getCompletionChunkKind +clang_getCompletionChunkText +clang_getCompletionFixIt +clang_getCompletionNumAnnotations +clang_getCompletionNumFixIts +clang_getCompletionParent +clang_getCompletionPriority +clang_getCursor +clang_getCursorAvailability +clang_getCursorCompletionString +clang_getCursorDefinition +clang_getCursorDisplayName +clang_getCursorExceptionSpecificationType +clang_getCursorExtent +clang_getCursorKind +clang_getCursorKindSpelling +clang_getCursorLanguage +clang_getCursorLexicalParent +clang_getCursorLinkage +clang_getCursorLocation +clang_getCursorPlatformAvailability +clang_getCursorPrettyPrinted +clang_getCursorPrintingPolicy +clang_getCursorReferenceNameRange +clang_getCursorReferenced +clang_getCursorResultType +clang_getCursorSemanticParent +clang_getCursorSpelling +clang_getCursorTLSKind +clang_getCursorType +clang_getCursorUSR +clang_getCursorVisibility +clang_getDeclObjCTypeEncoding +clang_getDefinitionSpellingAndExtent +clang_getDiagnostic +clang_getDiagnosticCategory +clang_getDiagnosticCategoryName +clang_getDiagnosticCategoryText +clang_getDiagnosticFixIt +clang_getDiagnosticInSet +clang_getDiagnosticLocation +clang_getDiagnosticNumFixIts +clang_getDiagnosticNumRanges +clang_getDiagnosticOption +clang_getDiagnosticRange +clang_getDiagnosticSetFromTU +clang_getDiagnosticSeverity +clang_getDiagnosticSpelling +clang_getElementType +clang_getEnumConstantDeclUnsignedValue +clang_getEnumConstantDeclValue +clang_getEnumDeclIntegerType +clang_getExceptionSpecificationType +clang_getExpansionLocation +clang_getFieldDeclBitWidth +clang_getFile +clang_getFileContents +clang_getFileLocation +clang_getFileName +clang_getFileTime +clang_getFileUniqueID +clang_getFunctionTypeCallingConv +clang_getIBOutletCollectionType +clang_getIncludedFile +clang_getInclusions +clang_getInstantiationLocation +clang_getLocation +clang_getLocationForOffset +clang_getModuleForFile +clang_getNullCursor +clang_getNullLocation +clang_getNullRange +clang_getNumArgTypes +clang_getNumCompletionChunks +clang_getNumDiagnostics +clang_getNumDiagnosticsInSet +clang_getNumElements +clang_getNumOverloadedDecls +clang_getOverloadedDecl +clang_getOverriddenCursors +clang_getPointeeType +clang_getPresumedLocation +clang_getRange +clang_getRangeEnd +clang_getRangeStart +clang_getRemappings +clang_getRemappingsFromFileList +clang_getResultType +clang_getSkippedRanges +clang_getSpecializedCursorTemplate +clang_getSpellingLocation +clang_getTUResourceUsageName +clang_getTemplateCursorKind +clang_getToken +clang_getTokenExtent +clang_getTokenKind +clang_getTokenLocation +clang_getTokenSpelling +clang_getTranslationUnitCursor +clang_getTranslationUnitSpelling +clang_getTranslationUnitTargetInfo +clang_getTypeDeclaration +clang_getTypeKindSpelling +clang_getTypeSpelling +clang_getTypedefDeclUnderlyingType +clang_getTypedefName +clang_hashCursor +clang_indexLoc_getCXSourceLocation +clang_indexLoc_getFileLocation +clang_indexSourceFile +clang_indexSourceFileFullArgv +clang_indexTranslationUnit +clang_index_getCXXClassDeclInfo +clang_index_getClientContainer +clang_index_getClientEntity +clang_index_getIBOutletCollectionAttrInfo +clang_index_getObjCCategoryDeclInfo +clang_index_getObjCContainerDeclInfo +clang_index_getObjCInterfaceDeclInfo +clang_index_getObjCPropertyDeclInfo +clang_index_getObjCProtocolRefListInfo +clang_index_isEntityObjCContainerKind +clang_index_setClientContainer +clang_index_setClientEntity +clang_install_aborting_llvm_fatal_error_handler +clang_isAttribute +clang_isConstQualifiedType +clang_isCursorDefinition +clang_isDeclaration +clang_isExpression +clang_isFileMultipleIncludeGuarded +clang_isFunctionTypeVariadic +clang_isInvalid +clang_isInvalidDeclaration +clang_isPODType +clang_isPreprocessing +clang_isReference +clang_isRestrictQualifiedType +clang_isStatement +clang_isTranslationUnit +clang_isUnexposed +clang_isVirtualBase +clang_isVolatileQualifiedType +clang_loadDiagnostics +clang_parseTranslationUnit +clang_parseTranslationUnit2 +clang_parseTranslationUnit2FullArgv +clang_remap_dispose +clang_remap_getFilenames +clang_remap_getNumFiles +clang_reparseTranslationUnit +clang_saveTranslationUnit +clang_sortCodeCompletionResults +clang_suspendTranslationUnit +clang_toggleCrashRecovery +clang_tokenize +clang_uninstall_llvm_fatal_error_handler +clang_visitChildren +clang_visitChildrenWithBlock diff --git a/contrib/libs/clang14/tools/libclang/ya.make b/contrib/libs/clang14/tools/libclang/ya.make new file mode 100644 index 0000000000..3377a83c1d --- /dev/null +++ b/contrib/libs/clang14/tools/libclang/ya.make @@ -0,0 +1,87 @@ +# Generated by devtools/yamaker. + +LIBRARY() + +LICENSE(Apache-2.0 WITH LLVM-exception) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +PEERDIR( + contrib/libs/clang14 + contrib/libs/clang14/include + contrib/libs/clang14/lib/ARCMigrate + contrib/libs/clang14/lib/AST + contrib/libs/clang14/lib/Basic + contrib/libs/clang14/lib/Driver + contrib/libs/clang14/lib/Frontend + contrib/libs/clang14/lib/Index + contrib/libs/clang14/lib/Lex + contrib/libs/clang14/lib/Rewrite + contrib/libs/clang14/lib/Sema + contrib/libs/clang14/lib/Serialization + contrib/libs/clang14/lib/Tooling + contrib/libs/llvm14 + contrib/libs/llvm14/lib/Support + contrib/libs/llvm14/lib/Target/AArch64 + contrib/libs/llvm14/lib/Target/AArch64/AsmParser + contrib/libs/llvm14/lib/Target/AArch64/MCTargetDesc + contrib/libs/llvm14/lib/Target/AArch64/TargetInfo + contrib/libs/llvm14/lib/Target/ARM + contrib/libs/llvm14/lib/Target/ARM/AsmParser + contrib/libs/llvm14/lib/Target/ARM/MCTargetDesc + contrib/libs/llvm14/lib/Target/ARM/TargetInfo + contrib/libs/llvm14/lib/Target/BPF + contrib/libs/llvm14/lib/Target/BPF/AsmParser + contrib/libs/llvm14/lib/Target/BPF/MCTargetDesc + contrib/libs/llvm14/lib/Target/BPF/TargetInfo + contrib/libs/llvm14/lib/Target/NVPTX + contrib/libs/llvm14/lib/Target/NVPTX/MCTargetDesc + contrib/libs/llvm14/lib/Target/NVPTX/TargetInfo + contrib/libs/llvm14/lib/Target/PowerPC + contrib/libs/llvm14/lib/Target/PowerPC/AsmParser + contrib/libs/llvm14/lib/Target/PowerPC/MCTargetDesc + contrib/libs/llvm14/lib/Target/PowerPC/TargetInfo + contrib/libs/llvm14/lib/Target/X86 + contrib/libs/llvm14/lib/Target/X86/AsmParser + contrib/libs/llvm14/lib/Target/X86/MCTargetDesc + contrib/libs/llvm14/lib/Target/X86/TargetInfo +) + +ADDINCL( + contrib/libs/clang14/tools/libclang +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +CFLAGS( + -D_CINDEX_LIB_ +) + +SRCS( + ARCMigrate.cpp + BuildSystem.cpp + CIndex.cpp + CIndexCXX.cpp + CIndexCodeCompletion.cpp + CIndexDiagnostic.cpp + CIndexHigh.cpp + CIndexInclusionStack.cpp + CIndexUSRs.cpp + CIndexer.cpp + CXComment.cpp + CXCompilationDatabase.cpp + CXCursor.cpp + CXIndexDataConsumer.cpp + CXLoadedDiagnostic.cpp + CXSourceLocation.cpp + CXStoredDiagnostic.cpp + CXString.cpp + CXType.cpp + FatalErrorHandler.cpp + Indexing.cpp + Rewrite.cpp +) + +END() |