mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Create a new FallthroughStmt, which transfers control from a 'case' or 'default' block to the next 'case' or 'default' block within a switch. Implement parsing and sema for FallthroughStmt, which syntactically consists of a single 'fallthrough' keyword. Sema verifies that 'fallthrough' actually appears inside a switch statement and that there is a following case or default block to pass control to. SILGen/IRGen support forthcoming. Swift SVN r4653
766 lines
26 KiB
C++
766 lines
26 KiB
C++
//===--- NameLookup.cpp - Swift Name Lookup Routines ----------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements interfaces for performing name lookup.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/AST/ASTVisitor.h"
|
|
|
|
using namespace swift;
|
|
|
|
static void DoGlobalExtensionLookup(Type BaseType, Identifier Name,
|
|
ArrayRef<ValueDecl*> BaseMembers,
|
|
Module *CurModule,
|
|
Module *BaseModule,
|
|
bool IsTypeLookup,
|
|
SmallVectorImpl<ValueDecl*> &Result) {
|
|
bool CurModuleHasTypeDecl = false;
|
|
llvm::SmallPtrSet<CanType, 8> CurModuleTypes;
|
|
|
|
// FIXME: Hack to avoid searching Clang modules more than once.
|
|
bool searchedClangModule = isa<ClangModule>(CurModule);
|
|
|
|
// Find all extensions in this module.
|
|
for (ExtensionDecl *ED : CurModule->lookupExtensions(BaseType)) {
|
|
for (Decl *Member : ED->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member)) {
|
|
if (VD->getName() == Name) {
|
|
Result.push_back(VD);
|
|
if (!IsTypeLookup)
|
|
CurModuleTypes.insert(VD->getType()->getCanonicalType());
|
|
CurModuleHasTypeDecl |= isa<TypeDecl>(VD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BaseModule == CurModule) {
|
|
for (ValueDecl *VD : BaseMembers) {
|
|
if (VD->getName() == Name) {
|
|
Result.push_back(VD);
|
|
if (!IsTypeLookup)
|
|
CurModuleTypes.insert(VD->getType()->getCanonicalType());
|
|
CurModuleHasTypeDecl |= isa<TypeDecl>(VD);
|
|
}
|
|
}
|
|
}
|
|
|
|
// The builtin module has no imports.
|
|
if (isa<BuiltinModule>(CurModule)) return;
|
|
|
|
// The Clang module loader handles transitive lookups itself... but is that
|
|
// what we want?
|
|
if (isa<ClangModule>(CurModule)) return;
|
|
|
|
// If we find a type in the current module, don't look into any
|
|
// imported modules.
|
|
if (CurModuleHasTypeDecl) return;
|
|
|
|
TranslationUnit &TU = *cast<TranslationUnit>(CurModule);
|
|
|
|
// Otherwise, check our imported extensions as well.
|
|
// FIXME: Implement DAG-based shadowing rules.
|
|
llvm::SmallPtrSet<Module *, 16> Visited;
|
|
for (auto &ImpEntry : TU.getImportedModules()) {
|
|
if (!Visited.insert(ImpEntry.second))
|
|
continue;
|
|
|
|
// FIXME: Don't search Clang modules more than once.
|
|
if (isa<ClangModule>(ImpEntry.second)) {
|
|
if (searchedClangModule)
|
|
continue;
|
|
|
|
searchedClangModule = true;
|
|
}
|
|
|
|
for (ExtensionDecl *ED : ImpEntry.second->lookupExtensions(BaseType)) {
|
|
for (Decl *Member : ED->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member)) {
|
|
if (VD->getName() == Name &&
|
|
(IsTypeLookup || isa<TypeDecl>(VD) ||
|
|
!CurModuleTypes.count(VD->getType()->getCanonicalType()))) {
|
|
Result.push_back(VD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BaseModule != CurModule) {
|
|
for (ValueDecl *VD : BaseMembers) {
|
|
if (VD->getName() == Name &&
|
|
(IsTypeLookup || isa<TypeDecl>(VD) ||
|
|
!CurModuleTypes.count(VD->getType()->getCanonicalType()))) {
|
|
Result.push_back(VD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MemberLookup::MemberLookup(Type BaseTy, Identifier Name, Module &M,
|
|
bool TypeLookup) {
|
|
MemberName = Name;
|
|
IsTypeLookup = TypeLookup;
|
|
VisitedSet Visited;
|
|
doIt(BaseTy, M, /*OnlyInstanceMembers=*/!TypeLookup, Visited);
|
|
}
|
|
|
|
/// doIt - Lookup a member 'Name' in 'BaseTy' within the context
|
|
/// of a given module 'M'. This operation corresponds to a standard "dot"
|
|
/// lookup operation like "a.b" where 'this' is the type of 'a'. This
|
|
/// operation is only valid after name binding.
|
|
///
|
|
/// \param OnlyInstanceMembers Only instance members should be found by
|
|
/// name lookup.
|
|
void MemberLookup::doIt(Type BaseTy, Module &M, bool OnlyInstanceMembers,
|
|
VisitedSet &Visited) {
|
|
typedef MemberLookupResult Result;
|
|
|
|
// Just look through l-valueness. It doesn't affect name lookup.
|
|
BaseTy = BaseTy->getRValueType();
|
|
|
|
// Type check metatype references, as in "some_type.some_member". These are
|
|
// special and can't have extensions.
|
|
if (MetaTypeType *MTT = BaseTy->getAs<MetaTypeType>()) {
|
|
// The metatype represents an arbitrary named type: dig through to the
|
|
// declared type to see what we're dealing with.
|
|
Type Ty = MTT->getInstanceType();
|
|
|
|
// Just perform normal dot lookup on the type with the specified
|
|
// member name to see if we find extensions or anything else. For example,
|
|
// type SomeTy.SomeMember can look up static functions, and can even look
|
|
// up non-static functions as well (thus getting the address of the member).
|
|
doIt(Ty, M, /*OnlyInstanceMembers=*/false, Visited);
|
|
return;
|
|
}
|
|
|
|
// Lookup module references, as on some_module.some_member. These are
|
|
// special and can't have extensions.
|
|
if (ModuleType *MT = BaseTy->getAs<ModuleType>()) {
|
|
SmallVector<ValueDecl*, 8> Decls;
|
|
MT->getModule()->lookupValue(Module::AccessPathTy(), MemberName,
|
|
NLKind::QualifiedLookup, Decls);
|
|
for (ValueDecl *VD : Decls) {
|
|
Results.push_back(Result::getMetatypeMember(VD));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If the base is a protocol, see if this is a reference to a declared
|
|
// protocol member.
|
|
if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) {
|
|
if (!Visited.insert(PT->getDecl()))
|
|
return;
|
|
|
|
for (auto Inherited : PT->getDecl()->getInherited())
|
|
doIt(Inherited.getType(), M, OnlyInstanceMembers, Visited);
|
|
|
|
for (auto Member : PT->getDecl()->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member)) {
|
|
if (VD->getName() != MemberName) continue;
|
|
if (isa<VarDecl>(VD) || isa<SubscriptDecl>(VD) || isa<FuncDecl>(VD)) {
|
|
if (OnlyInstanceMembers && !VD->isInstanceMember())
|
|
continue;
|
|
|
|
Results.push_back(Result::getExistentialMember(VD));
|
|
} else {
|
|
assert(isa<TypeDecl>(VD) && "Unhandled protocol member");
|
|
Results.push_back(Result::getMetatypeMember(VD));
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If the base is a protocol composition, see if this is a reference to a
|
|
// declared protocol member in any of the protocols.
|
|
if (auto PC = BaseTy->getAs<ProtocolCompositionType>()) {
|
|
for (auto Proto : PC->getProtocols())
|
|
doIt(Proto, M, OnlyInstanceMembers, Visited);
|
|
return;
|
|
}
|
|
|
|
// Check to see if any of an archetype's requirements have the member.
|
|
if (ArchetypeType *Archetype = BaseTy->getAs<ArchetypeType>()) {
|
|
for (auto Proto : Archetype->getConformsTo())
|
|
doIt(Proto->getDeclaredType(), M, OnlyInstanceMembers, Visited);
|
|
|
|
if (auto superclass = Archetype->getSuperclass())
|
|
doIt(superclass, M, OnlyInstanceMembers, Visited);
|
|
|
|
// Change existential and metatype members to archetype members, since
|
|
// we're in an archetype.
|
|
for (auto &Result : Results) {
|
|
switch (Result.Kind) {
|
|
case MemberLookupResult::ExistentialMember:
|
|
Result.Kind = MemberLookupResult::ArchetypeMember;
|
|
break;
|
|
|
|
case MemberLookupResult::MetatypeMember:
|
|
Result.Kind = MemberLookupResult::MetaArchetypeMember;
|
|
break;
|
|
|
|
case MemberLookupResult::MemberProperty:
|
|
case MemberLookupResult::MemberFunction:
|
|
case MemberLookupResult::GenericParameter:
|
|
break;
|
|
|
|
case MemberLookupResult::MetaArchetypeMember:
|
|
case MemberLookupResult::ArchetypeMember:
|
|
llvm_unreachable("wrong member lookup result in archetype");
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
do {
|
|
// Look in for members of a nominal type.
|
|
SmallVector<ValueDecl*, 8> ExtensionMethods;
|
|
lookupMembers(BaseTy, M, ExtensionMethods);
|
|
|
|
for (ValueDecl *VD : ExtensionMethods) {
|
|
if (TypeDecl *TD = dyn_cast<TypeDecl>(VD)) {
|
|
auto TAD = dyn_cast<TypeAliasDecl>(TD);
|
|
if (TAD && TAD->isGenericParameter())
|
|
Results.push_back(Result::getGenericParameter(TAD));
|
|
else
|
|
Results.push_back(Result::getMetatypeMember(TD));
|
|
continue;
|
|
}
|
|
|
|
if (OnlyInstanceMembers && !VD->isInstanceMember())
|
|
continue;
|
|
|
|
if (FuncDecl *FD = dyn_cast<FuncDecl>(VD)) {
|
|
if (FD->isStatic())
|
|
Results.push_back(Result::getMetatypeMember(FD));
|
|
else
|
|
Results.push_back(Result::getMemberFunction(FD));
|
|
continue;
|
|
}
|
|
if (OneOfElementDecl *OOED = dyn_cast<OneOfElementDecl>(VD)) {
|
|
Results.push_back(Result::getMetatypeMember(OOED));
|
|
continue;
|
|
}
|
|
assert((isa<VarDecl>(VD) || isa<SubscriptDecl>(VD)) &&
|
|
"Unexpected extension member");
|
|
Results.push_back(Result::getMemberProperty(VD));
|
|
}
|
|
|
|
// If we have a class type, look into its base class.
|
|
ClassDecl *CurClass = nullptr;
|
|
if (auto CT = BaseTy->getAs<ClassType>())
|
|
CurClass = CT->getDecl();
|
|
else if (auto BGT = BaseTy->getAs<BoundGenericType>())
|
|
CurClass = dyn_cast<ClassDecl>(BGT->getDecl());
|
|
else if (UnboundGenericType *UGT = BaseTy->getAs<UnboundGenericType>())
|
|
CurClass = dyn_cast<ClassDecl>(UGT->getDecl());
|
|
|
|
if (CurClass && CurClass->hasBaseClass()) {
|
|
BaseTy = CurClass->getBaseClass();
|
|
} else {
|
|
break;
|
|
}
|
|
} while (1);
|
|
|
|
// Find any overridden methods.
|
|
llvm::SmallPtrSet<ValueDecl*, 8> Overridden;
|
|
for (const auto &Result : Results) {
|
|
if (auto FD = dyn_cast<FuncDecl>(Result.D)) {
|
|
if (FD->getOverriddenDecl())
|
|
Overridden.insert(FD->getOverriddenDecl());
|
|
} else if (auto VarD = dyn_cast<VarDecl>(Result.D)) {
|
|
if (VarD->getOverriddenDecl())
|
|
Overridden.insert(VarD->getOverriddenDecl());
|
|
} else if (auto SD = dyn_cast<SubscriptDecl>(Result.D)) {
|
|
if (SD->getOverriddenDecl())
|
|
Overridden.insert(SD->getOverriddenDecl());
|
|
}
|
|
}
|
|
|
|
// If any methods were overridden, remove them from the results.
|
|
if (!Overridden.empty()) {
|
|
Results.erase(std::remove_if(Results.begin(), Results.end(),
|
|
[&](MemberLookupResult &Res) -> bool {
|
|
return Overridden.count(Res.D);
|
|
}),
|
|
Results.end());
|
|
}
|
|
}
|
|
|
|
void MemberLookup::lookupMembers(Type BaseType, Module &M,
|
|
SmallVectorImpl<ValueDecl*> &Result) {
|
|
NominalTypeDecl *D;
|
|
ArrayRef<ValueDecl*> BaseMembers;
|
|
SmallVector<ValueDecl*, 2> BaseMembersStorage;
|
|
if (BoundGenericType *BGT = BaseType->getAs<BoundGenericType>()) {
|
|
BaseType = BGT->getDecl()->getDeclaredType();
|
|
D = BGT->getDecl();
|
|
} else if (UnboundGenericType *UGT = BaseType->getAs<UnboundGenericType>()) {
|
|
D = UGT->getDecl();
|
|
} else if (NominalType *NT = BaseType->getAs<NominalType>()) {
|
|
D = NT->getDecl();
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
for (Decl* Member : D->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member)) {
|
|
BaseMembersStorage.push_back(VD);
|
|
}
|
|
}
|
|
if (D->getGenericParams())
|
|
for (auto param : *D->getGenericParams())
|
|
BaseMembersStorage.push_back(param.getDecl());
|
|
BaseMembers = BaseMembersStorage;
|
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
while (!DC->isModuleContext())
|
|
DC = DC->getParent();
|
|
|
|
DoGlobalExtensionLookup(BaseType, MemberName, BaseMembers, &M,
|
|
cast<Module>(DC), IsTypeLookup, Result);
|
|
}
|
|
|
|
ConstructorLookup::ConstructorLookup(Type BaseType, Module &M) {
|
|
NominalTypeDecl *D;
|
|
if (NominalType *NT = BaseType->getAs<NominalType>())
|
|
D = NT->getDecl();
|
|
else if (BoundGenericType *BGT = BaseType->getAs<BoundGenericType>())
|
|
D = BGT->getDecl();
|
|
else
|
|
return;
|
|
|
|
SmallVector<ValueDecl*, 16> BaseMembers;
|
|
if (StructDecl *SD = dyn_cast<StructDecl>(D)) {
|
|
for (Decl* Member : SD->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member))
|
|
BaseMembers.push_back(VD);
|
|
}
|
|
} else if (OneOfDecl *OOD = dyn_cast<OneOfDecl>(D)) {
|
|
for (Decl* Member : OOD->getMembers()) {
|
|
// FIXME: We shouldn't be injecting OneOfElementDecls into the results
|
|
// like this.
|
|
if (OneOfElementDecl *OOED = dyn_cast<OneOfElementDecl>(Member))
|
|
Results.push_back(OOED);
|
|
else if (ValueDecl *VD = dyn_cast<ValueDecl>(Member))
|
|
BaseMembers.push_back(VD);
|
|
}
|
|
} else if (ClassDecl *CD = dyn_cast<ClassDecl>(D)) {
|
|
for (Decl* Member : CD->getMembers()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(Member))
|
|
BaseMembers.push_back(VD);
|
|
}
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
Identifier Constructor = M.Ctx.getIdentifier("constructor");
|
|
DeclContext *DC = D->getDeclContext();
|
|
if (!DC->isModuleContext()) {
|
|
for (ValueDecl *VD : BaseMembers) {
|
|
if (VD->getName() == Constructor)
|
|
Results.push_back(VD);
|
|
}
|
|
return;
|
|
}
|
|
|
|
DoGlobalExtensionLookup(BaseType, Constructor, BaseMembers, &M,
|
|
cast<Module>(DC), /*IsTypeLookup*/false, Results);
|
|
}
|
|
|
|
struct FindLocalVal : public StmtVisitor<FindLocalVal> {
|
|
SourceLoc Loc;
|
|
Identifier Name;
|
|
ValueDecl *MatchingValue;
|
|
|
|
FindLocalVal(SourceLoc Loc, Identifier Name)
|
|
: Loc(Loc), Name(Name), MatchingValue(nullptr) {}
|
|
|
|
bool IntersectsRange(SourceRange R) {
|
|
return R.Start.Value.getPointer() <= Loc.Value.getPointer() &&
|
|
R.End.Value.getPointer() >= Loc.Value.getPointer();
|
|
}
|
|
|
|
void checkValueDecl(ValueDecl *D) {
|
|
if (D->getName() == Name) {
|
|
assert(!MatchingValue);
|
|
MatchingValue = D;
|
|
}
|
|
}
|
|
|
|
void checkPattern(Pattern *Pat) {
|
|
switch (Pat->getKind()) {
|
|
case PatternKind::Tuple:
|
|
for (auto &field : cast<TuplePattern>(Pat)->getFields())
|
|
checkPattern(field.getPattern());
|
|
return;
|
|
case PatternKind::Paren:
|
|
return checkPattern(cast<ParenPattern>(Pat)->getSubPattern());
|
|
case PatternKind::Typed:
|
|
return checkPattern(cast<TypedPattern>(Pat)->getSubPattern());
|
|
case PatternKind::Named:
|
|
return checkValueDecl(cast<NamedPattern>(Pat)->getDecl());
|
|
// Handle non-vars.
|
|
case PatternKind::Any:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void checkGenericParams(GenericParamList *Params) {
|
|
if (!Params)
|
|
return;
|
|
|
|
for (auto P : *Params)
|
|
checkValueDecl(P.getDecl());
|
|
}
|
|
|
|
void checkTranslationUnit(TranslationUnit *TU) {
|
|
for (Decl *D : TU->Decls) {
|
|
if (TopLevelCodeDecl *TLCD = dyn_cast<TopLevelCodeDecl>(D))
|
|
visit(TLCD->getBody());
|
|
}
|
|
}
|
|
|
|
void visitBreakStmt(BreakStmt *) {}
|
|
void visitContinueStmt(ContinueStmt *) {}
|
|
void visitFallthroughStmt(FallthroughStmt *) {}
|
|
void visitAssignStmt(AssignStmt *) {}
|
|
void visitReturnStmt(ReturnStmt *) {}
|
|
void visitIfStmt(IfStmt * S) {
|
|
visit(S->getThenStmt());
|
|
if (S->getElseStmt())
|
|
visit(S->getElseStmt());
|
|
}
|
|
void visitWhileStmt(WhileStmt *S) {
|
|
visit(S->getBody());
|
|
}
|
|
void visitDoWhileStmt(DoWhileStmt *S) {
|
|
visit(S->getBody());
|
|
}
|
|
|
|
void visitForStmt(ForStmt *S) {
|
|
if (!IntersectsRange(S->getSourceRange()))
|
|
return;
|
|
visit(S->getBody());
|
|
if (MatchingValue)
|
|
return;
|
|
for (Decl *D : S->getInitializerVarDecls()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
checkValueDecl(VD);
|
|
}
|
|
}
|
|
void visitForEachStmt(ForEachStmt *S) {
|
|
if (!IntersectsRange(S->getSourceRange()))
|
|
return;
|
|
visit(S->getBody());
|
|
if (MatchingValue)
|
|
return;
|
|
checkPattern(S->getPattern());
|
|
}
|
|
void visitBraceStmt(BraceStmt *S) {
|
|
if (!IntersectsRange(S->getSourceRange()))
|
|
return;
|
|
for (auto elem : S->getElements()) {
|
|
if (Stmt *S = elem.dyn_cast<Stmt*>())
|
|
visit(S);
|
|
}
|
|
if (MatchingValue)
|
|
return;
|
|
for (auto elem : S->getElements()) {
|
|
if (Decl *D = elem.dyn_cast<Decl*>()) {
|
|
if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
|
|
checkValueDecl(VD);
|
|
}
|
|
}
|
|
}
|
|
void visitSwitchStmt(SwitchStmt *S) {
|
|
if (!IntersectsRange(S->getSourceRange()))
|
|
return;
|
|
for (CaseStmt *C : S->getCases()) {
|
|
visit(C);
|
|
}
|
|
}
|
|
|
|
void visitCaseStmt(CaseStmt *S) {
|
|
if (!IntersectsRange(S->getSourceRange()))
|
|
return;
|
|
|
|
// TODO: Check patterns in pattern-matching case.
|
|
visit(S->getBody());
|
|
}
|
|
};
|
|
|
|
UnqualifiedLookup::UnqualifiedLookup(Identifier Name, DeclContext *DC,
|
|
SourceLoc Loc, bool IsTypeLookup) {
|
|
typedef UnqualifiedLookupResult Result;
|
|
|
|
DeclContext *ModuleDC = DC;
|
|
while (!ModuleDC->isModuleContext())
|
|
ModuleDC = ModuleDC->getParent();
|
|
|
|
Module &M = *cast<Module>(ModuleDC);
|
|
|
|
// Never perform local lookup for operators.
|
|
if (Name.isOperator())
|
|
DC = ModuleDC;
|
|
|
|
// If we are inside of a method, check to see if there are any ivars in scope,
|
|
// and if so, whether this is a reference to one of them.
|
|
while (!DC->isModuleContext()) {
|
|
ValueDecl *BaseDecl = 0;
|
|
ValueDecl *MetaBaseDecl = 0;
|
|
GenericParamList *GenericParams = nullptr;
|
|
Type ExtendedType;
|
|
if (FuncExpr *FE = dyn_cast<FuncExpr>(DC)) {
|
|
// Look for local variables; normally, the parser resolves these
|
|
// for us, but it can't do the right thing inside local types.
|
|
if (Loc.isValid()) {
|
|
FindLocalVal localVal(Loc, Name);
|
|
localVal.visit(FE->getBody());
|
|
if (!localVal.MatchingValue) {
|
|
for (Pattern *P : FE->getBodyParamPatterns())
|
|
localVal.checkPattern(P);
|
|
}
|
|
if (localVal.MatchingValue) {
|
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
return;
|
|
}
|
|
}
|
|
|
|
FuncDecl *FD = FE->getDecl();
|
|
if (FD && FD->getExtensionType()) {
|
|
ExtendedType = FD->getExtensionType();
|
|
BaseDecl = FD->getImplicitThisDecl();
|
|
if (NominalType *NT = ExtendedType->getAs<NominalType>())
|
|
MetaBaseDecl = NT->getDecl();
|
|
else if (auto UGT = ExtendedType->getAs<UnboundGenericType>())
|
|
MetaBaseDecl = UGT->getDecl();
|
|
DC = DC->getParent();
|
|
|
|
if (FD->isStatic())
|
|
ExtendedType = MetaTypeType::get(ExtendedType, M.getASTContext());
|
|
}
|
|
|
|
// Look in the generic parameters after checking our local declaration.
|
|
if (FD)
|
|
GenericParams = FD->getGenericParams();
|
|
|
|
} else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(DC)) {
|
|
ExtendedType = ED->getExtendedType();
|
|
if (NominalType *NT = ExtendedType->getAs<NominalType>())
|
|
BaseDecl = NT->getDecl();
|
|
else if (auto UGT = ExtendedType->getAs<UnboundGenericType>())
|
|
BaseDecl = UGT->getDecl();
|
|
MetaBaseDecl = BaseDecl;
|
|
} else if (NominalTypeDecl *ND = dyn_cast<NominalTypeDecl>(DC)) {
|
|
ExtendedType = ND->getDeclaredType();
|
|
BaseDecl = ND;
|
|
MetaBaseDecl = BaseDecl;
|
|
} else if (ConstructorDecl *CD = dyn_cast<ConstructorDecl>(DC)) {
|
|
// Look for local variables; normally, the parser resolves these
|
|
// for us, but it can't do the right thing inside local types.
|
|
if (Loc.isValid()) {
|
|
FindLocalVal localVal(Loc, Name);
|
|
localVal.visit(CD->getBody());
|
|
if (!localVal.MatchingValue)
|
|
localVal.checkPattern(CD->getArguments());
|
|
if (localVal.MatchingValue) {
|
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
return;
|
|
}
|
|
}
|
|
|
|
BaseDecl = CD->getImplicitThisDecl();
|
|
ExtendedType = CD->getDeclContext()->getDeclaredTypeOfContext();
|
|
if (NominalType *NT = ExtendedType->getAs<NominalType>())
|
|
MetaBaseDecl = NT->getDecl();
|
|
else if (auto UGT = ExtendedType->getAs<UnboundGenericType>())
|
|
MetaBaseDecl = UGT->getDecl();
|
|
DC = DC->getParent();
|
|
} else if (DestructorDecl *DD = dyn_cast<DestructorDecl>(DC)) {
|
|
// Look for local variables; normally, the parser resolves these
|
|
// for us, but it can't do the right thing inside local types.
|
|
if (Loc.isValid()) {
|
|
FindLocalVal localVal(Loc, Name);
|
|
localVal.visit(CD->getBody());
|
|
if (!localVal.MatchingValue)
|
|
localVal.checkPattern(CD->getArguments());
|
|
if (localVal.MatchingValue) {
|
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
return;
|
|
}
|
|
}
|
|
|
|
BaseDecl = DD->getImplicitThisDecl();
|
|
ExtendedType = DD->getDeclContext()->getDeclaredTypeOfContext();
|
|
if (NominalType *NT = ExtendedType->getAs<NominalType>())
|
|
MetaBaseDecl = NT->getDecl();
|
|
else if (auto UGT = ExtendedType->getAs<UnboundGenericType>())
|
|
MetaBaseDecl = UGT->getDecl();
|
|
DC = DC->getParent();
|
|
}
|
|
|
|
if (BaseDecl) {
|
|
MemberLookup Lookup(ExtendedType, Name, M, IsTypeLookup);
|
|
|
|
for (auto Result : Lookup.Results) {
|
|
switch (Result.Kind) {
|
|
case MemberLookupResult::MemberProperty:
|
|
Results.push_back(Result::getMemberProperty(BaseDecl, Result.D));
|
|
break;
|
|
case MemberLookupResult::MemberFunction:
|
|
Results.push_back(Result::getMemberFunction(BaseDecl, Result.D));
|
|
break;
|
|
case MemberLookupResult::MetatypeMember:
|
|
// For results that can only be accessed via the metatype (e.g.,
|
|
// type aliases), we need to use the metatype declaration as the
|
|
// base.
|
|
Results.push_back(Result::getMetatypeMember(isa<FuncDecl>(Result.D)?
|
|
BaseDecl : MetaBaseDecl,
|
|
Result.D));
|
|
break;
|
|
case MemberLookupResult::ExistentialMember:
|
|
Results.push_back(Result::getExistentialMember(BaseDecl, Result.D));
|
|
break;
|
|
case MemberLookupResult::ArchetypeMember:
|
|
Results.push_back(Result::getArchetypeMember(BaseDecl, Result.D));
|
|
break;
|
|
case MemberLookupResult::MetaArchetypeMember:
|
|
// For results that can only be accessed via the metatype (e.g.,
|
|
// type aliases), we need to use the metatype declaration as the
|
|
// base.
|
|
Results.push_back(Result::getMetaArchetypeMember(
|
|
isa<FuncDecl>(Result.D)? BaseDecl : MetaBaseDecl,
|
|
Result.D));
|
|
break;
|
|
case MemberLookupResult::GenericParameter:
|
|
// All generic parameters are 'local'.
|
|
Results.push_back(Result::getLocalDecl(Result.D));
|
|
break;
|
|
}
|
|
}
|
|
if (Lookup.isSuccess())
|
|
return;
|
|
}
|
|
|
|
// Check the generic parameters for something with the given name.
|
|
if (GenericParams) {
|
|
FindLocalVal localVal(Loc, Name);
|
|
localVal.checkGenericParams(GenericParams);
|
|
|
|
if (localVal.MatchingValue) {
|
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
return;
|
|
}
|
|
}
|
|
|
|
DC = DC->getParent();
|
|
}
|
|
|
|
if (Loc.isValid()) {
|
|
if (TranslationUnit *TU = dyn_cast<TranslationUnit>(&M)) {
|
|
// Look for local variables in top-level code; normally, the parser
|
|
// resolves these for us, but it can't do the right thing for
|
|
// local types.
|
|
FindLocalVal localVal(Loc, Name);
|
|
localVal.checkTranslationUnit(TU);
|
|
if (localVal.MatchingValue) {
|
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Track whether we've already searched the Clang modules.
|
|
// FIXME: This is a weird hack. We either need to filter within the
|
|
// Clang module importer, or we need to change how this works.
|
|
bool searchedClangModule = false;
|
|
|
|
// Do a local lookup within the current module.
|
|
llvm::SmallVector<ValueDecl*, 4> CurModuleResults;
|
|
M.lookupValue(Module::AccessPathTy(), Name, NLKind::UnqualifiedLookup,
|
|
CurModuleResults);
|
|
searchedClangModule = isa<ClangModule>(&M);
|
|
for (ValueDecl *VD : CurModuleResults)
|
|
Results.push_back(Result::getModuleMember(VD));
|
|
|
|
// The builtin module has no imports.
|
|
if (isa<BuiltinModule>(M)) return;
|
|
|
|
TranslationUnit &TU = cast<TranslationUnit>(M);
|
|
|
|
llvm::SmallPtrSet<CanType, 8> CurModuleTypes;
|
|
for (ValueDecl *VD : CurModuleResults) {
|
|
// If we find a type in the current module, don't look into any
|
|
// imported modules.
|
|
if (isa<TypeDecl>(VD))
|
|
return;
|
|
if (!IsTypeLookup)
|
|
CurModuleTypes.insert(VD->getType()->getCanonicalType());
|
|
}
|
|
|
|
// Scrape through all of the imports looking for additional results.
|
|
// FIXME: Implement DAG-based shadowing rules.
|
|
llvm::SmallPtrSet<Module *, 16> Visited;
|
|
for (auto &ImpEntry : TU.getImportedModules()) {
|
|
if (!Visited.insert(ImpEntry.second))
|
|
continue;
|
|
|
|
// FIXME: Only searching Clang modules once.
|
|
if (isa<ClangModule>(ImpEntry.second)) {
|
|
if (searchedClangModule)
|
|
continue;
|
|
|
|
searchedClangModule = true;
|
|
}
|
|
|
|
SmallVector<ValueDecl*, 8> ImportedModuleResults;
|
|
ImpEntry.second->lookupValue(ImpEntry.first, Name, NLKind::UnqualifiedLookup,
|
|
ImportedModuleResults);
|
|
for (ValueDecl *VD : ImportedModuleResults) {
|
|
if (IsTypeLookup || isa<TypeDecl>(VD) ||
|
|
!CurModuleTypes.count(VD->getType()->getCanonicalType())) {
|
|
Results.push_back(Result::getModuleMember(VD));
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we've found something, we're done.
|
|
if (!Results.empty())
|
|
return;
|
|
|
|
// Look for a module with the given name.
|
|
if (Name == M.Name) {
|
|
Results.push_back(Result::getModuleName(&M));
|
|
} else {
|
|
for (const auto &ImpEntry : TU.getImportedModules())
|
|
if (ImpEntry.second->Name == Name) {
|
|
Results.push_back(Result::getModuleName(ImpEntry.second));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TypeDecl* UnqualifiedLookup::getSingleTypeResult() {
|
|
if (Results.size() != 1 || !Results.back().hasValueDecl() ||
|
|
!isa<TypeDecl>(Results.back().getValueDecl()))
|
|
return nullptr;
|
|
return cast<TypeDecl>(Results.back().getValueDecl());
|
|
}
|