blob: 188cadf70218073f503fe586475303c09403caac [file] [log] [blame]
//===--- SourceEntityWalker.cpp - Routines for semantic source info -------===//
//
// 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/IDE/SourceEntityWalker.h"
#include "swift/Parse/Lexer.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/TypeRepr.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceManager.h"
#include "clang/Basic/Module.h"
using namespace swift;
namespace {
class SemaAnnotator : public ASTWalker {
SourceEntityWalker &SEWalker;
SmallVector<ConstructorRefCallExpr *, 2> CtorRefs;
SmallVector<ExtensionDecl *, 2> ExtDecls;
bool Cancelled = false;
public:
explicit SemaAnnotator(SourceEntityWalker &SEWalker)
: SEWalker(SEWalker) { }
bool isDone() const { return Cancelled; }
private:
bool shouldWalkIntoGenericParams() override {
return SEWalker.shouldWalkIntoGenericParams();
}
bool walkToDeclPre(Decl *D) override;
std::pair<bool, Expr *> walkToExprPre(Expr *E) override;
bool walkToTypeReprPre(TypeRepr *T) override;
bool walkToDeclPost(Decl *D) override;
Expr *walkToExprPost(Expr *E) override;
bool walkToTypeReprPost(TypeRepr *T) override;
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override;
Stmt *walkToStmtPost(Stmt *S) override;
std::pair<bool, Pattern *> walkToPatternPre(Pattern *P) override;
bool handleImports(ImportDecl *Import);
bool passModulePathElements(ArrayRef<ImportDecl::AccessPathElement> Path,
const clang::Module *ClangMod);
bool passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc, ReferenceMetaData Data);
bool passReference(ModuleEntity Mod, std::pair<Identifier, SourceLoc> IdLoc);
bool passSubscriptReference(ValueDecl *D, SourceLoc Loc,
Optional<AccessKind> AccKind,
bool IsOpenBracket);
bool passCallArgNames(Expr *Fn, TupleExpr *TupleE);
bool shouldIgnore(Decl *D, bool &ShouldVisitChildren);
ValueDecl *extractDecl(Expr *Fn) const {
if (auto *DRE = dyn_cast<DeclRefExpr>(Fn))
return DRE->getDecl();
if (auto ApplyE = dyn_cast<ApplyExpr>(Fn))
return extractDecl(ApplyE->getFn());
return nullptr;
}
};
} // end anonymous namespace
bool SemaAnnotator::walkToDeclPre(Decl *D) {
if (isDone())
return false;
bool ShouldVisitChildren;
if (shouldIgnore(D, ShouldVisitChildren))
return ShouldVisitChildren;
SourceLoc Loc = D->getLoc();
unsigned NameLen = 0;
bool IsExtension = false;
if (auto *VD = dyn_cast<ValueDecl>(D)) {
if (VD->hasName() && !VD->isImplicit())
NameLen = VD->getBaseName().userFacingName().size();
auto ReportParamList = [&](ParameterList *PL) {
for (auto *PD : *PL) {
auto Loc = PD->getArgumentNameLoc();
if (Loc.isInvalid())
continue;
if (!SEWalker.visitDeclarationArgumentName(PD->getArgumentName(), Loc,
VD)) {
Cancelled = true;
return true;
}
}
return false;
};
if (auto AF = dyn_cast<AbstractFunctionDecl>(VD)) {
for (auto *PL : AF->getParameterLists())
if (ReportParamList(PL))
return false;
}
if (auto SD = dyn_cast<SubscriptDecl>(VD)) {
if (ReportParamList(SD->getIndices()))
return false;
}
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
SourceRange SR = ED->getExtendedTypeLoc().getSourceRange();
Loc = SR.Start;
if (Loc.isValid())
NameLen = ED->getASTContext().SourceMgr.getByteDistance(SR.Start, SR.End);
IsExtension = true;
} else if (auto Import = dyn_cast<ImportDecl>(D)) {
if (!handleImports(Import))
return false;
} else if (auto OpD = dyn_cast<OperatorDecl>(D)) {
Loc = OpD->getLoc();
if (Loc.isValid())
NameLen = OpD->getName().getLength();
} else if (auto PrecD = dyn_cast<PrecedenceGroupDecl>(D)) {
Loc = PrecD->getLoc();
if (Loc.isValid())
NameLen = PrecD->getName().getLength();
} else if (auto *ICD = dyn_cast<IfConfigDecl>(D)) {
if (SEWalker.shouldWalkInactiveConfigRegion()) {
for (auto Clause : ICD->getClauses()) {
for (auto Member : Clause.Elements) {
Member.walk(*this);
}
}
return false;
}
} else {
return true;
}
CharSourceRange Range = (Loc.isValid()) ? CharSourceRange(Loc, NameLen)
: CharSourceRange();
ShouldVisitChildren = SEWalker.walkToDeclPre(D, Range);
if (ShouldVisitChildren && IsExtension) {
ExtDecls.push_back(static_cast<ExtensionDecl*>(D));
}
return ShouldVisitChildren;
}
bool SemaAnnotator::walkToDeclPost(Decl *D) {
if (isDone())
return false;
bool ShouldVisitChildren;
if (shouldIgnore(D, ShouldVisitChildren))
return true;
// FIXME: rdar://17671977 the initializer for a lazy property has already
// been moved into its implicit getter.
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
if (auto *VD = PBD->getSingleVar()) {
if (VD->getAttrs().hasAttribute<LazyAttr>()) {
if (auto *Get = VD->getGetter()) {
assert((Get->isImplicit() || Get->isInvalid())
&& "lazy var getter must be either implicitly computed or invalid");
// Note that an implicit getter may not have the body synthesized
// in case the owning PatternBindingDecl is invalid.
if (auto *Body = Get->getBody()) {
Body->walk(*this);
}
}
}
}
}
if (isa<ExtensionDecl>(D)) {
assert(ExtDecls.back() == D);
ExtDecls.pop_back();
}
if (!isa<ValueDecl>(D) && !isa<ExtensionDecl>(D) && !isa<ImportDecl>(D) &&
!isa<IfConfigDecl>(D))
return true;
bool Continue = SEWalker.walkToDeclPost(D);
if (!Continue)
Cancelled = true;
return Continue;
}
std::pair<bool, Stmt *> SemaAnnotator::walkToStmtPre(Stmt *S) {
bool TraverseChildren = SEWalker.walkToStmtPre(S);
if (TraverseChildren) {
if (auto *DeferS = dyn_cast<DeferStmt>(S)) {
// Since 'DeferStmt::getTempDecl()' is marked as implicit, we manually
// walk into the body.
if (auto *FD = DeferS->getTempDecl()) {
auto *RetS = FD->getBody()->walk(*this);
assert(RetS == FD->getBody());
(void)RetS;
}
bool Continue = SEWalker.walkToStmtPost(DeferS);
if (!Continue)
Cancelled = true;
// Already walked children.
return { false, Continue ? DeferS : nullptr };
}
}
return { TraverseChildren, S };
}
Stmt *SemaAnnotator::walkToStmtPost(Stmt *S) {
bool Continue = SEWalker.walkToStmtPost(S);
if (!Continue)
Cancelled = true;
return Continue ? S : nullptr;
}
static SemaReferenceKind getReferenceKind(Expr *Parent, Expr *E) {
if (auto SA = dyn_cast_or_null<SelfApplyExpr>(Parent)) {
if (SA->getFn() == E)
return SemaReferenceKind::DeclMemberRef;
}
return SemaReferenceKind::DeclRef;
}
static Optional<AccessKind> getAccessKind(Expr *E) {
if (E->hasLValueAccessKind())
return E->getLValueAccessKind();
return None;
}
std::pair<bool, Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
if (isDone())
return { false, nullptr };
if (!SEWalker.walkToExprPre(E))
return { false, E };
if (auto *CtorRefE = dyn_cast<ConstructorRefCallExpr>(E))
CtorRefs.push_back(CtorRefE);
if (E->isImplicit())
return { true, E };
Optional<AccessKind> OpAccess = getAccessKind(E);
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
if (auto *module = dyn_cast<ModuleDecl>(DRE->getDecl())) {
if (!passReference(ModuleEntity(module),
std::make_pair(module->getName(), E->getLoc())))
return { false, nullptr };
} else if (!passReference(DRE->getDecl(), DRE->getType(),
DRE->getNameLoc(),
ReferenceMetaData(getReferenceKind(Parent.getAsExpr(), DRE),
OpAccess))) {
return { false, nullptr };
}
} else if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
// Visit in source order.
if (!MRE->getBase()->walk(*this))
return { false, nullptr };
if (!passReference(MRE->getMember().getDecl(), MRE->getType(),
MRE->getNameLoc(),
ReferenceMetaData(SemaReferenceKind::DeclMemberRef,
OpAccess)))
return { false, nullptr };
// We already visited the children.
if (!walkToExprPost(E))
return { false, nullptr };
return { false, E };
} else if (auto OtherCtorE = dyn_cast<OtherConstructorDeclRefExpr>(E)) {
if (!passReference(OtherCtorE->getDecl(), OtherCtorE->getType(),
OtherCtorE->getConstructorLoc(),
ReferenceMetaData(SemaReferenceKind::DeclConstructorRef,
OpAccess)))
return { false, nullptr };
} else if (auto *SE = dyn_cast<SubscriptExpr>(E)) {
// Visit in source order.
if (!SE->getBase()->walk(*this))
return { false, nullptr };
ValueDecl *SubscrD = nullptr;
if (SE->hasDecl())
SubscrD = SE->getDecl().getDecl();
if (SubscrD) {
if (!passSubscriptReference(SubscrD, E->getLoc(), OpAccess, true))
return { false, nullptr };
}
if (!SE->getIndex()->walk(*this))
return { false, nullptr };
if (SubscrD) {
if (!passSubscriptReference(SubscrD, E->getEndLoc(), OpAccess, false))
return { false, nullptr };
}
// We already visited the children.
if (!walkToExprPost(E))
return { false, nullptr };
return { false, E };
} else if (auto *BinE = dyn_cast<BinaryExpr>(E)) {
// Visit in source order.
if (!BinE->getArg()->getElement(0)->walk(*this))
return { false, nullptr };
if (!BinE->getFn()->walk(*this))
return { false, nullptr };
if (!BinE->getArg()->getElement(1)->walk(*this))
return { false, nullptr };
// We already visited the children.
if (!walkToExprPost(E))
return { false, nullptr };
return { false, E };
} else if (auto TupleE = dyn_cast<TupleExpr>(E)) {
if (auto CallE = dyn_cast_or_null<CallExpr>(Parent.getAsExpr())) {
if (!passCallArgNames(CallE->getFn(), TupleE))
return { false, nullptr };
}
}
return { true, E };
}
bool SemaAnnotator::walkToTypeReprPre(TypeRepr *T) {
if (isDone())
return false;
if (auto IdT = dyn_cast<ComponentIdentTypeRepr>(T)) {
if (ValueDecl *VD = IdT->getBoundDecl()) {
if (auto *ModD = dyn_cast<ModuleDecl>(VD))
return passReference(ModD, std::make_pair(IdT->getIdentifier(),
IdT->getIdLoc()));
return passReference(VD, Type(), DeclNameLoc(IdT->getIdLoc()),
ReferenceMetaData(SemaReferenceKind::TypeRef, None));
}
}
return true;
}
Expr *SemaAnnotator::walkToExprPost(Expr *E) {
if (isa<ConstructorRefCallExpr>(E)) {
assert(CtorRefs.back() == E);
CtorRefs.pop_back();
}
bool Continue = SEWalker.walkToExprPost(E);
if (!Continue)
Cancelled = true;
return Continue ? E : nullptr;
}
bool SemaAnnotator::walkToTypeReprPost(TypeRepr *T) {
return !isDone();
}
std::pair<bool, Pattern *> SemaAnnotator::walkToPatternPre(Pattern *P) {
if (P->isImplicit())
return { true, P };
if (auto *EP = dyn_cast<EnumElementPattern>(P)) {
auto *Element = EP->getElementDecl();
if (!Element)
return { true, P };
Type T = EP->hasType() ? EP->getType() : Type();
return { passReference(Element, T, DeclNameLoc(EP->getLoc()),
ReferenceMetaData(SemaReferenceKind::EnumElementRef, None)), P };
}
auto *TP = dyn_cast<TypedPattern>(P);
if (!TP || !TP->isPropagatedType())
return { true, P };
// If the typed pattern was propagated from somewhere, just walk the
// subpattern. The type will be walked as a part of another TypedPattern.
TP->getSubPattern()->walk(*this);
return { false, P };
}
bool SemaAnnotator::handleImports(ImportDecl *Import) {
auto Mod = Import->getModule();
if (!Mod)
return true;
auto ClangMod = Mod->findUnderlyingClangModule();
if (ClangMod && ClangMod->isSubModule()) {
if (!passModulePathElements(Import->getModulePath(), ClangMod))
return false;
} else {
if (!passReference(Mod, Import->getModulePath().front()))
return false;
}
auto Decls = Import->getDecls();
if (Decls.size() == 1) {
// FIXME: ImportDecl should store a DeclNameLoc.
// FIXME: Handle overloaded funcs too by passing a reference for each?
if (!passReference(Decls.front(), Type(), DeclNameLoc(Import->getEndLoc()),
ReferenceMetaData(SemaReferenceKind::DeclRef, None)))
return false;
}
return true;
}
bool SemaAnnotator::passModulePathElements(
ArrayRef<ImportDecl::AccessPathElement> Path,
const clang::Module *ClangMod) {
if (Path.empty() || !ClangMod)
return true;
if (!passModulePathElements(Path.drop_back(1), ClangMod->Parent))
return false;
return passReference(ClangMod, Path.back());
}
bool SemaAnnotator::passSubscriptReference(ValueDecl *D, SourceLoc Loc,
Optional<AccessKind> AccKind,
bool IsOpenBracket) {
CharSourceRange Range = Loc.isValid()
? CharSourceRange(Loc, 1)
: CharSourceRange();
bool Continue = SEWalker.visitSubscriptReference(D, Range, AccKind,
IsOpenBracket);
if (!Continue)
Cancelled = true;
return Continue;
}
bool SemaAnnotator::
passReference(ValueDecl *D, Type Ty, DeclNameLoc Loc, ReferenceMetaData Data) {
TypeDecl *CtorTyRef = nullptr;
ExtensionDecl *ExtDecl = nullptr;
if (auto *TD = dyn_cast<TypeDecl>(D)) {
if (!CtorRefs.empty() && Loc.isValid()) {
Expr *Fn = CtorRefs.back()->getFn();
if (Fn->getLoc() == Loc.getBaseNameLoc()) {
D = extractDecl(Fn);
CtorTyRef = TD;
}
}
if (!ExtDecls.empty() && Loc.isValid()) {
auto ExtTyLoc = ExtDecls.back()->getExtendedTypeLoc().getLoc();
if (ExtTyLoc.isValid() && ExtTyLoc == Loc.getBaseNameLoc()) {
ExtDecl = ExtDecls.back();
}
}
}
CharSourceRange Range =
Lexer::getCharSourceRangeFromSourceRange(D->getASTContext().SourceMgr,
Loc.getSourceRange());
bool Continue = SEWalker.visitDeclReference(D, Range, CtorTyRef, ExtDecl, Ty,
Data);
if (!Continue)
Cancelled = true;
return Continue;
}
bool SemaAnnotator::passReference(ModuleEntity Mod,
std::pair<Identifier, SourceLoc> IdLoc) {
if (IdLoc.second.isInvalid())
return true;
unsigned NameLen = IdLoc.first.getLength();
CharSourceRange Range{ IdLoc.second, NameLen };
bool Continue = SEWalker.visitModuleReference(Mod, Range);
if (!Continue)
Cancelled = true;
return Continue;
}
bool SemaAnnotator::passCallArgNames(Expr *Fn, TupleExpr *TupleE) {
ValueDecl *D = extractDecl(Fn);
if (!D)
return true; // continue.
ArrayRef<Identifier> ArgNames = TupleE->getElementNames();
ArrayRef<SourceLoc> ArgLocs = TupleE->getElementNameLocs();
for (auto i : indices(ArgNames)) {
Identifier Name = ArgNames[i];
if (Name.empty())
continue;
SourceLoc Loc = ArgLocs[i];
if (Loc.isInvalid())
continue;
CharSourceRange Range{ Loc, Name.getLength() };
bool Continue = SEWalker.visitCallArgName(Name, Range, D);
if (!Continue) {
Cancelled = true;
return false;
}
}
return true;
}
bool SemaAnnotator::shouldIgnore(Decl *D, bool &ShouldVisitChildren) {
if (D->isImplicit() &&
!isa<PatternBindingDecl>(D) &&
!isa<ConstructorDecl>(D)) {
ShouldVisitChildren = false;
return true;
}
return false;
}
bool SourceEntityWalker::walk(SourceFile &SrcFile) {
SemaAnnotator Annotator(*this);
return SrcFile.walk(Annotator);
}
bool SourceEntityWalker::walk(ModuleDecl &Mod) {
SemaAnnotator Annotator(*this);
return Mod.walk(Annotator);
}
bool SourceEntityWalker::walk(Stmt *S) {
SemaAnnotator Annotator(*this);
return S->walk(Annotator);
}
bool SourceEntityWalker::walk(Expr *E) {
SemaAnnotator Annotator(*this);
return E->walk(Annotator);
}
bool SourceEntityWalker::walk(Decl *D) {
SemaAnnotator Annotator(*this);
return D->walk(Annotator);
}
bool SourceEntityWalker::walk(DeclContext *DC) {
SemaAnnotator Annotator(*this);
return DC->walkContext(Annotator);
}
bool SourceEntityWalker::walk(ASTNode N) {
if (auto *E = N.dyn_cast<Expr*>())
return walk(E);
if (auto *S = N.dyn_cast<Stmt*>())
return walk(S);
if (auto *D = N.dyn_cast<Decl*>())
return walk(D);
llvm_unreachable("unsupported AST node");
}
bool SourceEntityWalker::visitDeclReference(ValueDecl *D, CharSourceRange Range,
TypeDecl *CtorTyRef,
ExtensionDecl *ExtTyRef, Type T,
ReferenceMetaData Data) {
return true;
}
bool SourceEntityWalker::visitSubscriptReference(ValueDecl *D,
CharSourceRange Range,
Optional<AccessKind> AccKind,
bool IsOpenBracket) {
// Most of the clients treat subscript reference the same way as a
// regular reference when called on the open bracket and
// ignore the closing one.
return IsOpenBracket ? visitDeclReference(D, Range, nullptr, nullptr, Type(),
ReferenceMetaData(SemaReferenceKind::SubscriptRef, AccKind)) : true;
}
bool SourceEntityWalker::visitCallArgName(Identifier Name,
CharSourceRange Range,
ValueDecl *D) {
return true;
}
bool SourceEntityWalker::
visitDeclarationArgumentName(Identifier Name, SourceLoc Start, ValueDecl *D) {
return true;
}
bool SourceEntityWalker::visitModuleReference(ModuleEntity Mod,
CharSourceRange Range) {
return true;
}
void SourceEntityWalker::anchor() {}