//===--- CompletionLookup.cpp ---------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2022 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/IDE/CompletionLookup.h" #include "CodeCompletionResultBuilder.h" #include "ExprContextAnalysis.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ParameterList.h" #include "swift/AST/SourceFile.h" #include "swift/Basic/Assertions.h" using namespace swift; using namespace swift::ide; namespace { static bool SwiftKeyPathFilter(ValueDecl *decl, DeclVisibilityKind) { switch (decl->getKind()) { case DeclKind::Var: case DeclKind::Subscript: return true; default: return false; } } static bool isTopLevelSubcontext(const DeclContext *DC) { for (; DC && DC->isLocalContext(); DC = DC->getParent()) { switch (DC->getContextKind()) { case DeclContextKind::TopLevelCodeDecl: return true; case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::EnumElementDecl: return false; default: continue; } } return false; } static KnownProtocolKind protocolForLiteralKind(CodeCompletionLiteralKind kind) { switch (kind) { case CodeCompletionLiteralKind::ArrayLiteral: return KnownProtocolKind::ExpressibleByArrayLiteral; case CodeCompletionLiteralKind::BooleanLiteral: return KnownProtocolKind::ExpressibleByBooleanLiteral; case CodeCompletionLiteralKind::ColorLiteral: return KnownProtocolKind::ExpressibleByColorLiteral; case CodeCompletionLiteralKind::ImageLiteral: return KnownProtocolKind::ExpressibleByImageLiteral; case CodeCompletionLiteralKind::DictionaryLiteral: return KnownProtocolKind::ExpressibleByDictionaryLiteral; case CodeCompletionLiteralKind::IntegerLiteral: return KnownProtocolKind::ExpressibleByIntegerLiteral; case CodeCompletionLiteralKind::NilLiteral: return KnownProtocolKind::ExpressibleByNilLiteral; case CodeCompletionLiteralKind::StringLiteral: return KnownProtocolKind::ExpressibleByUnicodeScalarLiteral; case CodeCompletionLiteralKind::Tuple: llvm_unreachable("no such protocol kind"); } llvm_unreachable("Unhandled CodeCompletionLiteralKind in switch."); } static Type defaultTypeLiteralKind(CodeCompletionLiteralKind kind, ASTContext &Ctx) { switch (kind) { case CodeCompletionLiteralKind::BooleanLiteral: return Ctx.getBoolType(); case CodeCompletionLiteralKind::IntegerLiteral: return Ctx.getIntType(); case CodeCompletionLiteralKind::StringLiteral: return Ctx.getStringType(); case CodeCompletionLiteralKind::ArrayLiteral: if (!Ctx.getArrayDecl()) return Type(); return Ctx.getArrayDecl()->getDeclaredInterfaceType(); case CodeCompletionLiteralKind::DictionaryLiteral: if (!Ctx.getDictionaryDecl()) return Type(); return Ctx.getDictionaryDecl()->getDeclaredInterfaceType(); case CodeCompletionLiteralKind::NilLiteral: case CodeCompletionLiteralKind::ColorLiteral: case CodeCompletionLiteralKind::ImageLiteral: case CodeCompletionLiteralKind::Tuple: return Type(); } llvm_unreachable("Unhandled CodeCompletionLiteralKind in switch."); } /// Whether the provided type has a single argument (not including defaulted /// arguments) that is of type () -> (). static bool hasTrivialTrailingClosure(const ValueDecl *VD, Type type) { if (!VD->hasParameterList()) return false; auto *funcType = type->getAs(); if (!funcType) return false; ParameterListInfo paramInfo(funcType->getParams(), VD, /*skipCurriedSelf*/ VD->hasCurriedSelf()); if (paramInfo.size() - paramInfo.numNonDefaultedParameters() == 1) { auto param = funcType->getParams().back(); if (!param.isAutoClosure()) { if (auto Fn = param.getOldType()->getAs()) { return Fn->getParams().empty() && Fn->getResult()->isVoid(); } } } return false; } } // end anonymous namespace bool swift::ide::DefaultFilter(ValueDecl *VD, DeclVisibilityKind Kind, DynamicLookupInfo dynamicLookupInfo) { return true; } bool swift::ide::KeyPathFilter(ValueDecl *decl, DeclVisibilityKind, DynamicLookupInfo dynamicLookupInfo) { return isa(decl) || (isa(decl) && decl->getDeclContext()->isTypeContext()); } bool swift::ide::MacroFilter(ValueDecl *decl, DeclVisibilityKind, DynamicLookupInfo dynamicLookupInfo) { return isa(decl); } bool swift::ide::isCodeCompletionAtTopLevel(const DeclContext *DC) { if (DC->isModuleScopeContext()) return true; // CC token at top-level is parsed as an expression. If the only element // body of the TopLevelCodeDecl is a CodeCompletionExpr without a base // expression, the user might be writing a top-level declaration. if (const TopLevelCodeDecl *TLCD = dyn_cast(DC)) { auto body = TLCD->getBody(); if (!body || body->empty()) return true; if (body->getElements().size() > 1) return false; auto expr = body->getFirstElement().dyn_cast(); if (!expr) return false; if (CodeCompletionExpr *CCExpr = dyn_cast(expr)) { if (CCExpr->getBase() == nullptr) return true; } } return false; } bool swift::ide::isCompletionDeclContextLocalContext(DeclContext *DC) { if (!DC->isLocalContext()) return false; if (isCodeCompletionAtTopLevel(DC)) return false; return true; } /// Returns \c true if \p DC can handles async call. bool swift::ide::canDeclContextHandleAsync(const DeclContext *DC) { if (auto *func = dyn_cast(DC)) return func->isAsyncContext(); if (auto *closure = dyn_cast(DC)) { // See if the closure has 'async' function type. if (auto closureType = closure->getType()) if (auto fnType = closureType->getAs()) if (fnType->isAsync()) return true; // If the closure doesn't contain any async call in the body, closure itself // doesn't have 'async' type even if 'async' closure is expected. // func foo(fn: () async -> Void) // foo { } // In this case, the closure is wrapped with a 'FunctionConversionExpr' // which has 'async' function type. struct AsyncClosureChecker : public ASTWalker { const ClosureExpr *Target; bool Result = false; /// Walk everything in a macro. MacroWalking getMacroWalkingBehavior() const override { return MacroWalking::ArgumentsAndExpansion; } AsyncClosureChecker(const ClosureExpr *Target) : Target(Target) {} PreWalkResult walkToExprPre(Expr *E) override { if (E == Target) return Action::SkipNode(E); if (auto conversionExpr = dyn_cast(E)) { if (conversionExpr->getSubExpr() == Target) { if (conversionExpr->getType()->is() && conversionExpr->getType()->castTo()->isAsync()) Result = true; return Action::SkipNode(E); } } return Action::Continue(E); } } checker(closure); closure->getParent()->walkContext(checker); return checker.Result; } return false; } /// Return \c true if the completion happens at top-level of a library file. bool swift::ide::isCodeCompletionAtTopLevelOfLibraryFile( const DeclContext *DC) { if (DC->getParentSourceFile()->isScriptMode()) return false; return isCodeCompletionAtTopLevel(DC); } // MARK: - CompletionLookup void CompletionLookup::foundFunction(const AbstractFunctionDecl *AFD) { FoundFunctionCalls = true; const DeclName Name = AFD->getName(); auto ArgNames = Name.getArgumentNames(); if (ArgNames.empty()) return; if (ArgNames[0].empty()) FoundFunctionsWithoutFirstKeyword = true; } void CompletionLookup::foundFunction(const AnyFunctionType *AFT) { FoundFunctionCalls = true; auto Params = AFT->getParams(); if (Params.empty()) return; if (Params.size() == 1 && !Params[0].hasLabel()) { FoundFunctionsWithoutFirstKeyword = true; return; } if (!Params[0].hasLabel()) FoundFunctionsWithoutFirstKeyword = true; } bool CompletionLookup::canBeUsedAsRequirementFirstType(Type selfTy, TypeAliasDecl *TAD) { if (TAD->isGeneric()) return false; auto T = TAD->getDeclaredInterfaceType(); auto subMap = selfTy->getContextSubstitutionMap(TAD->getDeclContext()); return T.subst(subMap)->is(); } CompletionLookup::CompletionLookup(CodeCompletionResultSink &Sink, ASTContext &Ctx, const DeclContext *CurrDeclContext, CodeCompletionContext *CompletionContext) : Sink(Sink), Ctx(Ctx), CurrDeclContext(CurrDeclContext), CurrModule(CurrDeclContext ? CurrDeclContext->getParentModule() : nullptr), Importer(static_cast( CurrDeclContext->getASTContext().getClangModuleLoader())), CompletionContext(CompletionContext) { // Determine if we are doing code completion inside a static method. if (CurrDeclContext) { CurrentMethod = CurrDeclContext->getInnermostMethodContext(); if (auto *FD = dyn_cast_or_null(CurrentMethod)) InsideStaticMethod = FD->isStatic(); CanCurrDeclContextHandleAsync = canDeclContextHandleAsync(CurrDeclContext); } } void CompletionLookup::addSubModuleNames( std::vector> &SubModuleNameVisibilityPairs) { for (auto &Pair : SubModuleNameVisibilityPairs) { CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Declaration, SemanticContextKind::None); auto *MD = ModuleDecl::createEmpty(Ctx.getIdentifier(Pair.first), Ctx); Builder.setAssociatedDecl(MD); Builder.addBaseName(MD->getNameStr()); Builder.addTypeAnnotation("Module"); if (Pair.second) Builder.setContextualNotRecommended( ContextualNotRecommendedReason::RedundantImport); } } void CompletionLookup::collectImportedModules( llvm::StringSet<> &directImportedModules, llvm::StringSet<> &allImportedModules) { SmallVector Imported; SmallVector FurtherImported; CurrDeclContext->getParentSourceFile()->getImportedModules( Imported, ModuleDecl::getImportFilterLocal()); for (ImportedModule &imp : Imported) directImportedModules.insert(imp.importedModule->getNameStr()); while (!Imported.empty()) { ModuleDecl *MD = Imported.back().importedModule; Imported.pop_back(); if (!allImportedModules.insert(MD->getNameStr()).second) continue; FurtherImported.clear(); MD->getImportedModules(FurtherImported, ModuleDecl::ImportFilterKind::Exported); Imported.append(FurtherImported.begin(), FurtherImported.end()); } } void CompletionLookup::addModuleName( ModuleDecl *MD, std::optional R) { // Don't add underscored cross-import overlay modules. if (MD->getDeclaringModuleIfCrossImportOverlay()) return; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Declaration, SemanticContextKind::None); Builder.setAssociatedDecl(MD); auto moduleName = MD->getName(); // This checks if module aliasing was used. For example, when editing // `import ...`, and `-module-alias Foo=Bar` was passed, we want to show // Foo as an option to import, instead of Bar (name of the binary), as // Foo is the name that should appear in source files. auto aliasedName = Ctx.getRealModuleName( moduleName, ASTContext::ModuleAliasLookupOption::aliasFromRealName); if (aliasedName != moduleName && // check if module aliasing was applied !aliasedName.empty()) { // check an alias mapped to the binary name exists moduleName = aliasedName; // if so, use the aliased name } Builder.addBaseName(moduleName.str()); Builder.addTypeAnnotation("Module"); if (R) Builder.setContextualNotRecommended(*R); } void CompletionLookup::addImportModuleNames() { SmallVector ModuleNames; Ctx.getVisibleTopLevelModuleNames(ModuleNames); llvm::StringSet<> directImportedModules; llvm::StringSet<> allImportedModules; collectImportedModules(directImportedModules, allImportedModules); auto mainModuleName = CurrModule->getName(); for (auto ModuleName : ModuleNames) { if (ModuleName == mainModuleName || isHiddenModuleName(ModuleName)) continue; auto *MD = ModuleDecl::createEmpty(ModuleName, Ctx); std::optional Reason = std::nullopt; // Imported modules are not recommended. if (directImportedModules.contains(MD->getNameStr())) { Reason = ContextualNotRecommendedReason::RedundantImport; } else if (allImportedModules.contains(MD->getNameStr())) { Reason = ContextualNotRecommendedReason::RedundantImportIndirect; } addModuleName(MD, Reason); } } SemanticContextKind CompletionLookup::getSemanticContext(const Decl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (ForcedSemanticContext) return *ForcedSemanticContext; switch (Reason) { case DeclVisibilityKind::LocalDecl: case DeclVisibilityKind::FunctionParameter: case DeclVisibilityKind::GenericParameter: return SemanticContextKind::Local; case DeclVisibilityKind::MemberOfCurrentNominal: return SemanticContextKind::CurrentNominal; case DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal: case DeclVisibilityKind::MemberOfSuper: return SemanticContextKind::Super; case DeclVisibilityKind::MemberOfOutsideNominal: return SemanticContextKind::OutsideNominal; case DeclVisibilityKind::VisibleAtTopLevel: if (CurrDeclContext && D->getModuleContext() == CurrModule) { // Treat global variables from the same source file as local when // completing at top-level. if (isa(D) && isTopLevelSubcontext(CurrDeclContext) && D->getDeclContext()->getParentSourceFile() == CurrDeclContext->getParentSourceFile()) { return SemanticContextKind::Local; } else { return SemanticContextKind::CurrentModule; } } else { return SemanticContextKind::OtherModule; } case DeclVisibilityKind::DynamicLookup: switch (dynamicLookupInfo.getKind()) { case DynamicLookupInfo::None: llvm_unreachable("invalid DynamicLookupInfo::Kind for dynamic lookup"); case DynamicLookupInfo::AnyObject: // AnyObject results can come from different modules, including the // current module, but we always assign them the OtherModule semantic // context. These declarations are uniqued by signature, so it is // totally random (determined by the hash function) which of the // equivalent declarations (across multiple modules) we will get. return SemanticContextKind::OtherModule; case DynamicLookupInfo::KeyPathDynamicMember: // Use the visibility of the underlying declaration. // FIXME: KeyPath !?!? assert(dynamicLookupInfo.getKeyPathDynamicMember().originalVisibility != DeclVisibilityKind::DynamicLookup); return getSemanticContext( D, dynamicLookupInfo.getKeyPathDynamicMember().originalVisibility, {}); } case DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal: llvm_unreachable("should not see this kind"); } llvm_unreachable("unhandled kind"); } bool CompletionLookup::isUnresolvedMemberIdealType(Type Ty) { assert(Ty); if (!IsUnresolvedMember) return false; Type idealTy = expectedTypeContext.getIdealType(); if (!idealTy) return false; /// Consider optional object type is the ideal. /// For example: /// enum MyEnum { case foo, bar } /// func foo(_: MyEnum?) /// fooo(.) /// Prefer '.foo' and '.bar' over '.some' and '.none'. idealTy = idealTy->lookThroughAllOptionalTypes(); return idealTy->isEqual(Ty); } CodeCompletionResultBuilder CompletionLookup::makeResultBuilder(CodeCompletionResultKind kind, SemanticContextKind semanticContext) const { CodeCompletionResultBuilder builder(Sink, kind, semanticContext); builder.setTypeContext(expectedTypeContext, CurrDeclContext); return builder; } void CompletionLookup::addValueBaseName(CodeCompletionResultBuilder &Builder, DeclBaseName Name) { auto NameStr = Name.userFacingName(); if (Name.mustAlwaysBeEscaped()) { // Names that are raw identifiers must always be escaped regardless of // their position. SmallString<16> buffer; Builder.addBaseName(Builder.escapeWithBackticks(NameStr, buffer)); return; } bool shouldEscapeKeywords; if (Name.isSpecial()) { // Special names (i.e. 'init') are always displayed as its user facing // name. shouldEscapeKeywords = false; } else if (ExprType) { // After dot. User can write any keyword after '.' except for `init` and // `self`. E.g. 'func `init`()' must be called by 'expr.`init`()'. shouldEscapeKeywords = NameStr == "self" || NameStr == "init"; } else { // As primary expresson. We have to escape almost every keywords except // for 'self' and 'Self'. shouldEscapeKeywords = NameStr != "self" && NameStr != "Self"; } if (!shouldEscapeKeywords) { Builder.addBaseName(NameStr); } else { SmallString<16> buffer; Builder.addBaseName(Builder.escapeKeyword(NameStr, true, buffer)); } } void CompletionLookup::addIdentifier(CodeCompletionResultBuilder &Builder, Identifier Name) { if (Name.mustAlwaysBeEscaped()) { SmallString<16> buffer; Builder.addBaseName(Builder.escapeWithBackticks(Name.str(), buffer)); } else { Builder.addBaseName(Name.str()); } } void CompletionLookup::addLeadingDot(CodeCompletionResultBuilder &Builder) { if (NeedOptionalUnwrap) { Builder.setNumBytesToErase(NumBytesToEraseForOptionalUnwrap); Builder.addQuestionMark(); Builder.addLeadingDot(); return; } if (needDot()) Builder.addLeadingDot(); } void CompletionLookup::addTypeAnnotation(CodeCompletionResultBuilder &Builder, Type T, GenericSignature genericSig) { PrintOptions PO; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) PO.setBaseType(typeContext->getDeclaredTypeInContext()); Builder.addTypeAnnotation(eraseArchetypes(T, genericSig), PO); Builder.setResultTypes(T); } void CompletionLookup::addTypeAnnotationForImplicitlyUnwrappedOptional( CodeCompletionResultBuilder &Builder, Type T, GenericSignature genericSig, bool dynamicOrOptional) { std::string suffix; // FIXME: This retains previous behavior, but in reality the type of dynamic // lookups is IUO, not Optional as it is for the @optional attribute. if (dynamicOrOptional) { T = T->getOptionalObjectType(); suffix = "?"; } PrintOptions PO; PO.PrintOptionalAsImplicitlyUnwrapped = true; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) PO.setBaseType(typeContext->getDeclaredTypeInContext()); Builder.addTypeAnnotation(eraseArchetypes(T, genericSig), PO, suffix); Builder.setResultTypes(T); Builder.setTypeContext(expectedTypeContext, CurrDeclContext); } /// For printing in code completion results, replace archetypes with /// protocol compositions. /// /// FIXME: Perhaps this should be an option in PrintOptions instead. Type CompletionLookup::eraseArchetypes(Type type, GenericSignature genericSig) { if (!genericSig) return type; if (auto *genericFuncType = type->getAs()) { assert(genericFuncType->getGenericSignature()->isEqual(genericSig) && "if not, just use the GFT's signature instead below"); SmallVector erasedParams; for (const auto ¶m : genericFuncType->getParams()) { auto erasedTy = eraseArchetypes(param.getPlainType(), genericSig); erasedParams.emplace_back(param.withType(erasedTy)); } return GenericFunctionType::get( genericSig, erasedParams, eraseArchetypes(genericFuncType->getResult(), genericSig), genericFuncType->getExtInfo()); } return type.transformRec([&](Type t) -> std::optional { // FIXME: Code completion should only deal with one or the other, // and not both. if (auto *archetypeType = t->getAs()) { // Don't erase opaque archetype. if (isa(archetypeType) && archetypeType->isRoot()) return std::nullopt; auto genericSig = archetypeType->getGenericEnvironment()->getGenericSignature(); auto upperBound = genericSig->getUpperBound( archetypeType->getInterfaceType(), /*forExistentialSelf=*/false, /*withParameterizedProtocols=*/false); if (!upperBound->isAny()) return upperBound; } if (t->isTypeParameter()) { auto upperBound = genericSig->getUpperBound( t, /*forExistentialSelf=*/false, /*withParameterizedProtocols=*/false); if (!upperBound->isAny()) return upperBound; } return std::nullopt; }); } Type CompletionLookup::getTypeOfMember(const ValueDecl *VD, DynamicLookupInfo dynamicLookupInfo) { switch (dynamicLookupInfo.getKind()) { case DynamicLookupInfo::None: return getTypeOfMember(VD, getMemberBaseType()); case DynamicLookupInfo::AnyObject: return getTypeOfMember(VD, Type()); case DynamicLookupInfo::KeyPathDynamicMember: { auto &keyPathInfo = dynamicLookupInfo.getKeyPathDynamicMember(); // Map the result of VD to keypath member lookup results. // Given: // struct Wrapper { // subscript(dynamicMember: KeyPath) -> Wrapped { get } // } // struct Circle { // var center: Point { get } // var radius: Length { get } // } // // Consider 'Wrapper.center'. // 'VD' is 'Circle.center' decl. // 'keyPathInfo.subscript' is 'Wrapper.subscript' decl. // 'keyPathInfo.baseType' is 'Wrapper' type. // FIXME: Handle nested keypath member lookup. // i.e. cases where 'ExprType' != 'keyPathInfo.baseType'. auto *SD = keyPathInfo.subscript; const auto elementTy = SD->getElementInterfaceType(); if (!elementTy->hasTypeParameter()) return elementTy; // Map is: // { τ_0_0(T) => Circle // τ_1_0(U) => U } auto subs = keyPathInfo.baseType->getMemberSubstitutions(SD); // FIXME: The below should use substitution map substitution. // If the keyPath result type has type parameters, that might affect the // subscript result type. auto keyPathResultTy = getResultTypeOfKeypathDynamicMember(SD); if (keyPathResultTy->hasTypeParameter()) { auto keyPathRootTy = getRootTypeOfKeypathDynamicMember(SD).subst( QueryTypeSubstitutionMap{subs}, LookUpConformanceInModule()); // The result type of the VD. // i.e. 'Circle.center' => 'Point'. auto innerResultTy = getTypeOfMember(VD, keyPathRootTy); if (auto paramTy = keyPathResultTy->getAs()) { // Replace keyPath result type in the map with the inner result type. // i.e. Make the map as: // { τ_0_0(T) => Circle // τ_1_0(U) => Point } auto key = paramTy->getCanonicalType()->castTo(); subs[key] = innerResultTy; } else { // FIXME: Handle the case where the KeyPath result is generic. // e.g. 'subscript(dynamicMember: KeyPath>) -> Bag' // For now, just return the inner type. return innerResultTy; } } // Substitute the element type of the subscript using modified map. // i.e. 'Wrapped' => 'Wrapped'. return elementTy.subst(QueryTypeSubstitutionMap{subs}, LookUpConformanceInModule()); } } llvm_unreachable("Unhandled DynamicLookupInfo Kind in switch"); } Type CompletionLookup::getTypeOfMember(const ValueDecl *VD, Type ExprType) { Type T; if (auto *TD = dyn_cast(VD)) { // For a type decl we're interested in the declared interface type, i.e // we don't want a metatype. T = TD->getDeclaredInterfaceType(); } else { T = VD->getInterfaceType(); } assert(!T.isNull()); if (ExprType) { Type ContextTy = VD->getDeclContext()->getDeclaredInterfaceType(); if (ContextTy) { // Look through lvalue types and metatypes Type MaybeNominalType = ExprType->getRValueType(); if (auto Metatype = MaybeNominalType->getAs()) MaybeNominalType = Metatype->getInstanceType(); if (auto SelfType = MaybeNominalType->getAs()) MaybeNominalType = SelfType->getSelfType(); // For optional protocol requirements and dynamic dispatch, // strip off optionality from the base type, but only if // we're not actually completing a member of Optional. if (!ContextTy->getOptionalObjectType() && MaybeNominalType->getOptionalObjectType()) MaybeNominalType = MaybeNominalType->getOptionalObjectType(); // For dynamic lookup don't substitute in the base type. if (MaybeNominalType->isAnyObject()) return T; // FIXME: Sometimes ExprType is the type of the member here, // and not the type of the base. That is inconsistent and // should be cleaned up. if (!MaybeNominalType->mayHaveMembers()) return T; // We can't do anything if the base type has unbound generic parameters. if (MaybeNominalType->hasUnboundGenericType()) return T; // If we are doing implicit member lookup on a protocol and we have found // a declaration in a constrained extension, use the extension's `Self` // type for the generic substitution. // Eg in the following, the `Self` type returned by `qux` is // `MyGeneric`, not `MyProto` because of the `Self` type restriction. // ``` // protocol MyProto {} // struct MyGeneric: MyProto {} // extension MyProto where Self == MyGeneric { // static func qux() -> Self { .init() } // } // func takeMyProto(_: any MyProto) {} // func test() { // takeMyProto(.#^COMPLETE^#) // } // ``` if (MaybeNominalType->isExistentialType()) { Type SelfType; if (auto *ED = dyn_cast(VD->getDeclContext())) { if (ED->getSelfProtocolDecl() && ED->isConstrainedExtension()) { auto Sig = ED->getGenericSignature(); SelfType = Sig->getConcreteType(ED->getSelfInterfaceType()); } } if (SelfType) { MaybeNominalType = SelfType; } else { return T; } } // For everything else, substitute in the base type. auto Subs = MaybeNominalType->getMemberSubstitutionMap(VD); // For a GenericFunctionType, we only want to substitute the // param/result types, as otherwise we might end up with a bad generic // signature if there are UnresolvedTypes present in the base type. Note // we pass in DesugarMemberTypes so that we see the actual concrete type // witnesses instead of type alias types. if (auto *GFT = T->getAs()) { T = GFT->substGenericArgs(Subs, SubstFlags::DesugarMemberTypes); } else { T = T.subst(Subs, SubstFlags::DesugarMemberTypes); } } } return T; } Type CompletionLookup::getAssociatedTypeType(const AssociatedTypeDecl *ATD) { Type BaseTy = getMemberBaseType(); if (!BaseTy && CurrDeclContext) BaseTy = CurrDeclContext->getInnermostTypeContext()->getDeclaredTypeInContext(); if (BaseTy) { BaseTy = BaseTy->getInOutObjectType()->getMetatypeInstanceType(); if (BaseTy->getAnyNominal()) { auto Conformance = lookupConformance(BaseTy, ATD->getProtocol()); if (Conformance.isConcrete()) { return Conformance.getConcrete()->getTypeWitness( const_cast(ATD)); } } } return Type(); } void CompletionLookup::analyzeActorIsolation( const ValueDecl *VD, Type T, bool &implicitlyAsync, std::optional &NotRecommended) { auto isolation = getActorIsolation(const_cast(VD)); switch (isolation.getKind()) { case ActorIsolation::ActorInstance: { // TODO: implicitlyThrowing here for distributed if (IsCrossActorReference) { implicitlyAsync = true; // TODO: 'NotRecommended' if this is a r-value reference. } break; } case ActorIsolation::GlobalActor: { // For "preconcurrency" global actor isolation, automatic 'async' only happens // if the context has adopted concurrency. if (isolation.preconcurrency() && !CanCurrDeclContextHandleAsync && !completionContextUsesConcurrencyFeatures(CurrDeclContext)) { return; } auto getClosureActorIsolation = [this](AbstractClosureExpr *CE) { // Prefer solution-specific actor-isolations and fall back to the one // recorded in the AST. auto isolation = ClosureActorIsolations.find(CE); if (isolation != ClosureActorIsolations.end()) { return isolation->second; } else { return CE->getActorIsolation(); } }; auto contextIsolation = getActorIsolationOfContext( const_cast(CurrDeclContext), getClosureActorIsolation); if (contextIsolation != isolation) { implicitlyAsync = true; } break; } case ActorIsolation::Erased: implicitlyAsync = true; break; case ActorIsolation::Unspecified: case ActorIsolation::Nonisolated: case ActorIsolation::CallerIsolationInheriting: case ActorIsolation::NonisolatedUnsafe: return; } } void CompletionLookup::addVarDeclRef(const VarDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (!VD->hasName()) return; const Identifier Name = VD->getName(); assert(!Name.empty() && "name should not be empty"); Type VarType; auto SolutionSpecificType = SolutionSpecificVarTypes.find(VD); if (SolutionSpecificType != SolutionSpecificVarTypes.end()) { assert(!VarType && "Type recorded in the AST and is also solution-specific?"); VarType = SolutionSpecificType->second; } else if (VD->hasInterfaceType()) { VarType = getTypeOfMember(VD, dynamicLookupInfo); } std::optional NotRecommended; // "not recommended" in its own getter. if (Kind == LookupKind::ValueInDeclContext) { if (auto accessor = dyn_cast(CurrDeclContext)) { if (accessor->getStorage() == VD && accessor->isGetter()) NotRecommended = ContextualNotRecommendedReason::VariableUsedInOwnDefinition; } } bool implicitlyAsync = false; analyzeActorIsolation(VD, VarType, implicitlyAsync, NotRecommended); CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(VD, Reason, dynamicLookupInfo)); Builder.setCanCurrDeclContextHandleAsync(CanCurrDeclContextHandleAsync); Builder.setAssociatedDecl(VD); addLeadingDot(Builder); addValueBaseName(Builder, Name); if (NotRecommended) Builder.setContextualNotRecommended(*NotRecommended); if (!VarType) return; if (auto *PD = dyn_cast(VD)) { if (Name != Ctx.Id_self && PD->isInOut()) { // It is useful to show inout for function parameters. // But for 'self' it is just noise. VarType = InOutType::get(VarType); } } auto DynamicOrOptional = IsDynamicLookup || VD->getAttrs().hasAttribute(); if (DynamicOrOptional) { // Values of properties that were found on a AnyObject have // Optional type. Same applies to optional members. VarType = OptionalType::get(VarType); } auto genericSig = VD->getInnermostDeclContext()->getGenericSignatureOfContext(); if (VD->isImplicitlyUnwrappedOptional()) addTypeAnnotationForImplicitlyUnwrappedOptional( Builder, VarType, genericSig, DynamicOrOptional); else addTypeAnnotation(Builder, VarType, genericSig); if (implicitlyAsync) Builder.addAnnotatedAsync(); if (isUnresolvedMemberIdealType(VarType)) Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific); if (auto Accessor = VD->getEffectfulGetAccessor()) { if (auto AFT = getTypeOfMember(Accessor, dynamicLookupInfo)->getAs()) { if (Accessor->hasImplicitSelfDecl()) { AFT = AFT->getResult()->getAs(); assert(AFT); } addEffectsSpecifiers(Builder, AFT, Accessor); } } } /// Return whether \p param has a non-desirable default value for code /// completion. /// /// 'ClangImporter::Implementation::inferDefaultArgument()' automatically adds /// default values for some parameters; /// * NS_OPTIONS enum type with the name '...Options'. /// * NSDictionary and labeled 'options', 'attributes', or 'userInfo'. /// /// But sometimes, this behavior isn't really desirable. This function add a /// heuristic where if a parameter matches all the following condition, we /// consider the imported default value is _not_ desirable: /// * it is the first parameter, /// * it doesn't have an argument label, and /// * the imported function base name ends with those words /// For example, ClangImporter imports: /// /// -(void)addAttributes:(NSDictionary *)attrs, options:(NSDictionary *)opts; /// /// as: /// /// func addAttributes(_ attrs: [AnyHashable:Any] = [:], /// options opts: [AnyHashable:Any] = [:]) /// /// In this case, we don't want 'attrs' defaulted because the function name have /// 'Attribute' in its name so calling 'value.addAttribute()' doesn't make /// sense, but we _do_ want to keep 'opts' defaulted. /// /// Note that: /// /// -(void)performWithOptions:(NSDictionary *) opts; /// /// This doesn't match the condition because the base name of the function in /// Swift is 'peform': /// /// func perform(options opts: [AnyHashable:Any] = [:]) /// bool isNonDesirableImportedDefaultArg(const ParamDecl *param) { auto kind = param->getDefaultArgumentKind(); if (kind != DefaultArgumentKind::EmptyArray && kind != DefaultArgumentKind::EmptyDictionary) return false; if (!param->getArgumentName().empty()) return false; auto *func = dyn_cast(param->getDeclContext()); if (!func->hasClangNode()) return false; if (func->getParameters()->front() != param) return false; if (func->getBaseName().isSpecial()) return false; auto baseName = func->getBaseName().getIdentifier().str(); switch (kind) { case DefaultArgumentKind::EmptyArray: return (baseName.ends_with("Options")); case DefaultArgumentKind::EmptyDictionary: return (baseName.ends_with("Options") || baseName.ends_with("Attributes") || baseName.ends_with("UserInfo")); default: llvm_unreachable("unhandled DefaultArgumentKind"); } } bool CompletionLookup::hasInterestingDefaultValue(const ParamDecl *param) { if (!param) return false; switch (param->getDefaultArgumentKind()) { case DefaultArgumentKind::Normal: case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::StoredProperty: case DefaultArgumentKind::Inherited: return true; case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: if (isNonDesirableImportedDefaultArg(param)) return false; return true; case DefaultArgumentKind::None: #define MAGIC_IDENTIFIER(NAME, STRING) \ case DefaultArgumentKind::NAME: #include "swift/AST/MagicIdentifierKinds.def" case DefaultArgumentKind::ExpressionMacro: return false; } } bool CompletionLookup::shouldAddItemWithoutDefaultArgs( const AbstractFunctionDecl *func) { if (!func || !Sink.addCallWithNoDefaultArgs) return false; for (auto param : *func->getParameters()) { if (hasInterestingDefaultValue(param)) return true; } return false; } bool CompletionLookup::addCallArgumentPatterns( CodeCompletionResultBuilder &Builder, ArrayRef typeParams, ArrayRef declParams, GenericSignature genericSig, bool includeDefaultArgs) { assert(declParams.empty() || typeParams.size() == declParams.size()); bool modifiedBuilder = false; bool needComma = false; // Iterate over each parameter. for (unsigned i = 0; i != typeParams.size(); ++i) { auto &typeParam = typeParams[i]; Identifier argName = typeParam.getLabel(); Identifier bodyName; bool isIUO = false; bool hasDefault = false; if (!declParams.empty()) { const ParamDecl *PD = declParams[i]; hasDefault = PD->isDefaultArgument() && !isNonDesirableImportedDefaultArg(PD); // Skip default arguments if we're either not including them or they // aren't interesting if (hasDefault && (!includeDefaultArgs || !hasInterestingDefaultValue(PD))) continue; argName = PD->getArgumentName(); bodyName = PD->getParameterName(); isIUO = PD->isImplicitlyUnwrappedOptional(); } bool isVariadic = typeParam.isVariadic(); bool isInOut = typeParam.isInOut(); bool isAutoclosure = typeParam.isAutoClosure(); Type paramTy = typeParam.getPlainType(); if (isVariadic) paramTy = ParamDecl::getVarargBaseTy(paramTy); Type contextTy; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) contextTy = typeContext->getDeclaredTypeInContext(); if (needComma) Builder.addComma(); Builder.addCallArgument(argName, bodyName, eraseArchetypes(paramTy, genericSig), contextTy, isVariadic, isInOut, isIUO, isAutoclosure, /*IsLabeledTrailingClosure=*/false, /*IsForOperator=*/false, hasDefault); modifiedBuilder = true; needComma = true; } return modifiedBuilder; } bool CompletionLookup::addCallArgumentPatterns( CodeCompletionResultBuilder &Builder, const AnyFunctionType *AFT, const ParameterList *Params, GenericSignature genericSig, bool includeDefaultArgs) { ArrayRef declParams; if (Params) declParams = Params->getArray(); return addCallArgumentPatterns(Builder, AFT->getParams(), declParams, genericSig, includeDefaultArgs); } void CompletionLookup::addEffectsSpecifiers( CodeCompletionResultBuilder &Builder, const AnyFunctionType *AFT, const AbstractFunctionDecl *AFD, bool forceAsync) { assert(AFT != nullptr); // 'async'. if (forceAsync || (AFD && AFD->hasAsync()) || (AFT->hasExtInfo() && AFT->isAsync())) Builder.addAnnotatedAsync(); // 'throws' or 'rethrows'. if (AFD && AFD->getAttrs().hasAttribute()) Builder.addAnnotatedRethrows(); else if (AFT->hasExtInfo() && AFT->isThrowing()) Builder.addAnnotatedThrows(); } void CompletionLookup::addPoundAvailable(std::optional ParentKind) { if (ParentKind != StmtKind::If && ParentKind != StmtKind::Guard) return; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, // FIXME: SemanticContextKind::Local is not correct. // Use 'None' (and fix prioritization) or introduce a new context. SemanticContextKind::Local); Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific); Builder.addBaseName("available"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("Platform", /*IsVarArg=*/true); Builder.addComma(); Builder.addTextChunk("*"); Builder.addRightParen(); } void CompletionLookup::addPoundSelector(bool needPound) { // #selector is only available when the Objective-C runtime is. if (!Ctx.LangOpts.EnableObjCInterop) return; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); if (needPound) Builder.addTextChunk("#selector"); else Builder.addTextChunk("selector"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("@objc method", /*IsVarArg=*/false); Builder.addRightParen(); Builder.addTypeAnnotation("Selector"); // This function is called only if the context type is 'Selector'. Builder.setResultTypes(Ctx.getSelectorType()); Builder.setTypeContext(expectedTypeContext, CurrDeclContext); } void CompletionLookup::addPoundKeyPath(bool needPound) { // #keyPath is only available when the Objective-C runtime is. if (!Ctx.LangOpts.EnableObjCInterop) return; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); if (needPound) Builder.addTextChunk("#keyPath"); else Builder.addTextChunk("keyPath"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("@objc property sequence", /*IsVarArg=*/false); Builder.addRightParen(); Builder.addTypeAnnotation("String"); Builder.setResultTypes(Ctx.getStringType()); Builder.setTypeContext(expectedTypeContext, CurrDeclContext); } SemanticContextKind CompletionLookup::getSemanticContextKind(const ValueDecl *VD) { // FIXME: to get the corect semantic context we need to know how lookup // would have found the VD. For now, just infer a reasonable semantics. if (!VD) return SemanticContextKind::CurrentModule; DeclContext *calleeDC = VD->getDeclContext(); if (calleeDC->isTypeContext()) // FIXME: We should distinguish CurrentNominal and Super. We need to // propagate the base type to do that. return SemanticContextKind::CurrentNominal; if (calleeDC->isLocalContext()) return SemanticContextKind::Local; if (calleeDC->getParentModule() == CurrModule) return SemanticContextKind::CurrentModule; return SemanticContextKind::OtherModule; } void CompletionLookup::addSubscriptCallPattern( const AnyFunctionType *AFT, const SubscriptDecl *SD, const std::optional SemanticContext) { foundFunction(AFT); GenericSignature genericSig; if (SD) genericSig = SD->getGenericSignatureOfContext(); CodeCompletionResultBuilder Builder = makeResultBuilder( SD ? CodeCompletionResultKind::Declaration : CodeCompletionResultKind::Pattern, SemanticContext ? *SemanticContext : getSemanticContextKind(SD)); if (SD) Builder.setAssociatedDecl(SD); if (!HaveLParen) { Builder.addLeftBracket(); } else { // Add 'ArgumentLabels' only if it has '['. Without existing '[', // consider it suggesting 'subscript' itself, not call arguments for it. Builder.addFlair(CodeCompletionFlairBit::ArgumentLabels); Builder.addAnnotatedLeftBracket(); } ArrayRef declParams; if (SD) declParams = SD->getIndices()->getArray(); addCallArgumentPatterns(Builder, AFT->getParams(), declParams, genericSig); if (!HaveLParen) Builder.addRightBracket(); else Builder.addAnnotatedRightBracket(); if (SD && SD->isImplicitlyUnwrappedOptional()) addTypeAnnotationForImplicitlyUnwrappedOptional(Builder, AFT->getResult(), genericSig); else addTypeAnnotation(Builder, AFT->getResult(), genericSig); } void CompletionLookup::addFunctionCallPattern( const AnyFunctionType *AFT, const AbstractFunctionDecl *AFD, const std::optional SemanticContext) { GenericSignature genericSig; if (AFD) genericSig = AFD->getGenericSignatureOfContext(); // Add the pattern, possibly including any default arguments. auto addPattern = [&](ArrayRef declParams = {}, bool includeDefaultArgs = true) { CodeCompletionResultBuilder Builder = makeResultBuilder( AFD ? CodeCompletionResultKind::Declaration : CodeCompletionResultKind::Pattern, SemanticContext ? *SemanticContext : getSemanticContextKind(AFD)); Builder.addFlair(CodeCompletionFlairBit::ArgumentLabels); if (DotLoc) { Builder.setNumBytesToErase(Ctx.SourceMgr.getByteDistance( DotLoc, Ctx.SourceMgr.getIDEInspectionTargetLoc())); } if (AFD) Builder.setAssociatedDecl(AFD); if (!HaveLParen) Builder.addLeftParen(); else Builder.addAnnotatedLeftParen(); addCallArgumentPatterns(Builder, AFT->getParams(), declParams, genericSig, includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) Builder.addRightParen(); else Builder.addAnnotatedRightParen(); addEffectsSpecifiers(Builder, AFT, AFD); if (AFD && AFD->isImplicitlyUnwrappedOptional()) addTypeAnnotationForImplicitlyUnwrappedOptional(Builder, AFT->getResult(), genericSig); else addTypeAnnotation(Builder, AFT->getResult(), genericSig); Builder.setCanCurrDeclContextHandleAsync(CanCurrDeclContextHandleAsync); }; if (!AFD || !AFD->getInterfaceType()->is()) { // Probably, calling closure type expression. foundFunction(AFT); addPattern(); return; } else { // Calling function or method. foundFunction(AFD); // FIXME: Hack because we don't know we are calling instance // method or not. There's invariant that funcTy is derived from AFD. // Only if we are calling instance method on meta type, AFT is still // curried. So we should be able to detect that by comparing curried level // of AFT and the interface type of AFD. auto getCurriedLevel = [](const AnyFunctionType *funcTy) -> unsigned { unsigned level = 0; while ((funcTy = funcTy->getResult()->getAs())) ++level; return level; }; bool isImplicitlyCurriedInstanceMethod = (AFD->hasImplicitSelfDecl() && getCurriedLevel(AFT) == getCurriedLevel( AFD->getInterfaceType()->castTo()) && // NOTE: shouldn't be necessary, but just in case curried level check // is insufficient. AFT->getParams().size() == 1 && AFT->getParams()[0].getLabel().empty()); if (isImplicitlyCurriedInstanceMethod) { addPattern({AFD->getImplicitSelfDecl()}, /*includeDefaultArgs=*/true); } else { if (shouldAddItemWithoutDefaultArgs(AFD)) addPattern(AFD->getParameters()->getArray(), /*includeDefaultArgs=*/false); addPattern(AFD->getParameters()->getArray(), /*includeDefaultArgs=*/true); } } } bool CompletionLookup::isImplicitlyCurriedInstanceMethod( const AbstractFunctionDecl *FD) { if (FD->isStatic()) return false; switch (Kind) { case LookupKind::ValueExpr: case LookupKind::StoredProperty: return ExprType->is(); case LookupKind::ValueInDeclContext: if (InsideStaticMethod) return FD->getDeclContext() == CurrentMethod->getDeclContext(); if (auto Init = dyn_cast(CurrDeclContext)) { if (auto PatInit = dyn_cast(Init)) { if (PatInit->getInitializedLazyVar()) return false; } return FD->getDeclContext() == Init->getInnermostTypeContext(); } return false; case LookupKind::EnumElement: case LookupKind::Type: case LookupKind::TypeInDeclContext: case LookupKind::GenericRequirement: llvm_unreachable("cannot have a method call while doing a " "type completion"); case LookupKind::ImportFromModule: return false; } llvm_unreachable("Unhandled LookupKind in switch."); } void CompletionLookup::addMethodCall(const FuncDecl *FD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (FD->getBaseIdentifier().empty()) return; foundFunction(FD); const Identifier Name = FD->getBaseIdentifier(); assert(!Name.empty() && "name should not be empty"); Type FunctionType = getTypeOfMember(FD, dynamicLookupInfo); assert(FunctionType); auto AFT = FunctionType->getAs(); bool IsImplicitlyCurriedInstanceMethod = false; if (FD->hasImplicitSelfDecl()) { IsImplicitlyCurriedInstanceMethod = isImplicitlyCurriedInstanceMethod(FD); // Strip off '(_ self: Self)' if needed. if (AFT && !IsImplicitlyCurriedInstanceMethod) { AFT = AFT->getResult()->getAs(); // Check for duplicates with the adjusted type too. if (isDuplicate(FD, AFT)) return; } } bool trivialTrailingClosure = false; if (AFT && !IsImplicitlyCurriedInstanceMethod) trivialTrailingClosure = hasTrivialTrailingClosure(FD, AFT); std::optional NotRecommended; bool implictlyAsync = false; analyzeActorIsolation(FD, AFT, implictlyAsync, NotRecommended); // Add the method, possibly including any default arguments. auto addMethodImpl = [&](bool includeDefaultArgs = true, bool trivialTrailingClosure = false) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(FD, Reason, dynamicLookupInfo)); Builder.setHasAsyncAlternative( FD->getAsyncAlternative() && !FD->getAsyncAlternative()->shouldHideFromEditor()); Builder.setCanCurrDeclContextHandleAsync(CanCurrDeclContextHandleAsync); Builder.setAssociatedDecl(FD); if (IsSuperRefExpr && CurrentMethod && CurrentMethod->getOverriddenDecl() == FD) Builder.addFlair(CodeCompletionFlairBit::SuperChain); if (NotRecommended) Builder.setContextualNotRecommended(*NotRecommended); addLeadingDot(Builder); addValueBaseName(Builder, Name); if (IsDynamicLookup) Builder.addDynamicLookupMethodCallTail(); else if (FD->getAttrs().hasAttribute()) Builder.addOptionalMethodCallTail(); if (!AFT) { addTypeAnnotation(Builder, FunctionType, FD->getGenericSignatureOfContext()); return; } if (IsImplicitlyCurriedInstanceMethod) { Builder.addLeftParen(); addCallArgumentPatterns( Builder, AFT->getParams(), {FD->getImplicitSelfDecl()}, FD->getGenericSignatureOfContext(), includeDefaultArgs); Builder.addRightParen(); } else if (trivialTrailingClosure) { Builder.addBraceStmtWithCursor(" { code }"); addEffectsSpecifiers(Builder, AFT, FD, implictlyAsync); } else { Builder.addLeftParen(); addCallArgumentPatterns(Builder, AFT, FD->getParameters(), FD->getGenericSignatureOfContext(), includeDefaultArgs); Builder.addRightParen(); addEffectsSpecifiers(Builder, AFT, FD, implictlyAsync); } // Build type annotation. Type ResultType = AFT->getResult(); // As we did with parameters in addParamPatternFromFunction, // for regular methods we'll print '!' after implicitly // unwrapped optional results. bool IsIUO = !IsImplicitlyCurriedInstanceMethod && FD->isImplicitlyUnwrappedOptional(); PrintOptions PO; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; PO.PrintOptionalAsImplicitlyUnwrapped = IsIUO; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) PO.setBaseType(typeContext->getDeclaredTypeInContext()); Type AnnotationTy = eraseArchetypes(ResultType, FD->getGenericSignatureOfContext()); if (Builder.shouldAnnotateResults()) { Builder.withNestedGroup( CodeCompletionString::Chunk::ChunkKind::TypeAnnotationBegin, [&] { CodeCompletionStringPrinter printer(Builder); auto TL = TypeLoc::withoutLoc(AnnotationTy); printer.printTypePre(TL); if (IsImplicitlyCurriedInstanceMethod) { auto *FnType = AnnotationTy->castTo(); AnyFunctionType::printParams(FnType->getParams(), printer, PrintOptions()); AnnotationTy = FnType->getResult(); printer.printText(" -> "); } // What's left is the result type. if (AnnotationTy->isVoid()) AnnotationTy = Ctx.getVoidDecl()->getDeclaredInterfaceType(); AnnotationTy.print(printer, PO); printer.printTypePost(TL); }); } else { llvm::SmallString<32> TypeStr; llvm::raw_svector_ostream OS(TypeStr); if (IsImplicitlyCurriedInstanceMethod) { auto *FnType = AnnotationTy->castTo(); AnyFunctionType::printParams(FnType->getParams(), OS); AnnotationTy = FnType->getResult(); OS << " -> "; } // What's left is the result type. if (AnnotationTy->isVoid()) AnnotationTy = Ctx.getVoidDecl()->getDeclaredInterfaceType(); AnnotationTy.print(OS, PO); Builder.addTypeAnnotation(TypeStr); } Builder.setResultTypes(ResultType); Builder.setTypeContext(expectedTypeContext, CurrDeclContext); if (isUnresolvedMemberIdealType(ResultType)) Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific); }; // Do not add imported C++ methods that are treated as unsafe in Swift. if (Importer->isUnsafeCXXMethod(FD)) return; if (!AFT || IsImplicitlyCurriedInstanceMethod) { addMethodImpl(); } else { if (trivialTrailingClosure) addMethodImpl(/*includeDefaultArgs=*/false, /*trivialTrailingClosure=*/true); if (shouldAddItemWithoutDefaultArgs(FD)) addMethodImpl(/*includeDefaultArgs=*/false); addMethodImpl(/*includeDefaultArgs=*/true); } } void CompletionLookup::addConstructorCall(const ConstructorDecl *CD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, std::optional BaseType, std::optional Result, bool IsOnType, Identifier addName) { foundFunction(CD); Type MemberType = getTypeOfMember(CD, BaseType.value_or(ExprType)); AnyFunctionType *ConstructorType = nullptr; if (auto MemberFuncType = MemberType->getAs()) ConstructorType = MemberFuncType->getResult()->castTo(); bool needInit = false; if (!IsOnType) { assert(addName.empty()); needInit = true; } else if (addName.empty() && HaveDot) { needInit = true; } // If we won't be able to provide a result, bail out. if (!ConstructorType && addName.empty() && !needInit) return; // Add the constructor, possibly including any default arguments. auto addConstructorImpl = [&](bool includeDefaultArgs = true) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(CD, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(CD); if (IsSuperRefExpr && CurrentMethod && CurrentMethod->getOverriddenDecl() == CD) Builder.addFlair(CodeCompletionFlairBit::SuperChain); if (needInit) { assert(addName.empty()); addLeadingDot(Builder); Builder.addBaseName("init"); } else if (!addName.empty()) { addIdentifier(Builder, addName); } else { Builder.addFlair(CodeCompletionFlairBit::ArgumentLabels); } if (!ConstructorType) { addTypeAnnotation(Builder, MemberType, CD->getGenericSignatureOfContext()); return; } if (!HaveLParen) Builder.addLeftParen(); else Builder.addAnnotatedLeftParen(); addCallArgumentPatterns(Builder, ConstructorType, CD->getParameters(), CD->getGenericSignatureOfContext(), includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) Builder.addRightParen(); else Builder.addAnnotatedRightParen(); addEffectsSpecifiers(Builder, ConstructorType, CD); if (!Result.has_value()) Result = ConstructorType->getResult(); if (CD->isImplicitlyUnwrappedOptional()) { addTypeAnnotationForImplicitlyUnwrappedOptional( Builder, *Result, CD->getGenericSignatureOfContext()); } else { addTypeAnnotation(Builder, *Result, CD->getGenericSignatureOfContext()); } Builder.setCanCurrDeclContextHandleAsync(CanCurrDeclContextHandleAsync); }; if (ConstructorType && shouldAddItemWithoutDefaultArgs(CD)) addConstructorImpl(/*includeDefaultArgs=*/false); addConstructorImpl(); } void CompletionLookup::addConstructorCallsForType( Type type, Identifier name, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (!Sink.addInitsToTopLevel) return; // Existential types cannot be instantiated. e.g. 'MyProtocol()'. if (type->isExistentialType()) return; // 'AnyObject' is not initializable. // FIXME: Should we do this in 'AnyObjectLookupRequest'? if (type->isAnyObject()) return; assert(CurrDeclContext); auto results = swift::lookupSemanticMember(const_cast(CurrDeclContext), type, DeclBaseName::createConstructor()); for (const auto &entry : results.allResults()) { auto *init = cast(entry.getValueDecl()); if (init->shouldHideFromEditor()) continue; addConstructorCall(cast(init), Reason, dynamicLookupInfo, type, std::nullopt, /*IsOnType=*/true, name); } } void CompletionLookup::addSubscriptCall(const SubscriptDecl *SD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { // Don't add subscript call to unqualified completion. if (!ExprType) return; // Subscript after '.' is valid only after type part of Swift keypath // expression. (e.g. '\TyName.SubTy.[0]) if (HaveDot && !IsAfterSwiftKeyPathRoot) return; auto subscriptType = getTypeOfMember(SD, dynamicLookupInfo)->getAs(); if (!subscriptType) return; std::optional NotRecommended; bool implictlyAsync = false; analyzeActorIsolation(SD, subscriptType, implictlyAsync, NotRecommended); CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(SD, Reason, dynamicLookupInfo)); Builder.setCanCurrDeclContextHandleAsync(CanCurrDeclContextHandleAsync); Builder.setAssociatedDecl(SD); if (NotRecommended) Builder.setContextualNotRecommended(*NotRecommended); // '\TyName#^TOKEN^#' requires leading dot. if (!HaveDot && IsAfterSwiftKeyPathRoot) Builder.addLeadingDot(); if (NeedOptionalUnwrap) { Builder.setNumBytesToErase(NumBytesToEraseForOptionalUnwrap); Builder.addQuestionMark(); } Builder.addLeftBracket(); addCallArgumentPatterns(Builder, subscriptType, SD->getIndices(), SD->getGenericSignatureOfContext(), true); Builder.addRightBracket(); // Add a type annotation. Type resultTy = subscriptType->getResult(); if (IsDynamicLookup) { // Values of properties that were found on a AnyObject have // std::optional type. resultTy = OptionalType::get(resultTy); } if (implictlyAsync) Builder.addAnnotatedAsync(); addTypeAnnotation(Builder, resultTy, SD->getGenericSignatureOfContext()); } static StringRef getTypeAnnotationString(const NominalTypeDecl *NTD, SmallVectorImpl &stash) { SmallVector attrRoleStrs; if (NTD->getAttrs().hasAttribute()) attrRoleStrs.push_back("Property Wrapper"); if (NTD->getAttrs().hasAttribute()) attrRoleStrs.push_back("Result Builder"); if (NTD->isGlobalActor()) attrRoleStrs.push_back("Global Actor"); if (attrRoleStrs.empty()) return StringRef(); if (attrRoleStrs.size() == 1) return attrRoleStrs[0]; assert(stash.empty()); llvm::raw_svector_ostream OS(stash); llvm::interleave(attrRoleStrs, OS, ", "); return {stash.data(), stash.size()}; } void CompletionLookup::addNominalTypeRef(const NominalTypeDecl *NTD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(NTD, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(NTD); addLeadingDot(Builder); addValueBaseName(Builder, NTD->getBaseName()); // Substitute the base type for a nested type if needed. auto nominalTy = getTypeOfMember(NTD, dynamicLookupInfo); // "Fake" annotation for custom attribute types. SmallVector stash; StringRef customAttributeAnnotation = getTypeAnnotationString(NTD, stash); if (!customAttributeAnnotation.empty()) { Builder.addTypeAnnotation(customAttributeAnnotation); } else { addTypeAnnotation(Builder, nominalTy); } // Override the type relation for NominalTypes. Use the better relation // for the metatypes and the instance type. For example, // // func receiveInstance(_: Int) {} // func receiveMetatype(_: Int.Type) {} // // We want to suggest 'Int' as 'Identical' for both arguments. Builder.setResultTypes({MetatypeType::get(nominalTy), nominalTy}); Builder.setTypeContext(expectedTypeContext, CurrDeclContext); } Type CompletionLookup::getTypeAliasType(const TypeAliasDecl *TAD, DynamicLookupInfo dynamicLookupInfo) { // Substitute the base type for a nested typealias if needed. auto ty = getTypeOfMember(TAD, dynamicLookupInfo); auto *typeAliasTy = dyn_cast(ty.getPointer()); if (!typeAliasTy) return ty; // If the underlying type has an error, prefer to print the full typealias, // otherwise get the underlying type. We only want the direct underlying type, // not the full desugared type, since that more faithfully reflects what's // written in source. Type underlyingTy = typeAliasTy->getSinglyDesugaredType(); if (underlyingTy->hasError()) return ty; // The underlying type might be unbound for e.g: // // struct S {} // typealias X = S // // Introduce type parameters such that we print the underlying type as // 'S'. We only expect unbound generics at the top-level of a type-alias, // they are rejected by type resolution in any other position. // // FIXME: This is a hack – using the declared interface type isn't correct // since the generic parameters ought to be introduced at a higher depth, // i.e we should be treating it as `typealias X = S`. Ideally this would // be fixed by desugaring the unbound typealias during type resolution. For // now this is fine though since we only use the resulting type for printing // the type annotation; the type relation logic currently skips type // parameters. if (auto *UGT = underlyingTy->getAs()) underlyingTy = UGT->getDecl()->getDeclaredInterfaceType(); ASSERT(!underlyingTy->hasUnboundGenericType()); return underlyingTy; } void CompletionLookup::addTypeAliasRef(const TypeAliasDecl *TAD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(TAD, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(TAD); addLeadingDot(Builder); addValueBaseName(Builder, TAD->getBaseName()); addTypeAnnotation(Builder, getTypeAliasType(TAD, dynamicLookupInfo)); } void CompletionLookup::addGenericTypeParamRef( const GenericTypeParamDecl *GP, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { assert(!GP->getName().empty()); CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(GP, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(GP); addLeadingDot(Builder); addValueBaseName(Builder, GP->getBaseName()); addTypeAnnotation(Builder, GP->getDeclaredInterfaceType()); } void CompletionLookup::addAssociatedTypeRef( const AssociatedTypeDecl *AT, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(AT, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(AT); addLeadingDot(Builder); addValueBaseName(Builder, AT->getBaseName()); if (Type T = getAssociatedTypeType(AT)) addTypeAnnotation(Builder, T); } void CompletionLookup::addPrecedenceGroupRef(PrecedenceGroupDecl *PGD) { auto semanticContext = getSemanticContext(PGD, DeclVisibilityKind::VisibleAtTopLevel, {}); CodeCompletionResultBuilder builder = makeResultBuilder(CodeCompletionResultKind::Declaration, semanticContext); addIdentifier(builder, PGD->getName()); builder.setAssociatedDecl(PGD); } void CompletionLookup::addBuiltinMemberRef(StringRef Name, Type TypeAnnotation) { CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Pattern, SemanticContextKind::CurrentNominal); addLeadingDot(Builder); Builder.addBaseName(Name); addTypeAnnotation(Builder, TypeAnnotation); } void CompletionLookup::addEnumElementRef(const EnumElementDecl *EED, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, bool HasTypeContext) { if (!EED->hasName() || !EED->isAccessibleFrom(CurrDeclContext) || EED->shouldHideFromEditor()) return; CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(EED, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(EED); addLeadingDot(Builder); addValueBaseName(Builder, EED->getBaseIdentifier()); // Enum element is of function type; (Self.type) -> Self or // (Self.Type) -> (Args...) -> Self. Type EnumType = getTypeOfMember(EED, dynamicLookupInfo); if (EnumType->is()) EnumType = EnumType->castTo()->getResult(); if (EnumType->is()) { Builder.addLeftParen(); addCallArgumentPatterns(Builder, EnumType->castTo(), EED->getParameterList(), EED->getGenericSignatureOfContext()); Builder.addRightParen(); // Extract result as the enum type. EnumType = EnumType->castTo()->getResult(); } addTypeAnnotation(Builder, EnumType, EED->getGenericSignatureOfContext()); if (isUnresolvedMemberIdealType(EnumType)) Builder.addFlair(CodeCompletionFlairBit::ExpressionSpecific); } static StringRef getTypeAnnotationString(const MacroDecl *MD, SmallVectorImpl &stash) { auto roles = MD->getMacroRoles(); SmallVector roleStrs; for (auto role : getAllMacroRoles()) { if (!roles.contains(role)) continue; switch (role) { case MacroRole::Accessor: roleStrs.push_back("Accessor Macro"); break; case MacroRole::CodeItem: roleStrs.push_back("Code Item Macro"); break; case MacroRole::Conformance: roleStrs.push_back("Conformance Macro"); break; case MacroRole::Declaration: roleStrs.push_back("Declaration Macro"); break; case MacroRole::Expression: roleStrs.push_back("Expression Macro"); break; case MacroRole::Extension: roleStrs.push_back("Extension Macro"); break; case MacroRole::Member: roleStrs.push_back("Member Macro"); break; case MacroRole::MemberAttribute: roleStrs.push_back("Member Attribute Macro"); break; case MacroRole::Peer: roleStrs.push_back("Peer Macro"); break; case MacroRole::Preamble: roleStrs.push_back("Preamble Macro"); break; case MacroRole::Body: roleStrs.push_back("Body Macro"); break; } } if (roleStrs.empty()) return "Macro"; if (roleStrs.size() == 1) return roleStrs[0]; assert(stash.empty()); llvm::raw_svector_ostream OS(stash); llvm::interleave(roleStrs, OS, ", "); return {stash.data(), stash.size()}; } void CompletionLookup::addMacroCallArguments(const MacroDecl *MD, DeclVisibilityKind Reason, bool forTrivialTrailingClosure) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(MD, Reason, DynamicLookupInfo())); Builder.setAssociatedDecl(MD); addValueBaseName(Builder, MD->getBaseIdentifier()); if (forTrivialTrailingClosure) { Builder.addBraceStmtWithCursor(" { code }"); } else if (MD->parameterList && MD->parameterList->size() > 0) { auto *macroTy = MD->getInterfaceType()->castTo(); Builder.addLeftParen(); addCallArgumentPatterns(Builder, macroTy, MD->parameterList, MD->getGenericSignature()); Builder.addRightParen(); } auto roles = MD->getMacroRoles(); if (roles.containsOnly(MacroRole::Expression)) { addTypeAnnotation(Builder, MD->getResultInterfaceType(), MD->getGenericSignature()); } else { llvm::SmallVector stash; Builder.addTypeAnnotation(getTypeAnnotationString(MD, stash)); } } void CompletionLookup::addMacroExpansion(const MacroDecl *MD, DeclVisibilityKind Reason) { if (!MD->hasName() || !MD->isAccessibleFrom(CurrDeclContext) || MD->shouldHideFromEditor()) return; OptionSet expectedKinds = expectedTypeContext.getExpectedCustomAttributeKinds(); if (expectedKinds) { CodeCompletionMacroRoles expectedRoles = getCompletionMacroRoles(expectedKinds); CodeCompletionMacroRoles roles = getCompletionMacroRoles(MD); if (!(roles & expectedRoles)) return; } if (hasTrivialTrailingClosure(MD, MD->getInterfaceType())) addMacroCallArguments(MD, Reason, /*forTrivialTrailingClosure*/ true); addMacroCallArguments(MD, Reason); } void CompletionLookup::addKeyword(StringRef Name, Type TypeAnnotation, SemanticContextKind SK, CodeCompletionKeywordKind KeyKind, unsigned NumBytesToErase) { CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Keyword, SK); addLeadingDot(Builder); Builder.addKeyword(Name); Builder.setKeywordKind(KeyKind); if (TypeAnnotation) addTypeAnnotation(Builder, TypeAnnotation); if (NumBytesToErase > 0) Builder.setNumBytesToErase(NumBytesToErase); } void CompletionLookup::addKeyword(StringRef Name, StringRef TypeAnnotation, CodeCompletionKeywordKind KeyKind, CodeCompletionFlair flair) { CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); Builder.addFlair(flair); addLeadingDot(Builder); Builder.addKeyword(Name); Builder.setKeywordKind(KeyKind); if (!TypeAnnotation.empty()) Builder.addTypeAnnotation(TypeAnnotation); } void CompletionLookup::addDeclAttrParamKeyword(StringRef Name, ArrayRef Parameters, StringRef Annotation, bool NeedSpecify) { CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); Builder.addDeclAttrParamKeyword(Name, Parameters, Annotation, NeedSpecify); } void CompletionLookup::addDeclAttrKeyword(StringRef Name, StringRef Annotation) { CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); Builder.addDeclAttrKeyword(Name, Annotation); } /// Add the compound function name for the given function. /// Returns \c true if the compound function name is actually used. bool CompletionLookup::addCompoundFunctionNameIfDesiable( AbstractFunctionDecl *AFD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { auto funcTy = getTypeOfMember(AFD, dynamicLookupInfo)->getAs(); bool dropCurryLevel = funcTy && AFD->getDeclContext()->isTypeContext() && !isImplicitlyCurriedInstanceMethod(AFD); if (dropCurryLevel) funcTy = funcTy->getResult()->getAs(); bool useFunctionReference = PreferFunctionReferencesToCalls; if (!useFunctionReference && funcTy) { // We know that the CodeCompletionResultType is AST-based so we can pass // nullptr for USRTypeContext. auto maxFuncTyRel = CodeCompletionResultType(funcTy).calculateTypeRelation( &expectedTypeContext, CurrDeclContext, /*USRTypeContext=*/nullptr); auto maxResultTyRel = CodeCompletionResultType(funcTy->getResult()).calculateTypeRelation( &expectedTypeContext, CurrDeclContext, /*USRTypeContext=*/nullptr); useFunctionReference = maxFuncTyRel > maxResultTyRel; } if (!useFunctionReference) return false; // Check for duplicates with the adjusted type too. if (dropCurryLevel && isDuplicate(AFD, funcTy)) return true; CodeCompletionResultBuilder Builder = makeResultBuilder(CodeCompletionResultKind::Declaration, getSemanticContext(AFD, Reason, dynamicLookupInfo)); Builder.setAssociatedDecl(AFD); // Base name addLeadingDot(Builder); addValueBaseName(Builder, AFD->getBaseName()); // Add the argument labels. const auto ArgLabels = AFD->getName().getArgumentNames(); if (!ArgLabels.empty()) { if (!HaveLParen) Builder.addLeftParen(); else Builder.addAnnotatedLeftParen(); for (auto ArgLabel : ArgLabels) { if (ArgLabel.empty()) Builder.addTextChunk("_"); else Builder.addTextChunk(ArgLabel.str()); Builder.addTextChunk(":"); } Builder.addRightParen(); } if (funcTy) addTypeAnnotation(Builder, funcTy, AFD->getGenericSignatureOfContext()); return true; } void CompletionLookup::onLookupNominalTypeMembers(NominalTypeDecl *NTD, DeclVisibilityKind Reason) { // Remember the decl name to SmallString<32> buffer; llvm::raw_svector_ostream OS(buffer); PrintOptions PS = PrintOptions::printDocInterface(); PS.FullyQualifiedTypes = true; NTD->getDeclaredType()->print(OS, PS); NullTerminatedStringRef qualifiedName( buffer, *CompletionContext->getResultSink().Allocator); CompletionContext->LookedupNominalTypeNames.push_back(qualifiedName); } Type CompletionLookup::normalizeTypeForDuplicationCheck(Type Ty) { return Ty.transformRec([](Type T) -> std::optional { if (auto opaque = T->getAs()) { /// Opaque type has a _invisible_ substitution map. Since IDE can't /// differentiate them, replace it with empty substitution map. return Type(OpaqueTypeArchetypeType::get(opaque->getDecl(), opaque->getInterfaceType(), /*Substitutions=*/{})); } return std::nullopt; }); } void CompletionLookup::foundDecl(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { assert(Reason != DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal && "Including derived requirement in non-override lookup"); if (D->shouldHideFromEditor()) return; if (IsKeyPathExpr && !KeyPathFilter(D, Reason, dynamicLookupInfo)) return; if (IsSwiftKeyPathExpr && !SwiftKeyPathFilter(D, Reason)) return; // If we've seen this decl+type before (possible when multiple lookups are // performed e.g. because of ambiguous base types), bail. if (isDuplicate(D, dynamicLookupInfo)) return; // FIXME(InterfaceTypeRequest): Remove this. (void)D->getInterfaceType(); switch (Kind) { case LookupKind::ValueExpr: if (auto *CD = dyn_cast(D)) { // Do we want compound function names here? if (addCompoundFunctionNameIfDesiable(CD, Reason, dynamicLookupInfo)) return; if (auto MT = ExprType->getAs()) { Type Ty = MT->getInstanceType(); assert(Ty && "Cannot find instance type."); // If instance type is type alias, show users that the constructed // type is the typealias instead of the underlying type of the alias. std::optional Result = std::nullopt; if (!CD->getInterfaceType()->is() && isa(Ty.getPointer()) && Ty->getDesugaredType() == CD->getResultInterfaceType().getPointer()) { Result = Ty; } // If the expression type is not a static metatype or an archetype, the // base is not a type. Direct call syntax is illegal on values, so we // only add initializer completions if we do not have a left parenthesis // and either the initializer is required, the base type's instance type // is not a class, or this is a 'self' or 'super' reference. if (IsStaticMetatype || IsUnresolvedMember || Ty->is()) addConstructorCall(CD, Reason, dynamicLookupInfo, std::nullopt, Result, /*isOnType*/ true); else if ((IsSelfRefExpr || IsSuperRefExpr || !Ty->is() || CD->isRequired()) && !HaveLParen) addConstructorCall(CD, Reason, dynamicLookupInfo, std::nullopt, Result, /*isOnType*/ false); return; } if (!HaveLParen) { auto CDC = dyn_cast(CurrDeclContext); if (!CDC) return; // For classes, we do not want 'init' completions for 'self' in // non-convenience initializers and for 'super' in convenience // initializers. if (ExprType->is()) { if ((IsSelfRefExpr && !CDC->isConvenienceInit()) || (IsSuperRefExpr && CDC->isConvenienceInit())) return; } if (IsSelfRefExpr || IsSuperRefExpr) addConstructorCall(CD, Reason, dynamicLookupInfo, std::nullopt, std::nullopt, /*IsOnType=*/false); } return; } if (HaveLParen) return; LLVM_FALLTHROUGH; case LookupKind::ValueInDeclContext: case LookupKind::ImportFromModule: if (auto *VD = dyn_cast(D)) { addVarDeclRef(VD, Reason, dynamicLookupInfo); return; } if (auto *FD = dyn_cast(D)) { // We cannot call operators with a postfix parenthesis syntax. if (FD->isBinaryOperator() || FD->isUnaryOperator()) return; // We cannot call accessors. We use VarDecls and SubscriptDecls to // produce completions that refer to getters and setters. if (isa(FD)) return; // Do we want compound function names here? if (addCompoundFunctionNameIfDesiable(FD, Reason, dynamicLookupInfo)) return; addMethodCall(FD, Reason, dynamicLookupInfo); // SE-0253: Callable values of user-defined nominal types. if (FD->isCallAsFunctionMethod() && !HaveDot && (!ExprType || !ExprType->is())) { Type funcType = getTypeOfMember(FD, dynamicLookupInfo) ->castTo() ->getResult(); // Check for duplicates with the adjusted type too. if (isDuplicate(FD, funcType)) return; addFunctionCallPattern( funcType->castTo(), FD, getSemanticContext(FD, Reason, dynamicLookupInfo)); } return; } if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason, dynamicLookupInfo); addConstructorCallsForType(NTD->getDeclaredInterfaceType(), NTD->getName(), Reason, dynamicLookupInfo); return; } if (auto *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason, dynamicLookupInfo); auto type = TAD->mapTypeIntoContext(TAD->getDeclaredInterfaceType()); if (type->mayHaveMembers()) addConstructorCallsForType(type, TAD->getName(), Reason, dynamicLookupInfo); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason, dynamicLookupInfo); auto type = CurrDeclContext->mapTypeIntoContext(GP->getDeclaredInterfaceType()); addConstructorCallsForType(type, GP->getName(), Reason, dynamicLookupInfo); return; } if (auto *AT = dyn_cast(D)) { addAssociatedTypeRef(AT, Reason, dynamicLookupInfo); return; } if (auto *EED = dyn_cast(D)) { addEnumElementRef(EED, Reason, dynamicLookupInfo, /*HasTypeContext=*/false); return; } // Swift key path allows .[0] if (auto *SD = dyn_cast(D)) { addSubscriptCall(SD, Reason, dynamicLookupInfo); return; } if (auto *MD = dyn_cast(D)) { addMacroExpansion(MD, Reason); return; } return; case LookupKind::EnumElement: handleEnumElement(D, Reason, dynamicLookupInfo); return; case LookupKind::Type: case LookupKind::TypeInDeclContext: if (auto *NTD = dyn_cast(D)) { addNominalTypeRef(NTD, Reason, dynamicLookupInfo); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason, dynamicLookupInfo); return; } LLVM_FALLTHROUGH; case LookupKind::GenericRequirement: if (TypeAliasDecl *TAD = dyn_cast(D)) { if (Kind == LookupKind::GenericRequirement && !canBeUsedAsRequirementFirstType(BaseType, TAD)) return; addTypeAliasRef(TAD, Reason, dynamicLookupInfo); return; } if (auto *AT = dyn_cast(D)) { addAssociatedTypeRef(AT, Reason, dynamicLookupInfo); return; } return; case LookupKind::StoredProperty: if (auto *VD = dyn_cast(D)) { if (VD->hasStorage()) { addVarDeclRef(VD, Reason, dynamicLookupInfo); } return; } } } bool CompletionLookup::handleEnumElement(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (auto *EED = dyn_cast(D)) { addEnumElementRef(EED, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); return true; } else if (auto *ED = dyn_cast(D)) { for (auto *Ele : ED->getAllElements()) { addEnumElementRef(Ele, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); } return true; } return false; } bool CompletionLookup::tryTupleExprCompletions(Type ExprType) { auto *TT = ExprType->getAs(); if (!TT) return false; unsigned Index = 0; for (auto TupleElt : TT->getElements()) { auto Ty = TupleElt.getType(); if (TupleElt.hasName()) { addBuiltinMemberRef(TupleElt.getName().str(), Ty); } else { llvm::SmallString<4> IndexStr; { llvm::raw_svector_ostream OS(IndexStr); OS << Index; } addBuiltinMemberRef(IndexStr, Ty); } ++Index; } return true; } void CompletionLookup::tryFunctionIsolationCompletion(Type ExprType) { auto *FT = ExprType->getAs(); if (!FT || !FT->getIsolation().isErased()) return; // The type of `.isolation` is `(any Actor)?` auto *actorProto = Ctx.getProtocol(KnownProtocolKind::Actor); auto memberTy = OptionalType::get(actorProto->getDeclaredExistentialType()); addBuiltinMemberRef(Ctx.Id_isolation.str(), memberTy); } bool CompletionLookup::tryFunctionCallCompletions( Type ExprType, const ValueDecl *VD, std::optional SemanticContext) { ExprType = ExprType->getRValueType(); if (auto AFT = ExprType->getAs()) { if (auto *AFD = dyn_cast_or_null(VD)) { addFunctionCallPattern(AFT, AFD, SemanticContext); } else { addFunctionCallPattern(AFT); } return true; } return false; } bool CompletionLookup::tryModuleCompletions(Type ExprType, CodeCompletionFilter Filter) { if (auto MT = ExprType->getAs()) { ModuleDecl *M = MT->getModule(); // Only lookup this module's symbols from the cache if it is not the // current module. if (M == CurrModule) return false; // If the module is shadowed by a separately imported overlay(s), look up // the symbols from the overlay(s) instead. SmallVector ShadowingOrOriginal; if (auto *SF = CurrDeclContext->getParentSourceFile()) { SF->getSeparatelyImportedOverlays(M, ShadowingOrOriginal); if (ShadowingOrOriginal.empty()) ShadowingOrOriginal.push_back(M); } for (ModuleDecl *M : ShadowingOrOriginal) { RequestedResultsTy Request = RequestedResultsTy::fromModule(M, Filter).needLeadingDot(needDot()); RequestedCachedResults.insert(Request); } return true; } return false; } bool CompletionLookup::tryUnwrappedCompletions(Type ExprType, bool isIUO) { // FIXME: consider types convertible to T?. ExprType = ExprType->getRValueType(); // FIXME: We don't always pass down whether a type is from an // unforced IUO. if (isIUO) { if (Type Unwrapped = ExprType->getOptionalObjectType()) { lookupVisibleMemberDecls(*this, Unwrapped, DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); return true; } assert(IsUnwrappedOptional && "IUOs should be optional if not bound/forced"); return false; } if (Type Unwrapped = ExprType->getOptionalObjectType()) { llvm::SaveAndRestore ChangeNeedOptionalUnwrap(NeedOptionalUnwrap, true); if (DotLoc.isValid()) { // Let's not erase the dot if the completion is after a swift key path // root because \A?.?.member is the correct way to access wrapped type // member from an optional key path root. auto loc = IsAfterSwiftKeyPathRoot ? DotLoc.getAdvancedLoc(1) : DotLoc; NumBytesToEraseForOptionalUnwrap = Ctx.SourceMgr.getByteDistance( loc, Ctx.SourceMgr.getIDEInspectionTargetLoc()); } else { NumBytesToEraseForOptionalUnwrap = 0; } if (NumBytesToEraseForOptionalUnwrap <= CodeCompletionResult::MaxNumBytesToErase) { // Add '.isolation' to @isolated(any) functions. tryFunctionIsolationCompletion(Unwrapped); if (!tryTupleExprCompletions(Unwrapped)) { lookupVisibleMemberDecls(*this, Unwrapped, DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); } } return true; } return false; } void CompletionLookup::getPostfixKeywordCompletions(Type ExprType, Expr *ParsedExpr) { if (IsSuperRefExpr) return; NeedLeadingDot = !HaveDot; if (!ExprType->getAs()) { addKeyword(getTokenText(tok::kw_self), ExprType->getRValueType(), SemanticContextKind::CurrentNominal, CodeCompletionKeywordKind::kw_self); } if (isa(ParsedExpr)) { if (auto *T = ExprType->getAs()) { auto instanceTy = T->getInstanceType(); if (instanceTy->isAnyExistentialType()) { addKeyword("Protocol", MetatypeType::get(instanceTy), SemanticContextKind::CurrentNominal); addKeyword("Type", ExistentialMetatypeType::get(instanceTy), SemanticContextKind::CurrentNominal); } else { addKeyword("Type", MetatypeType::get(instanceTy), SemanticContextKind::CurrentNominal); } } } } void CompletionLookup::getValueExprCompletions(Type ExprType, ValueDecl *VD, bool IsDeclUnapplied) { Kind = LookupKind::ValueExpr; NeedLeadingDot = !HaveDot; ExprType = ExprType->getRValueType(); assert(!ExprType->hasTypeParameter()); this->ExprType = ExprType; // Open existential types, so that lookupVisibleMemberDecls() can properly // substitute them. bool WasOptional = false; if (auto OptionalType = ExprType->getOptionalObjectType()) { ExprType = OptionalType; WasOptional = true; } if (!ExprType->getMetatypeInstanceType()->isAnyObject()) { if (ExprType->isAnyExistentialType()) { ExprType = ExistentialArchetypeType::getAny(ExprType->getCanonicalType()); } } if (!IsSelfRefExpr && !IsSuperRefExpr && ExprType->getAnyNominal() && ExprType->getAnyNominal()->isActor()) { IsCrossActorReference = true; } if (WasOptional) ExprType = OptionalType::get(ExprType); // Handle special cases // Add '.isolation' to @isolated(any) functions. tryFunctionIsolationCompletion(ExprType); bool isIUO = VD && VD->isImplicitlyUnwrappedOptional(); if (tryFunctionCallCompletions(ExprType, IsDeclUnapplied ? VD : nullptr)) return; if (tryModuleCompletions(ExprType, {CodeCompletionFilterFlag::Expr, CodeCompletionFilterFlag::Type})) return; if (tryTupleExprCompletions(ExprType)) return; // Don't check/return so we still add the members of Optional itself below tryUnwrappedCompletions(ExprType, isIUO); lookupVisibleMemberDecls(*this, ExprType, DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); } void CompletionLookup::getStoredPropertyCompletions(const NominalTypeDecl *D) { Kind = LookupKind::StoredProperty; NeedLeadingDot = false; lookupVisibleMemberDecls(*this, D->getDeclaredInterfaceType(), /*DotLoc=*/SourceLoc(), CurrDeclContext, /*IncludeInstanceMembers*/ true, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ false); } void CompletionLookup::collectOperators( SmallVectorImpl &results) { assert(CurrDeclContext); for (auto import : namelookup::getAllImports(CurrDeclContext)) import.importedModule->getOperatorDecls(results); } void CompletionLookup::addPostfixBang(Type resultType) { CodeCompletionResultBuilder builder = makeResultBuilder( CodeCompletionResultKind::BuiltinOperator, SemanticContextKind::None); // FIXME: we can't use the exclamation mark chunk kind, or it isn't // included in the completion name. builder.addTextChunk("!"); assert(resultType); addTypeAnnotation(builder, resultType); } void CompletionLookup::addPostfixOperatorCompletion(OperatorDecl *op, Type resultType) { // FIXME: we should get the semantic context of the function, not the // operator decl. auto semanticContext = getSemanticContext(op, DeclVisibilityKind::VisibleAtTopLevel, {}); CodeCompletionResultBuilder builder = makeResultBuilder(CodeCompletionResultKind::Declaration, semanticContext); // FIXME: handle variable amounts of space. if (HaveLeadingSpace) builder.setNumBytesToErase(1); builder.setAssociatedDecl(op); builder.addBaseName(op->getName().str()); assert(resultType); addTypeAnnotation(builder, resultType); } void CompletionLookup::addAssignmentOperator(Type RHSType) { CodeCompletionResultBuilder builder = makeResultBuilder( CodeCompletionResultKind::BuiltinOperator, SemanticContextKind::None); if (HaveLeadingSpace) builder.addAnnotatedWhitespace(" "); else builder.addWhitespace(" "); builder.addEqual(); builder.addWhitespace(" "); assert(RHSType); Type contextTy; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) contextTy = typeContext->getDeclaredTypeInContext(); builder.addCallArgument(Identifier(), RHSType, contextTy, /*IsForOperator=*/true); } void CompletionLookup::addInfixOperatorCompletion(OperatorDecl *op, Type resultType, Type RHSType) { // FIXME: we should get the semantic context of the function, not the // operator decl. auto semanticContext = getSemanticContext(op, DeclVisibilityKind::VisibleAtTopLevel, {}); CodeCompletionResultBuilder builder = makeResultBuilder(CodeCompletionResultKind::Declaration, semanticContext); builder.setAssociatedDecl(op); if (HaveLeadingSpace) builder.addAnnotatedWhitespace(" "); else builder.addWhitespace(" "); builder.addBaseName(op->getName().str()); builder.addWhitespace(" "); if (RHSType) { Type contextTy; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) contextTy = typeContext->getDeclaredTypeInContext(); builder.addCallArgument(Identifier(), RHSType, contextTy, /*IsForOperator=*/true); } if (resultType) addTypeAnnotation(builder, resultType); } void CompletionLookup::addTypeRelationFromProtocol( CodeCompletionResultBuilder &builder, CodeCompletionLiteralKind kind) { Type literalType; // The literal can produce any type that conforms to its ExpressibleBy // protocol. Figure out as which type we want to show it in code completion. auto *PD = Ctx.getProtocol(protocolForLiteralKind(kind)); for (auto T : expectedTypeContext.getPossibleTypes()) { if (!T) continue; // Convert through optional types unless we're looking for a protocol // that Optional itself conforms to. if (kind != CodeCompletionLiteralKind::NilLiteral) { if (auto optionalObjT = T->getOptionalObjectType()) { T = optionalObjT; } } // Check for conformance to the literal protocol. if (T->getAnyNominal()) { if (lookupConformance(T, PD)) { literalType = T; break; } } } // Fallback to showing the default type. if (!literalType) { literalType = defaultTypeLiteralKind(kind, Ctx); } if (literalType) { addTypeAnnotation(builder, literalType); builder.setResultTypes(literalType); builder.setTypeContext(expectedTypeContext, CurrDeclContext); } } void CompletionLookup::addValueLiteralCompletions() { auto &context = CurrDeclContext->getASTContext(); CodeCompletionFlair flair; if (isCodeCompletionAtTopLevelOfLibraryFile(CurrDeclContext)) flair |= CodeCompletionFlairBit::ExpressionAtNonScriptOrMainFileScope; auto addFromProto = [&](CodeCompletionLiteralKind kind, llvm::function_ref consumer, bool isKeyword = false) { CodeCompletionResultBuilder builder = makeResultBuilder( CodeCompletionResultKind::Literal, SemanticContextKind::None); builder.setLiteralKind(kind); builder.addFlair(flair); consumer(builder); addTypeRelationFromProtocol(builder, kind); }; // FIXME: the pedantically correct way is to resolve Swift.*LiteralType. using LK = CodeCompletionLiteralKind; using Builder = CodeCompletionResultBuilder; // Add literal completions that conform to specific protocols. addFromProto(LK::IntegerLiteral, [](Builder &builder) { builder.addTextChunk("0"); }); addFromProto( LK::BooleanLiteral, [](Builder &builder) { builder.addBaseName("true"); }, /*isKeyword=*/true); addFromProto( LK::BooleanLiteral, [](Builder &builder) { builder.addBaseName("false"); }, /*isKeyword=*/true); addFromProto( LK::NilLiteral, [](Builder &builder) { builder.addBaseName("nil"); }, /*isKeyword=*/true); addFromProto(LK::StringLiteral, [&](Builder &builder) { builder.addTextChunk("\""); builder.addSimpleNamedParameter("abc"); builder.addTextChunk("\""); }); addFromProto(LK::ArrayLiteral, [&](Builder &builder) { builder.addLeftBracket(); builder.addSimpleNamedParameter("values"); builder.addRightBracket(); }); addFromProto(LK::DictionaryLiteral, [&](Builder &builder) { builder.addLeftBracket(); builder.addSimpleNamedParameter("key"); builder.addTextChunk(": "); builder.addSimpleNamedParameter("value"); builder.addRightBracket(); }); // Optionally add object literals. if (Sink.includeObjectLiterals) { auto floatType = context.getFloatType(); addFromProto(LK::ColorLiteral, [&](Builder &builder) { builder.addBaseName("#colorLiteral"); builder.addLeftParen(); builder.addCallArgument(context.getIdentifier("red"), floatType); builder.addComma(); builder.addCallArgument(context.getIdentifier("green"), floatType); builder.addComma(); builder.addCallArgument(context.getIdentifier("blue"), floatType); builder.addComma(); builder.addCallArgument(context.getIdentifier("alpha"), floatType); builder.addRightParen(); }); auto stringType = context.getStringType(); addFromProto(LK::ImageLiteral, [&](Builder &builder) { builder.addBaseName("#imageLiteral"); builder.addLeftParen(); builder.addCallArgument(context.getIdentifier("resourceName"), stringType); builder.addRightParen(); }); } // Add tuple completion (item, item). { CodeCompletionResultBuilder builder = makeResultBuilder( CodeCompletionResultKind::Literal, SemanticContextKind::None); builder.setLiteralKind(LK::Tuple); builder.addFlair(flair); builder.addLeftParen(); builder.addSimpleNamedParameter("values"); builder.addRightParen(); for (auto T : expectedTypeContext.getPossibleTypes()) { if (T && T->is() && !T->isVoid()) { addTypeAnnotation(builder, T); builder.setResultTypes(T); builder.setTypeContext(expectedTypeContext, CurrDeclContext); break; } } } } void CompletionLookup::addObjCPoundKeywordCompletions(bool needPound) { if (!Ctx.LangOpts.EnableObjCInterop) return; // If the expected type is ObjectiveC.Selector, add #selector. If // it's String, add #keyPath. bool addedSelector = false; bool addedKeyPath = false; for (auto T : expectedTypeContext.getPossibleTypes()) { T = T->lookThroughAllOptionalTypes(); if (auto structDecl = T->getStructOrBoundGenericStruct()) { if (!addedSelector && structDecl->getName() == Ctx.Id_Selector && structDecl->getParentModule()->getName() == Ctx.Id_ObjectiveC) { addPoundSelector(needPound); if (addedKeyPath) break; addedSelector = true; continue; } } if (!addedKeyPath && T->isString()) { addPoundKeyPath(needPound); if (addedSelector) break; addedKeyPath = true; continue; } } } void CompletionLookup::getMacroCompletions(CodeCompletionMacroRoles roles) { RequestedCachedResults.insert( RequestedResultsTy::topLevelResults(getCompletionFilter(roles))); } void CompletionLookup::getValueCompletionsInDeclContext(SourceLoc Loc, DeclFilter Filter, bool LiteralCompletions, bool ModuleQualifier) { ExprType = Type(); Kind = LookupKind::ValueInDeclContext; NeedLeadingDot = false; AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext, *this); FilteredDeclConsumer FilteringConsumer(AccessFilteringConsumer, Filter); lookupVisibleDecls(FilteringConsumer, Loc, CurrDeclContext, /*IncludeTopLevel=*/false); CodeCompletionFilter filter{CodeCompletionFilterFlag::Expr, CodeCompletionFilterFlag::Type}; if (ModuleQualifier) { filter |= CodeCompletionFilterFlag::Module; } RequestedCachedResults.insert(RequestedResultsTy::topLevelResults(filter)); if (CompletionContext) { // FIXME: this is an awful simplification that says all and only enums can // use implicit member syntax (leading dot). Computing the accurate answer // using lookup (e.g. getUnresolvedMemberCompletions) is too expensive, // and for some clients this approximation is good enough. CompletionContext->MayUseImplicitMemberExpr = llvm::any_of(expectedTypeContext.getPossibleTypes(), [](Type T) { if (auto *NTD = T->getAnyNominal()) return isa(NTD); return false; }); } if (LiteralCompletions) { addValueLiteralCompletions(); } addObjCPoundKeywordCompletions(/*needPound=*/true); } bool CompletionLookup::isInitializerOnOptional(Type T, ValueDecl *VD) { bool IsOptionalType = false; IsOptionalType |= static_cast(T->getOptionalObjectType()); if (auto *NTD = T->getAnyNominal()) { IsOptionalType |= NTD->getBaseIdentifier() == VD->getASTContext().Id_OptionalNilComparisonType; } if (IsOptionalType && VD->getModuleContext()->isStdlibModule() && isa(VD)) { return true; } else { return false; } } void CompletionLookup::getUnresolvedMemberCompletions(Type T) { if (!T->mayHaveMembers()) return; NeedLeadingDot = !HaveDot; if (auto objT = T->getOptionalObjectType()) { // Add 'nil' keyword with erasing '.' instruction. unsigned bytesToErase = 0; auto &SM = CurrDeclContext->getASTContext().SourceMgr; if (DotLoc.isValid()) bytesToErase = SM.getByteDistance(DotLoc, SM.getIDEInspectionTargetLoc()); addKeyword("nil", T, SemanticContextKind::None, CodeCompletionKeywordKind::kw_nil, bytesToErase); } // We can only say .foo where foo is a static member of the contextual // type and has the same type (or if the member is a function, then the // same result type) as the contextual type. FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { // In optional context, ignore // '.init()', 'init(nilLiteral:)', return !isInitializerOnOptional(T, VD); }); auto baseType = MetatypeType::get(T); llvm::SaveAndRestore SaveLook(Kind, LookupKind::ValueExpr); llvm::SaveAndRestore SaveType(ExprType, baseType); llvm::SaveAndRestore SaveUnresolved(IsUnresolvedMember, true); lookupVisibleMemberDecls(consumer, baseType, DotLoc, CurrDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); } void CompletionLookup::getEnumElementPatternCompletions(Type T) { if (!isa_and_nonnull(T->getAnyNominal())) return; auto baseType = MetatypeType::get(T); llvm::SaveAndRestore SaveLook(Kind, LookupKind::EnumElement); llvm::SaveAndRestore SaveType(ExprType, baseType); llvm::SaveAndRestore SaveUnresolved(IsUnresolvedMember, true); lookupVisibleMemberDecls(*this, baseType, DotLoc, CurrDeclContext, /*includeInstanceMembers=*/false, /*includeDerivedRequirements=*/false, /*includeProtocolExtensionMembers=*/true); } void CompletionLookup::getUnresolvedMemberCompletions(ArrayRef Types) { NeedLeadingDot = !HaveDot; SmallPtrSet seenTypes; for (auto T : Types) { if (!T || !seenTypes.insert(T->getCanonicalType()).second) continue; if (auto objT = T->getOptionalObjectType()) { // If this is optional type, perform completion for the object type. // i.e. 'let _: Enum??? = .enumMember' is legal. objT = objT->lookThroughAllOptionalTypes(); if (seenTypes.insert(objT->getCanonicalType()).second) getUnresolvedMemberCompletions(objT); } getUnresolvedMemberCompletions(T); } } void CompletionLookup::addCallArgumentCompletionResults( ArrayRef ParamInfos, bool isLabeledTrailingClosure) { Type ContextType; if (auto typeContext = CurrDeclContext->getInnermostTypeContext()) ContextType = typeContext->getDeclaredTypeInContext(); for (auto Info : ParamInfos) { const auto *Arg = Info.Param; if (!Arg) continue; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Pattern, // FIXME: SemanticContextKind::Local is not correct. // Use 'None' (and fix prioritization) or introduce a new context. SemanticContextKind::Local); Builder.addCallArgument(Arg->getLabel(), Identifier(), Arg->getPlainType(), ContextType, Arg->isVariadic(), Arg->isInOut(), /*IsIUO=*/false, Arg->isAutoClosure(), isLabeledTrailingClosure, /*IsForOperator=*/false, /*HasDefault=*/false); Builder.addFlair(CodeCompletionFlairBit::ArgumentLabels); auto Ty = Arg->getPlainType(); if (Arg->isInOut()) { Ty = InOutType::get(Ty); } else if (Arg->isAutoClosure()) { // 'Ty' may be ErrorType. if (auto funcTy = Ty->getAs()) Ty = funcTy->getResult(); } // The type annotation is the argument type. But the argument label itself // does not produce an expression with a result type so we set the result // type as being not applicable. addTypeAnnotation(Builder, Ty); Builder.setResultTypeNotApplicable(); } } void CompletionLookup::getTypeCompletions(Type BaseType) { if (tryModuleCompletions(BaseType, CodeCompletionFilterFlag::Type)) return; Kind = LookupKind::Type; this->BaseType = BaseType; NeedLeadingDot = !HaveDot; lookupVisibleMemberDecls(*this, MetatypeType::get(BaseType), DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ false); if (BaseType->isAnyExistentialType()) { addKeyword("Protocol", MetatypeType::get(BaseType)); addKeyword("Type", ExistentialMetatypeType::get(BaseType)); } else if (!BaseType->is()) { addKeyword("Type", MetatypeType::get(BaseType)); } } void CompletionLookup::getInvertedTypeCompletions() { Kind = LookupKind::Type; auto addCompletion = [&](InvertibleProtocolKind invertableKind) { auto *P = Ctx.getProtocol(getKnownProtocolKind(invertableKind)); if (!P) return; addNominalTypeRef(P, DeclVisibilityKind::VisibleAtTopLevel, DynamicLookupInfo()); }; #define INVERTIBLE_PROTOCOL(Name, Bit) \ addCompletion(InvertibleProtocolKind::Name); #include "swift/ABI/InvertibleProtocols.def" } void CompletionLookup::getGenericRequirementCompletions( DeclContext *DC, SourceLoc CodeCompletionLoc) { auto genericSig = DC->getGenericSignatureOfContext(); if (!genericSig) return; for (auto GPT : genericSig.getGenericParams()) { addGenericTypeParamRef(GPT->getDecl(), DeclVisibilityKind::GenericParameter, {}); } // For non-protocol nominal type decls, only suggest generic parameters. if (auto D = DC->getAsDecl()) if (isa(D) && !isa(D)) return; auto typeContext = DC->getInnermostTypeContext(); if (!typeContext) return; auto selfTy = typeContext->getSelfTypeInContext(); Kind = LookupKind::GenericRequirement; this->BaseType = selfTy; NeedLeadingDot = false; lookupVisibleMemberDecls(*this, MetatypeType::get(selfTy), DotLoc, CurrDeclContext, IncludeInstanceMembers, /*includeDerivedRequirements*/ false, /*includeProtocolExtensionMembers*/ true); // We not only allow referencing nested types/typealiases directly, but also // qualified by the current type, as long as it's a top-level type (nested // types need to be qualified). Thus also suggest current self type so the // user can do a memberwise lookup on it. if (auto *NTD = typeContext->getSelfNominalTypeDecl()) { if (!NTD->getDeclContext()->isTypeContext()) { addNominalTypeRef(NTD, DeclVisibilityKind::LocalDecl, DynamicLookupInfo()); } } // Self is also valid in all cases in which it can be used in function // bodies. Suggest it if applicable. getSelfTypeCompletionInDeclContext(CodeCompletionLoc, /*isForResultType=*/false); } bool CompletionLookup::canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil, const LangOptions &langOpts, std::optional DK, StringRef Name) { if (DeclAttribute::isUserInaccessible(DAK)) return false; if (DeclAttribute::isDeclModifier(DAK)) return false; if (DeclAttribute::shouldBeRejectedByParser(DAK)) return false; if (!IsInSil && DeclAttribute::isSilOnly(DAK)) return false; if (!langOpts.EnableExperimentalConcurrency && DeclAttribute::isConcurrencyOnly(DAK)) return false; if (auto feature = DeclAttribute::getRequiredFeature(DAK)) if (!langOpts.hasFeature(*feature)) return false; if (!DK.has_value()) return true; // Hide underscored attributes even if they are not marked as user // inaccessible. This can happen for attributes that are an underscored // variant of a user-accessible attribute (like @_backDeployed) if (Name.empty() || Name[0] == '_') return false; return DeclAttribute::canAttributeAppearOnDeclKind(DAK, DK.value()); } void CompletionLookup::getAttributeDeclCompletions(bool IsInSil, std::optional DK) { // FIXME: also include user-defined attribute keywords StringRef TargetName = "Declaration"; if (DK.has_value()) { switch (DK.value()) { #define DECL(Id, ...) \ case DeclKind::Id: \ TargetName = #Id; \ break; #include "swift/AST/DeclNodes.def" } } std::string Description = TargetName.str() + " Attribute"; #define DECL_ATTR_ALIAS(KEYWORD, NAME) DECL_ATTR(KEYWORD, NAME, 0, 0) #define DECL_ATTR(KEYWORD, NAME, ...) \ if (canUseAttributeOnDecl(DeclAttrKind::NAME, IsInSil, Ctx.LangOpts, \ DK, #KEYWORD)) \ addDeclAttrKeyword(#KEYWORD, Description); #include "swift/AST/DeclAttr.def" } void CompletionLookup::getAttributeDeclParamCompletions( ParameterizedDeclAttributeKind AttrKind, int ParamIndex, bool HasLabel) { switch (AttrKind) { case ParameterizedDeclAttributeKind::Unowned: addDeclAttrParamKeyword("safe", /*Parameters=*/{}, "", false); addDeclAttrParamKeyword("unsafe", /*Parameters=*/{}, "", false); break; case ParameterizedDeclAttributeKind::Nonisolated: addDeclAttrParamKeyword("unsafe", /*Parameters=*/{}, "", false); addDeclAttrParamKeyword("nonsending", /*Parameters=*/{}, "", false); break; case ParameterizedDeclAttributeKind::InheritActorContext: addDeclAttrParamKeyword("always", /*Parameters=*/{}, "", false); break; case ParameterizedDeclAttributeKind::AccessControl: addDeclAttrParamKeyword("set", /*Parameters=*/{}, "", false); break; case ParameterizedDeclAttributeKind::Available: if (ParamIndex == 0) { addDeclAttrParamKeyword("*", /*Parameters=*/{}, "Platform", false); #define AVAILABILITY_PLATFORM(X, PrettyName) \ addDeclAttrParamKeyword(swift::platformString(PlatformKind::X), \ /*Parameters=*/{}, "Platform", false); #include "swift/AST/PlatformKinds.def" } else { addDeclAttrParamKeyword("unavailable", /*Parameters=*/{}, "", false); addDeclAttrParamKeyword("message", /*Parameters=*/{}, "Specify message", true); addDeclAttrParamKeyword("renamed", /*Parameters=*/{}, "Specify replacing name", true); addDeclAttrParamKeyword("introduced", /*Parameters=*/{}, "Specify version number", true); addDeclAttrParamKeyword("deprecated", /*Parameters=*/{}, "Specify version number", true); } break; case ParameterizedDeclAttributeKind::FreestandingMacro: case ParameterizedDeclAttributeKind::AttachedMacro: switch (ParamIndex) { case 0: for (auto role : getAllMacroRoles()) { bool isRoleSupported = isMacroSupported(role, Ctx); if (AttrKind == ParameterizedDeclAttributeKind::FreestandingMacro) { isRoleSupported &= isFreestandingMacro(role); } else if (AttrKind == ParameterizedDeclAttributeKind::AttachedMacro) { isRoleSupported &= isAttachedMacro(role); } if (isRoleSupported) { addDeclAttrParamKeyword(getMacroRoleString(role), /*Parameters=*/{}, /*Annotation=*/"", /*NeedsSpecify=*/false); } } break; case 1: if (HasLabel) { for (auto kind : getAllMacroIntroducedDeclNameKinds()) { auto name = getMacroIntroducedDeclNameString(kind); SmallVector Parameters; if (macroIntroducedNameRequiresArgument(kind)) { Parameters = {"name"}; } addDeclAttrParamKeyword(name, Parameters, /*Annotation=*/"", /*NeedsSpecify=*/false); } } else { addDeclAttrParamKeyword("names", /*Parameters=*/{}, "Specify declared names", /*NeedsSpecify=*/true); } break; } break; case ParameterizedDeclAttributeKind::StorageRestrictions: { bool suggestInitializesLabel = false; bool suggestAccessesLabel = false; bool suggestArgument = false; switch (static_cast(ParamIndex)) { case StorageRestrictionsCompletionKind::Label: suggestAccessesLabel = true; suggestInitializesLabel = true; break; case StorageRestrictionsCompletionKind::Argument: suggestArgument = true; break; case StorageRestrictionsCompletionKind::ArgumentOrInitializesLabel: suggestArgument = true; suggestInitializesLabel = true; break; case StorageRestrictionsCompletionKind::ArgumentOrAccessesLabel: suggestArgument = true; suggestAccessesLabel = true; break; } if (suggestInitializesLabel) { addDeclAttrParamKeyword( "initializes", /*Parameters=*/{}, "Specify stored properties initialized by the accessor", true); } if (suggestAccessesLabel) { addDeclAttrParamKeyword( "accesses", /*Parameters=*/{}, "Specify stored properties accessed by the accessor", true); } if (suggestArgument) { if (auto NT = dyn_cast(CurrDeclContext)) { getStoredPropertyCompletions(NT); } } } } } void CompletionLookup::getTypeAttributeKeywordCompletions( CompletionKind completionKind) { auto addTypeAttr = [&](TypeAttrKind Kind, StringRef Name) { if (completionKind != CompletionKind::TypeAttrInheritanceBeginning) { switch (Kind) { case TypeAttrKind::Retroactive: case TypeAttrKind::Preconcurrency: case TypeAttrKind::Nonisolated: case TypeAttrKind::Unchecked: case TypeAttrKind::Unsafe: // These attributes are only available in inheritance clasuses. return; default: break; } } CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::None); Builder.addAttributeKeyword(Name, "Type Attribute"); }; // Add simple user-accessible attributes. #define SIL_TYPE_ATTR(SPELLING, C) #define SIMPLE_SIL_TYPE_ATTR(SPELLING, C) #define SIMPLE_TYPE_ATTR(SPELLING, C) \ if (!TypeAttribute::isUserInaccessible(TypeAttrKind::C)) \ addTypeAttr(TypeAttrKind::C, #SPELLING); #include "swift/AST/TypeAttr.def" // Add non-simple cases. addTypeAttr(TypeAttrKind::Convention, "convention(swift)"); addTypeAttr(TypeAttrKind::Convention, "convention(block)"); addTypeAttr(TypeAttrKind::Convention, "convention(c)"); addTypeAttr(TypeAttrKind::Convention, "convention(thin)"); addTypeAttr(TypeAttrKind::Isolated, "isolated(any)"); } void CompletionLookup::collectPrecedenceGroups() { assert(CurrDeclContext); if (CurrModule) { for (auto FU : CurrModule->getFiles()) { // We are looking through the current module, // inspect only source files. if (FU->getKind() != FileUnitKind::Source) continue; llvm::SmallVector results; cast(FU)->getPrecedenceGroups(results); for (auto PG : results) addPrecedenceGroupRef(PG); } } for (auto Import : namelookup::getAllImports(CurrDeclContext)) { auto Module = Import.importedModule; if (Module == CurrModule) continue; RequestedCachedResults.insert(RequestedResultsTy::fromModule( Module, CodeCompletionFilterFlag::PrecedenceGroup)); } } void CompletionLookup::getPrecedenceGroupCompletions( CodeCompletionCallbacks::PrecedenceGroupCompletionKind SK) { switch (SK) { case CodeCompletionCallbacks::PrecedenceGroupCompletionKind::Associativity: addKeyword(getAssociativitySpelling(Associativity::None)); addKeyword(getAssociativitySpelling(Associativity::Left)); addKeyword(getAssociativitySpelling(Associativity::Right)); return; case CodeCompletionCallbacks::PrecedenceGroupCompletionKind::Assignment: addKeyword(getTokenText(tok::kw_false), Type(), SemanticContextKind::None, CodeCompletionKeywordKind::kw_false); addKeyword(getTokenText(tok::kw_true), Type(), SemanticContextKind::None, CodeCompletionKeywordKind::kw_true); return; case CodeCompletionCallbacks::PrecedenceGroupCompletionKind::AttributeList: addKeyword("associativity"); addKeyword("higherThan"); addKeyword("lowerThan"); addKeyword("assignment"); return; case CodeCompletionCallbacks::PrecedenceGroupCompletionKind::Relation: collectPrecedenceGroups(); return; } llvm_unreachable("not a precedencegroup SyntaxKind"); } void CompletionLookup::getPoundAvailablePlatformCompletions() { // The platform names should be identical to those in @available. getAttributeDeclParamCompletions(ParameterizedDeclAttributeKind::Available, 0, /*HasLabel=*/false); } void CompletionLookup::getSelfTypeCompletionInDeclContext( SourceLoc Loc, bool isForDeclResult) { const DeclContext *typeDC = CurrDeclContext->getInnermostTypeContext(); if (!typeDC) return; // For protocols, there's a 'Self' generic parameter. if (typeDC->getSelfProtocolDecl()) return; Type selfType = CurrDeclContext->mapTypeIntoContext(typeDC->getSelfInterfaceType()); if (typeDC->getSelfClassDecl()) { // In classes, 'Self' can be used in result type of func, subscript and // computed property, or inside function bodies. bool canUseDynamicSelf = false; if (isForDeclResult) { canUseDynamicSelf = true; } else { const auto *checkDC = CurrDeclContext; if (isa(checkDC)) checkDC = checkDC->getParent(); if (const auto *AFD = checkDC->getInnermostMethodContext()) { canUseDynamicSelf = Ctx.SourceMgr.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } } if (!canUseDynamicSelf) return; // 'Self' in class is a dynamic type. selfType = DynamicSelfType::get(selfType, Ctx); } else { // In enums and structs, 'Self' is just an alias for the nominal type, // and can be used anywhere. } CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Keyword, SemanticContextKind::CurrentNominal); Builder.addKeyword("Self"); Builder.setKeywordKind(CodeCompletionKeywordKind::kw_Self); addTypeAnnotation(Builder, selfType); } void CompletionLookup::getTypeCompletionsInDeclContext(SourceLoc Loc, bool ModuleQualifier) { Kind = LookupKind::TypeInDeclContext; AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext, *this); lookupVisibleDecls(AccessFilteringConsumer, Loc, CurrDeclContext, /*IncludeTopLevel=*/false); CodeCompletionFilter filter{CodeCompletionFilterFlag::Type}; if (ModuleQualifier) { filter |= CodeCompletionFilterFlag::Module; } RequestedCachedResults.insert(RequestedResultsTy::topLevelResults(filter)); } namespace { /// A \c VisibleDeclConsumer that stores all decls that are found and is able /// to forward the to another \c VisibleDeclConsumer later. class StoringDeclConsumer : public VisibleDeclConsumer { struct FoundDecl { ValueDecl *VD; DeclVisibilityKind Reason; DynamicLookupInfo DynamicLookupInfo; }; std::vector FoundDecls; void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo DynamicLookupInfo = {}) override { FoundDecls.push_back({VD, Reason, DynamicLookupInfo}); } public: /// Call \c foundDecl for every declaration that this consumer has found. void forward(VisibleDeclConsumer &Consumer) { for (auto &FoundDecl : FoundDecls) { Consumer.foundDecl(FoundDecl.VD, FoundDecl.Reason, FoundDecl.DynamicLookupInfo); } } }; } // namespace void CompletionLookup::getToplevelCompletions(CodeCompletionFilter Filter) { Kind = (Filter - CodeCompletionFilterFlag::Module) .containsOnly(CodeCompletionFilterFlag::Type) ? LookupKind::TypeInDeclContext : LookupKind::ValueInDeclContext; NeedLeadingDot = false; // If we have 'addinitstotoplevel' enabled, calling `foundDecl` on `this` // can cause macros to get expanded, which can then cause new members ot get // added to 'TopLevelValues', invalidating iterator over `TopLevelDecls` in // `SourceLookupCache::lookupVisibleDecls`. // // Technically `foundDecl` should not expand macros or discover new top level // members in any way because those newly discovered decls will not be added // to the code completion results. However, it's preferrable to miss results // than to silently invalidate a collection, resulting in hard-to-diagnose // crashes. // Thus, store all the decls found by `CurrModule->lookupVisibleDecls` in a // vector first and only call `this->foundDecl` once we have left the // iteration loop over `TopLevelDecls`. StoringDeclConsumer StoringConsumer; UsableFilteringDeclConsumer UsableFilteringConsumer( Ctx.SourceMgr, CurrDeclContext, Ctx.SourceMgr.getIDEInspectionTargetLoc(), StoringConsumer); AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext, UsableFilteringConsumer); CodeCompletionMacroRoles ExpectedRoles = getCompletionMacroRoles(Filter); DeclFilter VisibleFilter = [ExpectedRoles](ValueDecl *VD, DeclVisibilityKind Kind, DynamicLookupInfo DynamicLookupInfo) { CodeCompletionMacroRoles Roles = getCompletionMacroRoles(VD); if (!ExpectedRoles) return !Roles; return (bool)(Roles & ExpectedRoles); }; FilteredDeclConsumer FilteringConsumer(AccessFilteringConsumer, VisibleFilter); CurrModule->lookupVisibleDecls({}, FilteringConsumer, NLKind::UnqualifiedLookup); StoringConsumer.forward(*this); } void CompletionLookup::lookupExternalModuleDecls( const ModuleDecl *TheModule, ArrayRef AccessPath, bool ResultsHaveLeadingDot) { assert(CurrModule != TheModule && "requested module should be external"); Kind = LookupKind::ImportFromModule; NeedLeadingDot = ResultsHaveLeadingDot; ImportPath::Access::Builder builder; for (auto Piece : AccessPath) { builder.push_back(Ctx.getIdentifier(Piece)); } AccessFilteringDeclConsumer FilteringConsumer(CurrDeclContext, *this); TheModule->lookupVisibleDecls(builder.get(), FilteringConsumer, NLKind::UnqualifiedLookup); llvm::SmallVector precedenceGroups; TheModule->getPrecedenceGroups(precedenceGroups); for (auto PGD : precedenceGroups) addPrecedenceGroupRef(PGD); } void CompletionLookup::getStmtLabelCompletions(SourceLoc Loc, bool isContinue) { auto *SF = CurrDeclContext->getParentSourceFile(); llvm::SmallPtrSet labels; for (auto *LS : ASTScope::lookupLabeledStmts(SF, Loc)) { if (isContinue && !LS->isPossibleContinueTarget()) continue; auto labelInfo = LS->getLabelInfo(); if (!labelInfo) continue; auto label = labelInfo.Name; if (!labels.insert(label).second) continue; CodeCompletionResultBuilder Builder = makeResultBuilder( CodeCompletionResultKind::Pattern, SemanticContextKind::Local); Builder.addTextChunk(label.str()); } } void CompletionLookup::getOptionalBindingCompletions(SourceLoc Loc) { ExprType = Type(); Kind = LookupKind::ValueInDeclContext; NeedLeadingDot = false; AccessFilteringDeclConsumer AccessFilteringConsumer(CurrDeclContext, *this); // Suggest only 'Optional' type var decls (incl. parameters) FilteredDeclConsumer FilteringConsumer( AccessFilteringConsumer, [&](ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) -> bool { auto *VarD = dyn_cast(VD); if (!VarD) return false; auto Ty = getTypeOfMember(VD, dynamicLookupInfo); return Ty->isOptional(); }); // FIXME: Currently, it doesn't include top level decls for performance // reason. Enabling 'IncludeTopLevel' pulls everything including imported // modules. For suggesting top level results, we need a way to filter cached // results. lookupVisibleDecls(FilteringConsumer, Loc, CurrDeclContext, /*IncludeTopLevel=*/false); }