Files
swift-mirror/lib/IDE/SourceEntityWalker.cpp
Jordan Rose 417b5d3982 Merge TranslationUnit into Module, and eliminate the term "translation unit".
This completes the FileUnit refactoring. A module consists of multiple
FileUnits, which provide decls from various file-like sources. I say
"file-like" because the Builtin module is implemented with a single
BuiltinUnit, and imported Clang modules are just a single FileUnit source
within a module.

Most modules, therefore, contain a single file unit; only the main module
will contain multiple source files (and eventually partial AST files).

The term "translation unit" has been scrubbed from the project. To refer
to the context of declarations outside of any other declarations, use
"top-level" or "module scope". To refer to a .swift file or its DeclContext,
use "source file". To refer to a single unit of compilation, use "module",
since the model is that an entire module will be compiled with a single
driver call. (It will still be possible to compile a single source file
through the direct-to-frontend interface, but only in the context of the
whole module.)

Swift SVN r10837
2013-12-05 01:51:15 +00:00

277 lines
7.3 KiB
C++

//===- SourceEntityWalker.cpp - Routines for semantic source info ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/IDE/SourceEntityWalker.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/TypeRepr.h"
#include "swift/AST/Types.h"
#include "swift/Basic/SourceManager.h"
using namespace swift;
using namespace ide;
namespace {
class SemaAnnotator : public ASTWalker {
SourceEntityWalker &SEWalker;
SmallVector<ConstructorRefCallExpr *, 2> CtorRefs;
bool Cancelled = false;
public:
explicit SemaAnnotator(SourceEntityWalker &SEWalker)
: SEWalker(SEWalker) { }
bool isDone() const { return Cancelled; }
private:
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;
bool passReference(ValueDecl *D, SourceLoc Loc);
TypeDecl *getTypeDecl(Type Ty);
bool shouldIgnore(Decl *D, bool &ShouldVisitChildren);
ValueDecl *extractDecl(Expr *Fn) const {
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Fn))
return DRE->getDecl();
return nullptr;
}
};
}
bool SemaAnnotator::walkToDeclPre(Decl *D) {
if (isDone())
return false;
bool ShouldVisitChildren;
if (shouldIgnore(D, ShouldVisitChildren))
return ShouldVisitChildren;
SourceLoc Loc = D->getLoc();
unsigned NameLen = 0;
if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
if (auto FD = dyn_cast<FuncDecl>(D)) {
if (FD->isGetterOrSetter()) {
NameLen = 0;
} else {
NameLen = VD->getName().getLength();
}
} else {
NameLen = VD->getName().getLength();
}
} else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D)) {
if (TypeRepr *TR = ED->getExtendedTypeLoc().getTypeRepr()) {
SourceRange SR = TR->getSourceRange();
Loc = SR.Start;
NameLen = ED->getASTContext().SourceMgr.getByteDistance(SR.Start, SR.End);
} else {
Loc = SourceLoc();
}
} else {
return true;
}
CharSourceRange Range = (Loc.isValid()) ? CharSourceRange(Loc, NameLen)
: CharSourceRange();
return SEWalker.walkToDeclPre(D, Range);
}
bool SemaAnnotator::walkToDeclPost(Decl *D) {
if (isDone())
return false;
bool ShouldVisitChildren;
if (shouldIgnore(D, ShouldVisitChildren))
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);
return { TraverseChildren, S };
}
Stmt *SemaAnnotator::walkToStmtPost(Stmt *S) {
bool Continue = SEWalker.walkToStmtPost(S);
if (!Continue)
Cancelled = true;
return Continue ? S : nullptr;
}
std::pair<bool, Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
if (isDone())
return { false, nullptr };
if (!SEWalker.walkToExprPre(E))
return { false, E };
if (ConstructorRefCallExpr *CtorRefE = dyn_cast<ConstructorRefCallExpr>(E))
CtorRefs.push_back(CtorRefE);
if (E->isImplicit())
return { true, E };
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
if (!passReference(DRE->getDecl(), E->getLoc()))
return { false, nullptr };
} else if (MemberRefExpr *MRE = dyn_cast<MemberRefExpr>(E)) {
// Visit in source order.
if (!MRE->getBase()->walk(*this))
return { false, nullptr };
if (!passReference(MRE->getMember().getDecl(), E->getLoc()))
return { false, nullptr };
// We already visited the children.
if (!walkToExprPost(E))
return { false, nullptr };
return { false, E };
} else if (SubscriptExpr *SE = dyn_cast<SubscriptExpr>(E)) {
if (SE->hasDecl())
if (!passReference(SE->getDecl().getDecl(), E->getLoc()))
return { false, nullptr };
} else if (BinaryExpr *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 };
}
return { true, E };
}
bool SemaAnnotator::walkToTypeReprPre(TypeRepr *T) {
if (isDone())
return false;
if (IdentTypeRepr *IdT = dyn_cast<IdentTypeRepr>(T)) {
for (auto &Comp : IdT->Components) {
if (ValueDecl *VD = Comp.getBoundDecl())
return passReference(VD, Comp.getIdLoc());
if (TypeDecl *TyD = getTypeDecl(Comp.getBoundType()))
return passReference(TyD, Comp.getIdLoc());
}
}
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) {
if (isDone())
return false;
return true;
}
bool SemaAnnotator::passReference(ValueDecl *D, SourceLoc Loc) {
unsigned NameLen = D->getName().getLength();
TypeDecl *CtorTyRef = nullptr;
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
if (!CtorRefs.empty() && Loc.isValid()) {
Expr *Fn = CtorRefs.back()->getFn();
if (Fn->getLoc() == Loc) {
D = extractDecl(Fn);
CtorTyRef = TD;
}
}
}
CharSourceRange Range = (Loc.isValid()) ? CharSourceRange(Loc, NameLen)
: CharSourceRange();
bool Continue = SEWalker.visitDeclReference(D, Range, CtorTyRef);
if (!Continue)
Cancelled = true;
return Continue;
}
TypeDecl *SemaAnnotator::getTypeDecl(Type Ty) {
if (Ty.isNull())
return nullptr;
if (NameAliasType *NAT = dyn_cast<NameAliasType>(Ty.getPointer()))
return NAT->getDecl();
return Ty->getAnyNominal();
}
bool SemaAnnotator::shouldIgnore(Decl *D, bool &ShouldVisitChildren) {
if (D->isImplicit()) {
ShouldVisitChildren = false;
return true;
}
return false;
}
bool SourceEntityWalker::walk(SourceFile &SrcFile) {
SemaAnnotator Annotator(*this);
return SrcFile.walk(Annotator);
}
bool SourceEntityWalker::walk(Module &Mod) {
SemaAnnotator Annotator(*this);
return Mod.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);
}
void SourceEntityWalker::anchor() {}