示例#1
0
static unsigned getCallEditDistance(DeclName writtenName,
                                    DeclName correctedName,
                                    unsigned maxEditDistance) {
  // TODO: consider arguments.
  // TODO: maybe ignore certain kinds of missing / present labels for the
  //   first argument label?
  // TODO: word-based rather than character-based?
  if (writtenName.getBaseName().getKind() !=
        correctedName.getBaseName().getKind()) {
    return UnreasonableCallEditDistance;
  }

  if (writtenName.getBaseName().getKind() != DeclBaseName::Kind::Normal) {
    return 0;
  }

  StringRef writtenBase = writtenName.getBaseName().userFacingName();
  StringRef correctedBase = correctedName.getBaseName().userFacingName();

  unsigned distance = writtenBase.edit_distance(correctedBase, maxEditDistance);

  // Bound the distance to UnreasonableCallEditDistance.
  if (distance >= maxEditDistance ||
      distance > (correctedBase.size() + 2) / 3) {
    return UnreasonableCallEditDistance;
  }

  return distance;
}
示例#2
0
void TypeChecker::noteTypoCorrection(DeclName writtenName, DeclNameLoc loc,
                                     const LookupResult::Result &suggestion) {
  auto decl = suggestion.Decl;
  auto &&diagnostic = diagnoseTypoCorrection(*this, loc, decl);

  DeclName declName = decl->getFullName();

  if (writtenName.getBaseName() != declName.getBaseName())
    diagnostic.fixItReplace(loc.getBaseNameLoc(), declName.getBaseName().str());

  // TODO: add fix-its for typo'ed argument labels.  This is trickier
  // because of the reordering rules.
}
示例#3
0
static unsigned getCallEditDistance(DeclName argName, DeclName paramName,
                                    unsigned maxEditDistance) {
  // TODO: consider arguments.
  // TODO: maybe ignore certain kinds of missing / present labels for the
  //   first argument label?
  // TODO: word-based rather than character-based?
  StringRef argBase = argName.getBaseName().str();
  StringRef paramBase = paramName.getBaseName().str();

  unsigned distance = argBase.edit_distance(paramBase, maxEditDistance);

  // Bound the distance to UnreasonableCallEditDistance.
  if (distance >= maxEditDistance ||
      distance > (paramBase.size() + 2) / 3) {
    return UnreasonableCallEditDistance;
  }

  return distance;
}
示例#4
0
static void recordLookupOfTopLevelName(DeclContext *topLevelContext,
                                       DeclName name,
                                       bool isCascading) {
  auto SF = dyn_cast<SourceFile>(topLevelContext);
  if (!SF)
    return;
  auto *nameTracker = SF->getReferencedNameTracker();
  if (!nameTracker)
    return;
  nameTracker->addTopLevelName(name.getBaseName(), isCascading);
}
示例#5
0
void ModuleFile::lookupValue(DeclName name,
                             SmallVectorImpl<ValueDecl*> &results) {
  PrettyModuleFileDeserialization stackEntry(*this);

  if (TopLevelDecls) {
    // Find top-level declarations with the given name.
    // FIXME: As a bit of a hack, do lookup by the simple name, then filter
    // compound decls, to avoid having to completely redo how modules are
    // serialized.
    auto iter = TopLevelDecls->find(name.getBaseName());
    if (iter != TopLevelDecls->end()) {
      if (name.isSimpleName()) {
        for (auto item : *iter) {
          auto VD = cast<ValueDecl>(getDecl(item.second));
          results.push_back(VD);
        }
      } else {
        for (auto item : *iter) {
          auto VD = cast<ValueDecl>(getDecl(item.second));
          if (VD->getFullName().matchesRef(name))
            results.push_back(VD);
        }
      }
    }
  }

  // If the name is an operator name, also look for operator methods.
  if (name.isOperator() && OperatorMethodDecls) {
    auto iter = OperatorMethodDecls->find(name.getBaseName());
    if (iter != OperatorMethodDecls->end()) {
      for (auto item : *iter) {
        auto VD = cast<ValueDecl>(getDecl(item.second));
        results.push_back(VD);
      }
    }
  }
}
示例#6
0
void ModuleFile::lookupClassMember(Module::AccessPathTy accessPath,
                                   DeclName name,
                                   SmallVectorImpl<ValueDecl*> &results) {
  PrettyModuleFileDeserialization stackEntry(*this);
  assert(accessPath.size() <= 1 && "can only refer to top-level decls");

  if (!ClassMembersByName)
    return;

  auto iter = ClassMembersByName->find(name.getBaseName());
  if (iter == ClassMembersByName->end())
    return;

  if (!accessPath.empty()) {
    // As a hack to avoid completely redoing how the module is indexed, we take
    // the simple-name-based lookup then filter by the compound name if we have
    // one.
    if (name.isSimpleName()) {
      for (auto item : *iter) {
        auto vd = cast<ValueDecl>(getDecl(item.second));
        auto dc = vd->getDeclContext();
        while (!dc->getParent()->isModuleScopeContext())
          dc = dc->getParent();
        if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext())
          if (nominal->getName() == accessPath.front().first)
            results.push_back(vd);
      }
    } else {
      for (auto item : *iter) {
        auto vd = cast<ValueDecl>(getDecl(item.second));
        if (!vd->getFullName().matchesRef(name))
          continue;
        
        auto dc = vd->getDeclContext();
        while (!dc->getParent()->isModuleScopeContext())
          dc = dc->getParent();
        if (auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext())
          if (nominal->getName() == accessPath.front().first)
            results.push_back(vd);
      }
    }
    return;
  }

  for (auto item : *iter) {
    auto vd = cast<ValueDecl>(getDecl(item.second));
    results.push_back(vd);
  }
}
示例#7
0
void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry,
                                clang::DeclContext *effectiveContext) {
  assert(!Reader && "Cannot modify a lookup table stored on disk");

  // Translate the context.
  auto contextOpt = translateContext(effectiveContext);
  if (!contextOpt) return;
  auto context = *contextOpt;

  // Find the list of entries for this base name.
  auto &entries = LookupTable[name.getBaseName().str()];
  auto decl = newEntry.dyn_cast<clang::NamedDecl *>();
  auto macro = newEntry.dyn_cast<clang::MacroInfo *>();
  for (auto &entry : entries) {
    if (entry.Context == context) {
      // We have entries for this context.

      // Check whether this entry matches any existing entry.
      for (auto &existingEntry : entry.DeclsOrMacros) {
        // If it matches an existing declaration, there's nothing to do.
        if (decl && isDeclEntry(existingEntry) && 
            matchesExistingDecl(decl, mapStoredDecl(existingEntry)))
          return;

        // If it matches an existing macro, overwrite the existing entry.
        if (macro && isMacroEntry(existingEntry)) {
          existingEntry = encodeEntry(macro);
          return;
        }
      }

      // Add an entry to this context.
      if (decl)
        entry.DeclsOrMacros.push_back(encodeEntry(decl));
      else
        entry.DeclsOrMacros.push_back(encodeEntry(macro));
      return;
    }
  }

  // This is a new context for this name. Add it.
  FullTableEntry entry;
  entry.Context = context;
  if (decl)
    entry.DeclsOrMacros.push_back(encodeEntry(decl));
  else
    entry.DeclsOrMacros.push_back(encodeEntry(macro));
  entries.push_back(entry);
}
示例#8
0
int DeclName::compare(DeclName other) const {
  // Compare base names.
  if (int result = getBaseName().compare(other.getBaseName()))
    return result;

  // Compare argument names.
  auto argNames = getArgumentNames();
  auto otherArgNames = other.getArgumentNames();
  for (unsigned i = 0, n = std::min(argNames.size(), otherArgNames.size());
       i != n; ++i) {
    if (int result = argNames[i].compare(otherArgNames[i]))
      return result;
  }

  if (argNames.size() == otherArgNames.size())
    return 0;

  return argNames.size() < otherArgNames.size() ? -1 : 1;
}
示例#9
0
UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC,
                                     LazyResolver *TypeResolver,
                                     bool IsKnownNonCascading,
                                     SourceLoc Loc, bool IsTypeLookup,
                                     bool AllowProtocolMembers) {
  Module &M = *DC->getParentModule();
  ASTContext &Ctx = M.getASTContext();
  const SourceManager &SM = Ctx.SourceMgr;
  DebuggerClient *DebugClient = M.getDebugClient();

  NamedDeclConsumer Consumer(Name, Results, IsTypeLookup);

  Optional<bool> isCascadingUse;
  if (IsKnownNonCascading)
    isCascadingUse = false;

  SmallVector<UnqualifiedLookupResult, 4> UnavailableInnerResults;

  // Never perform local lookup for operators.
  if (Name.isOperator()) {
    if (!isCascadingUse.hasValue()) {
      isCascadingUse =
        DC->isCascadingContextForLookup(/*excludeFunctions=*/true);
    }
    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 (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()) {
          if (!isCascadingUse.hasValue()) {
            isCascadingUse =
                !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc);
          }

          namelookup::FindLocalVal localVal(SM, Loc, Consumer);
          localVal.visit(AFD->getBody());
          if (!Results.empty())
            return;
          for (auto *PL : AFD->getParameterLists())
            localVal.checkParameterList(PL);
          if (!Results.empty())
            return;
        }
        if (!isCascadingUse.hasValue() || isCascadingUse.getValue())
          isCascadingUse = AFD->isCascadingContextForLookup(false);

        if (AFD->getExtensionType()) {
          if (AFD->getDeclContext()->getAsProtocolOrProtocolExtensionContext()) {
            ExtendedType = AFD->getDeclContext()->getSelfTypeInContext();

            // Fallback path.
            if (!ExtendedType)
              ExtendedType = AFD->getExtensionType();
          } else {
            ExtendedType = AFD->getExtensionType();
          }
          BaseDecl = AFD->getImplicitSelfDecl();
          MetaBaseDecl = AFD->getExtensionType()->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)) {
            namelookup::FindLocalVal localVal(SM, Loc, Consumer);
            localVal.visit(CE->getBody());
            if (!Results.empty())
              return;
            localVal.checkParameterList(CE->getParameters());
            if (!Results.empty())
              return;
          }
        }
        if (!isCascadingUse.hasValue())
          isCascadingUse = ACE->isCascadingContextForLookup(false);
      } else if (ExtensionDecl *ED = dyn_cast<ExtensionDecl>(DC)) {
        ExtendedType = ED->getSelfTypeInContext();

        BaseDecl = ED->getAsNominalTypeOrNominalTypeExtensionContext();
        MetaBaseDecl = BaseDecl;
        if (!isCascadingUse.hasValue())
          isCascadingUse = ED->isCascadingContextForLookup(false);
      } else if (NominalTypeDecl *ND = dyn_cast<NominalTypeDecl>(DC)) {
        ExtendedType = ND->getDeclaredType();
        BaseDecl = ND;
        MetaBaseDecl = BaseDecl;
        if (!isCascadingUse.hasValue())
          isCascadingUse = ND->isCascadingContextForLookup(false);
      } else if (auto I = dyn_cast<DefaultArgumentInitializer>(DC)) {
        // In a default argument, skip immediately out of both the
        // initializer and the function.
        isCascadingUse = false;
        DC = I->getParent()->getParent();
        continue;
      } else {
        assert(isa<TopLevelCodeDecl>(DC) || isa<Initializer>(DC));
        if (!isCascadingUse.hasValue())
          isCascadingUse = DC->isCascadingContextForLookup(false);
      }

      // Check the generic parameters for something with the given name.
      if (GenericParams) {
        namelookup::FindLocalVal localVal(SM, Loc, Consumer);
        localVal.checkGenericParams(GenericParams);

        if (!Results.empty())
          return;
      }

      if (BaseDecl) {
        if (TypeResolver)
          TypeResolver->resolveDeclSignature(BaseDecl);

        NLOptions options = NL_UnqualifiedDefault;
        if (isCascadingUse.getValue())
          options |= NL_KnownCascadingDependency;
        else
          options |= NL_KnownNonCascadingDependency;

        if (AllowProtocolMembers)
          options |= NL_ProtocolMembers;
        if (IsTypeLookup)
          options |= NL_OnlyTypes;

        if (!ExtendedType)
          ExtendedType = ErrorType::get(Ctx);

        SmallVector<ValueDecl *, 4> Lookup;
        DC->lookupQualified(ExtendedType, Name, options, 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(UnqualifiedLookupResult(Result));
            else
              Results.push_back(UnqualifiedLookupResult(MetaBaseDecl, Result));
            continue;
          } else if (auto FD = dyn_cast<FuncDecl>(Result)) {
            if (FD->isStatic() && !isMetatypeType)
              continue;
          } else if (isa<EnumElementDecl>(Result)) {
            Results.push_back(UnqualifiedLookupResult(BaseDecl, Result));
            continue;
          }

          Results.push_back(UnqualifiedLookupResult(BaseDecl, Result));
        }

        if (FoundAny) {
          // Predicate that determines whether a lookup result should
          // be unavailable except as a last-ditch effort.
          auto unavailableLookupResult =
            [&](const UnqualifiedLookupResult &result) {
            return result.getValueDecl()->getAttrs()
                     .isUnavailableInCurrentSwift();
          };

          // If all of the results we found are unavailable, keep looking.
          if (std::all_of(Results.begin(), Results.end(),
                          unavailableLookupResult)) {
            UnavailableInnerResults.append(Results.begin(), Results.end());
            Results.clear();
            FoundAny = false;
          } else {
            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) {
          namelookup::FindLocalVal localVal(SM, Loc, Consumer);
          localVal.checkGenericParams(dcGenericParams);

          if (!Results.empty())
            return;
        }
      }

      DC = DC->getParent();
    }

    if (!isCascadingUse.hasValue())
      isCascadingUse = true;
  }

  if (auto SF = dyn_cast<SourceFile>(DC)) {
    if (Loc.isValid()) {
      // 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.
      namelookup::FindLocalVal localVal(SM, Loc, Consumer);
      localVal.checkSourceFile(*SF);
      if (!Results.empty())
        return;
    }
  }

  // TODO: Does the debugger client care about compound names?
  if (Name.isSimpleName()
      && DebugClient && DebugClient->lookupOverrides(Name.getBaseName(), DC,
                                                   Loc, IsTypeLookup, Results))
    return;

  recordLookupOfTopLevelName(DC, Name, isCascadingUse.getValue());

  // Add private imports to the extra search list.
  SmallVector<Module::ImportedModule, 8> extraImports;
  if (auto FU = dyn_cast<FileUnit>(DC))
    FU->getImportedModules(extraImports, Module::ImportFilter::Private);

  using namespace namelookup;
  SmallVector<ValueDecl *, 8> CurModuleResults;
  auto resolutionKind =
    IsTypeLookup ? ResolutionKind::TypesOnly : ResolutionKind::Overloadable;
  lookupInModule(&M, {}, Name, CurModuleResults, NLKind::UnqualifiedLookup,
                 resolutionKind, TypeResolver, DC, extraImports);

  for (auto VD : CurModuleResults)
    Results.push_back(UnqualifiedLookupResult(VD));

  if (DebugClient)
    filterForDiscriminator(Results, DebugClient);

  // Now add any names the DebugClient knows about to the lookup.
  if (Name.isSimpleName() && DebugClient)
      DebugClient->lookupAdditions(Name.getBaseName(), DC, Loc, IsTypeLookup,
                                   Results);

  // If we've found something, we're done.
  if (!Results.empty())
    return;

  // If we still haven't found anything, but we do have some
  // declarations that are "unavailable in the current Swift", drop
  // those in.
  if (!UnavailableInnerResults.empty()) {
    Results = std::move(UnavailableInnerResults);
    return;
  }

  if (!Name.isSimpleName())
    return;

  // Look for a module with the given name.
  if (Name.isSimpleName(M.getName())) {
    Results.push_back(UnqualifiedLookupResult(&M));
    return;
  }

  Module *desiredModule = Ctx.getLoadedModule(Name.getBaseName());
  if (!desiredModule && Name == Ctx.TheBuiltinModule->getName())
    desiredModule = Ctx.TheBuiltinModule;
  if (desiredModule) {
    forAllVisibleModules(DC, [&](const Module::ImportedModule &import) -> bool {
      if (import.second == desiredModule) {
        Results.push_back(UnqualifiedLookupResult(import.second));
        return false;
      }
      return true;
    });
  }
}
示例#10
0
bool DeclContext::lookupQualified(Type type,
                                  DeclName member,
                                  NLOptions options,
                                  LazyResolver *typeResolver,
                                  SmallVectorImpl<ValueDecl *> &decls) const {
  using namespace namelookup;
  assert(decls.empty() && "additive lookup not supported");

  if (type->is<ErrorType>())
    return false;

  auto checkLookupCascading = [this, options]() -> Optional<bool> {
    switch (static_cast<unsigned>(options & NL_KnownDependencyMask)) {
    case 0:
      return isCascadingContextForLookup(/*excludeFunctions=*/false);
    case NL_KnownNonCascadingDependency:
      return false;
    case NL_KnownCascadingDependency:
      return true;
    case NL_KnownNoDependency:
      return None;
    default:
      // FIXME: Use llvm::CountPopulation_64 when that's declared constexpr.
      static_assert(__builtin_popcountll(NL_KnownDependencyMask) == 2,
                    "mask should only include four values");
      llvm_unreachable("mask only includes four values");
    }
  };

  // Look through lvalue and inout types.
  type = type->getLValueOrInOutObjectType();

  // Look through metatypes.
  if (auto metaTy = type->getAs<AnyMetatypeType>())
    type = metaTy->getInstanceType();

  // Look through DynamicSelf.
  if (auto dynamicSelf = type->getAs<DynamicSelfType>())
    type = dynamicSelf->getSelfType();

  // Look for module references.
  if (auto moduleTy = type->getAs<ModuleType>()) {
    Module *module = moduleTy->getModule();
    auto topLevelScope = getModuleScopeContext();
    if (module == topLevelScope->getParentModule()) {
      if (auto maybeLookupCascade = checkLookupCascading()) {
        recordLookupOfTopLevelName(topLevelScope, member,
                                   maybeLookupCascade.getValue());
      }
      lookupInModule(module, /*accessPath=*/{}, member, decls,
                     NLKind::QualifiedLookup, ResolutionKind::Overloadable,
                     typeResolver, topLevelScope);
    } else {
      // Note: This is a lookup into another module. Unless we're compiling
      // multiple modules at once, or if the other module re-exports this one,
      // it shouldn't be possible to have a dependency from that module on
      // anything in this one.

      // Perform the lookup in all imports of this module.
      forAllVisibleModules(this,
                           [&](const Module::ImportedModule &import) -> bool {
        if (import.second != module)
          return true;
        lookupInModule(import.second, import.first, member, decls,
                       NLKind::QualifiedLookup, ResolutionKind::Overloadable,
                       typeResolver, topLevelScope);
        // If we're able to do an unscoped lookup, we see everything. No need
        // to keep going.
        return !import.first.empty();
      });
    }

    llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
    decls.erase(std::remove_if(decls.begin(), decls.end(),
                               [&](ValueDecl *vd) -> bool {
      // If we're performing a type lookup, don't even attempt to validate
      // the decl if its not a type.
      if ((options & NL_OnlyTypes) && !isa<TypeDecl>(vd))
        return true;

      return !knownDecls.insert(vd).second;
    }), decls.end());

    if (auto *debugClient = topLevelScope->getParentModule()->getDebugClient())
      filterForDiscriminator(decls, debugClient);
    
    return !decls.empty();
  }

  auto &ctx = getASTContext();
  if (!ctx.LangOpts.EnableAccessControl)
    options |= NL_IgnoreAccessibility;

  // The set of nominal type declarations we should (and have) visited.
  SmallVector<NominalTypeDecl *, 4> stack;
  llvm::SmallPtrSet<NominalTypeDecl *, 4> visited;

  // Handle nominal types.
  bool wantProtocolMembers = false;
  bool wantLookupInAllClasses = false;
  if (auto nominal = type->getAnyNominal()) {
    visited.insert(nominal);
    stack.push_back(nominal);
    
    wantProtocolMembers = (options & NL_ProtocolMembers) &&
                          !isa<ProtocolDecl>(nominal);

    // If we want dynamic lookup and we're searching in the
    // AnyObject protocol, note this for later.
    if (options & NL_DynamicLookup) {
      if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
        if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
          wantLookupInAllClasses = true;
      }
    }
  }
  // Handle archetypes
  else if (auto archetypeTy = type->getAs<ArchetypeType>()) {
    // Look in the protocols to which the archetype conforms (always).
    for (auto proto : archetypeTy->getConformsTo())
      if (visited.insert(proto).second)
        stack.push_back(proto);

    // If requested, look into the superclasses of this archetype.
    if (options & NL_VisitSupertypes) {
      if (auto superclassTy = archetypeTy->getSuperclass()) {
        if (auto superclassDecl = superclassTy->getAnyNominal()) {
          if (visited.insert(superclassDecl).second) {
            stack.push_back(superclassDecl);

            wantProtocolMembers = (options & NL_ProtocolMembers) &&
                                  !isa<ProtocolDecl>(superclassDecl);
          }
        }
      }
    }
  }
  // Handle protocol compositions.
  else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
    SmallVector<ProtocolDecl *, 4> protocols;
    if (compositionTy->isExistentialType(protocols)) {
      for (auto proto : protocols) {
        if (visited.insert(proto).second) {
          stack.push_back(proto);

          // If we want dynamic lookup and this is the AnyObject
          // protocol, note this for later.
          if ((options & NL_DynamicLookup) &&
              proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
            wantLookupInAllClasses = true;
        }
      }
    }
  }

  // Allow filtering of the visible declarations based on various
  // criteria.
  bool onlyCompleteObjectInits = false;
  auto isAcceptableDecl = [&](NominalTypeDecl *current, Decl *decl) -> bool {
    // If the decl is currently being type checked, then we have something
    // cyclic going on.  Instead of poking at parts that are potentially not
    // set up, just assume it is acceptable.  This will make sure we produce an
    // error later.
    if (decl->isBeingTypeChecked())
      return true;
    
    // Filter out designated initializers, if requested.
    if (onlyCompleteObjectInits) {
      if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
        if (!ctor->isInheritable())
          return false;
      } else {
        return false;
      }
    }

    // Ignore stub implementations.
    if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
      if (ctor->hasStubImplementation())
        return false;
    }

    // Check access.
    if (!(options & NL_IgnoreAccessibility))
      if (auto VD = dyn_cast<ValueDecl>(decl))
        return VD->isAccessibleFrom(this);

    return true;
  };

  ReferencedNameTracker *tracker = nullptr;
  if (auto containingSourceFile = dyn_cast<SourceFile>(getModuleScopeContext()))
    tracker = containingSourceFile->getReferencedNameTracker();

  bool isLookupCascading;
  if (tracker) {
    if (auto maybeLookupCascade = checkLookupCascading())
      isLookupCascading = maybeLookupCascade.getValue();
    else
      tracker = nullptr;
  }

  // Visit all of the nominal types we know about, discovering any others
  // we need along the way.
  while (!stack.empty()) {
    auto current = stack.back();
    stack.pop_back();

    if (tracker)
      tracker->addUsedMember({current, member.getBaseName()},isLookupCascading);

    // Make sure we've resolved implicit constructors, if we need them.
    if (member.getBaseName() == ctx.Id_init && typeResolver)
      typeResolver->resolveImplicitConstructors(current);

    // Look for results within the current nominal type and its extensions.
    bool currentIsProtocol = isa<ProtocolDecl>(current);
    for (auto decl : current->lookupDirect(member)) {
      // If we're performing a type lookup, don't even attempt to validate
      // the decl if its not a type.
      if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
        continue;

      // Resolve the declaration signature when we find the
      // declaration.
      if (typeResolver && !decl->isBeingTypeChecked()) {
        typeResolver->resolveDeclSignature(decl);

        if (!decl->hasType())
          continue;
      }

      if (isAcceptableDecl(current, decl))
        decls.push_back(decl);
    }

    // If we're not supposed to visit our supertypes, we're done.
    if ((options & NL_VisitSupertypes) == 0)
      continue;

    // Visit superclass.
    if (auto classDecl = dyn_cast<ClassDecl>(current)) {
      // If we're looking for initializers, only look at the superclass if the
      // current class permits inheritance. Even then, only find complete
      // object initializers.
      bool visitSuperclass = true;
      if (member.getBaseName() == ctx.Id_init) {
        if (classDecl->inheritsSuperclassInitializers(typeResolver))
          onlyCompleteObjectInits = true;
        else
          visitSuperclass = false;
      }

      if (visitSuperclass) {
        if (auto superclassType = classDecl->getSuperclass())
          if (auto superclassDecl = superclassType->getClassOrBoundGenericClass())
            if (visited.insert(superclassDecl).second)
              stack.push_back(superclassDecl);
      }
    }

    // If we're not looking at a protocol and we're not supposed to
    // visit the protocols that this type conforms to, skip the next
    // step.
    if (!wantProtocolMembers && !currentIsProtocol)
      continue;

    SmallVector<ProtocolDecl *, 4> protocols;
    for (auto proto : current->getAllProtocols()) {
      if (visited.insert(proto).second) {
        stack.push_back(proto);
      }
    }

    // For a class, we don't need to visit the protocol members of the
    // superclass: that's already handled.
    if (isa<ClassDecl>(current))
      wantProtocolMembers = false;
  }

  // If we want to perform lookup into all classes, do so now.
  if (wantLookupInAllClasses) {
    if (tracker)
      tracker->addDynamicLookupName(member.getBaseName(), isLookupCascading);

    // Collect all of the visible declarations.
    SmallVector<ValueDecl *, 4> allDecls;
    forAllVisibleModules(this, [&](Module::ImportedModule import) {
      import.second->lookupClassMember(import.first, member, allDecls);
    });

    // For each declaration whose context is not something we've
    // already visited above, add it to the list of declarations.
    llvm::SmallPtrSet<ValueDecl *, 4> knownDecls;
    for (auto decl : allDecls) {
      // If we're performing a type lookup, don't even attempt to validate
      // the decl if its not a type.
      if ((options & NL_OnlyTypes) && !isa<TypeDecl>(decl))
        continue;

      if (typeResolver && !decl->isBeingTypeChecked()) {
        typeResolver->resolveDeclSignature(decl);
        if (!decl->hasType())
          continue;
      }

      // If the declaration has an override, name lookup will also have
      // found the overridden method. Skip this declaration, because we
      // prefer the overridden method.
      if (decl->getOverriddenDecl())
        continue;

      auto dc = decl->getDeclContext();
      auto nominal = dyn_cast<NominalTypeDecl>(dc);
      if (!nominal) {
        auto ext = cast<ExtensionDecl>(dc);
        nominal = ext->getExtendedType()->getAnyNominal();
        assert(nominal && "Couldn't find nominal type?");
      }

      // If we didn't visit this nominal type above, add this
      // declaration to the list.
      if (!visited.count(nominal) && knownDecls.insert(decl).second &&
          isAcceptableDecl(nominal, decl))
        decls.push_back(decl);
    }
  }

  // If we're supposed to remove overridden declarations, do so now.
  if (options & NL_RemoveOverridden)
    removeOverriddenDecls(decls);

  // If we're supposed to remove shadowed/hidden declarations, do so now.
  Module *M = getParentModule();
  if (options & NL_RemoveNonVisible)
    removeShadowedDecls(decls, M, typeResolver);

  if (auto *debugClient = M->getDebugClient())
    filterForDiscriminator(decls, debugClient);

  // We're done. Report success/failure.
  return !decls.empty();
}