mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Dependencies: start tracking whether a lookup is private to a file or not.
This is sort of two commits squashed into one: first, update ReferencedNameTracker to record whether a name or type is non-private, along with changing all clients to assume non-private; and second, actually try to (conservatively) decide if a particular unqualified lookup can be considered private. What does "private" mean? That means that a dependency does not affect "downstream" files. For example, if file A depends on B, and B depends on C, then a change in C normally means A will get rebuilt. But if B's dependencies on C are all private dependencies (e.g. lookups from within function bodies), then A does not need to be rebuilt. In practice there are several rules about when we can make this assumption, and a few places where our current DeclContext model is not good enough to distinguish private uses from non-private uses. In these cases we have to be conservative and assume that the use is non-private (and thus that downstream files will need to be rebuilt). Part of rdar://problem/15353101 Swift SVN r23447
This commit is contained in:
@@ -14,28 +14,29 @@
|
|||||||
#define SWIFT_REFERENCEDNAMETRACKER_H
|
#define SWIFT_REFERENCEDNAMETRACKER_H
|
||||||
|
|
||||||
#include "swift/AST/Identifier.h"
|
#include "swift/AST/Identifier.h"
|
||||||
#include "swift/Basic/LLVM.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
|
||||||
|
|
||||||
namespace swift {
|
namespace swift {
|
||||||
|
|
||||||
|
class NominalTypeDecl;
|
||||||
|
|
||||||
class ReferencedNameTracker {
|
class ReferencedNameTracker {
|
||||||
SmallPtrSet<Identifier, 1> TopLevelNames;
|
llvm::DenseMap<Identifier, bool> TopLevelNames;
|
||||||
SmallPtrSet<const NominalTypeDecl *, 1> UsedNominals;
|
llvm::DenseMap<const NominalTypeDecl *, bool> UsedNominals;
|
||||||
public:
|
public:
|
||||||
void addTopLevelName(Identifier name) {
|
void addTopLevelName(Identifier name, bool isNonPrivateUse) {
|
||||||
TopLevelNames.insert(name);
|
TopLevelNames[name] |= isNonPrivateUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SmallPtrSetImpl<Identifier> &getTopLevelNames() const {
|
const llvm::DenseMap<Identifier, bool> &getTopLevelNames() const {
|
||||||
return TopLevelNames;
|
return TopLevelNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addUsedNominal(const NominalTypeDecl *nominal) {
|
void addUsedNominal(const NominalTypeDecl *nominal, bool isNonPrivateUse) {
|
||||||
UsedNominals.insert(nominal);
|
UsedNominals[nominal] |= isNonPrivateUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SmallPtrSetImpl<const NominalTypeDecl *> &getUsedNominals() const {
|
const llvm::DenseMap<const NominalTypeDecl *, bool> &getUsedNominals() const {
|
||||||
return UsedNominals;
|
return UsedNominals;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1134,8 +1134,9 @@ SourceFile::lookup##Kind##Operator(Identifier name, SourceLoc loc) { \
|
|||||||
auto result = lookupOperatorDeclForName(*this, loc, name, true, \
|
auto result = lookupOperatorDeclForName(*this, loc, name, true, \
|
||||||
&SourceFile::Kind##Operators); \
|
&SourceFile::Kind##Operators); \
|
||||||
if (result.hasValue() && !result.getValue()) { \
|
if (result.hasValue() && !result.getValue()) { \
|
||||||
|
/* FIXME: Track whether this is a private use or not. */ \
|
||||||
if (ReferencedNames) \
|
if (ReferencedNames) \
|
||||||
ReferencedNames->addTopLevelName(name); \
|
ReferencedNames->addTopLevelName(name, true); \
|
||||||
result = lookupOperatorDeclForName(getParentModule(), loc, name, \
|
result = lookupOperatorDeclForName(getParentModule(), loc, name, \
|
||||||
&SourceFile::Kind##Operators); \
|
&SourceFile::Kind##Operators); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -422,15 +422,64 @@ static void filterForDiscriminator(SmallVectorImpl<Result> &results,
|
|||||||
results.push_back(lastMatch);
|
results.push_back(lastMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isPrivateContextForLookup(const DeclContext *DC,
|
||||||
|
bool functionsArePrivate) {
|
||||||
|
switch (DC->getContextKind()) {
|
||||||
|
case DeclContextKind::AbstractClosureExpr:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclContextKind::Initializer:
|
||||||
|
// Default arguments still require a type.
|
||||||
|
if (isa<DefaultArgumentInitializer>(DC))
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclContextKind::TopLevelCodeDecl:
|
||||||
|
// FIXME: Pattern initializers at top-level scope end up here.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case DeclContextKind::AbstractFunctionDecl:
|
||||||
|
if (functionsArePrivate)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DeclContextKind::Module:
|
||||||
|
case DeclContextKind::FileUnit:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case DeclContextKind::NominalTypeDecl: {
|
||||||
|
auto *nominal = cast<NominalTypeDecl>(DC);
|
||||||
|
if (nominal->hasAccessibility())
|
||||||
|
return nominal->getAccessibility() == Accessibility::Private;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DeclContextKind::ExtensionDecl: {
|
||||||
|
auto *extension = cast<ExtensionDecl>(DC);
|
||||||
|
if (extension->hasDefaultAccessibility())
|
||||||
|
return extension->getDefaultAccessibility() == Accessibility::Private;
|
||||||
|
// FIXME: duplicated from computeDefaultAccessibility in TypeCheckDecl.cpp.
|
||||||
|
if (auto *AA = extension->getAttrs().getAttribute<AccessibilityAttr>())
|
||||||
|
return AA->getAccess() == Accessibility::Private;
|
||||||
|
if (Type extendedTy = extension->getExtendedType())
|
||||||
|
return isPrivateContextForLookup(extendedTy->getAnyNominal(), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isPrivateContextForLookup(DC->getParent(), true);
|
||||||
|
}
|
||||||
|
|
||||||
static void recordLookupOfTopLevelName(DeclContext *topLevelContext,
|
static void recordLookupOfTopLevelName(DeclContext *topLevelContext,
|
||||||
DeclName name) {
|
DeclName name,
|
||||||
|
bool isNonPrivateUse) {
|
||||||
auto SF = dyn_cast<SourceFile>(topLevelContext);
|
auto SF = dyn_cast<SourceFile>(topLevelContext);
|
||||||
if (!SF)
|
if (!SF)
|
||||||
return;
|
return;
|
||||||
auto *nameTracker = SF->getReferencedNameTracker();
|
auto *nameTracker = SF->getReferencedNameTracker();
|
||||||
if (!nameTracker)
|
if (!nameTracker)
|
||||||
return;
|
return;
|
||||||
nameTracker->addTopLevelName(name.getBaseName());
|
nameTracker->addTopLevelName(name.getBaseName(), isNonPrivateUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
|
UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
|
||||||
@@ -443,185 +492,201 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
|
|||||||
const SourceManager &SM = Ctx.SourceMgr;
|
const SourceManager &SM = Ctx.SourceMgr;
|
||||||
DebuggerClient *DebugClient = M.getDebugClient();
|
DebuggerClient *DebugClient = M.getDebugClient();
|
||||||
|
|
||||||
|
bool isPrivateUse = false;
|
||||||
|
|
||||||
// Never perform local lookup for operators.
|
// Never perform local lookup for operators.
|
||||||
if (Name.isOperator())
|
if (Name.isOperator()) {
|
||||||
|
isPrivateUse = isPrivateContextForLookup(DC, /*includeFunctions=*/true);
|
||||||
DC = DC->getModuleScopeContext();
|
DC = DC->getModuleScopeContext();
|
||||||
|
} else {
|
||||||
|
// 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.
|
||||||
|
// FIXME: We should persist this information between lookups.
|
||||||
|
while (!DC->isModuleScopeContext()) {
|
||||||
|
ValueDecl *BaseDecl = 0;
|
||||||
|
ValueDecl *MetaBaseDecl = 0;
|
||||||
|
GenericParamList *GenericParams = nullptr;
|
||||||
|
Type ExtendedType;
|
||||||
|
|
||||||
// If we are inside of a method, check to see if there are any ivars in scope,
|
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
|
||||||
// and if so, whether this is a reference to one of them.
|
// Look for local variables; normally, the parser resolves these
|
||||||
while (!DC->isModuleScopeContext()) {
|
// for us, but it can't do the right thing inside local types.
|
||||||
ValueDecl *BaseDecl = 0;
|
// FIXME: when we can parse and typecheck the function body partially for
|
||||||
ValueDecl *MetaBaseDecl = 0;
|
// code completion, AFD->getBody() check can be removed.
|
||||||
GenericParamList *GenericParams = nullptr;
|
if (Loc.isValid() && AFD->getBody()) {
|
||||||
Type ExtendedType;
|
isPrivateUse =
|
||||||
|
SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc);
|
||||||
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(DC)) {
|
|
||||||
// Look for local variables; normally, the parser resolves these
|
|
||||||
// for us, but it can't do the right thing inside local types.
|
|
||||||
// FIXME: when we can parse and typecheck the function body partially for
|
|
||||||
// code completion, AFD->getBody() check can be removed.
|
|
||||||
if (Loc.isValid() && AFD->getBody()) {
|
|
||||||
FindLocalVal localVal(SM, Loc, Name);
|
|
||||||
localVal.visit(AFD->getBody());
|
|
||||||
if (!localVal.MatchingValue) {
|
|
||||||
for (Pattern *P : AFD->getBodyParamPatterns())
|
|
||||||
localVal.checkPattern(P);
|
|
||||||
}
|
|
||||||
if (localVal.MatchingValue) {
|
|
||||||
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AFD->getExtensionType()) {
|
|
||||||
ExtendedType = AFD->getExtensionType();
|
|
||||||
BaseDecl = AFD->getImplicitSelfDecl();
|
|
||||||
MetaBaseDecl = ExtendedType->getAnyNominal();
|
|
||||||
DC = DC->getParent();
|
|
||||||
|
|
||||||
if (auto *FD = dyn_cast<FuncDecl>(AFD))
|
|
||||||
if (FD->isStatic())
|
|
||||||
ExtendedType = MetatypeType::get(ExtendedType);
|
|
||||||
|
|
||||||
// If we're not in the body of the function, the base declaration
|
|
||||||
// is the nominal type, not 'self'.
|
|
||||||
if (Loc.isValid() &&
|
|
||||||
AFD->getBodySourceRange().isValid() &&
|
|
||||||
!SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)) {
|
|
||||||
BaseDecl = MetaBaseDecl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look in the generic parameters after checking our local declaration.
|
|
||||||
GenericParams = AFD->getGenericParams();
|
|
||||||
} else if (auto *ACE = dyn_cast<AbstractClosureExpr>(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()) {
|
|
||||||
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
|
|
||||||
FindLocalVal localVal(SM, Loc, Name);
|
FindLocalVal localVal(SM, Loc, Name);
|
||||||
localVal.visit(CE->getBody());
|
localVal.visit(AFD->getBody());
|
||||||
if (!localVal.MatchingValue) {
|
if (!localVal.MatchingValue) {
|
||||||
localVal.checkPattern(CE->getParams());
|
for (Pattern *P : AFD->getBodyParamPatterns())
|
||||||
|
localVal.checkPattern(P);
|
||||||
}
|
}
|
||||||
if (localVal.MatchingValue) {
|
if (localVal.MatchingValue) {
|
||||||
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!isPrivateUse)
|
||||||
} else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(DC)) {
|
isPrivateUse = isPrivateContextForLookup(AFD, false);
|
||||||
ExtendedType = ED->getExtendedType();
|
|
||||||
BaseDecl = ExtendedType->getNominalOrBoundGenericNominal();
|
|
||||||
MetaBaseDecl = BaseDecl;
|
|
||||||
} else if (NominalTypeDecl *ND = dyn_cast<NominalTypeDecl>(DC)) {
|
|
||||||
ExtendedType = ND->getDeclaredType();
|
|
||||||
BaseDecl = ND;
|
|
||||||
MetaBaseDecl = BaseDecl;
|
|
||||||
} else if (auto I = dyn_cast<DefaultArgumentInitializer>(DC)) {
|
|
||||||
// In a default argument, skip immediately out of both the
|
|
||||||
// initializer and the function.
|
|
||||||
DC = I->getParent()->getParent();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the generic parameters for something with the given name.
|
if (AFD->getExtensionType()) {
|
||||||
if (GenericParams) {
|
ExtendedType = AFD->getExtensionType();
|
||||||
FindLocalVal localVal(SM, Loc, Name);
|
BaseDecl = AFD->getImplicitSelfDecl();
|
||||||
localVal.checkGenericParams(GenericParams);
|
MetaBaseDecl = ExtendedType->getAnyNominal();
|
||||||
|
DC = DC->getParent();
|
||||||
|
|
||||||
if (localVal.MatchingValue) {
|
if (auto *FD = dyn_cast<FuncDecl>(AFD))
|
||||||
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
if (FD->isStatic())
|
||||||
return;
|
ExtendedType = MetatypeType::get(ExtendedType);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BaseDecl) {
|
// If we're not in the body of the function, the base declaration
|
||||||
if (TypeResolver)
|
// is the nominal type, not 'self'.
|
||||||
TypeResolver->resolveDeclSignature(BaseDecl);
|
if (Loc.isValid() &&
|
||||||
|
AFD->getBodySourceRange().isValid() &&
|
||||||
SmallVector<ValueDecl *, 4> Lookup;
|
!SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)) {
|
||||||
DC->lookupQualified(ExtendedType, Name, NL_UnqualifiedDefault,
|
BaseDecl = MetaBaseDecl;
|
||||||
TypeResolver, Lookup);
|
|
||||||
bool isMetatypeType = ExtendedType->is<AnyMetatypeType>();
|
|
||||||
bool FoundAny = false;
|
|
||||||
for (auto Result : Lookup) {
|
|
||||||
// If we're looking into an instance, skip static functions.
|
|
||||||
if (!isMetatypeType &&
|
|
||||||
isa<FuncDecl>(Result) &&
|
|
||||||
cast<FuncDecl>(Result)->isStatic())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Classify this declaration.
|
|
||||||
FoundAny = true;
|
|
||||||
|
|
||||||
// Types are local or metatype members.
|
|
||||||
if (auto TD = dyn_cast<TypeDecl>(Result)) {
|
|
||||||
if (isa<GenericTypeParamDecl>(TD))
|
|
||||||
Results.push_back(Result::getLocalDecl(Result));
|
|
||||||
else
|
|
||||||
Results.push_back(Result::getMetatypeMember(MetaBaseDecl, Result));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions are either metatype members or member functions.
|
|
||||||
if (auto FD = dyn_cast<FuncDecl>(Result)) {
|
|
||||||
if (FD->isStatic()) {
|
|
||||||
if (isMetatypeType)
|
|
||||||
Results.push_back(Result::getMetatypeMember(BaseDecl, Result));
|
|
||||||
} else {
|
|
||||||
Results.push_back(Result::getMemberFunction(BaseDecl, Result));
|
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isa<EnumElementDecl>(Result)) {
|
// Look in the generic parameters after checking our local declaration.
|
||||||
Results.push_back(Result::getMetatypeMember(MetaBaseDecl, Result));
|
GenericParams = AFD->getGenericParams();
|
||||||
continue;
|
} else if (auto *ACE = dyn_cast<AbstractClosureExpr>(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()) {
|
||||||
|
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
|
||||||
|
FindLocalVal localVal(SM, Loc, Name);
|
||||||
|
localVal.visit(CE->getBody());
|
||||||
|
if (!localVal.MatchingValue) {
|
||||||
|
localVal.checkPattern(CE->getParams());
|
||||||
|
}
|
||||||
|
if (localVal.MatchingValue) {
|
||||||
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
isPrivateUse = isPrivateContextForLookup(ACE, false);
|
||||||
// Archetype members
|
} else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(DC)) {
|
||||||
if (ExtendedType->is<ArchetypeType>()) {
|
ExtendedType = ED->getExtendedType();
|
||||||
Results.push_back(Result::getArchetypeMember(BaseDecl, Result));
|
BaseDecl = ExtendedType->getNominalOrBoundGenericNominal();
|
||||||
continue;
|
MetaBaseDecl = BaseDecl;
|
||||||
}
|
isPrivateUse = isPrivateContextForLookup(ED, false);
|
||||||
|
} else if (NominalTypeDecl *ND = dyn_cast<NominalTypeDecl>(DC)) {
|
||||||
// Existential members.
|
ExtendedType = ND->getDeclaredType();
|
||||||
if (ExtendedType->isExistentialType()) {
|
BaseDecl = ND;
|
||||||
Results.push_back(Result::getExistentialMember(BaseDecl, Result));
|
MetaBaseDecl = BaseDecl;
|
||||||
continue;
|
isPrivateUse = isPrivateContextForLookup(ND, false);
|
||||||
}
|
} else if (auto I = dyn_cast<DefaultArgumentInitializer>(DC)) {
|
||||||
|
// In a default argument, skip immediately out of both the
|
||||||
// Everything else is a member property.
|
// initializer and the function.
|
||||||
Results.push_back(Result::getMemberProperty(BaseDecl, Result));
|
isPrivateUse = true;
|
||||||
|
DC = I->getParent()->getParent();
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
assert(isa<TopLevelCodeDecl>(DC) || isa<Initializer>(DC));
|
||||||
|
isPrivateUse = isPrivateContextForLookup(DC, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FoundAny) {
|
// Check the generic parameters for something with the given name.
|
||||||
if (DebugClient)
|
if (GenericParams) {
|
||||||
filterForDiscriminator(Results, DebugClient);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the generic parameters if our context is a generic type or
|
|
||||||
// extension thereof.
|
|
||||||
GenericParamList *dcGenericParams = nullptr;
|
|
||||||
if (auto nominal = dyn_cast<NominalTypeDecl>(DC))
|
|
||||||
dcGenericParams = nominal->getGenericParams();
|
|
||||||
else if (auto ext = dyn_cast<ExtensionDecl>(DC))
|
|
||||||
dcGenericParams = ext->getGenericParams();
|
|
||||||
|
|
||||||
if (dcGenericParams) {
|
|
||||||
FindLocalVal localVal(SM, Loc, Name);
|
FindLocalVal localVal(SM, Loc, Name);
|
||||||
localVal.checkGenericParams(dcGenericParams);
|
localVal.checkGenericParams(GenericParams);
|
||||||
|
|
||||||
if (localVal.MatchingValue) {
|
if (localVal.MatchingValue) {
|
||||||
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DC = DC->getParent();
|
if (BaseDecl) {
|
||||||
|
if (TypeResolver)
|
||||||
|
TypeResolver->resolveDeclSignature(BaseDecl);
|
||||||
|
|
||||||
|
SmallVector<ValueDecl *, 4> Lookup;
|
||||||
|
DC->lookupQualified(ExtendedType, Name, NL_UnqualifiedDefault,
|
||||||
|
TypeResolver, Lookup);
|
||||||
|
bool isMetatypeType = ExtendedType->is<AnyMetatypeType>();
|
||||||
|
bool FoundAny = false;
|
||||||
|
for (auto Result : Lookup) {
|
||||||
|
// If we're looking into an instance, skip static functions.
|
||||||
|
if (!isMetatypeType &&
|
||||||
|
isa<FuncDecl>(Result) &&
|
||||||
|
cast<FuncDecl>(Result)->isStatic())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Classify this declaration.
|
||||||
|
FoundAny = true;
|
||||||
|
|
||||||
|
// Types are local or metatype members.
|
||||||
|
if (auto TD = dyn_cast<TypeDecl>(Result)) {
|
||||||
|
if (isa<GenericTypeParamDecl>(TD))
|
||||||
|
Results.push_back(Result::getLocalDecl(Result));
|
||||||
|
else
|
||||||
|
Results.push_back(Result::getMetatypeMember(MetaBaseDecl, Result));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions are either metatype members or member functions.
|
||||||
|
if (auto FD = dyn_cast<FuncDecl>(Result)) {
|
||||||
|
if (FD->isStatic()) {
|
||||||
|
if (isMetatypeType)
|
||||||
|
Results.push_back(Result::getMetatypeMember(BaseDecl, Result));
|
||||||
|
} else {
|
||||||
|
Results.push_back(Result::getMemberFunction(BaseDecl, Result));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isa<EnumElementDecl>(Result)) {
|
||||||
|
Results.push_back(Result::getMetatypeMember(MetaBaseDecl, Result));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Archetype members
|
||||||
|
if (ExtendedType->is<ArchetypeType>()) {
|
||||||
|
Results.push_back(Result::getArchetypeMember(BaseDecl, Result));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Existential members.
|
||||||
|
if (ExtendedType->isExistentialType()) {
|
||||||
|
Results.push_back(Result::getExistentialMember(BaseDecl, Result));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else is a member property.
|
||||||
|
Results.push_back(Result::getMemberProperty(BaseDecl, Result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FoundAny) {
|
||||||
|
if (DebugClient)
|
||||||
|
filterForDiscriminator(Results, DebugClient);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the generic parameters if our context is a generic type or
|
||||||
|
// extension thereof.
|
||||||
|
GenericParamList *dcGenericParams = nullptr;
|
||||||
|
if (auto nominal = dyn_cast<NominalTypeDecl>(DC))
|
||||||
|
dcGenericParams = nominal->getGenericParams();
|
||||||
|
else if (auto ext = dyn_cast<ExtensionDecl>(DC))
|
||||||
|
dcGenericParams = ext->getGenericParams();
|
||||||
|
|
||||||
|
if (dcGenericParams) {
|
||||||
|
FindLocalVal localVal(SM, Loc, Name);
|
||||||
|
localVal.checkGenericParams(dcGenericParams);
|
||||||
|
|
||||||
|
if (localVal.MatchingValue) {
|
||||||
|
Results.push_back(Result::getLocalDecl(localVal.MatchingValue));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DC = DC->getParent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto SF = dyn_cast<SourceFile>(DC)) {
|
if (auto SF = dyn_cast<SourceFile>(DC)) {
|
||||||
@@ -644,7 +709,7 @@ UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
|
|||||||
Loc, IsTypeLookup, Results))
|
Loc, IsTypeLookup, Results))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
recordLookupOfTopLevelName(DC, Name);
|
recordLookupOfTopLevelName(DC, Name, !isPrivateUse);
|
||||||
|
|
||||||
// Add private imports to the extra search list.
|
// Add private imports to the extra search list.
|
||||||
SmallVector<Module::ImportedModule, 8> extraImports;
|
SmallVector<Module::ImportedModule, 8> extraImports;
|
||||||
@@ -1121,7 +1186,10 @@ bool DeclContext::lookupQualified(Type type,
|
|||||||
Module *module = moduleTy->getModule();
|
Module *module = moduleTy->getModule();
|
||||||
auto topLevelScope = getModuleScopeContext();
|
auto topLevelScope = getModuleScopeContext();
|
||||||
if (module == topLevelScope->getParentModule()) {
|
if (module == topLevelScope->getParentModule()) {
|
||||||
recordLookupOfTopLevelName(topLevelScope, member);
|
// FIXME: We should be able to tell if this is part of a function body
|
||||||
|
// or not.
|
||||||
|
recordLookupOfTopLevelName(topLevelScope, member,
|
||||||
|
isPrivateContextForLookup(this, false));
|
||||||
lookupInModule(module, /*accessPath=*/{}, member, decls,
|
lookupInModule(module, /*accessPath=*/{}, member, decls,
|
||||||
NLKind::QualifiedLookup, ResolutionKind::Overloadable,
|
NLKind::QualifiedLookup, ResolutionKind::Overloadable,
|
||||||
typeResolver, topLevelScope);
|
typeResolver, topLevelScope);
|
||||||
@@ -1262,8 +1330,10 @@ bool DeclContext::lookupQualified(Type type,
|
|||||||
while (!stack.empty()) {
|
while (!stack.empty()) {
|
||||||
auto current = stack.back();
|
auto current = stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
|
|
||||||
|
// FIXME: We should be able to tell if this is a local or non-local use.
|
||||||
if (tracker)
|
if (tracker)
|
||||||
tracker->addUsedNominal(current);
|
tracker->addUsedNominal(current, true);
|
||||||
|
|
||||||
// Make sure we've resolved implicit constructors, if we need them.
|
// Make sure we've resolved implicit constructors, if we need them.
|
||||||
if (member.getBaseName() == ctx.Id_init && typeResolver)
|
if (member.getBaseName() == ctx.Id_init && typeResolver)
|
||||||
|
|||||||
@@ -3580,8 +3580,9 @@ public:
|
|||||||
D->getStartLoc(), D);
|
D->getStartLoc(), D);
|
||||||
conformances.push_back(conformance);
|
conformances.push_back(conformance);
|
||||||
|
|
||||||
|
// FIXME: We should be able to tell if this is a private use or not.
|
||||||
if (tracker)
|
if (tracker)
|
||||||
tracker->addUsedNominal(proto);
|
tracker->addUsedNominal(proto, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
D->setConformances(D->getASTContext().AllocateCopy(conformances));
|
D->setConformances(D->getASTContext().AllocateCopy(conformances));
|
||||||
@@ -4710,8 +4711,9 @@ public:
|
|||||||
|
|
||||||
if (auto *SF = PD->getParentSourceFile()) {
|
if (auto *SF = PD->getParentSourceFile()) {
|
||||||
if (auto *tracker = SF->getReferencedNameTracker()) {
|
if (auto *tracker = SF->getReferencedNameTracker()) {
|
||||||
|
// FIXME: Track whether this is a private use or not.
|
||||||
for (auto *parentProto : PD->getProtocols())
|
for (auto *parentProto : PD->getProtocols())
|
||||||
tracker->addUsedNominal(parentProto);
|
tracker->addUsedNominal(parentProto, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2538,8 +2538,9 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
|
|||||||
const DeclContext *topLevelContext = DC->getModuleScopeContext();
|
const DeclContext *topLevelContext = DC->getModuleScopeContext();
|
||||||
if (auto *constSF = dyn_cast<SourceFile>(topLevelContext)) {
|
if (auto *constSF = dyn_cast<SourceFile>(topLevelContext)) {
|
||||||
auto *SF = const_cast<SourceFile *>(constSF);
|
auto *SF = const_cast<SourceFile *>(constSF);
|
||||||
|
// FIXME: Track whether this is a private use or not.
|
||||||
if (auto *tracker = SF->getReferencedNameTracker())
|
if (auto *tracker = SF->getReferencedNameTracker())
|
||||||
tracker->addUsedNominal(nominal);
|
tracker->addUsedNominal(nominal, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Module *M = topLevelContext->getParentModule();
|
Module *M = topLevelContext->getParentModule();
|
||||||
|
|||||||
@@ -33,3 +33,31 @@ protocol OtherFileProto2 {}
|
|||||||
struct OtherFileProtoImplementor2 : OtherFileProto2 {}
|
struct OtherFileProtoImplementor2 : OtherFileProto2 {}
|
||||||
func otherFileGetImpl2() -> OtherFileProtoImplementor2 {}
|
func otherFileGetImpl2() -> OtherFileProtoImplementor2 {}
|
||||||
func otherFileUseGeneric<T: OtherFileProto2>(_: T) {}
|
func otherFileUseGeneric<T: OtherFileProto2>(_: T) {}
|
||||||
|
|
||||||
|
func topLevel1() -> Int { return 2 }
|
||||||
|
func topLevel2() -> Int { return 2 }
|
||||||
|
func topLevel3() -> Int { return 2 }
|
||||||
|
func topLevel4() -> Int { return 2 }
|
||||||
|
func topLevel5() -> Int { return 2 }
|
||||||
|
func topLevel6() -> Int { return 2 }
|
||||||
|
func topLevel7() -> Int { return 2 }
|
||||||
|
func topLevel8() -> Int { return 2 }
|
||||||
|
func topLevel9() -> Int { return 2 }
|
||||||
|
|
||||||
|
typealias TopLevelTy1 = Int
|
||||||
|
typealias TopLevelTy2 = Int
|
||||||
|
typealias TopLevelTy3 = Int
|
||||||
|
|
||||||
|
func privateTopLevel1() -> Int { return 2 }
|
||||||
|
func privateTopLevel2() -> Int { return 2 }
|
||||||
|
func privateTopLevel3() -> Int { return 2 }
|
||||||
|
func privateTopLevel4() -> Int { return 2 }
|
||||||
|
func privateTopLevel5() -> Int { return 2 }
|
||||||
|
func privateTopLevel6() -> Int { return 2 }
|
||||||
|
func privateTopLevel7() -> Int { return 2 }
|
||||||
|
func privateTopLevel8() -> Int { return 2 }
|
||||||
|
func privateTopLevel9() -> Int { return 2 }
|
||||||
|
|
||||||
|
typealias PrivateTopLevelTy1 = Int
|
||||||
|
typealias PrivateTopLevelTy2 = Int
|
||||||
|
typealias PrivateTopLevelTy3 = Int
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
// RUN: %swift -parse -primary-file %s %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps
|
// RUN: rm -rf %t && mkdir %t
|
||||||
|
// RUN: cp %s %t/main.swift
|
||||||
|
// RUN: %swift -parse -primary-file %t/main.swift %S/Inputs/reference-dependencies-helper.swift -emit-reference-dependencies-path - > %t.swiftdeps
|
||||||
// RUN: FileCheck %s < %t.swiftdeps
|
// RUN: FileCheck %s < %t.swiftdeps
|
||||||
// RUN: FileCheck -check-prefix=NEGATIVE %s < %t.swiftdeps
|
// RUN: FileCheck -check-prefix=NEGATIVE %s < %t.swiftdeps
|
||||||
|
|
||||||
@@ -13,7 +15,7 @@
|
|||||||
// CHECK-NEXT: "someGlobal"
|
// CHECK-NEXT: "someGlobal"
|
||||||
// CHECK-NEXT: "ExtraFloatLiteralConvertible"
|
// CHECK-NEXT: "ExtraFloatLiteralConvertible"
|
||||||
// CHECK-NEXT: "lookUpManyTopLevelNames"
|
// CHECK-NEXT: "lookUpManyTopLevelNames"
|
||||||
// CHECK-NEXT: "eof"
|
// CHECK: "eof"
|
||||||
|
|
||||||
// CHECK-LABEL: {{^nominals:$}}
|
// CHECK-LABEL: {{^nominals:$}}
|
||||||
// CHECK-NEXT: "V4main10IntWrapper"
|
// CHECK-NEXT: "V4main10IntWrapper"
|
||||||
@@ -74,22 +76,22 @@ func lookUpManyTopLevelNames() {
|
|||||||
// CHECK-DAG: "Dictionary"
|
// CHECK-DAG: "Dictionary"
|
||||||
let _: Dictionary = [1:1]
|
let _: Dictionary = [1:1]
|
||||||
|
|
||||||
// CHECK-DAG: "UInt"
|
// CHECK-DAG: !private "UInt"
|
||||||
// CHECK-DAG: "reduce"
|
// CHECK-DAG: !private "reduce"
|
||||||
// CHECK-DAG: "+"
|
// CHECK-DAG: !private "+"
|
||||||
let _: UInt = reduce([1,2], 0, +)
|
let _: UInt = reduce([1,2], 0, +)
|
||||||
|
|
||||||
// CHECK-DAG: "AliasFromOtherFile"
|
// CHECK-DAG: !private "AliasFromOtherFile"
|
||||||
let _: AliasFromOtherFile = 1
|
let _: AliasFromOtherFile = 1
|
||||||
|
|
||||||
// CHECK-DAG: "funcFromOtherFile"
|
// CHECK-DAG: !private "funcFromOtherFile"
|
||||||
funcFromOtherFile()
|
funcFromOtherFile()
|
||||||
|
|
||||||
// "CInt" is not used as a top-level name here.
|
// "CInt" is not used as a top-level name here.
|
||||||
// CHECK-DAG: "StringLiteralType"
|
// CHECK-DAG: "StringLiteralType"
|
||||||
// NEGATIVE-NOT: "CInt"
|
// NEGATIVE-NOT: "CInt"
|
||||||
let CInt = "abc"
|
let CInt = "abc"
|
||||||
// CHECK-DAG: "println"
|
// CHECK-DAG: !private "println"
|
||||||
println(CInt)
|
println(CInt)
|
||||||
|
|
||||||
// NEGATIVE-NOT: "max"
|
// NEGATIVE-NOT: "max"
|
||||||
@@ -98,24 +100,83 @@ func lookUpManyTopLevelNames() {
|
|||||||
// NEGATIVE-NOT: "Stride"
|
// NEGATIVE-NOT: "Stride"
|
||||||
let _: Int.Stride = 0
|
let _: Int.Stride = 0
|
||||||
|
|
||||||
// CHECK-DAG: "OtherFileOuterType"
|
// CHECK-DAG: !private "OtherFileOuterType"
|
||||||
_ = OtherFileOuterType.InnerType.sharedConstant
|
_ = OtherFileOuterType.InnerType.sharedConstant
|
||||||
|
|
||||||
// CHECK-DAG: "OtherFileAliasForSecret"
|
// CHECK-DAG: !private "OtherFileAliasForSecret"
|
||||||
_ = OtherFileAliasForSecret.constant
|
_ = OtherFileAliasForSecret.constant
|
||||||
|
|
||||||
// CHECK-DAG: otherFileUse
|
// CHECK-DAG: !private "otherFileUse"
|
||||||
// CHECK-DAG: otherFileGetImpl
|
// CHECK-DAG: !private "otherFileGetImpl"
|
||||||
otherFileUse(otherFileGetImpl())
|
otherFileUse(otherFileGetImpl())
|
||||||
|
|
||||||
// CHECK-DAG: otherFileUse
|
// CHECK-DAG: !private "otherFileUseGeneric"
|
||||||
// CHECK-DAG: otherFileGetImpl
|
// CHECK-DAG: !private "otherFileGetImpl2"
|
||||||
otherFileUseGeneric(otherFileGetImpl2())
|
otherFileUseGeneric(otherFileGetImpl2())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEGATIVE-NOT: "privateFunc"
|
// NEGATIVE-NOT: "privateFunc"
|
||||||
private func privateFunc() {}
|
private func privateFunc() {}
|
||||||
|
|
||||||
|
// CHECK-DAG: - "topLevel1"
|
||||||
|
var use1 = topLevel1()
|
||||||
|
// CHECK-DAG: - "topLevel2"
|
||||||
|
var use2 = { topLevel2() }
|
||||||
|
// CHECK-DAG: - "topLevel3"
|
||||||
|
var use3 = { ({ topLevel3() })() }
|
||||||
|
// CHECK-DAG: - "topLevel4"
|
||||||
|
struct Use4 {
|
||||||
|
var use4 = topLevel4()
|
||||||
|
}
|
||||||
|
// CHECK-DAG: - "*"
|
||||||
|
print(42 * 30)
|
||||||
|
|
||||||
|
// FIXME: Incorrectly marked non-private dependencies
|
||||||
|
// CHECK-DAG: - "topLevel6"
|
||||||
|
print(topLevel6())
|
||||||
|
// CHECK-DAG: - "topLevel7"
|
||||||
|
private var use7 = topLevel7()
|
||||||
|
// CHECK-DAG: - "topLevel8"
|
||||||
|
var use8: Int = topLevel8()
|
||||||
|
// CHECK-DAG: - "topLevel9"
|
||||||
|
var use9 = { () -> Int in return topLevel9() }
|
||||||
|
|
||||||
|
|
||||||
|
// CHECK-DAG: - "TopLevelTy1"
|
||||||
|
func useTy1(x: TopLevelTy1) {}
|
||||||
|
// CHECK-DAG: - "TopLevelTy2"
|
||||||
|
func useTy2() -> TopLevelTy2 {}
|
||||||
|
// CHECK-DAG: - "TopLevelTy3"
|
||||||
|
extension Use4 {
|
||||||
|
var useTy3: TopLevelTy3? { return nil }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: !private "privateTopLevel1"
|
||||||
|
func private1(a: Int = privateTopLevel1()) {}
|
||||||
|
// CHECK-DAG: !private "privateTopLevel2"
|
||||||
|
private struct Private2 {
|
||||||
|
var private2 = privateTopLevel2()
|
||||||
|
}
|
||||||
|
// CHECK-DAG: !private "privateTopLevel3"
|
||||||
|
func outerPrivate3() {
|
||||||
|
let private3 = { privateTopLevel3() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: !private "PrivateTopLevelTy1"
|
||||||
|
private extension Use4 {
|
||||||
|
var privateTy1: PrivateTopLevelTy1? { return nil }
|
||||||
|
}
|
||||||
|
// CHECK-DAG: !private "PrivateTopLevelTy2"
|
||||||
|
extension Private2 {
|
||||||
|
var privateTy2: PrivateTopLevelTy2? { return nil }
|
||||||
|
}
|
||||||
|
// CHECK-DAG: !private "PrivateTopLevelTy3"
|
||||||
|
func outerPrivateTy3() {
|
||||||
|
func inner(a: PrivateTopLevelTy3?) {}
|
||||||
|
inner(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// CHECK-LABEL: {{^member-access:$}}
|
// CHECK-LABEL: {{^member-access:$}}
|
||||||
// CHECK-DAG: "V4main10IntWrapper"
|
// CHECK-DAG: "V4main10IntWrapper"
|
||||||
// CHECK-DAG: "PSs10Comparable"
|
// CHECK-DAG: "PSs10Comparable"
|
||||||
|
|||||||
@@ -187,20 +187,26 @@ static bool emitReferenceDependencies(DiagnosticEngine &diags,
|
|||||||
|
|
||||||
// FIXME: Sort these?
|
// FIXME: Sort these?
|
||||||
out << "top-level:\n";
|
out << "top-level:\n";
|
||||||
for (Identifier name : tracker->getTopLevelNames()) {
|
for (auto &entry : tracker->getTopLevelNames()) {
|
||||||
out << "- \"" << name << "\"\n";
|
out << "- ";
|
||||||
|
if (!entry.second)
|
||||||
|
out << "!private ";
|
||||||
|
out << "\"" << entry.first << "\"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Sort these?
|
// FIXME: Sort these?
|
||||||
out << "member-access:\n";
|
out << "member-access:\n";
|
||||||
for (auto usedNominal : tracker->getUsedNominals()) {
|
for (auto &entry : tracker->getUsedNominals()) {
|
||||||
if (usedNominal->hasAccessibility() &&
|
if (entry.first->hasAccessibility() &&
|
||||||
usedNominal->getAccessibility() == Accessibility::Private)
|
entry.first->getAccessibility() == Accessibility::Private)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Mangle::Mangler mangler(out, /*debug style=*/false, /*Unicode=*/true);
|
Mangle::Mangler mangler(out, /*debug style=*/false, /*Unicode=*/true);
|
||||||
out << "- \"";
|
out << "- ";
|
||||||
mangler.mangleContext(usedNominal, Mangle::Mangler::BindGenerics::None);
|
if (!entry.second)
|
||||||
|
out << "!private ";
|
||||||
|
out << "\"";
|
||||||
|
mangler.mangleContext(entry.first, Mangle::Mangler::BindGenerics::None);
|
||||||
out << "\"\n";
|
out << "\"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user