blob: 4426ab9fdb62ca645daf5c85a55089e629557895 [file] [log] [blame]
//===--- NameLookupImpl.h - Helpers used to implement lookup ----*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_NAME_LOOKUP_IMPL_H
#define SWIFT_AST_NAME_LOOKUP_IMPL_H
#include "swift/AST/NameLookup.h"
#include "swift/AST/ASTVisitor.h"
#include "swift/AST/ParameterList.h"
namespace swift {
namespace namelookup {
/// Performs a qualified lookup into the given module and, if necessary, its
/// reexports, observing proper shadowing rules.
void
lookupVisibleDeclsInModule(ModuleDecl *M, ModuleDecl::AccessPathTy accessPath,
SmallVectorImpl<ValueDecl *> &decls,
NLKind lookupKind,
ResolutionKind resolutionKind,
LazyResolver *typeResolver,
const DeclContext *moduleScopeContext,
ArrayRef<ModuleDecl::ImportedModule> extraImports = {});
/// Searches through statements and patterns for local variable declarations.
class FindLocalVal : public StmtVisitor<FindLocalVal> {
friend class ASTVisitor<FindLocalVal>;
const SourceManager &SM;
SourceLoc Loc;
VisibleDeclConsumer &Consumer;
public:
FindLocalVal(const SourceManager &SM, SourceLoc Loc,
VisibleDeclConsumer &Consumer)
: SM(SM), Loc(Loc), Consumer(Consumer) {}
void checkValueDecl(ValueDecl *D, DeclVisibilityKind Reason) {
Consumer.foundDecl(D, Reason);
}
void checkPattern(const Pattern *Pat, DeclVisibilityKind Reason) {
switch (Pat->getKind()) {
case PatternKind::Tuple:
for (auto &field : cast<TuplePattern>(Pat)->getElements())
checkPattern(field.getPattern(), Reason);
return;
case PatternKind::Paren:
case PatternKind::Typed:
case PatternKind::Var:
return checkPattern(Pat->getSemanticsProvidingPattern(), Reason);
case PatternKind::Named:
return checkValueDecl(cast<NamedPattern>(Pat)->getDecl(), Reason);
case PatternKind::EnumElement: {
auto *OP = cast<EnumElementPattern>(Pat);
if (OP->hasSubPattern())
checkPattern(OP->getSubPattern(), Reason);
return;
}
case PatternKind::OptionalSome:
checkPattern(cast<OptionalSomePattern>(Pat)->getSubPattern(), Reason);
return;
case PatternKind::Is: {
auto *isPat = cast<IsPattern>(Pat);
if (isPat->hasSubPattern())
checkPattern(isPat->getSubPattern(), Reason);
return;
}
// Handle non-vars.
case PatternKind::Bool:
case PatternKind::Expr:
case PatternKind::Any:
return;
}
}
void checkParameterList(const ParameterList *params) {
for (auto param : *params) {
checkValueDecl(param, DeclVisibilityKind::FunctionParameter);
}
}
void checkGenericParams(GenericParamList *Params) {
if (!Params)
return;
for (auto P : *Params)
checkValueDecl(P, DeclVisibilityKind::GenericParameter);
}
void checkSourceFile(const SourceFile &SF) {
for (Decl *D : SF.Decls)
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D))
visitBraceStmt(TLCD->getBody(), /*isTopLevel=*/true);
}
private:
bool isReferencePointInRange(SourceRange R) {
return SM.rangeContainsTokenLoc(R, Loc);
}
void visitBreakStmt(BreakStmt *) {}
void visitContinueStmt(ContinueStmt *) {}
void visitFallthroughStmt(FallthroughStmt *) {}
void visitFailStmt(FailStmt *) {}
void visitReturnStmt(ReturnStmt *) {}
void visitThrowStmt(ThrowStmt *) {}
void visitDeferStmt(DeferStmt *DS) {
// Nothing in the defer is visible.
}
void checkStmtCondition(const StmtCondition &Cond) {
SourceLoc start = SourceLoc();
for (auto entry : Cond) {
if (start.isInvalid())
start = entry.getStartLoc();
if (auto *P = entry.getPatternOrNull()) {
SourceRange previousConditionsToHere = SourceRange(start, entry.getEndLoc());
if (!isReferencePointInRange(previousConditionsToHere))
checkPattern(P, DeclVisibilityKind::LocalVariable);
}
}
}
void visitIfStmt(IfStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
if (!S->getElseStmt() ||
!isReferencePointInRange(S->getElseStmt()->getSourceRange())) {
checkStmtCondition(S->getCond());
}
visit(S->getThenStmt());
if (S->getElseStmt())
visit(S->getElseStmt());
}
void visitGuardStmt(GuardStmt *S) {
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
return;
// Names in the guard aren't visible until after the body.
if (!isReferencePointInRange(S->getBody()->getSourceRange()))
checkStmtCondition(S->getCond());
visit(S->getBody());
}
void visitWhileStmt(WhileStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
checkStmtCondition(S->getCond());
visit(S->getBody());
}
void visitRepeatWhileStmt(RepeatWhileStmt *S) {
visit(S->getBody());
}
void visitDoStmt(DoStmt *S) {
visit(S->getBody());
}
void visitForEachStmt(ForEachStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
visit(S->getBody());
if (!isReferencePointInRange(S->getSequence()->getSourceRange()))
checkPattern(S->getPattern(), DeclVisibilityKind::LocalVariable);
}
void visitBraceStmt(BraceStmt *S, bool isTopLevelCode = false) {
if (isTopLevelCode) {
if (SM.isBeforeInBuffer(Loc, S->getStartLoc()))
return;
} else {
if (!isReferencePointInRange(S->getSourceRange()))
return;
}
for (auto elem : S->getElements()) {
if (auto *S = elem.dyn_cast<Stmt*>())
visit(S);
}
for (auto elem : S->getElements()) {
if (auto *D = elem.dyn_cast<Decl*>()) {
if (auto *VD = dyn_cast<ValueDecl>(D))
checkValueDecl(VD, DeclVisibilityKind::LocalVariable);
}
}
}
void visitSwitchStmt(SwitchStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
for (CaseStmt *C : S->getCases()) {
visit(C);
}
}
void visitCaseStmt(CaseStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
// Pattern names aren't visible in the patterns themselves,
// just in the body or in where guards.
auto body = S->getBody();
bool inPatterns = isReferencePointInRange(S->getLabelItemsRange());
auto items = S->getCaseLabelItems();
if (inPatterns) {
for (const auto &CLI : items) {
auto guard = CLI.getGuardExpr();
if (guard && isReferencePointInRange(guard->getSourceRange())) {
inPatterns = false;
break;
}
}
}
if (!inPatterns && items.size() > 0)
checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable);
visit(body);
}
void visitDoCatchStmt(DoCatchStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
visit(S->getBody());
visitCatchClauses(S->getCatches());
}
void visitCatchClauses(ArrayRef<CatchStmt*> clauses) {
// TODO: some sort of binary search?
for (auto clause : clauses) {
visitCatchStmt(clause);
}
}
void visitCatchStmt(CatchStmt *S) {
if (!isReferencePointInRange(S->getSourceRange()))
return;
// Names in the pattern aren't visible until after the pattern.
if (!isReferencePointInRange(S->getErrorPattern()->getSourceRange()))
checkPattern(S->getErrorPattern(), DeclVisibilityKind::LocalVariable);
visit(S->getBody());
}
};
} // end namespace namelookup
} // end namespace swift
#endif