Example #1
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);
  }
}
Example #2
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);
      }
    }
  }
}
Example #3
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;
    });
  }
}