blob: 5d43692c2c748eff2ed4dcf50f9dd6967514c14d [file] [log] [blame]
//===--- Index.cpp --------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Index/Index.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Comment.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/Types.h"
#include "swift/AST/USRGeneration.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/StringExtras.h"
#include "swift/IDE/SourceEntityWalker.h"
#include "swift/Markup/Markup.h"
#include "swift/Sema/IDETypeChecking.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include <tuple>
using namespace swift;
using namespace swift::index;
static bool
printArtificialName(const swift::AbstractStorageDecl *ASD, AccessorKind AK, llvm::raw_ostream &OS) {
switch (AK) {
case AccessorKind::Get:
OS << "getter:" << ASD->getFullName();
return false;
case AccessorKind::Set:
OS << "setter:" << ASD->getFullName();
return false;
case AccessorKind::DidSet:
OS << "didSet:" << ASD->getFullName();
return false;
case AccessorKind::WillSet:
OS << "willSet:" << ASD->getFullName() ;
return false;
case AccessorKind::Address:
case AccessorKind::MutableAddress:
case AccessorKind::Read:
case AccessorKind::Modify:
return true;
}
llvm_unreachable("Unhandled AccessorKind in switch.");
}
static bool printDisplayName(const swift::ValueDecl *D, llvm::raw_ostream &OS) {
if (!D->hasName() && !isa<ParamDecl>(D)) {
auto *FD = dyn_cast<AccessorDecl>(D);
if (!FD)
return true;
return printArtificialName(FD->getStorage(), FD->getAccessorKind(), OS);
}
OS << D->getFullName();
return false;
}
static bool isMemberwiseInit(swift::ValueDecl *D) {
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D))
return AFD->getBodyKind() == AbstractFunctionDecl::BodyKind::MemberwiseInitializer;
return false;
}
static SourceLoc getLocForExtension(ExtensionDecl *D) {
// Use the 'End' token of the range, in case it is a compound name, e.g.
// extension A.B {}
// we want the location of 'B' token.
if (auto *repr = D->getExtendedTypeRepr()) {
return repr->getSourceRange().End;
}
return SourceLoc();
}
namespace {
// Adapter providing a common interface for a SourceFile/Module.
class SourceFileOrModule {
llvm::PointerUnion<SourceFile *, ModuleDecl *> SFOrMod;
public:
SourceFileOrModule(SourceFile &SF) : SFOrMod(&SF) {}
SourceFileOrModule(ModuleDecl &Mod) : SFOrMod(&Mod) {}
SourceFile *getAsSourceFile() const {
return SFOrMod.dyn_cast<SourceFile *>();
}
ModuleDecl *getAsModule() const { return SFOrMod.dyn_cast<ModuleDecl *>(); }
ModuleDecl &getModule() const {
if (auto SF = SFOrMod.dyn_cast<SourceFile *>())
return *SF->getParentModule();
return *SFOrMod.get<ModuleDecl *>();
}
ArrayRef<FileUnit *> getFiles() const {
return SFOrMod.is<SourceFile *>() ? *SFOrMod.getAddrOfPtr1()
: SFOrMod.get<ModuleDecl *>()->getFiles();
}
StringRef getFilename() const {
if (auto *SF = SFOrMod.dyn_cast<SourceFile *>())
return SF->getFilename();
return SFOrMod.get<ModuleDecl *>()->getModuleFilename();
}
void
getImportedModules(SmallVectorImpl<ModuleDecl::ImportedModule> &Modules) const {
ModuleDecl::ImportFilter ImportFilter;
ImportFilter |= ModuleDecl::ImportFilterKind::Public;
ImportFilter |= ModuleDecl::ImportFilterKind::Private;
ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
if (auto *SF = SFOrMod.dyn_cast<SourceFile *>()) {
SF->getImportedModules(Modules, ImportFilter);
} else {
SFOrMod.get<ModuleDecl *>()->getImportedModules(Modules, ImportFilter);
}
}
};
struct IndexedWitness {
ValueDecl *Member;
ValueDecl *Requirement;
};
class IndexSwiftASTWalker : public SourceEntityWalker {
IndexDataConsumer &IdxConsumer;
SourceManager &SrcMgr;
unsigned BufferID;
bool enableWarnings;
bool IsModuleFile = false;
bool isSystemModule = false;
struct Entity {
Decl *D;
SymbolInfo SymInfo;
SymbolRoleSet Roles;
SmallVector<IndexedWitness, 6> ExplicitWitnesses;
SmallVector<SourceLoc, 6> RefsToSuppress;
};
SmallVector<Entity, 6> EntitiesStack;
SmallVector<Expr *, 8> ExprStack;
SmallVector<const AccessorDecl *, 4> ManuallyVisitedAccessorStack;
bool Cancelled = false;
struct NameAndUSR {
StringRef USR;
StringRef name;
};
typedef llvm::PointerIntPair<Decl *, 3> DeclAccessorPair;
llvm::DenseMap<void *, NameAndUSR> nameAndUSRCache;
llvm::DenseMap<DeclAccessorPair, NameAndUSR> accessorNameAndUSRCache;
StringScratchSpace stringStorage;
bool getNameAndUSR(ValueDecl *D, ExtensionDecl *ExtD,
StringRef &name, StringRef &USR) {
auto &result = nameAndUSRCache[ExtD ? (Decl*)ExtD : D];
if (result.USR.empty()) {
SmallString<128> storage;
{
llvm::raw_svector_ostream OS(storage);
if (ExtD) {
if (ide::printExtensionUSR(ExtD, OS))
return true;
} else {
if (ide::printValueDeclUSR(D, OS))
return true;
}
result.USR = stringStorage.copyString(OS.str());
}
storage.clear();
{
llvm::raw_svector_ostream OS(storage);
printDisplayName(D, OS);
result.name = stringStorage.copyString(OS.str());
}
}
name = result.name;
USR = result.USR;
return false;
}
bool getModuleNameAndUSR(ModuleEntity Mod, StringRef &name, StringRef &USR) {
auto &result = nameAndUSRCache[Mod.getOpaqueValue()];
if (result.USR.empty()) {
SmallString<128> storage;
{
llvm::raw_svector_ostream OS(storage);
if (ide::printModuleUSR(Mod, OS))
return true;
result.USR = stringStorage.copyString(OS.str());
}
storage.clear();
{
llvm::raw_svector_ostream OS(storage);
OS << Mod.getFullName();
result.name = stringStorage.copyString(OS.str());
}
}
name = result.name;
USR = result.USR;
return false;
}
bool getPseudoAccessorNameAndUSR(AbstractStorageDecl *D, AccessorKind AK, StringRef &Name, StringRef &USR) {
assert(static_cast<int>(AK) < 0x111 && "AccessorKind too big for pair");
DeclAccessorPair key(D, static_cast<int>(AK));
auto &result = accessorNameAndUSRCache[key];
if (result.USR.empty()) {
SmallString<128> storage;
{
llvm::raw_svector_ostream OS(storage);
if (ide::printAccessorUSR(D, AK, OS))
return true;
result.USR = stringStorage.copyString(OS.str());
}
storage.clear();
{
llvm::raw_svector_ostream OS(storage);
printArtificialName(D, AK, OS);
result.name = stringStorage.copyString(OS.str());
}
}
Name = result.name;
USR = result.USR;
return false;
}
bool addRelation(IndexSymbol &Info, SymbolRoleSet RelationRoles, Decl *D) {
assert(D);
auto Match = std::find_if(Info.Relations.begin(), Info.Relations.end(),
[D](IndexRelation R) { return R.decl == D; });
if (Match != Info.Relations.end()) {
Match->roles |= RelationRoles;
Info.roles |= RelationRoles;
return false;
}
StringRef Name, USR;
SymbolInfo SymInfo = getSymbolInfoForDecl(D);
if (SymInfo.Kind == SymbolKind::Unknown)
return true;
if (auto *ExtD = dyn_cast<ExtensionDecl>(D)) {
NominalTypeDecl *NTD = ExtD->getExtendedNominal();
if (getNameAndUSR(NTD, ExtD, Name, USR))
return true;
} else {
if (getNameAndUSR(cast<ValueDecl>(D), /*ExtD=*/nullptr, Name, USR))
return true;
}
Info.Relations.push_back(IndexRelation(RelationRoles, D, SymInfo, Name, USR));
Info.roles |= RelationRoles;
return false;
}
public:
IndexSwiftASTWalker(IndexDataConsumer &IdxConsumer, ASTContext &Ctx,
unsigned BufferID = -1)
: IdxConsumer(IdxConsumer), SrcMgr(Ctx.SourceMgr), BufferID(BufferID),
enableWarnings(IdxConsumer.enableWarnings()) {}
~IndexSwiftASTWalker() override {
assert(Cancelled || EntitiesStack.empty());
assert(Cancelled || ManuallyVisitedAccessorStack.empty());
}
void visitModule(ModuleDecl &Mod);
void visitDeclContext(DeclContext *DC);
private:
bool visitImports(SourceFileOrModule Mod,
llvm::SmallPtrSetImpl<ModuleDecl *> &Visited);
bool handleSourceOrModuleFile(SourceFileOrModule SFOrMod);
bool walkToDeclPre(Decl *D, CharSourceRange Range) override {
// Do not handle unavailable decls.
if (AvailableAttr::isUnavailable(D))
return false;
if (!handleCustomAttrInitRefs(D))
return false;
if (auto *AD = dyn_cast<AccessorDecl>(D)) {
if (ManuallyVisitedAccessorStack.empty() ||
ManuallyVisitedAccessorStack.back() != AD)
return false; // already handled as part of the var decl.
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
if (!report(VD))
return false;
}
if (auto *ED = dyn_cast<ExtensionDecl>(D))
return reportExtension(ED);
return true;
}
bool walkToDeclPost(Decl *D) override {
if (Cancelled)
return false;
if (getParentDecl() == D)
return finishCurrentEntity();
return true;
}
/// Report calls to the initializers of property wrapper types on wrapped properties.
///
/// These may be either explicit:
/// `\@Wrapper(initialialValue: 42) var x: Int`
/// or implicit:
/// `\@Wrapper var x = 10`
bool handleCustomAttrInitRefs(Decl * D) {
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
if (customAttr->isImplicit())
continue;
auto &Loc = customAttr->getTypeLoc();
if (auto *semanticInit = dyn_cast_or_null<CallExpr>(customAttr->getSemanticInit())) {
if (auto *CD = semanticInit->getCalledValue()) {
if (!shouldIndex(CD, /*IsRef*/true))
continue;
IndexSymbol Info;
if (initIndexSymbol(CD, Loc.getLoc(), /*IsRef=*/true, Info))
continue;
Info.roles |= (unsigned)SymbolRole::Call;
if (semanticInit->isImplicit())
Info.roles |= (unsigned)SymbolRole::Implicit;
if (!startEntity(CD, Info, /*IsRef=*/true) || !finishCurrentEntity())
return false;
}
}
}
return true;
}
void handleMemberwiseInitRefs(Expr *E) {
if (!isa<ConstructorRefCallExpr>(E))
return;
auto *DeclRef = dyn_cast<DeclRefExpr>(cast<ConstructorRefCallExpr>(E)->getFn());
if (!DeclRef || !isMemberwiseInit(DeclRef->getDecl()))
return;
// get label locations
auto *MemberwiseInit = DeclRef->getDecl();
std::vector<SourceLoc> LabelLocs;
ArrayRef<Identifier> Labels;
auto NameLoc = DeclRef->getNameLoc();
if (NameLoc.isCompound()) {
size_t LabelIndex = 0;
SourceLoc ArgLoc;
while ((ArgLoc = NameLoc.getArgumentLabelLoc(LabelIndex++)).isValid()) {
LabelLocs.push_back(ArgLoc);
}
Labels = MemberwiseInit->getFullName().getArgumentNames();
} else if (auto *CallParent = dyn_cast_or_null<CallExpr>(getParentExpr())) {
LabelLocs = CallParent->getArgumentLabelLocs();
Labels = CallParent->getArgumentLabels();
}
if (LabelLocs.empty())
return;
assert(Labels.size() == LabelLocs.size());
// match labels to properties
auto *TypeContext =
MemberwiseInit->getDeclContext()->getSelfNominalTypeDecl();
if (!TypeContext || !shouldIndex(TypeContext, false))
return;
unsigned CurLabel = 0;
for (auto Member : TypeContext->getMembers()) {
auto Prop = dyn_cast<VarDecl>(Member);
if (!Prop)
continue;
if (!Prop->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
continue;
if (CurLabel == LabelLocs.size())
break;
if (Labels[CurLabel] != Prop->getName())
continue;
IndexSymbol Info;
if (initIndexSymbol(Prop, LabelLocs[CurLabel++], /*IsRef=*/true, Info))
continue;
if (startEntity(Prop, Info, /*IsRef=*/true))
finishCurrentEntity();
}
}
bool walkToExprPre(Expr *E) override {
if (Cancelled)
return false;
ExprStack.push_back(E);
handleMemberwiseInitRefs(E);
return true;
}
bool walkToExprPost(Expr *E) override {
if (Cancelled)
return false;
assert(ExprStack.back() == E);
ExprStack.pop_back();
return true;
}
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type T,
ReferenceMetaData Data) override {
SourceLoc Loc = Range.getStart();
if (isRepressed(Loc) || Loc.isInvalid())
return true;
IndexSymbol Info;
if (Data.isImplicit)
Info.roles |= (unsigned)SymbolRole::Implicit;
if (CtorTyRef)
if (!reportRef(CtorTyRef, Loc, Info, Data.AccKind))
return false;
if (!reportRef(D, Loc, Info, Data.AccKind))
return false;
// If this is a reference to a property wrapper backing property or
// projected value, report a reference to the wrapped property too (i.e.
// report an occurrence of `foo` in `_foo` and '$foo').
if (auto *VD = dyn_cast<VarDecl>(D)) {
if (auto *Wrapped = VD->getOriginalWrappedProperty()) {
assert(Range.getByteLength() > 1 &&
(Range.str().front() == '_' || Range.str().front() == '$'));
auto AfterDollar = Loc.getAdvancedLoc(1);
reportRef(Wrapped, AfterDollar, Info, None);
}
}
return true;
}
bool visitModuleReference(ModuleEntity Mod, CharSourceRange Range) override {
SourceLoc Loc = Range.getStart();
if (Loc.isInvalid())
return true;
IndexSymbol Info;
std::tie(Info.line, Info.column, Info.offset) = getLineColAndOffset(Loc);
Info.roles |= (unsigned)SymbolRole::Reference;
Info.symInfo = getSymbolInfoForModule(Mod);
getModuleNameAndUSR(Mod, Info.name, Info.USR);
if (auto Container = getContainingDecl())
addRelation(Info, (unsigned)SymbolRole::RelationContainedBy, Container);
if (!IdxConsumer.startSourceEntity(Info)) {
Cancelled = true;
return true;
}
return finishSourceEntity(Info.symInfo, Info.roles);
}
Decl *getParentDecl() const {
if (!EntitiesStack.empty())
return EntitiesStack.back().D;
return nullptr;
}
Decl *getContainingDecl() const {
for (const auto &Entity: EntitiesStack) {
if (isa<AbstractFunctionDecl>(Entity.D) &&
(Entity.Roles & (SymbolRoleSet)SymbolRole::Definition)) {
return Entity.D;
}
}
return nullptr;
}
void repressRefAtLoc(SourceLoc Loc) {
if (Loc.isInvalid()) return;
assert(!EntitiesStack.empty());
EntitiesStack.back().RefsToSuppress.push_back(Loc);
}
bool isRepressed(SourceLoc Loc) const {
if (EntitiesStack.empty() || Loc.isInvalid())
return false;
auto &Suppressed = EntitiesStack.back().RefsToSuppress;
return std::find(Suppressed.begin(), Suppressed.end(), Loc) != Suppressed.end();
}
Expr *getContainingExpr(size_t index) const {
if (ExprStack.size() > index)
return ExprStack.end()[-std::ptrdiff_t(index + 1)];
return nullptr;
}
Expr *getCurrentExpr() const {
return ExprStack.empty() ? nullptr : ExprStack.back();
}
Expr *getParentExpr() const {
return getContainingExpr(1);
}
bool report(ValueDecl *D);
bool reportExtension(ExtensionDecl *D);
bool reportRef(ValueDecl *D, SourceLoc Loc, IndexSymbol &Info,
Optional<AccessKind> AccKind);
bool reportImplicitConformance(ValueDecl *witness, ValueDecl *requirement,
Decl *container);
bool startEntity(Decl *D, IndexSymbol &Info, bool IsRef);
bool startEntityDecl(ValueDecl *D);
bool reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit, SymbolRoleSet Relations, Decl *Related);
bool reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet Relations, Decl *Related);
bool reportInheritedTypeRefs(ArrayRef<TypeLoc> Inherited, Decl *Inheritee);
NominalTypeDecl *getTypeLocAsNominalTypeDecl(const TypeLoc &Ty);
bool reportPseudoGetterDecl(VarDecl *D) {
return reportPseudoAccessor(D, AccessorKind::Get, /*IsRef=*/false,
D->getLoc());
}
bool reportPseudoSetterDecl(VarDecl *D) {
return reportPseudoAccessor(D, AccessorKind::Set, /*IsRef=*/false,
D->getLoc());
}
bool reportPseudoAccessor(AbstractStorageDecl *D, AccessorKind AccKind,
bool IsRef, SourceLoc Loc);
bool finishCurrentEntity() {
Entity CurrEnt = EntitiesStack.pop_back_val();
assert(CurrEnt.SymInfo.Kind != SymbolKind::Unknown);
return finishSourceEntity(CurrEnt.SymInfo, CurrEnt.Roles);
}
bool finishSourceEntity(SymbolInfo symInfo, SymbolRoleSet roles) {
if (!IdxConsumer.finishSourceEntity(symInfo, roles)) {
Cancelled = true;
return false;
}
return true;
}
bool initIndexSymbol(ValueDecl *D, SourceLoc Loc, bool IsRef,
IndexSymbol &Info);
bool initIndexSymbol(ExtensionDecl *D, ValueDecl *ExtendedD, SourceLoc Loc,
IndexSymbol &Info);
bool initFuncDeclIndexSymbol(FuncDecl *D, IndexSymbol &Info);
bool initFuncRefIndexSymbol(ValueDecl *D, SourceLoc Loc, IndexSymbol &Info);
bool initVarRefIndexSymbols(Expr *CurrentE, ValueDecl *D, SourceLoc Loc,
IndexSymbol &Info, Optional<AccessKind> AccKind);
bool indexComment(const Decl *D);
std::tuple<unsigned, unsigned, Optional<unsigned>>
getLineColAndOffset(SourceLoc Loc) {
if (Loc.isInvalid())
return std::make_tuple(0, 0, None);
auto lineAndColumn = SrcMgr.getLineAndColumn(Loc, BufferID);
unsigned offset = SrcMgr.getLocOffsetInBuffer(Loc, BufferID);
return std::make_tuple(lineAndColumn.first, lineAndColumn.second, offset);
}
bool shouldIndex(ValueDecl *D, bool IsRef) const {
if (D->isImplicit() && isa<VarDecl>(D) && IsRef) {
// Bypass the implicit VarDecls introduced in CaseStmt bodies by using the
// canonical VarDecl for these checks instead.
D = cast<VarDecl>(D)->getCanonicalVarDecl();
}
if (D->isImplicit() && !isa<ConstructorDecl>(D))
return false;
// Do not handle non-public imported decls.
if (IsModuleFile && !D->isAccessibleFrom(nullptr))
return false;
if (!IdxConsumer.indexLocals() && isLocalSymbol(D))
return isa<ParamDecl>(D) && !IsRef &&
D->getDeclContext()->getContextKind() != DeclContextKind::AbstractClosureExpr;
if (D->isPrivateStdlibDecl())
return false;
return true;
}
/// Reports all implicit member value decl conformances that \p D introduces
/// as implicit overrides at the source location of \p D, and returns the
/// explicit ones so we can check against them later on when visiting them as
/// members.
///
/// \returns false if AST visitation should stop.
bool handleWitnesses(Decl *D, SmallVectorImpl<IndexedWitness> &explicitWitnesses);
void getRecursiveModuleImports(ModuleDecl &Mod,
SmallVectorImpl<ModuleDecl *> &Imports);
void
collectRecursiveModuleImports(ModuleDecl &Mod,
llvm::SmallPtrSetImpl<ModuleDecl *> &Visited);
template <typename F>
void warn(F log) {
if (!enableWarnings)
return;
SmallString<128> warning;
llvm::raw_svector_ostream OS(warning);
log(OS);
}
// This maps a module to all its imports, recursively.
llvm::DenseMap<ModuleDecl *, llvm::SmallVector<ModuleDecl *, 4>> ImportsMap;
};
} // anonymous namespace
void IndexSwiftASTWalker::visitDeclContext(DeclContext *Context) {
IsModuleFile = false;
isSystemModule = Context->getParentModule()->isSystemModule();
auto accessor = dyn_cast<AccessorDecl>(Context);
if (accessor)
ManuallyVisitedAccessorStack.push_back(accessor);
walk(Context);
if (accessor)
ManuallyVisitedAccessorStack.pop_back();
}
void IndexSwiftASTWalker::visitModule(ModuleDecl &Mod) {
SourceFile *SrcFile = nullptr;
for (auto File : Mod.getFiles()) {
if (auto SF = dyn_cast<SourceFile>(File)) {
auto BufID = SF->getBufferID();
if (BufID.hasValue() && *BufID == BufferID) {
SrcFile = SF;
break;
}
}
}
if (SrcFile != nullptr) {
IsModuleFile = false;
if (!handleSourceOrModuleFile(*SrcFile))
return;
walk(*SrcFile);
} else {
IsModuleFile = true;
isSystemModule = Mod.isSystemModule();
if (!handleSourceOrModuleFile(Mod))
return;
walk(Mod);
}
}
bool IndexSwiftASTWalker::handleSourceOrModuleFile(SourceFileOrModule SFOrMod) {
// Common reporting for TU/module file.
llvm::SmallPtrSet<ModuleDecl *, 16> Visited;
return visitImports(SFOrMod, Visited);
}
bool IndexSwiftASTWalker::visitImports(
SourceFileOrModule TopMod, llvm::SmallPtrSetImpl<ModuleDecl *> &Visited) {
// Dependencies of the stdlib module (like SwiftShims module) are
// implementation details.
if (TopMod.getModule().isStdlibModule())
return true;
bool IsNew = Visited.insert(&TopMod.getModule()).second;
if (!IsNew)
return true;
SmallVector<ModuleDecl::ImportedModule, 8> Imports;
TopMod.getImportedModules(Imports);
llvm::SmallPtrSet<ModuleDecl *, 8> Reported;
for (auto Import : Imports) {
ModuleDecl *Mod = Import.second;
bool NewReport = Reported.insert(Mod).second;
if (!NewReport)
continue;
// FIXME: Handle modules with multiple source files; these will fail on
// getModuleFilename() (by returning an empty path). Note that such modules
// may be heterogeneous.
StringRef Path = Mod->getModuleFilename();
if (Path.empty() || Path == TopMod.getFilename())
continue; // this is a submodule.
Optional<bool> IsClangModuleOpt;
for (auto File : Mod->getFiles()) {
switch (File->getKind()) {
case FileUnitKind::Source:
case FileUnitKind::Builtin:
break;
case FileUnitKind::SerializedAST:
assert(!IsClangModuleOpt.hasValue() &&
"cannot handle multi-file modules");
IsClangModuleOpt = false;
break;
case FileUnitKind::ClangModule:
case FileUnitKind::DWARFModule:
assert(!IsClangModuleOpt.hasValue() &&
"cannot handle multi-file modules");
IsClangModuleOpt = true;
break;
}
}
if (!IsClangModuleOpt.hasValue())
continue;
bool IsClangModule = *IsClangModuleOpt;
if (!IdxConsumer.startDependency(Mod->getName().str(), Path, IsClangModule,
Mod->isSystemModule()))
return false;
if (!IsClangModule)
if (!visitImports(*Mod, Visited))
return false;
if (!IdxConsumer.finishDependency(IsClangModule))
return false;
}
return true;
}
bool IndexSwiftASTWalker::handleWitnesses(Decl *D, SmallVectorImpl<IndexedWitness> &explicitWitnesses) {
auto DC = dyn_cast<DeclContext>(D);
if (!DC)
return true;
for (auto *conf : DC->getLocalConformances()) {
if (conf->isInvalid())
continue;
// Ignore self-conformances; they're not interesting to show to users.
auto normal = dyn_cast<NormalProtocolConformance>(conf->getRootConformance());
if (!normal)
continue;
normal->forEachValueWitness([&](ValueDecl *req, Witness witness) {
if (Cancelled)
return;
auto *decl = witness.getDecl();
if (decl == nullptr)
return;
if (decl->getDeclContext() == DC) {
explicitWitnesses.push_back({decl, req});
} else {
reportImplicitConformance(decl, req, D);
}
});
normal->forEachTypeWitness(
[&](AssociatedTypeDecl *assoc, Type type, TypeDecl *typeDecl) {
if (Cancelled)
return true;
if (typeDecl == nullptr)
return false;
if (typeDecl->getDeclContext() == DC) {
explicitWitnesses.push_back({typeDecl, assoc});
} else {
// Report the implicit conformance.
reportImplicitConformance(typeDecl, assoc, D);
}
return false;
});
}
if (Cancelled)
return false;
return true;
}
bool IndexSwiftASTWalker::startEntity(Decl *D, IndexSymbol &Info, bool IsRef) {
switch (IdxConsumer.startSourceEntity(Info)) {
case swift::index::IndexDataConsumer::Abort:
Cancelled = true;
LLVM_FALLTHROUGH;
case swift::index::IndexDataConsumer::Skip:
return false;
case swift::index::IndexDataConsumer::Continue: {
SmallVector<IndexedWitness, 6> explicitWitnesses;
if (!IsRef) {
if (!handleWitnesses(D, explicitWitnesses))
return false;
}
EntitiesStack.push_back({D, Info.symInfo, Info.roles, std::move(explicitWitnesses), {}});
return true;
}
}
llvm_unreachable("Unhandled IndexDataConsumer in switch.");
}
bool IndexSwiftASTWalker::startEntityDecl(ValueDecl *D) {
if (!shouldIndex(D, /*IsRef=*/false))
return false;
SourceLoc Loc = D->getLoc();
if (Loc.isInvalid() && !IsModuleFile)
return false;
if (!IsModuleFile) {
if (!indexComment(D))
return false;
}
IndexSymbol Info;
if (auto FD = dyn_cast<FuncDecl>(D)) {
if (initFuncDeclIndexSymbol(FD, Info))
return false;
} else {
if (initIndexSymbol(D, Loc, /*IsRef=*/false, Info))
return false;
}
for (auto Overriden: collectAllOverriddenDecls(D, /*IncludeProtocolReqs=*/false)) {
addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, Overriden);
}
if (auto Parent = getParentDecl()) {
for (const IndexedWitness &witness : EntitiesStack.back().ExplicitWitnesses) {
if (witness.Member == D)
addRelation(Info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, witness.Requirement);
}
if (auto ParentVD = dyn_cast<ValueDecl>(Parent)) {
SymbolRoleSet RelationsToParent = (SymbolRoleSet)SymbolRole::RelationChildOf;
if (Info.symInfo.SubKind == SymbolSubKind::AccessorGetter ||
Info.symInfo.SubKind == SymbolSubKind::AccessorSetter ||
(Info.symInfo.SubKind >= SymbolSubKind::SwiftAccessorWillSet &&
Info.symInfo.SubKind <= SymbolSubKind::SwiftAccessorMutableAddressor))
RelationsToParent |= (SymbolRoleSet)SymbolRole::RelationAccessorOf;
if (addRelation(Info, RelationsToParent, ParentVD))
return false;
} else if (auto ParentED = dyn_cast<ExtensionDecl>(Parent)) {
if (ParentED->getExtendedNominal()) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationChildOf, ParentED))
return false;
}
}
}
return startEntity(D, Info, /*IsRef=*/false);
}
bool IndexSwiftASTWalker::reportRelatedRef(ValueDecl *D, SourceLoc Loc, bool isImplicit,
SymbolRoleSet Relations, Decl *Related) {
if (!shouldIndex(D, /*IsRef=*/true))
return true;
IndexSymbol Info;
if (addRelation(Info, Relations, Related))
return true;
if (isImplicit)
Info.roles |= (unsigned)SymbolRole::Implicit;
// don't report this ref again when visitDeclReference reports it
repressRefAtLoc(Loc);
if (!reportRef(D, Loc, Info, None)) {
Cancelled = true;
return false;
}
return !Cancelled;
}
bool IndexSwiftASTWalker::reportInheritedTypeRefs(ArrayRef<TypeLoc> Inherited, Decl *Inheritee) {
for (auto Base : Inherited) {
if (!reportRelatedTypeRef(Base, (SymbolRoleSet) SymbolRole::RelationBaseOf, Inheritee))
return false;
}
return true;
}
bool IndexSwiftASTWalker::reportRelatedTypeRef(const TypeLoc &Ty, SymbolRoleSet Relations, Decl *Related) {
if (auto *T = dyn_cast_or_null<IdentTypeRepr>(Ty.getTypeRepr())) {
auto Comps = T->getComponentRange();
SourceLoc IdLoc = Comps.back()->getIdLoc();
NominalTypeDecl *NTD = nullptr;
bool isImplicit = false;
if (auto *VD = Comps.back()->getBoundDecl()) {
if (auto *TAD = dyn_cast<TypeAliasDecl>(VD)) {
IndexSymbol Info;
if (!reportRef(TAD, IdLoc, Info, None))
return false;
if (auto Ty = TAD->getUnderlyingType()) {
NTD = Ty->getAnyNominal();
isImplicit = true;
}
} else {
NTD = dyn_cast<NominalTypeDecl>(VD);
}
}
if (NTD) {
if (!reportRelatedRef(NTD, IdLoc, isImplicit, Relations, Related))
return false;
}
return true;
}
if (Ty.getType()) {
if (auto nominal = Ty.getType()->getAnyNominal())
if (!reportRelatedRef(nominal, Ty.getLoc(), /*isImplicit=*/false, Relations, Related))
return false;
}
return true;
}
static bool isDynamicVarAccessorOrFunc(ValueDecl *D, SymbolInfo symInfo) {
if (auto NTD = D->getDeclContext()->getSelfNominalTypeDecl()) {
bool isClassOrProtocol = isa<ClassDecl>(NTD) || isa<ProtocolDecl>(NTD);
bool isInternalAccessor =
symInfo.SubKind == SymbolSubKind::SwiftAccessorWillSet ||
symInfo.SubKind == SymbolSubKind::SwiftAccessorDidSet ||
symInfo.SubKind == SymbolSubKind::SwiftAccessorAddressor ||
symInfo.SubKind == SymbolSubKind::SwiftAccessorMutableAddressor;
if (isClassOrProtocol &&
symInfo.Kind != SymbolKind::StaticMethod &&
!isInternalAccessor &&
!D->isFinal()) {
return true;
}
}
return false;
}
bool IndexSwiftASTWalker::reportPseudoAccessor(AbstractStorageDecl *D,
AccessorKind AccKind, bool IsRef,
SourceLoc Loc) {
if (!shouldIndex(D, IsRef))
return true; // continue walking.
auto updateInfo = [this, D, AccKind](IndexSymbol &Info) {
if (getPseudoAccessorNameAndUSR(D, AccKind, Info.name, Info.USR))
return true;
Info.symInfo.Kind = SymbolKind::Function;
if (D->getDeclContext()->isTypeContext()) {
if (D->isStatic()) {
if (D->getCorrectStaticSpelling() == StaticSpellingKind::KeywordClass)
Info.symInfo.Kind = SymbolKind::ClassMethod;
else
Info.symInfo.Kind = SymbolKind::StaticMethod;
} else {
Info.symInfo.Kind = SymbolKind::InstanceMethod;
}
}
Info.symInfo.SubKind = getSubKindForAccessor(AccKind);
Info.roles |= (SymbolRoleSet)SymbolRole::Implicit;
Info.group = "";
if (isDynamicVarAccessorOrFunc(D, Info.symInfo)) {
Info.roles |= (SymbolRoleSet)SymbolRole::Dynamic;
}
return false;
};
if (IsRef) {
IndexSymbol Info;
// initFuncRefIndexSymbol uses the top of the entities stack as the caller,
// but in this case the top of the stack is the referenced
// AbstractStorageDecl.
assert(getParentDecl() == D);
auto PreviousTop = EntitiesStack.pop_back_val();
bool initFailed = initFuncRefIndexSymbol(D, Loc, Info);
EntitiesStack.push_back(PreviousTop);
if (initFailed)
return true; // continue walking.
if (updateInfo(Info))
return true;
if (!IdxConsumer.startSourceEntity(Info) || !IdxConsumer.finishSourceEntity(Info.symInfo, Info.roles))
Cancelled = true;
} else {
IndexSymbol Info;
if (initIndexSymbol(D, Loc, IsRef, Info))
return true; // continue walking.
if (updateInfo(Info))
return true;
if (addRelation(Info, (SymbolRoleSet)SymbolRole::RelationAccessorOf |
(SymbolRoleSet)SymbolRole::RelationChildOf , D))
return true;
if (!IdxConsumer.startSourceEntity(Info) || !IdxConsumer.finishSourceEntity(Info.symInfo, Info.roles))
Cancelled = true;
}
return !Cancelled;
}
NominalTypeDecl *
IndexSwiftASTWalker::getTypeLocAsNominalTypeDecl(const TypeLoc &Ty) {
if (Type T = Ty.getType())
return T->getAnyNominal();
if (auto *T = dyn_cast_or_null<IdentTypeRepr>(Ty.getTypeRepr())) {
auto Comp = T->getComponentRange().back();
if (auto NTD = dyn_cast_or_null<NominalTypeDecl>(Comp->getBoundDecl()))
return NTD;
}
return nullptr;
}
bool IndexSwiftASTWalker::reportExtension(ExtensionDecl *D) {
SourceLoc Loc = getLocForExtension(D);
NominalTypeDecl *NTD = D->getExtendedNominal();
if (!NTD)
return true;
if (!shouldIndex(NTD, /*IsRef=*/false))
return true;
IndexSymbol Info;
if (initIndexSymbol(D, NTD, Loc, Info))
return true;
if (!startEntity(D, Info, /*IsRef=*/false))
return false;
if (!reportRelatedRef(NTD, Loc, /*isImplicit=*/false,
(SymbolRoleSet)SymbolRole::RelationExtendedBy, D))
return false;
if (!reportInheritedTypeRefs(D->getInherited(), D))
return false;
return true;
}
bool IndexSwiftASTWalker::report(ValueDecl *D) {
if (startEntityDecl(D)) {
// Pass accessors.
if (auto StoreD = dyn_cast<AbstractStorageDecl>(D)) {
bool usedPseudoAccessors = false;
if (isa<VarDecl>(D) &&
!StoreD->getParsedAccessor(AccessorKind::Get) &&
!StoreD->getParsedAccessor(AccessorKind::Set)) {
usedPseudoAccessors = true;
auto VarD = cast<VarDecl>(D);
// No actual getter or setter, pass 'pseudo' accessors.
// We create accessor entities so we can implement the functionality
// of libclang, which reports implicit method property accessor
// declarations, invocations, and overrides for properties.
// Note that an ObjC class subclassing from a Swift class, may still
// be able to override its non-computed-property-accessors via a
// method.
if (!reportPseudoGetterDecl(VarD))
return false;
if (!reportPseudoSetterDecl(VarD))
return false;
}
for (auto accessor : StoreD->getAllAccessors()) {
// Don't include the implicit getter and setter if we added pseudo
// accessors above.
if (usedPseudoAccessors &&
(accessor->getAccessorKind() == AccessorKind::Get ||
accessor->getAccessorKind() == AccessorKind::Set))
continue;
ManuallyVisitedAccessorStack.push_back(accessor);
SourceEntityWalker::walk(cast<Decl>(accessor));
ManuallyVisitedAccessorStack.pop_back();
if (Cancelled)
return false;
}
} else if (auto NTD = dyn_cast<NominalTypeDecl>(D)) {
if (!reportInheritedTypeRefs(NTD->getInherited(), NTD))
return false;
}
} else {
// Even if we don't record a local property we still need to walk its
// accessor bodies.
if (auto StoreD = dyn_cast<AbstractStorageDecl>(D)) {
StoreD->visitParsedAccessors([&](AccessorDecl *accessor) {
if (Cancelled)
return;
ManuallyVisitedAccessorStack.push_back(accessor);
SourceEntityWalker::walk(cast<Decl>(accessor));
ManuallyVisitedAccessorStack.pop_back();
});
}
}
return !Cancelled;
}
static bool hasUsefulRoleInSystemModule(SymbolRoleSet roles) {
return roles & ((SymbolRoleSet)SymbolRole::Definition |
(SymbolRoleSet)SymbolRole::Declaration |
(SymbolRoleSet)SymbolRole::RelationChildOf |
(SymbolRoleSet)SymbolRole::RelationBaseOf |
(SymbolRoleSet)SymbolRole::RelationOverrideOf |
(SymbolRoleSet)SymbolRole::RelationExtendedBy |
(SymbolRoleSet)SymbolRole::RelationAccessorOf |
(SymbolRoleSet)SymbolRole::RelationIBTypeOf);
}
bool IndexSwiftASTWalker::reportRef(ValueDecl *D, SourceLoc Loc,
IndexSymbol &Info,
Optional<AccessKind> AccKind) {
if (!shouldIndex(D, /*IsRef=*/true))
return true; // keep walking
if (isa<AbstractFunctionDecl>(D)) {
if (initFuncRefIndexSymbol(D, Loc, Info))
return true;
} else if (isa<AbstractStorageDecl>(D)) {
if (initVarRefIndexSymbols(getCurrentExpr(), D, Loc, Info, AccKind))
return true;
} else {
if (initIndexSymbol(D, Loc, /*IsRef=*/true, Info))
return true;
}
if (isSystemModule && !hasUsefulRoleInSystemModule(Info.roles))
return true;
if (!startEntity(D, Info, /*IsRef=*/true))
return true;
// Report the accessors that were utilized.
if (auto *ASD = dyn_cast<AbstractStorageDecl>(D)) {
bool UsesGetter = Info.roles & (SymbolRoleSet)SymbolRole::Read;
bool UsesSetter = Info.roles & (SymbolRoleSet)SymbolRole::Write;
if (UsesGetter)
if (!reportPseudoAccessor(ASD, AccessorKind::Get, /*IsRef=*/true,
Loc))
return false;
if (UsesSetter)
if (!reportPseudoAccessor(ASD, AccessorKind::Set, /*IsRef=*/true,
Loc))
return false;
}
return finishCurrentEntity();
}
bool IndexSwiftASTWalker::reportImplicitConformance(ValueDecl *witness, ValueDecl *requirement,
Decl *container) {
if (!shouldIndex(witness, /*IsRef=*/true))
return true; // keep walking
SourceLoc loc;
if (auto *extD = dyn_cast<ExtensionDecl>(container))
loc = getLocForExtension(extD);
else
loc = container->getLoc();
IndexSymbol info;
if (initIndexSymbol(witness, loc, /*IsRef=*/true, info))
return true;
if (addRelation(info, (SymbolRoleSet) SymbolRole::RelationOverrideOf, requirement))
return true;
if (addRelation(info, (SymbolRoleSet) SymbolRole::RelationContainedBy, container))
return true;
// Remove the 'ref' role that \c initIndexSymbol introduces. This isn't
// actually a 'reference', but an 'implicit' override.
info.roles &= ~(SymbolRoleSet)SymbolRole::Reference;
info.roles |= (SymbolRoleSet)SymbolRole::Implicit;
if (!startEntity(witness, info, /*IsRef=*/true))
return true;
return finishCurrentEntity();
}
bool IndexSwiftASTWalker::initIndexSymbol(ValueDecl *D, SourceLoc Loc,
bool IsRef, IndexSymbol &Info) {
assert(D);
if (auto *VD = dyn_cast<VarDecl>(D)) {
// Always base the symbol information on the canonical VarDecl
D = VD->getCanonicalVarDecl();
}
Info.decl = D;
Info.symInfo = getSymbolInfoForDecl(D);
if (Info.symInfo.Kind == SymbolKind::Unknown)
return true;
// Cannot be extension, which is not a ValueDecl.
if (IsRef) {
Info.roles |= (unsigned)SymbolRole::Reference;
if (auto Container = getContainingDecl())
addRelation(Info, (unsigned)SymbolRole::RelationContainedBy, Container);
} else {
Info.roles |= (unsigned)SymbolRole::Definition;
if (D->isImplicit())
Info.roles |= (unsigned)SymbolRole::Implicit;
}
if (getNameAndUSR(D, /*ExtD=*/nullptr, Info.name, Info.USR))
return true;
std::tie(Info.line, Info.column, Info.offset) = getLineColAndOffset(Loc);
if (!IsRef) {
if (auto Group = D->getGroupName())
Info.group = Group.getValue();
}
return false;
}
bool IndexSwiftASTWalker::initIndexSymbol(ExtensionDecl *ExtD, ValueDecl *ExtendedD,
SourceLoc Loc, IndexSymbol &Info) {
assert(ExtD && ExtendedD);
Info.decl = ExtendedD;
Info.symInfo = getSymbolInfoForDecl(ExtD);
if (Info.symInfo.Kind == SymbolKind::Unknown)
return true;
Info.roles |= (unsigned)SymbolRole::Definition;
if (getNameAndUSR(ExtendedD, ExtD, Info.name, Info.USR))
return true;
std::tie(Info.line, Info.column, Info.offset) = getLineColAndOffset(Loc);
if (auto Group = ExtD->getGroupName())
Info.group = Group.getValue();
return false;
}
static NominalTypeDecl *getNominalParent(ValueDecl *D) {
return D->getDeclContext()->getSelfNominalTypeDecl();
}
bool IndexSwiftASTWalker::initFuncDeclIndexSymbol(FuncDecl *D,
IndexSymbol &Info) {
if (initIndexSymbol(D, D->getLoc(), /*IsRef=*/false, Info))
return true;
if (isDynamicVarAccessorOrFunc(D, Info.symInfo)) {
Info.roles |= (SymbolRoleSet)SymbolRole::Dynamic;
}
if (D->hasImplicitSelfDecl()) {
// If this is an @IBAction or @IBSegueAction method, find the sender
// parameter (if present) and relate the method to its type.
ParamDecl *senderParam = nullptr;
auto paramList = D->getParameters();
if (D->getAttrs().hasAttribute<IBActionAttr>()) {
if (paramList->size() > 0)
senderParam = paramList->get(0);
} else if (D->getAttrs().hasAttribute<IBSegueActionAttr>()) {
if (paramList->size() > 1)
senderParam = paramList->get(1);
}
if (senderParam)
if (auto nominal = senderParam->getType()->getAnyNominal())
addRelation(Info, (SymbolRoleSet) SymbolRole::RelationIBTypeOf,
nominal);
}
if (auto Group = D->getGroupName())
Info.group = Group.getValue();
return false;
}
static bool isSuperRefExpr(Expr *E) {
if (!E)
return false;
if (isa<SuperRefExpr>(E))
return true;
if (auto LoadE = dyn_cast<LoadExpr>(E))
return isSuperRefExpr(LoadE->getSubExpr());
return false;
}
static bool isDynamicCall(Expr *BaseE, ValueDecl *D) {
// The call is 'dynamic' if the method is not of a struct/enum and the
// receiver is not 'super'. Note that if the receiver is 'super' that
// does not mean that the call is statically determined (an extension
// method may have injected itself in the super hierarchy).
// For our purposes 'dynamic' means that the method call cannot invoke
// a method in a subclass.
auto TyD = getNominalParent(D);
if (!TyD)
return false;
if (isa<StructDecl>(TyD) || isa<EnumDecl>(TyD))
return false;
if (isSuperRefExpr(BaseE))
return false;
if (BaseE->getType()->is<MetatypeType>())
return false;
return true;
}
static bool isBeingCalled(Expr *Target, Expr *Parent, Expr *GrandParent) {
if (!Target || !Parent || !isa<ApplyExpr>(Parent))
return false;
if (!isa<SelfApplyExpr>(Parent))
return cast<ApplyExpr>(Parent)->getFn() == Target;
return GrandParent && isa<CallExpr>(GrandParent) &&
cast<CallExpr>(GrandParent)->getFn() == Parent;
}
bool IndexSwiftASTWalker::initFuncRefIndexSymbol(ValueDecl *D, SourceLoc Loc,
IndexSymbol &Info) {
if (initIndexSymbol(D, Loc, /*IsRef=*/true, Info))
return true;
Expr *CurrentE = getCurrentExpr();
if (!CurrentE)
return false;
Expr *ParentE = getParentExpr();
if (!isa<AbstractStorageDecl>(D) &&
!isBeingCalled(CurrentE, ParentE, getContainingExpr(2)))
return false;
Info.roles |= (unsigned)SymbolRole::Call;
if (auto *Caller = dyn_cast_or_null<AbstractFunctionDecl>(getParentDecl())) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationCalledBy, Caller))
return true;
}
Expr *BaseE = nullptr;
if (auto DotE = dyn_cast_or_null<DotSyntaxCallExpr>(ParentE))
BaseE = DotE->getBase();
else if (auto MembE = dyn_cast<MemberRefExpr>(CurrentE))
BaseE = MembE->getBase();
else if (auto SubsE = dyn_cast<SubscriptExpr>(CurrentE))
BaseE = SubsE->getBase();
if (!BaseE || BaseE == CurrentE)
return false;
if (Type ReceiverTy = BaseE->getType()) {
if (auto LVT = ReceiverTy->getAs<LValueType>())
ReceiverTy = LVT->getObjectType();
else if (auto MetaT = ReceiverTy->getAs<MetatypeType>())
ReceiverTy = MetaT->getInstanceType();
if (auto TyD = ReceiverTy->getAnyNominal()) {
if (addRelation(Info, (SymbolRoleSet) SymbolRole::RelationReceivedBy, TyD))
return true;
if (isDynamicCall(BaseE, D))
Info.roles |= (unsigned)SymbolRole::Dynamic;
}
}
return false;
}
bool IndexSwiftASTWalker::initVarRefIndexSymbols(Expr *CurrentE, ValueDecl *D,
SourceLoc Loc, IndexSymbol &Info,
Optional<AccessKind> AccKind) {
if (initIndexSymbol(D, Loc, /*IsRef=*/true, Info))
return true;
if (!CurrentE)
return false;
AccessKind Kind = AccKind.hasValue() ? *AccKind : AccessKind::Read;
switch (Kind) {
case swift::AccessKind::Read:
Info.roles |= (unsigned)SymbolRole::Read;
break;
case swift::AccessKind::ReadWrite:
Info.roles |= (unsigned)SymbolRole::Read;
LLVM_FALLTHROUGH;
case swift::AccessKind::Write:
Info.roles |= (unsigned)SymbolRole::Write;
}
return false;
}
bool IndexSwiftASTWalker::indexComment(const Decl *D) {
// FIXME: Workaround for getting tag locations. We should enhance cmark to
// keep track of node offsets in the original comment text.
struct TagLoc {
StringRef Text;
SourceLoc Loc;
};
SmallVector<TagLoc, 3> tagLocs;
for (const auto &single : D->getRawComment().Comments) {
size_t idx = single.RawText.find("- Tag:");
if (idx != StringRef::npos) {
tagLocs.push_back(TagLoc{single.RawText,
single.Range.getStart().getAdvancedLoc(idx)});
}
}
if (tagLocs.empty())
return true;
swift::markup::MarkupContext MC;
auto DC = getSingleDocComment(MC, D);
if (!DC)
return true;
for (StringRef tagName : DC->getTags()) {
tagName = tagName.trim();
if (tagName.empty())
continue;
SourceLoc loc;
for (const auto &tagLoc : tagLocs) {
if (tagLoc.Text.contains(tagName)) {
loc = tagLoc.Loc;
break;
}
}
if (loc.isInvalid())
continue;
IndexSymbol Info;
Info.decl = nullptr;
Info.symInfo = SymbolInfo{ SymbolKind::CommentTag, SymbolSubKind::None,
SymbolLanguage::Swift, SymbolPropertySet() };
Info.roles |= (unsigned)SymbolRole::Definition;
Info.name = StringRef();
SmallString<128> storage;
{
llvm::raw_svector_ostream OS(storage);
OS << "t:" << tagName;
Info.USR = stringStorage.copyString(OS.str());
}
std::tie(Info.line, Info.column, Info.offset) = getLineColAndOffset(loc);
if (!IdxConsumer.startSourceEntity(Info) || !IdxConsumer.finishSourceEntity(Info.symInfo, Info.roles)) {
Cancelled = true;
break;
}
}
return !Cancelled;
}
void IndexSwiftASTWalker::getRecursiveModuleImports(
ModuleDecl &Mod, SmallVectorImpl<ModuleDecl *> &Imports) {
auto It = ImportsMap.find(&Mod);
if (It != ImportsMap.end()) {
Imports.append(It->second.begin(), It->second.end());
return;
}
llvm::SmallPtrSet<ModuleDecl *, 16> Visited;
collectRecursiveModuleImports(Mod, Visited);
Visited.erase(&Mod);
warn([&Imports](llvm::raw_ostream &OS) {
std::for_each(Imports.begin(), Imports.end(), [&OS](ModuleDecl *M) {
if (M->getModuleFilename().empty()) {
std::string Info = "swift::ModuleDecl with empty file name!! \nDetails: \n";
Info += " name: ";
Info += M->getName().get();
Info += "\n";
auto Files = M->getFiles();
std::for_each(Files.begin(), Files.end(), [&](FileUnit *FU) {
Info += " file unit: ";
switch (FU->getKind()) {
case FileUnitKind::Builtin:
Info += "builtin";
break;
case FileUnitKind::Source:
Info += "source, file=\"";
Info += cast<SourceFile>(FU)->getFilename();
Info += "\"";
break;
case FileUnitKind::SerializedAST:
Info += "serialized ast, file=\"";
Info += cast<LoadedFile>(FU)->getFilename();
Info += "\"";
break;
case FileUnitKind::ClangModule:
case FileUnitKind::DWARFModule:
Info += "clang module, file=\"";
Info += cast<LoadedFile>(FU)->getFilename();
Info += "\"";
}
Info += "\n";
});
OS << "swift::ModuleDecl with empty file name! " << Info << "\n";
}
});
});
Imports.append(Visited.begin(), Visited.end());
std::sort(Imports.begin(), Imports.end(), [](ModuleDecl *LHS, ModuleDecl *RHS) {
return LHS->getModuleFilename() < RHS->getModuleFilename();
});
// Cache it.
ImportsMap[&Mod].append(Imports.begin(), Imports.end());
}
void IndexSwiftASTWalker::collectRecursiveModuleImports(
ModuleDecl &TopMod, llvm::SmallPtrSetImpl<ModuleDecl *> &Visited) {
bool IsNew = Visited.insert(&TopMod).second;
if (!IsNew)
return;
// Pure Clang modules are tied to their dependencies, no need to look into its
// imports.
// FIXME: What happens if the clang module imports a swift module ? So far
// the assumption is that the path to the swift module will be fixed, so no
// need to hash the clang module.
// FIXME: This is a bit of a hack.
if (TopMod.getFiles().size() == 1)
if (TopMod.getFiles().front()->getKind() == FileUnitKind::ClangModule ||
TopMod.getFiles().front()->getKind() == FileUnitKind::DWARFModule)
return;
auto It = ImportsMap.find(&TopMod);
if (It != ImportsMap.end()) {
Visited.insert(It->second.begin(), It->second.end());
return;
}
ModuleDecl::ImportFilter ImportFilter;
ImportFilter |= ModuleDecl::ImportFilterKind::Public;
ImportFilter |= ModuleDecl::ImportFilterKind::Private;
SmallVector<ModuleDecl::ImportedModule, 8> Imports;
TopMod.getImportedModules(Imports);
for (auto Import : Imports) {
collectRecursiveModuleImports(*Import.second, Visited);
}
}
//===----------------------------------------------------------------------===//
// Indexing entry points
//===----------------------------------------------------------------------===//
void index::indexDeclContext(DeclContext *DC, IndexDataConsumer &consumer) {
assert(DC);
unsigned bufferId = DC->getParentSourceFile()->getBufferID().getValue();
IndexSwiftASTWalker walker(consumer, DC->getASTContext(), bufferId);
walker.visitDeclContext(DC);
consumer.finish();
}
void index::indexSourceFile(SourceFile *SF, IndexDataConsumer &consumer) {
assert(SF);
unsigned bufferID = SF->getBufferID().getValue();
IndexSwiftASTWalker walker(consumer, SF->getASTContext(), bufferID);
walker.visitModule(*SF->getParentModule());
consumer.finish();
}
void index::indexModule(ModuleDecl *module, IndexDataConsumer &consumer) {
assert(module);
IndexSwiftASTWalker walker(consumer, module->getASTContext());
walker.visitModule(*module);
consumer.finish();
}