//===--- ExprContextAnalysis.cpp - Expession context analysis -------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2018 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 "ExprContextAnalysis.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParameterList.h" #include "swift/AST/Pattern.h" #include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/Basic/SourceManager.h" #include "swift/IDE/CodeCompletion.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Subsystems.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallSet.h" using namespace swift; using namespace ide; //===----------------------------------------------------------------------===// // typeCheckContextAt(DeclContext, SourceLoc) //===----------------------------------------------------------------------===// void swift::ide::typeCheckContextAt(DeclContext *DC, SourceLoc Loc) { while (isa(DC)) DC = DC->getParent(); // Make sure the extension has been bound. { // Even if the extension is invalid (e.g. nested in a function or another // type), we want to know the "intended nominal" of the extension so that // we can know the type of 'Self'. SmallVector extensions; for (auto typeCtx = DC->getInnermostTypeContext(); typeCtx != nullptr; typeCtx = typeCtx->getParent()->getInnermostTypeContext()) { if (auto *ext = dyn_cast(typeCtx)) extensions.push_back(ext); } while (!extensions.empty()) { extensions.back()->computeExtendedNominal(); extensions.pop_back(); } // If the completion happens in the inheritance clause of the extension, // 'DC' is the parent of the extension. We need to iterate the top level // decls to find it. In theory, we don't need the extended nominal in the // inheritance clause, but ASTScope lookup requires that. We don't care // unless 'DC' is not 'SourceFile' because non-toplevel extensions are // 'canNeverBeBound()' anyway. if (auto *SF = dyn_cast(DC)) { auto &SM = DC->getASTContext().SourceMgr; for (auto *decl : SF->getTopLevelDecls()) if (auto *ext = dyn_cast(decl)) if (SM.rangeContainsTokenLoc(ext->getSourceRange(), Loc)) ext->computeExtendedNominal(); } } // Type-check this context. switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::Module: case DeclContextKind::FileUnit: case DeclContextKind::SerializedLocal: case DeclContextKind::EnumElementDecl: case DeclContextKind::GenericTypeDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::ExtensionDecl: // Nothing to do for these. break; case DeclContextKind::Initializer: if (auto *patternInit = dyn_cast(DC)) { if (auto *PBD = patternInit->getBinding()) { auto i = patternInit->getBindingIndex(); PBD->getPattern(i)->forEachVariable( [](VarDecl *VD) { (void)VD->getInterfaceType(); }); if (PBD->getInit(i)) { if (!PBD->isInitializerChecked(i)) typeCheckPatternBinding(PBD, i); } } } else if (auto *defaultArg = dyn_cast(DC)) { if (auto *AFD = dyn_cast(defaultArg->getParent())) { auto *Param = AFD->getParameters()->get(defaultArg->getIndex()); (void)Param->getTypeCheckedDefaultExpr(); } } break; case DeclContextKind::TopLevelCodeDecl: swift::typeCheckASTNodeAtLoc(DC, Loc); break; case DeclContextKind::AbstractFunctionDecl: { auto *AFD = cast(DC); auto &SM = DC->getASTContext().SourceMgr; auto bodyRange = AFD->getBodySourceRange(); if (SM.rangeContainsTokenLoc(bodyRange, Loc)) { swift::typeCheckASTNodeAtLoc(DC, Loc); } else { assert(bodyRange.isInvalid() && "The body should not be parsed if the " "completion happens in the signature"); } break; } } } //===----------------------------------------------------------------------===// // findParsedExpr(DeclContext, Expr) //===----------------------------------------------------------------------===// namespace { class ExprFinder : public ASTWalker { SourceManager &SM; SourceRange TargetRange; Expr *FoundExpr = nullptr; template bool isInterstingRange(NodeType *Node) { return SM.rangeContains(Node->getSourceRange(), TargetRange); } bool shouldIgnore(Expr *E) { // E.g. instanceOfDerived.methodInBaseReturningSelf().#^HERE^#' // When calling a method in a base class returning 'Self', the call // expression itself has the type of the base class. That is wrapped with // CovariantReturnConversionExpr which downcasts it to the derived class. if (isa(E)) return false; // E.g. TypeName(#^HERE^# // In this case, we want the type expression instead of a reference to the // initializer. if (isa(E)) return true; // Ignore other implicit expression. if (E->isImplicit()) return true; return false; } public: ExprFinder(SourceManager &SM, SourceRange TargetRange) : SM(SM), TargetRange(TargetRange) {} Expr *get() const { return FoundExpr; } std::pair walkToExprPre(Expr *E) override { if (TargetRange == E->getSourceRange() && !shouldIgnore(E)) { assert(!FoundExpr && "non-nullptr for found expr"); FoundExpr = E; return {false, nullptr}; } return {isInterstingRange(E), E}; } std::pair walkToPatternPre(Pattern *P) override { return {isInterstingRange(P), P}; } std::pair walkToStmtPre(Stmt *S) override { return {isInterstingRange(S), S}; } bool walkToTypeReprPre(TypeRepr *T) override { return false; } }; } // anonymous namespace Expr *swift::ide::findParsedExpr(const DeclContext *DC, SourceRange TargetRange) { ExprFinder finder(DC->getASTContext().SourceMgr, TargetRange); const_cast(DC)->walkContext(finder); return finder.get(); } //===----------------------------------------------------------------------===// // removeCodeCompletionExpr(ASTContext, Expr) //===----------------------------------------------------------------------===// namespace { // TODO: Implement other expressions? class CCExprRemover: public ASTWalker, public ExprVisitor { ASTContext &Ctx; public: bool Removed = false; CCExprRemover(ASTContext &Ctx) : Ctx(Ctx) {} Expr *visitCallExpr(CallExpr *E) { SourceLoc lParenLoc, rParenLoc; SmallVector argLabels; SmallVector argLabelLocs; SmallVector args; SmallVector trailingClosures; bool removing = false; if (auto paren = dyn_cast(E->getArg())) { if (isa(paren->getSubExpr())) { lParenLoc = paren->getLParenLoc(); rParenLoc = paren->getRParenLoc(); removing = true; } } else if (auto tuple = dyn_cast(E->getArg())) { lParenLoc = tuple->getLParenLoc(); rParenLoc = tuple->getRParenLoc(); assert((!E->getUnlabeledTrailingClosureIndex().hasValue() || (tuple->getNumElements() == E->getArgumentLabels().size() && tuple->getNumElements() == E->getArgumentLabelLocs().size())) && "CallExpr with trailing closure must have the same number of " "argument labels"); assert(tuple->getNumElements() == E->getArgumentLabels().size()); assert(tuple->getNumElements() == E->getArgumentLabelLocs().size() || E->getArgumentLabelLocs().size() == 0); bool hasArgumentLabelLocs = E->getArgumentLabelLocs().size() > 0; for (unsigned i = 0, e = tuple->getNumElements(); i != e; ++i) { if (isa(tuple->getElement(i))) { removing = true; continue; } if (!E->getUnlabeledTrailingClosureIndex().hasValue() || i < *E->getUnlabeledTrailingClosureIndex()) { // Normal arguments. argLabels.push_back(E->getArgumentLabels()[i]); if (hasArgumentLabelLocs) argLabelLocs.push_back(E->getArgumentLabelLocs()[i]); args.push_back(tuple->getElement(i)); } else { // Trailing closure arguments. trailingClosures.emplace_back(E->getArgumentLabels()[i], E->getArgumentLabelLocs()[i], tuple->getElement(i)); } } } if (removing) { Removed = true; return CallExpr::create(Ctx, E->getFn(), lParenLoc, args, argLabels, argLabelLocs, rParenLoc, trailingClosures, E->isImplicit()); } return E; } Expr *visitExpr(Expr *E) { return E; } std::pair walkToExprPre(Expr *E) override { if (Removed) return {false, nullptr}; E = visit(E); return {!Removed, E}; } std::pair walkToStmtPre(Stmt *S) override { if (Removed) return {false, nullptr}; return {true, S}; } bool walkToDeclPre(Decl *D) override { return !Removed; } }; } bool swift::ide::removeCodeCompletionExpr(ASTContext &Ctx, Expr *&expr) { CCExprRemover remover(Ctx); expr = expr->walk(remover); return remover.Removed; } //===----------------------------------------------------------------------===// // collectPossibleReturnTypesFromContext(DeclContext, SmallVectorImpl) //===----------------------------------------------------------------------===// void swift::ide::collectPossibleReturnTypesFromContext( DeclContext *DC, SmallVectorImpl &candidates) { if (auto FD = dyn_cast(DC)) { auto Ty = FD->getInterfaceType(); if (FD->getDeclContext()->isTypeContext()) Ty = FD->getMethodInterfaceType(); if (auto FT = Ty->getAs()) { candidates.push_back(DC->mapTypeIntoContext(FT->getResult())); } } if (auto ACE = dyn_cast(DC)) { // Use the type checked type if it has. if (ACE->getType() && !ACE->getType()->hasError() && !ACE->getResultType()->hasUnresolvedType()) { candidates.push_back(ACE->getResultType()); return; } if (auto CE = dyn_cast(ACE)) { if (CE->hasExplicitResultType()) { // If the closure has a explicit return type, use it. if (auto ty = CE->getExplicitResultType()) { candidates.push_back(ty); return; } else { const auto type = swift::performTypeResolution( CE->getExplicitResultTypeRepr(), DC->getASTContext(), /*isSILMode=*/false, /*isSILType=*/false, DC->getGenericEnvironmentOfContext(), /*GenericParams=*/nullptr, const_cast(DC), /*diagnostics=*/false); if (!type->hasError()) { candidates.push_back(type); return; } } } else { // Otherwise, check the context type of the closure. ExprContextInfo closureCtxInfo(CE->getParent(), CE); for (auto closureTy : closureCtxInfo.getPossibleTypes()) { if (auto funcTy = closureTy->getAs()) candidates.push_back(funcTy->getResult()); } if (!candidates.empty()) return; } } // Even if the type checked type has unresolved types, it's better than // nothing. if (ACE->getType() && !ACE->getType()->hasError()) candidates.push_back(ACE->getResultType()); } } //===----------------------------------------------------------------------===// // ExprContextInfo(DeclContext, SourceRange) //===----------------------------------------------------------------------===// namespace { class ExprParentFinder : public ASTWalker { friend class ExprContextAnalyzer; Expr *ChildExpr; std::function Predicate; bool arePositionsSame(Expr *E1, Expr *E2) { return E1->getSourceRange().Start == E2->getSourceRange().Start && E1->getSourceRange().End == E2->getSourceRange().End; } public: llvm::SmallVector Ancestors; ExprParentFinder(Expr *ChildExpr, std::function Predicate) : ChildExpr(ChildExpr), Predicate(Predicate) {} std::pair walkToExprPre(Expr *E) override { // Finish if we found the target. 'ChildExpr' might have been replaced // with typechecked expression. In that case, match the position. if (E == ChildExpr || arePositionsSame(E, ChildExpr)) return {false, nullptr}; if (E != ChildExpr && Predicate(E, Parent)) { Ancestors.push_back(E); return {true, E}; } return {true, E}; } Expr *walkToExprPost(Expr *E) override { if (Predicate(E, Parent)) Ancestors.pop_back(); return E; } std::pair walkToStmtPre(Stmt *S) override { if (Predicate(S, Parent)) Ancestors.push_back(S); return {true, S}; } Stmt *walkToStmtPost(Stmt *S) override { if (Predicate(S, Parent)) Ancestors.pop_back(); return S; } bool walkToDeclPre(Decl *D) override { if (Predicate(D, Parent)) Ancestors.push_back(D); return true; } bool walkToDeclPost(Decl *D) override { if (Predicate(D, Parent)) Ancestors.pop_back(); return true; } std::pair walkToPatternPre(Pattern *P) override { if (Predicate(P, Parent)) Ancestors.push_back(P); return {true, P}; } Pattern *walkToPatternPost(Pattern *P) override { if (Predicate(P, Parent)) Ancestors.pop_back(); return P; } }; /// Collect function (or subscript) members with the given \p name on \p baseTy. static void collectPossibleCalleesByQualifiedLookup( DeclContext &DC, Type baseTy, DeclNameRef name, SmallVectorImpl &candidates) { auto baseInstanceTy = baseTy->getMetatypeInstanceType(); if (!baseInstanceTy->mayHaveMembers()) return; bool isOnMetaType = baseTy->is(); SmallVector decls; if (!DC.lookupQualified(baseInstanceTy, name.withoutArgumentLabels(), NL_QualifiedDefault | NL_ProtocolMembers, decls)) return; llvm::DenseMap, size_t> known; auto *baseNominal = baseInstanceTy->getAnyNominal(); for (auto *VD : decls) { if ((!isa(VD) && !isa(VD)) || VD->shouldHideFromEditor()) continue; if (!isMemberDeclApplied(&DC, baseInstanceTy, VD)) continue; Type declaredMemberType = VD->getInterfaceType(); if (!declaredMemberType->is()) continue; if (VD->getDeclContext()->isTypeContext()) { if (isa(VD)) { if (!isOnMetaType && VD->isStatic()) continue; if (isOnMetaType == VD->isStatic()) declaredMemberType = declaredMemberType->castTo()->getResult(); } else if (isa(VD)) { if (!isOnMetaType) continue; declaredMemberType = declaredMemberType->castTo()->getResult(); } else if (isa(VD)) { if (isOnMetaType != VD->isStatic()) continue; } } auto subs = baseInstanceTy->getMemberSubstitutionMap( DC.getParentModule(), VD, VD->getInnermostDeclContext()->getGenericEnvironmentOfContext()); auto fnType = declaredMemberType.subst(subs); if (!fnType || !fnType->is()) continue; // If we are calling on a type alias type, replace the canonicalized type // in the function type with the type alias. if (isa(baseInstanceTy.getPointer())) { auto canBaseTy = baseInstanceTy->getCanonicalType(); fnType = fnType.transform([&](Type t) -> Type { if (t->getCanonicalType()->isEqual(canBaseTy)) return baseInstanceTy; return t; }); } auto semanticContext = SemanticContextKind::CurrentNominal; if (baseNominal && VD->getDeclContext()->getSelfNominalTypeDecl() != baseNominal) semanticContext = SemanticContextKind::Super; FunctionTypeAndDecl entry(fnType->castTo(), VD, semanticContext); // Remember the index of the entry. auto knownResult = known.insert( {{VD->isStatic(), fnType->getCanonicalType()}, candidates.size()}); if (knownResult.second) { candidates.push_back(entry); continue; } auto idx = knownResult.first->second; if (AvailableAttr::isUnavailable(candidates[idx].Decl) && !AvailableAttr::isUnavailable(VD)) { // Replace the previously found "unavailable" with the "available" one. candidates[idx] = entry; } // Otherwise, skip redundant results. } } /// Collect function (or subscript) members with the given \p name on /// \p baseExpr expression. static void collectPossibleCalleesByQualifiedLookup( DeclContext &DC, Expr *baseExpr, DeclNameRef name, SmallVectorImpl &candidates) { ConcreteDeclRef ref = nullptr; // Re-typecheck TypeExpr so it's typechecked without the arguments which may // affects the inference of the generic arguments. if (TypeExpr *tyExpr = dyn_cast(baseExpr)) { if (!tyExpr->isImplicit()) tyExpr->setType(nullptr); } Type baseTy = baseExpr->getType(); if (!baseTy || baseTy->is()) { auto baseTyOpt = getTypeOfCompletionContextExpr( DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, baseExpr, ref); if (!baseTyOpt) return; baseTy = *baseTyOpt; } baseTy = baseTy->getWithoutSpecifierType(); // Use metatype for lookup 'super.init' and 'self.init' if it's inside // constructors. if (name == DeclNameRef::createConstructor() && isa(DC)) { bool isSuperCall = isa(baseExpr); bool isSelfCall = false; if (auto declRef = dyn_cast(baseExpr)) { if (declRef->getDecl()->getName() == DC.getASTContext().Id_self) { isSelfCall = true; } } if (isSuperCall || isSelfCall) { baseTy = MetatypeType::get(baseTy); } } collectPossibleCalleesByQualifiedLookup(DC, baseTy, name, candidates); // Add virtual 'subscript(keyPath: KeyPath) -> Value'. if (name.getBaseName() == DeclBaseName::createSubscript() && (baseTy->getAnyNominal() || baseTy->is() || baseTy->is())) { auto &Ctx = DC.getASTContext(); auto *kpDecl = Ctx.getKeyPathDecl(); Type kpTy = kpDecl->mapTypeIntoContext(kpDecl->getDeclaredInterfaceType()); Type kpValueTy = kpTy->castTo()->getGenericArgs()[1]; kpTy = BoundGenericType::get(kpDecl, Type(), {baseTy, kpValueTy}); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; Type fnTy = FunctionType::get( {AnyFunctionType::Param(kpTy, Ctx.Id_keyPath)}, kpValueTy, info); candidates.emplace_back(fnTy->castTo(), nullptr); } } /// For the given \p unresolvedMemberExpr, collect possible callee types and /// declarations. static bool collectPossibleCalleesForUnresolvedMember( DeclContext &DC, UnresolvedMemberExpr *unresolvedMemberExpr, SmallVectorImpl &candidates) { auto collectMembers = [&](Type expectedTy) { if (!expectedTy->mayHaveMembers()) return; collectPossibleCalleesByQualifiedLookup(DC, MetatypeType::get(expectedTy), unresolvedMemberExpr->getName(), candidates); }; // Get the context of the expression itself. ExprContextInfo contextInfo(&DC, unresolvedMemberExpr); for (auto expectedTy : contextInfo.getPossibleTypes()) { collectMembers(expectedTy); // If this is an optional type, let's also check its base type. if (auto baseTy = expectedTy->getOptionalObjectType()) { collectMembers(baseTy->lookThroughAllOptionalTypes()); } } return !candidates.empty(); } /// For the given \c callExpr, collect possible callee types and declarations. static bool collectPossibleCalleesForApply( DeclContext &DC, ApplyExpr *callExpr, SmallVectorImpl &candidates) { auto *fnExpr = callExpr->getFn(); if (auto *DRE = dyn_cast(fnExpr)) { if (auto *decl = DRE->getDecl()) { Type declTy = fnExpr->getType(); if ((!declTy || declTy->hasError() || declTy->hasUnresolvedType()) && decl->hasInterfaceType()) { declTy = decl->getInterfaceType(); declTy = decl->getInnermostDeclContext()->mapTypeIntoContext(declTy); } if (declTy) { declTy = declTy->getWithoutSpecifierType(); if (auto *funcTy = declTy->getAs()) candidates.emplace_back(funcTy, decl); } } } else if (auto *OSRE = dyn_cast(fnExpr)) { for (auto *decl : OSRE->getDecls()) { if (decl->hasInterfaceType()) { auto declTy = decl->getInterfaceType(); declTy = decl->getInnermostDeclContext()->mapTypeIntoContext(declTy); if (auto *funcType = declTy->getAs()) candidates.emplace_back(funcType, decl); } } } else if (auto *UDE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup(DC, UDE->getBase(), UDE->getName(), candidates); } else if (auto *DSCE = dyn_cast(fnExpr)) { if (auto *DRE = dyn_cast(DSCE->getFn())) { collectPossibleCalleesByQualifiedLookup( DC, DSCE->getArg(), DeclNameRef(DRE->getDecl()->getName()), candidates); } } else if (auto CRCE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, CRCE->getArg(), DeclNameRef::createConstructor(), candidates); } else if (auto TE = dyn_cast(fnExpr)) { collectPossibleCalleesByQualifiedLookup( DC, TE, DeclNameRef::createConstructor(), candidates); } else if (auto *UME = dyn_cast(fnExpr)) { collectPossibleCalleesForUnresolvedMember(DC, UME, candidates); } if (!candidates.empty()) return true; ConcreteDeclRef refDecl = nullptr; Type fnType = fnExpr->getType(); if (fnType) { refDecl = fnExpr->getReferencedDecl(); if (!refDecl) if (auto apply = dyn_cast(fnExpr)) refDecl = apply->getFn()->getReferencedDecl(); } if (!fnType) { auto fnTypeOpt = getTypeOfCompletionContextExpr( DC.getASTContext(), &DC, CompletionTypeCheckKind::Normal, fnExpr, refDecl); if (fnTypeOpt) fnType = *fnTypeOpt; } if (!fnType || fnType->hasUnresolvedType() || fnType->hasError()) return false; fnType = fnType->getWithoutSpecifierType(); if (auto *AFT = fnType->getAs()) { candidates.emplace_back(AFT, refDecl.getDecl()); } else if (auto *AMT = fnType->getAs()) { auto baseTy = AMT->getInstanceType(); if (isa(fnExpr) && baseTy->mayHaveMembers()) { collectPossibleCalleesByQualifiedLookup( DC, fnExpr, DeclNameRef::createConstructor(), candidates); } } else { // Otherwise, look for `callAsFunction` (SE-0253). collectPossibleCalleesByQualifiedLookup( DC, fnExpr, DeclNameRef(DC.getASTContext().Id_callAsFunction), candidates); } return !candidates.empty(); } /// For the given \c subscriptExpr, collect possible callee types and /// declarations. static bool collectPossibleCalleesForSubscript( DeclContext &DC, SubscriptExpr *subscriptExpr, SmallVectorImpl &candidates) { if (subscriptExpr->hasDecl()) { if (auto SD = dyn_cast(subscriptExpr->getDecl().getDecl())) { auto declType = SD->getInterfaceType(); declType = declType.subst(subscriptExpr->getDecl().getSubstitutions()); if (auto *funcType = declType->getAs()) candidates.emplace_back(funcType, SD); } } else { collectPossibleCalleesByQualifiedLookup(DC, subscriptExpr->getBase(), DeclNameRef::createSubscript(), candidates); } return !candidates.empty(); } /// Get index of \p CCExpr in \p Args. \p Args is usually a \c TupleExpr /// or \c ParenExpr. /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. static bool getPositionInArgs(DeclContext &DC, Expr *Args, Expr *CCExpr, unsigned &Position, bool &HasName) { if (isa(Args)) { HasName = false; Position = 0; return true; } auto *tuple = dyn_cast(Args); if (!tuple) return false; auto &SM = DC.getASTContext().SourceMgr; for (unsigned i = 0, n = tuple->getNumElements(); i != n; ++i) { if (SM.isBeforeInBuffer(tuple->getElement(i)->getEndLoc(), CCExpr->getStartLoc())) continue; HasName = tuple->getElementNameLoc(i).isValid(); Position = i; return true; } return false; } /// For function call arguments \p Args, return the argument at \p Position /// computed by \c getPositionInArgs static Expr *getArgAtPosition(Expr *Args, unsigned Position) { if (isa(Args)) { assert(Position == 0); return Args; } if (auto *tuple = dyn_cast(Args)) { return tuple->getElement(Position); } else { llvm_unreachable("Unable to retrieve arg at position returned by " "getPositionInArgs?"); } } /// Get index of \p CCExpr in \p Params. Note that the position in \p Params may /// be different than the position in \p Args if there are defaulted arguments /// in \p Params which don't occur in \p Args. /// /// \returns \c true if success, \c false if \p CCExpr is not a part of \p Args. static bool getPositionInParams(DeclContext &DC, Expr *Args, Expr *CCExpr, ArrayRef Params, unsigned &PosInParams) { if (isa(Args)) { PosInParams = 0; return true; } auto *tuple = dyn_cast(Args); if (!tuple) { return false; } auto &SM = DC.getASTContext().SourceMgr; PosInParams = 0; unsigned PosInArgs = 0; bool LastParamWasVariadic = false; // We advance PosInArgs until we find argument that is after the code // completion token, which is when we stop. // For each argument, we try to find a matching parameter either by matching // argument labels, in which case PosInParams may be advanced by more than 1, // or by advancing PosInParams and PosInArgs both by 1. for (; PosInArgs < tuple->getNumElements(); ++PosInArgs) { if (!SM.isBeforeInBuffer(tuple->getElement(PosInArgs)->getEndLoc(), CCExpr->getStartLoc())) { // The arg is after the code completion position. Stop. break; } auto ArgName = tuple->getElementName(PosInArgs); // If the last parameter we matched was variadic, we claim all following // unlabeled arguments for that variadic parameter -> advance PosInArgs but // not PosInParams. if (LastParamWasVariadic && ArgName.empty()) { continue; } else { LastParamWasVariadic = false; } // Look for a matching parameter label. bool AdvancedPosInParams = false; for (unsigned i = PosInParams; i < Params.size(); ++i) { if (Params[i].getLabel() == ArgName) { // We have found a label match. Advance the position in the params // to point to the param after the one with this label. PosInParams = i + 1; AdvancedPosInParams = true; if (Params[i].isVariadic()) { LastParamWasVariadic = true; } break; } } bool IsTrailingClosure = PosInArgs >= tuple->getNumElements() - tuple->getNumTrailingElements(); if (!AdvancedPosInParams && IsTrailingClosure) { // If the argument is a trailing closure, it can't match non-function // parameters. Advance to the next function parameter. for (unsigned i = PosInParams; i < Params.size(); ++i) { if (Params[i].getParameterType()->is()) { PosInParams = i + 1; AdvancedPosInParams = true; break; } } } if (!AdvancedPosInParams) { // We haven't performed any special advance logic. Assume the argument // and parameter match, so advance PosInParams by 1. ++PosInParams; } } if (PosInArgs < tuple->getNumElements() && PosInParams < Params.size()) { // We didn't search until the end, so we found a position in Params. Success return true; } else { return false; } } /// Given an expression and its context, the analyzer tries to figure out the /// expected type of the expression by analyzing its context. class ExprContextAnalyzer { DeclContext *DC; Expr *ParsedExpr; SourceManager &SM; ASTContext &Context; // Results populated by Analyze() SmallVectorImpl &PossibleTypes; SmallVectorImpl &PossibleParams; SmallVectorImpl &PossibleCallees; Expr *&AnalyzedExpr; bool &implicitSingleExpressionReturn; void recordPossibleType(Type ty) { if (!ty || ty->is()) return; PossibleTypes.push_back(ty->getRValueType()); } void recordPossibleParam(const AnyFunctionType::Param *arg, bool isRequired) { PossibleParams.emplace_back(arg, isRequired); } /// Collect context information at call argument position. bool analyzeApplyExpr(Expr *E) { // Collect parameter lists for possible func decls. SmallVector Candidates; Expr *Args = nullptr; if (auto *applyExpr = dyn_cast(E)) { if (!collectPossibleCalleesForApply(*DC, applyExpr, Candidates)) return false; Args = applyExpr->getArg(); } else if (auto *subscriptExpr = dyn_cast(E)) { if (!collectPossibleCalleesForSubscript(*DC, subscriptExpr, Candidates)) return false; Args = subscriptExpr->getIndex(); } else { llvm_unreachable("unexpected expression kind"); } assert(!Candidates.empty()); PossibleCallees.assign(Candidates.begin(), Candidates.end()); // Determine the position of code completion token in call argument. unsigned PositionInArgs; bool HasName; if (!getPositionInArgs(*DC, Args, ParsedExpr, PositionInArgs, HasName)) return false; // Collect possible types (or labels) at the position. { bool MayBeArgForLabeledParam = HasName || E->isImplicit() || (!isa(E) && !isa(E) && !isa(E)); // If the completion position cannot be the actual argument, it must be // able to be an argument label. bool MayBeLabel = !MayBeArgForLabeledParam; // Alternatively, the code completion position may complete to an argument // label if we are currently completing variadic args. // E.g. // func foo(x: Int..., y: Int...) {} // foo(x: 1, #^COMPLETE^#) // #^COMPLETE^# may complete to either an additional variadic arg or to // the argument label `y`. // // Varargs are represented by a VarargExpansionExpr that contains an // ArrayExpr on the call side. if (auto Vararg = dyn_cast( getArgAtPosition(Args, PositionInArgs))) { if (auto Array = dyn_cast_or_null(Vararg->getSubExpr())) { if (Array->getNumElements() > 0 && !isa(Array->getElement(0))) { // We can only complete as argument label if we have at least one // proper vararg before the code completion token. We shouldn't be // suggesting labels for: // foo(x: #^COMPLETE^#) MayBeLabel = true; } } } SmallPtrSet seenTypes; llvm::SmallSet, 4> seenArgs; for (auto &typeAndDecl : Candidates) { DeclContext *memberDC = nullptr; if (typeAndDecl.Decl) memberDC = typeAndDecl.Decl->getInnermostDeclContext(); auto Params = typeAndDecl.Type->getParams(); unsigned PositionInParams; if (!getPositionInParams(*DC, Args, ParsedExpr, Params, PositionInParams)) { // If the argument doesn't have a matching position in the parameters, // indicate that with optional nullptr param. if (seenArgs.insert({Identifier(), CanType()}).second) recordPossibleParam(nullptr, /*isRequired=*/false); continue; } ParameterList *paramList = nullptr; if (auto VD = typeAndDecl.Decl) { paramList = getParameterList(VD); if (paramList && paramList->size() != Params.size()) paramList = nullptr; } for (auto Pos = PositionInParams; Pos < Params.size(); ++Pos) { const auto ¶mType = Params[Pos]; Type ty = paramType.getPlainType(); if (memberDC && ty->hasTypeParameter()) ty = memberDC->mapTypeIntoContext(ty); bool canSkip = paramList && (paramList->get(Pos)->isDefaultArgument() || paramList->get(Pos)->isVariadic()); if (MayBeLabel && paramType.hasLabel()) { if (seenArgs.insert({paramType.getLabel(), ty->getCanonicalType()}) .second) recordPossibleParam(¶mType, !canSkip); } if (MayBeArgForLabeledParam || !paramType.hasLabel()) { auto argTy = ty; if (paramType.isInOut()) argTy = InOutType::get(argTy); else if (paramType.isAutoClosure() && argTy->is()) argTy = argTy->castTo()->getResult(); if (seenTypes.insert(argTy->getCanonicalType()).second) recordPossibleType(argTy); } if (!canSkip) break; } } } return !PossibleTypes.empty() || !PossibleParams.empty(); } void analyzeExpr(Expr *Parent) { AnalyzedExpr = Parent; switch (Parent->getKind()) { case ExprKind::Call: case ExprKind::Subscript: case ExprKind::Binary: case ExprKind::PrefixUnary: { analyzeApplyExpr(Parent); break; } case ExprKind::Array: { if (auto type = ParsedExpr->getType()) { if (!type->is()) { recordPossibleType(type); break; } } // Check context types of the array literal expression. ExprContextInfo arrayCtxtInfo(DC, Parent); for (auto arrayT : arrayCtxtInfo.getPossibleTypes()) { if (auto boundGenericT = arrayT->getAs()) { // let _: [Element] = [#HERE#] // In this case, 'Element' is the expected type. if (boundGenericT->isArray()) recordPossibleType(boundGenericT->getGenericArgs()[0]); // let _: [Key : Value] = [#HERE#] // In this case, 'Key' is the expected type. if (boundGenericT->isDictionary()) recordPossibleType(boundGenericT->getGenericArgs()[0]); } } break; } case ExprKind::Dictionary: { // Check context types of the dictionary literal expression. ExprContextInfo dictCtxtInfo(DC, Parent); for (auto dictT : dictCtxtInfo.getPossibleTypes()) { if (auto boundGenericT = dictT->getAs()) { if (boundGenericT->isDictionary()) { if (ParsedExpr->isImplicit() && isa(ParsedExpr)) { // let _: [Key : Value] = [#HERE#:] // let _: [Key : Value] = [#HERE#:val] // let _: [Key : Value] = [key:#HERE#] // In this case, this is called by 'ExprKind::Tuple' case. Return // '(Key,Value)' here, 'ExprKind::Tuple' branch can decide which // type in the tuple type is the exprected type. SmallVector elts; for (auto genericArg : boundGenericT->getGenericArgs()) elts.emplace_back(genericArg); recordPossibleType(TupleType::get(elts, DC->getASTContext())); } else { // let _: [Key : Value] = [key: val, #HERE#] // In this case, assume 'Key' is the expected type. if (boundGenericT->isDictionary()) recordPossibleType(boundGenericT->getGenericArgs()[0]); } } } } break; } case ExprKind::If: { auto *IE = cast(Parent); if (IE->isFolded() && SM.rangeContains(IE->getCondExpr()->getSourceRange(), ParsedExpr->getSourceRange())) { recordPossibleType(Context.getBoolType()); break; } ExprContextInfo ternaryCtxtInfo(DC, Parent); for (auto ternaryT : ternaryCtxtInfo.getPossibleTypes()) recordPossibleType(ternaryT); break; } case ExprKind::Assign: { auto *AE = cast(Parent); // Make sure code completion is on the right hand side. if (SM.isBeforeInBuffer(AE->getEqualLoc(), ParsedExpr->getStartLoc())) { // The destination is of the expected type. auto *destExpr = AE->getDest(); if (auto type = destExpr->getType()) { recordPossibleType(type); } else if (auto *DRE = dyn_cast(destExpr)) { if (auto *decl = DRE->getDecl()) { if (decl->hasInterfaceType()) recordPossibleType(decl->getDeclContext()->mapTypeIntoContext( decl->getInterfaceType())); } } } break; } case ExprKind::Tuple: { TupleType *tupleT = nullptr; if (Parent->getType() && Parent->getType()->is()) { tupleT = Parent->getType()->castTo(); } else { ExprContextInfo tupleCtxtInfo(DC, Parent); for (auto possibleT : tupleCtxtInfo.getPossibleTypes()) { if (auto possibleTupleT = possibleT->getAs()) { tupleT = possibleTupleT; break; } } if (!tupleT) return; } unsigned Position = 0; bool HasName; if (getPositionInArgs(*DC, Parent, ParsedExpr, Position, HasName)) { // The expected type may have fewer number of elements. if (Position < tupleT->getNumElements()) recordPossibleType(tupleT->getElementType(Position)); } break; } case ExprKind::Closure: { auto *CE = cast(Parent); assert(hasImplicitSingleExpressionReturn(CE->getBody())); implicitSingleExpressionReturn = true; SmallVector candidates; collectPossibleReturnTypesFromContext(CE, candidates); for (auto ty : candidates) recordPossibleType(ty); break; } default: llvm_unreachable("Unhandled expression kind."); } } void analyzeStmt(Stmt *Parent) { switch (Parent->getKind()) { case StmtKind::Return: { SmallVector candidates; collectPossibleReturnTypesFromContext(DC, candidates); for (auto ty : candidates) recordPossibleType(ty); break; } case StmtKind::ForEach: if (auto SEQ = cast(Parent)->getSequence()) { if (containsTarget(SEQ)) { recordPossibleType(Context.getSequenceType()); } } break; case StmtKind::RepeatWhile: case StmtKind::If: case StmtKind::While: case StmtKind::Guard: if (isBoolConditionOf(Parent)) { recordPossibleType(Context.getBoolType()); } break; default: llvm_unreachable("Unhandled statement kind."); } } bool isBoolConditionOf(Stmt *parent) { if (auto *repeat = dyn_cast(parent)) { return repeat->getCond() && containsTarget(repeat->getCond()); } if (auto *conditional = dyn_cast(parent)) { for (StmtConditionElement cond : conditional->getCond()) { if (auto *E = cond.getBooleanOrNull()) { if (containsTarget(E)) { return true; } } } } return false; } bool containsTarget(Expr *E) { assert(E && "expected parent expression"); return SM.rangeContains(E->getSourceRange(), ParsedExpr->getSourceRange()); } void analyzeDecl(Decl *D) { switch (D->getKind()) { case DeclKind::PatternBinding: { auto PBD = cast(D); for (unsigned I : range(PBD->getNumPatternEntries())) { if (auto Init = PBD->getInit(I)) { if (containsTarget(Init)) { if (PBD->getPattern(I)->hasType()) { recordPossibleType(PBD->getPattern(I)->getType()); break; } } } } break; } default: if (auto *FD = dyn_cast(D)) { assert(hasImplicitSingleExpressionReturn(FD->getBody())); implicitSingleExpressionReturn = true; SmallVector candidates; collectPossibleReturnTypesFromContext(DC, candidates); for (auto ty : candidates) recordPossibleType(ty); break; } llvm_unreachable("Unhandled decl kind."); } } void analyzePattern(Pattern *P) { switch (P->getKind()) { case PatternKind::Expr: { auto ExprPat = cast(P); if (auto D = ExprPat->getMatchVar()) { if (D->hasInterfaceType()) recordPossibleType( D->getDeclContext()->mapTypeIntoContext(D->getInterfaceType())); } break; } default: llvm_unreachable("Unhandled pattern kind."); } } void analyzeInitializer(Initializer *initDC) { switch (initDC->getInitializerKind()) { case swift::InitializerKind::PatternBinding: { auto initDC = cast(DC); auto PBD = initDC->getBinding(); if (!PBD) break; auto pat = PBD->getPattern(initDC->getBindingIndex()); if (pat->hasType()) recordPossibleType(pat->getType()); break; } case InitializerKind::DefaultArgument: { auto initDC = cast(DC); auto AFD = dyn_cast(initDC->getParent()); if (!AFD) return; auto param = AFD->getParameters()->get(initDC->getIndex()); recordPossibleType(AFD->mapTypeIntoContext(param->getInterfaceType())); break; } case InitializerKind::PropertyWrapper: { auto initDC = cast(DC); auto AFD = dyn_cast(initDC->getParent()); if (!AFD) return; auto *param = initDC->getParam(); recordPossibleType(AFD->mapTypeIntoContext(param->getInterfaceType())); break; } } } /// Whether the given \c BraceStmt, which must be the body of a function or /// closure, contains a single expression that would be implicitly returned if /// the single-expression-body transform had been performed. /// /// We cannot use hasSingleExpressionBody, because we explicitly do not use /// the single-expression-body transform when there is a code-completion in /// the expression in order to avoid a base expression affecting the type, and /// need to distinguish whether the single expression body was explicitly /// returned (in which case the expression's type *must* match the expected /// return type) or not (in which case it *may* match, as the user could intend /// it only as the first statement of many that they haven't finished writing /// yet. static bool hasImplicitSingleExpressionReturn(BraceStmt *body) { if (body->getNumElements() == 2) { if (auto *D = body->getFirstElement().dyn_cast()) { // Step into nested active clause. while (auto *ICD = dyn_cast(D)) { auto ACE = ICD->getActiveClauseElements(); if (ACE.size() == 1) { return body->getLastElement().is(); } else if (ACE.size() == 2) { if (auto *ND = ACE.front().dyn_cast()) { D = ND; continue; } } break; } } } return body->getNumElements() == 1 && body->getLastElement().is(); } public: ExprContextAnalyzer( DeclContext *DC, Expr *ParsedExpr, SmallVectorImpl &PossibleTypes, SmallVectorImpl &PossibleArgs, SmallVectorImpl &PossibleCallees, Expr *&AnalyzedExpr, bool &implicitSingleExpressionReturn) : DC(DC), ParsedExpr(ParsedExpr), SM(DC->getASTContext().SourceMgr), Context(DC->getASTContext()), PossibleTypes(PossibleTypes), PossibleParams(PossibleArgs), PossibleCallees(PossibleCallees), AnalyzedExpr(AnalyzedExpr), implicitSingleExpressionReturn(implicitSingleExpressionReturn) {} void Analyze() { // We cannot analyze without target. if (!ParsedExpr) return; ExprParentFinder Finder(ParsedExpr, [&](ASTWalker::ParentTy Node, ASTWalker::ParentTy Parent) { if (auto E = Node.getAsExpr()) { switch (E->getKind()) { case ExprKind::Call: { // Iff the cursor is in argument position. auto call = cast(E); auto fnRange = call->getFn()->getSourceRange(); auto argsRange = call->getArg()->getSourceRange(); auto exprRange = ParsedExpr->getSourceRange(); return !SM.rangeContains(fnRange, exprRange) && SM.rangeContains(argsRange, exprRange); } case ExprKind::Subscript: { // Iff the cursor is in index position. auto argsRange = cast(E)->getIndex()->getSourceRange(); return SM.rangeContains(argsRange, ParsedExpr->getSourceRange()); } case ExprKind::Binary: case ExprKind::PrefixUnary: case ExprKind::Assign: case ExprKind::Dictionary: case ExprKind::If: return true; case ExprKind::Array: return (!Parent.getAsExpr() || !isa(Parent.getAsExpr())); case ExprKind::Tuple: { auto ParentE = Parent.getAsExpr(); return !ParentE || (!isa(ParentE) && !isa(ParentE) && !isa(ParentE)); } case ExprKind::Closure: return hasImplicitSingleExpressionReturn( cast(E)->getBody()); default: return false; } } else if (auto S = Node.getAsStmt()) { switch (S->getKind()) { case StmtKind::Return: case StmtKind::ForEach: case StmtKind::RepeatWhile: case StmtKind::If: case StmtKind::While: case StmtKind::Guard: return true; default: return false; } } else if (auto D = Node.getAsDecl()) { switch (D->getKind()) { case DeclKind::PatternBinding: return true; default: if (auto *FD = dyn_cast(D)) if (auto *body = FD->getBody()) return hasImplicitSingleExpressionReturn(body); return false; } } else if (auto P = Node.getAsPattern()) { switch (P->getKind()) { case PatternKind::Expr: return true; default: return false; } } else return false; }); // For 'Initializer' context, we need to look into its parent. auto analyzeDC = isa(DC) ? DC->getParent() : DC; analyzeDC->walkContext(Finder); if (Finder.Ancestors.empty()) { // There's no parent context in DC. But still, the parent of the // initializer might constrain the initializer's type. if (auto initDC = dyn_cast(DC)) analyzeInitializer(initDC); return; } auto &P = Finder.Ancestors.back(); if (auto Parent = P.getAsExpr()) { analyzeExpr(Parent); } else if (auto Parent = P.getAsStmt()) { analyzeStmt(Parent); } else if (auto Parent = P.getAsDecl()) { analyzeDecl(Parent); } else if (auto Parent = P.getAsPattern()) { analyzePattern(Parent); } } }; } // end anonymous namespace ExprContextInfo::ExprContextInfo(DeclContext *DC, Expr *TargetExpr) { ExprContextAnalyzer Analyzer(DC, TargetExpr, PossibleTypes, PossibleParams, PossibleCallees, AnalyzedExpr, implicitSingleExpressionReturn); Analyzer.Analyze(); }