//===--- CodeCompletion.cpp - Code completion implementation --------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 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 "swift/IDE/CodeCompletion.h" #include "CodeCompletionResultBuilder.h" #include "ExprContextAnalysis.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/Comment.h" #include "swift/AST/Initializer.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/Defer.h" #include "swift/Basic/LLVM.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/IDE/CodeCompletionCache.h" #include "swift/IDE/Utils.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Syntax/SyntaxKind.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Comment.h" #include "clang/AST/CommentVisitor.h" #include "clang/AST/Decl.h" #include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" #include #include using namespace swift; using namespace ide; using CommandWordsPairs = std::vector>; enum CodeCompletionCommandKind { none, keyword, recommended, recommendedover, mutatingvariant, nonmutatingvariant, }; CodeCompletionCommandKind getCommandKind(StringRef Command) { #define CHECK_CASE(KIND) \ if (Command == #KIND) \ return CodeCompletionCommandKind::KIND; CHECK_CASE(keyword); CHECK_CASE(recommended); CHECK_CASE(recommendedover); CHECK_CASE(mutatingvariant); CHECK_CASE(nonmutatingvariant); #undef CHECK_CASE return CodeCompletionCommandKind::none; } StringRef getCommandName(CodeCompletionCommandKind Kind) { #define CHECK_CASE(KIND) \ if (CodeCompletionCommandKind::KIND == Kind) { \ static std::string Name(#KIND); \ return Name; \ } CHECK_CASE(keyword) CHECK_CASE(recommended) CHECK_CASE(recommendedover) CHECK_CASE(mutatingvariant); CHECK_CASE(nonmutatingvariant); #undef CHECK_CASE llvm_unreachable("Cannot handle this Kind."); } bool containsInterestedWords(StringRef Content, StringRef Splitter, bool AllowWhitespace) { do { Content = Content.split(Splitter).second; Content = AllowWhitespace ? Content.trim() : Content; #define CHECK_CASE(KIND) \ if (Content.startswith(#KIND)) \ return true; CHECK_CASE(keyword) CHECK_CASE(recommended) CHECK_CASE(recommendedover) CHECK_CASE(mutatingvariant); CHECK_CASE(nonmutatingvariant); #undef CHECK_CASE } while (!Content.empty()); return false; } void splitTextByComma(StringRef Text, std::vector& Subs) { do { auto Pair = Text.split(','); auto Key = Pair.first.trim(); if (!Key.empty()) Subs.push_back(Key); Text = Pair.second; } while (!Text.empty()); } namespace clang { namespace comments { class WordPairsArrangedViewer { ArrayRef> Content; std::vector ViewedText; std::vector Words; StringRef Key; bool isKeyViewed(StringRef K) { return std::find(ViewedText.begin(), ViewedText.end(), K) != ViewedText.end(); } public: WordPairsArrangedViewer(ArrayRef> Content): Content(Content) {} bool hasNext() { Words.clear(); bool Found = false; for (auto P : Content) { if (!Found && !isKeyViewed(P.first)) { Key = P.first; Found = true; } if (Found && P.first == Key) Words.push_back(P.second); } return Found; } std::pair> next() { bool HasNext = hasNext(); (void) HasNext; assert(HasNext && "Have no more data."); ViewedText.push_back(Key); return std::make_pair(Key, llvm::makeArrayRef(Words)); } }; class ClangCommentExtractor : public ConstCommentVisitor { CommandWordsPairs &Words; const CommandTraits &Traits; std::vector Parents; void visitChildren(const Comment* C) { Parents.push_back(C); for (auto It = C->child_begin(); It != C->child_end(); ++ It) visit(*It); Parents.pop_back(); } public: ClangCommentExtractor(CommandWordsPairs &Words, const CommandTraits &Traits) : Words(Words), Traits(Traits) {} #define CHILD_VISIT(NAME) \ void visit##NAME(const NAME *C) {\ visitChildren(C);\ } CHILD_VISIT(FullComment) CHILD_VISIT(ParagraphComment) #undef CHILD_VISIT void visitInlineCommandComment(const InlineCommandComment *C) { auto Command = C->getCommandName(Traits); auto CommandKind = getCommandKind(Command); if (CommandKind == CodeCompletionCommandKind::none) return; auto &Parent = Parents.back(); for (auto CIT = std::find(Parent->child_begin(), Parent->child_end(), C) + 1; CIT != Parent->child_end(); CIT++) { if (auto TC = dyn_cast(*CIT)) { auto Text = TC->getText(); std::vector Subs; splitTextByComma(Text, Subs); auto Kind = getCommandName(CommandKind); for (auto S : Subs) Words.push_back(std::make_pair(Kind, S)); } else break; } } }; void getClangDocKeyword(ClangImporter &Importer, const Decl *D, CommandWordsPairs &Words) { ClangCommentExtractor Extractor(Words, Importer.getClangASTContext(). getCommentCommandTraits()); if (auto RC = Importer.getClangASTContext().getRawCommentForAnyRedecl(D)) { auto RT = RC->getRawText(Importer.getClangASTContext().getSourceManager()); if (containsInterestedWords(RT, "@", /*AllowWhitespace*/false)) { FullComment* Comment = Importer.getClangASTContext(). getLocalCommentForDeclUncached(D); Extractor.visit(Comment); } } } } // end namespace comments } // end namespace clang namespace swift { namespace markup { class SwiftDocWordExtractor : public MarkupASTWalker { CommandWordsPairs &Pairs; CodeCompletionCommandKind Kind; public: SwiftDocWordExtractor(CommandWordsPairs &Pairs) : Pairs(Pairs), Kind(CodeCompletionCommandKind::none) {} void visitKeywordField(const KeywordField *Field) override { Kind = CodeCompletionCommandKind::keyword; } void visitRecommendedField(const RecommendedField *Field) override { Kind = CodeCompletionCommandKind::recommended; } void visitRecommendedoverField(const RecommendedoverField *Field) override { Kind = CodeCompletionCommandKind::recommendedover; } void visitMutatingvariantField(const MutatingvariantField *Field) override { Kind = CodeCompletionCommandKind::mutatingvariant; } void visitNonmutatingvariantField(const NonmutatingvariantField *Field) override { Kind = CodeCompletionCommandKind::nonmutatingvariant; } void visitText(const Text *Text) override { if (Kind == CodeCompletionCommandKind::none) return; StringRef CommandName = getCommandName(Kind); std::vector Subs; splitTextByComma(Text->str(), Subs); for (auto S : Subs) Pairs.push_back(std::make_pair(CommandName, S)); } }; void getSwiftDocKeyword(const Decl* D, CommandWordsPairs &Words) { auto Interested = false; for (auto C : D->getRawComment().Comments) { if (containsInterestedWords(C.RawText, "-", /*AllowWhitespace*/true)) { Interested = true; break; } } if (!Interested) return; static swift::markup::MarkupContext MC; auto DC = getSingleDocComment(MC, D); if (!DC.hasValue()) return; SwiftDocWordExtractor Extractor(Words); for (auto Part : DC.getValue()->getBodyNodes()) { switch (Part->getKind()) { case ASTNodeKind::KeywordField: case ASTNodeKind::RecommendedField: case ASTNodeKind::RecommendedoverField: case ASTNodeKind::MutatingvariantField: case ASTNodeKind::NonmutatingvariantField: Extractor.walk(Part); break; default: break; } } } } // end namespace markup } // end namespace swift using DeclFilter = std::function; static bool DefaultFilter(ValueDecl* VD, DeclVisibilityKind Kind) { return true; } static bool KeyPathFilter(ValueDecl* decl, DeclVisibilityKind) { return isa(decl) || (isa(decl) && decl->getDeclContext()->isTypeContext()); } static bool SwiftKeyPathFilter(ValueDecl* decl, DeclVisibilityKind) { switch(decl->getKind()){ case DeclKind::Var: case DeclKind::Subscript: return true; default: return false; } } std::string swift::ide::removeCodeCompletionTokens( StringRef Input, StringRef TokenName, unsigned *CompletionOffset) { assert(TokenName.size() >= 1); *CompletionOffset = ~0U; std::string CleanFile; CleanFile.reserve(Input.size()); const std::string Token = std::string("#^") + TokenName.str() + "^#"; for (const char *Ptr = Input.begin(), *End = Input.end(); Ptr != End; ++Ptr) { const char C = *Ptr; if (C == '#' && Ptr <= End - Token.size() && StringRef(Ptr, Token.size()) == Token) { Ptr += Token.size() - 1; *CompletionOffset = CleanFile.size(); CleanFile += '\0'; continue; } if (C == '#' && Ptr <= End - 2 && Ptr[1] == '^') { do { Ptr++; } while (Ptr < End && *Ptr != '#'); if (Ptr == End) break; continue; } CleanFile += C; } return CleanFile; } namespace { class StmtFinder : public ASTWalker { SourceManager &SM; SourceLoc Loc; StmtKind Kind; Stmt *Found = nullptr; public: StmtFinder(SourceManager &SM, SourceLoc Loc, StmtKind Kind) : SM(SM), Loc(Loc), Kind(Kind) {} std::pair walkToStmtPre(Stmt *S) override { return { SM.rangeContainsTokenLoc(S->getSourceRange(), Loc), S }; } Stmt *walkToStmtPost(Stmt *S) override { if (S->getKind() == Kind) { Found = S; return nullptr; } return S; } Stmt *getFoundStmt() const { return Found; } }; } // end anonymous namespace static Stmt *findNearestStmt(const DeclContext *DC, SourceLoc Loc, StmtKind Kind) { auto &SM = DC->getASTContext().SourceMgr; StmtFinder Finder(SM, Loc, Kind); // FIXME(thread-safety): the walker is mutating the AST. const_cast(DC)->walkContext(Finder); return Finder.getFoundStmt(); } CodeCompletionString::CodeCompletionString(ArrayRef Chunks) { std::uninitialized_copy(Chunks.begin(), Chunks.end(), getTrailingObjects()); NumChunks = Chunks.size(); } CodeCompletionString *CodeCompletionString::create(llvm::BumpPtrAllocator &Allocator, ArrayRef Chunks) { void *CCSMem = Allocator.Allocate(totalSizeToAlloc(Chunks.size()), alignof(CodeCompletionString)); return new (CCSMem) CodeCompletionString(Chunks); } void CodeCompletionString::print(raw_ostream &OS) const { unsigned PrevNestingLevel = 0; for (auto C : getChunks()) { bool AnnotatedTextChunk = false; if (C.getNestingLevel() < PrevNestingLevel) { OS << "#}"; } switch (C.getKind()) { using ChunkKind = Chunk::ChunkKind; case ChunkKind::AccessControlKeyword: case ChunkKind::DeclAttrKeyword: case ChunkKind::DeclAttrParamKeyword: case ChunkKind::OverrideKeyword: case ChunkKind::ThrowsKeyword: case ChunkKind::RethrowsKeyword: case ChunkKind::DeclIntroducer: case ChunkKind::Text: case ChunkKind::LeftParen: case ChunkKind::RightParen: case ChunkKind::LeftBracket: case ChunkKind::RightBracket: case ChunkKind::LeftAngle: case ChunkKind::RightAngle: case ChunkKind::Dot: case ChunkKind::Ellipsis: case ChunkKind::Comma: case ChunkKind::ExclamationMark: case ChunkKind::QuestionMark: case ChunkKind::Ampersand: case ChunkKind::Equal: case ChunkKind::Whitespace: AnnotatedTextChunk = C.isAnnotation(); LLVM_FALLTHROUGH; case ChunkKind::CallParameterName: case ChunkKind::CallParameterInternalName: case ChunkKind::CallParameterColon: case ChunkKind::DeclAttrParamColon: case ChunkKind::CallParameterType: case ChunkKind::CallParameterClosureType: case ChunkKind::GenericParameterName: if (AnnotatedTextChunk) OS << "['"; else if (C.getKind() == ChunkKind::CallParameterInternalName) OS << "("; else if (C.getKind() == ChunkKind::CallParameterClosureType) OS << "##"; for (char Ch : C.getText()) { if (Ch == '\n') OS << "\\n"; else OS << Ch; } if (AnnotatedTextChunk) OS << "']"; else if (C.getKind() == ChunkKind::CallParameterInternalName) OS << ")"; break; case ChunkKind::OptionalBegin: case ChunkKind::CallParameterBegin: case ChunkKind::GenericParameterBegin: OS << "{#"; break; case ChunkKind::DynamicLookupMethodCallTail: case ChunkKind::OptionalMethodCallTail: OS << C.getText(); break; case ChunkKind::TypeAnnotation: OS << "[#"; OS << C.getText(); OS << "#]"; break; case ChunkKind::BraceStmtWithCursor: OS << " {|}"; break; } PrevNestingLevel = C.getNestingLevel(); } while (PrevNestingLevel > 0) { OS << "#}"; PrevNestingLevel--; } } void CodeCompletionString::dump() const { print(llvm::errs()); } CodeCompletionDeclKind CodeCompletionResult::getCodeCompletionDeclKind(const Decl *D) { switch (D->getKind()) { case DeclKind::Import: case DeclKind::Extension: case DeclKind::PatternBinding: case DeclKind::EnumCase: case DeclKind::TopLevelCode: case DeclKind::IfConfig: case DeclKind::PoundDiagnostic: case DeclKind::MissingMember: case DeclKind::OpaqueType: llvm_unreachable("not expecting such a declaration result"); case DeclKind::Module: return CodeCompletionDeclKind::Module; case DeclKind::TypeAlias: return CodeCompletionDeclKind::TypeAlias; case DeclKind::AssociatedType: return CodeCompletionDeclKind::AssociatedType; case DeclKind::GenericTypeParam: return CodeCompletionDeclKind::GenericTypeParam; case DeclKind::Enum: return CodeCompletionDeclKind::Enum; case DeclKind::Struct: return CodeCompletionDeclKind::Struct; case DeclKind::Class: return CodeCompletionDeclKind::Class; case DeclKind::Protocol: return CodeCompletionDeclKind::Protocol; case DeclKind::Var: case DeclKind::Param: { auto DC = D->getDeclContext(); if (DC->isTypeContext()) { if (cast(D)->isStatic()) return CodeCompletionDeclKind::StaticVar; else return CodeCompletionDeclKind::InstanceVar; } if (DC->isLocalContext()) return CodeCompletionDeclKind::LocalVar; return CodeCompletionDeclKind::GlobalVar; } case DeclKind::Constructor: return CodeCompletionDeclKind::Constructor; case DeclKind::Destructor: return CodeCompletionDeclKind::Destructor; case DeclKind::Accessor: case DeclKind::Func: { auto DC = D->getDeclContext(); auto FD = cast(D); if (DC->isTypeContext()) { if (FD->isStatic()) return CodeCompletionDeclKind::StaticMethod; return CodeCompletionDeclKind::InstanceMethod; } if (FD->isOperator()) { if (auto op = FD->getOperatorDecl()) { switch (op->getKind()) { case DeclKind::PrefixOperator: return CodeCompletionDeclKind::PrefixOperatorFunction; case DeclKind::PostfixOperator: return CodeCompletionDeclKind::PostfixOperatorFunction; case DeclKind::InfixOperator: return CodeCompletionDeclKind::InfixOperatorFunction; default: llvm_unreachable("unexpected operator kind"); } } else { return CodeCompletionDeclKind::InfixOperatorFunction; } } return CodeCompletionDeclKind::FreeFunction; } case DeclKind::InfixOperator: return CodeCompletionDeclKind::InfixOperatorFunction; case DeclKind::PrefixOperator: return CodeCompletionDeclKind::PrefixOperatorFunction; case DeclKind::PostfixOperator: return CodeCompletionDeclKind::PostfixOperatorFunction; case DeclKind::PrecedenceGroup: return CodeCompletionDeclKind::PrecedenceGroup; case DeclKind::EnumElement: return CodeCompletionDeclKind::EnumElement; case DeclKind::Subscript: return CodeCompletionDeclKind::Subscript; } llvm_unreachable("invalid DeclKind"); } void CodeCompletionResult::print(raw_ostream &OS) const { llvm::SmallString<64> Prefix; switch (getKind()) { case ResultKind::Declaration: Prefix.append("Decl"); switch (getAssociatedDeclKind()) { case CodeCompletionDeclKind::Class: Prefix.append("[Class]"); break; case CodeCompletionDeclKind::Struct: Prefix.append("[Struct]"); break; case CodeCompletionDeclKind::Enum: Prefix.append("[Enum]"); break; case CodeCompletionDeclKind::EnumElement: Prefix.append("[EnumElement]"); break; case CodeCompletionDeclKind::Protocol: Prefix.append("[Protocol]"); break; case CodeCompletionDeclKind::TypeAlias: Prefix.append("[TypeAlias]"); break; case CodeCompletionDeclKind::AssociatedType: Prefix.append("[AssociatedType]"); break; case CodeCompletionDeclKind::GenericTypeParam: Prefix.append("[GenericTypeParam]"); break; case CodeCompletionDeclKind::Constructor: Prefix.append("[Constructor]"); break; case CodeCompletionDeclKind::Destructor: Prefix.append("[Destructor]"); break; case CodeCompletionDeclKind::Subscript: Prefix.append("[Subscript]"); break; case CodeCompletionDeclKind::StaticMethod: Prefix.append("[StaticMethod]"); break; case CodeCompletionDeclKind::InstanceMethod: Prefix.append("[InstanceMethod]"); break; case CodeCompletionDeclKind::PrefixOperatorFunction: Prefix.append("[PrefixOperatorFunction]"); break; case CodeCompletionDeclKind::PostfixOperatorFunction: Prefix.append("[PostfixOperatorFunction]"); break; case CodeCompletionDeclKind::InfixOperatorFunction: Prefix.append("[InfixOperatorFunction]"); break; case CodeCompletionDeclKind::FreeFunction: Prefix.append("[FreeFunction]"); break; case CodeCompletionDeclKind::StaticVar: Prefix.append("[StaticVar]"); break; case CodeCompletionDeclKind::InstanceVar: Prefix.append("[InstanceVar]"); break; case CodeCompletionDeclKind::LocalVar: Prefix.append("[LocalVar]"); break; case CodeCompletionDeclKind::GlobalVar: Prefix.append("[GlobalVar]"); break; case CodeCompletionDeclKind::Module: Prefix.append("[Module]"); break; case CodeCompletionDeclKind::PrecedenceGroup: Prefix.append("[PrecedenceGroup]"); break; } break; case ResultKind::Keyword: Prefix.append("Keyword"); switch (getKeywordKind()) { case CodeCompletionKeywordKind::None: break; #define KEYWORD(X) case CodeCompletionKeywordKind::kw_##X: \ Prefix.append("[" #X "]"); \ break; #define POUND_KEYWORD(X) case CodeCompletionKeywordKind::pound_##X: \ Prefix.append("[#" #X "]"); \ break; #include "swift/Syntax/TokenKinds.def" } break; case ResultKind::Pattern: Prefix.append("Pattern"); break; case ResultKind::Literal: Prefix.append("Literal"); switch (getLiteralKind()) { case CodeCompletionLiteralKind::ArrayLiteral: Prefix.append("[Array]"); break; case CodeCompletionLiteralKind::BooleanLiteral: Prefix.append("[Boolean]"); break; case CodeCompletionLiteralKind::ColorLiteral: Prefix.append("[_Color]"); break; case CodeCompletionLiteralKind::ImageLiteral: Prefix.append("[_Image]"); break; case CodeCompletionLiteralKind::DictionaryLiteral: Prefix.append("[Dictionary]"); break; case CodeCompletionLiteralKind::IntegerLiteral: Prefix.append("[Integer]"); break; case CodeCompletionLiteralKind::NilLiteral: Prefix.append("[Nil]"); break; case CodeCompletionLiteralKind::StringLiteral: Prefix.append("[String]"); break; case CodeCompletionLiteralKind::Tuple: Prefix.append("[Tuple]"); break; } break; case ResultKind::BuiltinOperator: Prefix.append("BuiltinOperator"); break; } Prefix.append("/"); switch (getSemanticContext()) { case SemanticContextKind::None: Prefix.append("None"); break; case SemanticContextKind::ExpressionSpecific: Prefix.append("ExprSpecific"); break; case SemanticContextKind::Local: Prefix.append("Local"); break; case SemanticContextKind::CurrentNominal: Prefix.append("CurrNominal"); break; case SemanticContextKind::Super: Prefix.append("Super"); break; case SemanticContextKind::OutsideNominal: Prefix.append("OutNominal"); break; case SemanticContextKind::CurrentModule: Prefix.append("CurrModule"); break; case SemanticContextKind::OtherModule: Prefix.append("OtherModule"); if (!ModuleName.empty()) Prefix.append((Twine("[") + ModuleName + "]").str()); break; } if (NotRecommended) Prefix.append("/NotRecommended"); if (NumBytesToErase != 0) { Prefix.append("/Erase["); Prefix.append(Twine(NumBytesToErase).str()); Prefix.append("]"); } switch (TypeDistance) { case ExpectedTypeRelation::Invalid: Prefix.append("/TypeRelation[Invalid]"); break; case ExpectedTypeRelation::Identical: Prefix.append("/TypeRelation[Identical]"); break; case ExpectedTypeRelation::Convertible: Prefix.append("/TypeRelation[Convertible]"); break; case ExpectedTypeRelation::Unrelated: break; } for (clang::comments::WordPairsArrangedViewer Viewer(DocWords); Viewer.hasNext();) { auto Pair = Viewer.next(); Prefix.append("/"); Prefix.append(Pair.first); Prefix.append("["); StringRef Sep = ", "; for (auto KW : Pair.second) { Prefix.append(KW); Prefix.append(Sep); } for (unsigned I = 0, N = Sep.size(); I < N; ++I) Prefix.pop_back(); Prefix.append("]"); } Prefix.append(": "); while (Prefix.size() < 36) { Prefix.append(" "); } OS << Prefix; CompletionString->print(OS); } void CodeCompletionResult::dump() const { print(llvm::errs()); } static StringRef copyString(llvm::BumpPtrAllocator &Allocator, StringRef Str) { char *Mem = Allocator.Allocate(Str.size()); std::copy(Str.begin(), Str.end(), Mem); return StringRef(Mem, Str.size()); } static ArrayRef copyStringArray(llvm::BumpPtrAllocator &Allocator, ArrayRef Arr) { StringRef *Buff = Allocator.Allocate(Arr.size()); std::copy(Arr.begin(), Arr.end(), Buff); return llvm::makeArrayRef(Buff, Arr.size()); } static ArrayRef> copyStringPairArray( llvm::BumpPtrAllocator &Allocator, ArrayRef> Arr) { std::pair *Buff = Allocator.Allocate>(Arr.size()); std::copy(Arr.begin(), Arr.end(), Buff); return llvm::makeArrayRef(Buff, Arr.size()); } void CodeCompletionResultBuilder::addChunkWithText( CodeCompletionString::Chunk::ChunkKind Kind, StringRef Text) { addChunkWithTextNoCopy(Kind, copyString(*Sink.Allocator, Text)); } void CodeCompletionResultBuilder::setAssociatedDecl(const Decl *D) { assert(Kind == CodeCompletionResult::ResultKind::Declaration); AssociatedDecl = D; if (auto *ClangD = D->getClangDecl()) CurrentModule = ClangD->getImportedOwningModule(); // FIXME: macros // FIXME: imported header module if (!CurrentModule) CurrentModule = D->getModuleContext(); if (D->getAttrs().getDeprecated(D->getASTContext())) setNotRecommended(CodeCompletionResult::Deprecated); } StringRef CodeCompletionContext::copyString(StringRef Str) { return ::copyString(*CurrentResults.Allocator, Str); } bool shouldCopyAssociatedUSRForDecl(const ValueDecl *VD) { // Avoid trying to generate a USR for some declaration types. if (isa(VD) && !isa(VD)) return false; if (isa(VD)) return false; if (isa(VD)) return false; if (VD->hasClangNode() && !VD->getClangDecl()) return false; return true; } template static void walkValueDeclAndOverriddenDecls(const Decl *D, const FnTy &Fn) { if (auto *VD = dyn_cast(D)) { Fn(VD); walkOverriddenDecls(VD, Fn); } } ArrayRef copyAssociatedUSRs(llvm::BumpPtrAllocator &Allocator, const Decl *D) { llvm::SmallVector USRs; walkValueDeclAndOverriddenDecls(D, [&](llvm::PointerUnion OD) { llvm::SmallString<128> SS; bool Ignored = true; if (auto *OVD = OD.dyn_cast()) { if (shouldCopyAssociatedUSRForDecl(OVD)) { llvm::raw_svector_ostream OS(SS); Ignored = printDeclUSR(OVD, OS); } } else if (auto *OND = OD.dyn_cast()) { Ignored = clang::index::generateUSRForDecl(OND, SS); } if (!Ignored) USRs.push_back(copyString(Allocator, SS)); }); if (!USRs.empty()) return copyStringArray(Allocator, USRs); return ArrayRef(); } static CodeCompletionResult::ExpectedTypeRelation calculateTypeRelation( Type Ty, Type ExpectedTy, DeclContext *DC) { if (Ty.isNull() || ExpectedTy.isNull() || Ty->is() || ExpectedTy->is()) return CodeCompletionResult::ExpectedTypeRelation::Unrelated; // Equality/Conversion of GenericTypeParameterType won't account for // requirements – ignore them if (!Ty->hasTypeParameter() && !ExpectedTy->hasTypeParameter()) { if (Ty->isEqual(ExpectedTy)) return CodeCompletionResult::ExpectedTypeRelation::Identical; if (!ExpectedTy->isAny() && isConvertibleTo(Ty, ExpectedTy, *DC)) return CodeCompletionResult::ExpectedTypeRelation::Convertible; } if (auto FT = Ty->getAs()) { if (FT->getResult()->isVoid()) return CodeCompletionResult::ExpectedTypeRelation::Invalid; } return CodeCompletionResult::ExpectedTypeRelation::Unrelated; } static CodeCompletionResult::ExpectedTypeRelation calculateTypeRelationForDecl(const Decl *D, Type ExpectedType, bool IsImplicitlyCurriedInstanceMethod, bool UseFuncResultType = true) { auto VD = dyn_cast(D); auto DC = D->getDeclContext(); if (!VD || !VD->hasInterfaceType()) return CodeCompletionResult::ExpectedTypeRelation::Unrelated; if (auto FD = dyn_cast(VD)) { auto funcType = FD->getInterfaceType()->getAs(); if (DC->isTypeContext() && funcType && funcType->is() && !IsImplicitlyCurriedInstanceMethod) funcType = funcType->getResult()->getAs(); if (funcType) { funcType = funcType->removeArgumentLabels(1)->castTo(); auto relation = calculateTypeRelation(funcType, ExpectedType, DC); if (UseFuncResultType) relation = std::max(relation, calculateTypeRelation(funcType->getResult(), ExpectedType, DC)); return relation; } } if (auto NTD = dyn_cast(VD)) { return std::max( calculateTypeRelation(NTD->getInterfaceType(), ExpectedType, DC), calculateTypeRelation(NTD->getDeclaredInterfaceType(), ExpectedType, DC)); } return calculateTypeRelation(VD->getInterfaceType(), ExpectedType, DC); } static CodeCompletionResult::ExpectedTypeRelation calculateMaxTypeRelationForDecl( const Decl *D, const ExpectedTypeContext &typeContext, bool IsImplicitlyCurriedInstanceMethod = false) { auto Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated; for (auto Type : typeContext.possibleTypes) { // Do not use Void type context for a single-expression body, since the // implicit return does not constrain the expression. // // { ... -> () in x } // x can be anything // // This behaves differently from explicit return, and from non-Void: // // { ... -> Int in x } // x must be Int // { ... -> () in return x } // x must be Void if (typeContext.isSingleExpressionBody && Type->isVoid()) continue; Result = std::max(Result, calculateTypeRelationForDecl( D, Type, IsImplicitlyCurriedInstanceMethod)); // Map invalid -> unrelated when in a single-expression body, since the // input may be incomplete. if (typeContext.isSingleExpressionBody && Result == CodeCompletionResult::ExpectedTypeRelation::Invalid) Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated; } return Result; } CodeCompletionOperatorKind CodeCompletionResult::getCodeCompletionOperatorKind(StringRef name) { using CCOK = CodeCompletionOperatorKind; using OpPair = std::pair; // This list must be kept in alphabetical order. static OpPair ops[] = { std::make_pair("!", CCOK::Bang), std::make_pair("!=", CCOK::NotEq), std::make_pair("!==", CCOK::NotEqEq), std::make_pair("%", CCOK::Modulo), std::make_pair("%=", CCOK::ModuloEq), std::make_pair("&", CCOK::Amp), std::make_pair("&&", CCOK::AmpAmp), std::make_pair("&*", CCOK::AmpStar), std::make_pair("&+", CCOK::AmpPlus), std::make_pair("&-", CCOK::AmpMinus), std::make_pair("&=", CCOK::AmpEq), std::make_pair("(", CCOK::LParen), std::make_pair("*", CCOK::Star), std::make_pair("*=", CCOK::StarEq), std::make_pair("+", CCOK::Plus), std::make_pair("+=", CCOK::PlusEq), std::make_pair("-", CCOK::Minus), std::make_pair("-=", CCOK::MinusEq), std::make_pair(".", CCOK::Dot), std::make_pair("...", CCOK::DotDotDot), std::make_pair("..<", CCOK::DotDotLess), std::make_pair("/", CCOK::Slash), std::make_pair("/=", CCOK::SlashEq), std::make_pair("<", CCOK::Less), std::make_pair("<<", CCOK::LessLess), std::make_pair("<<=", CCOK::LessLessEq), std::make_pair("<=", CCOK::LessEq), std::make_pair("=", CCOK::Eq), std::make_pair("==", CCOK::EqEq), std::make_pair("===", CCOK::EqEqEq), std::make_pair(">", CCOK::Greater), std::make_pair(">=", CCOK::GreaterEq), std::make_pair(">>", CCOK::GreaterGreater), std::make_pair(">>=", CCOK::GreaterGreaterEq), std::make_pair("?.", CCOK::QuestionDot), std::make_pair("^", CCOK::Caret), std::make_pair("^=", CCOK::CaretEq), std::make_pair("|", CCOK::Pipe), std::make_pair("|=", CCOK::PipeEq), std::make_pair("||", CCOK::PipePipe), std::make_pair("~=", CCOK::TildeEq), }; static auto opsSize = sizeof(ops) / sizeof(ops[0]); auto I = std::lower_bound( ops, &ops[opsSize], std::make_pair(name, CCOK::None), [](const OpPair &a, const OpPair &b) { return a.first < b.first; }); if (I == &ops[opsSize] || I->first != name) return CCOK::Unknown; return I->second; } static StringRef getOperatorName(CodeCompletionString *str) { return str->getFirstTextChunk(/*includeLeadingPunctuation=*/true); } CodeCompletionOperatorKind CodeCompletionResult::getCodeCompletionOperatorKind(CodeCompletionString *str) { return getCodeCompletionOperatorKind(getOperatorName(str)); } CodeCompletionResult *CodeCompletionResultBuilder::takeResult() { auto *CCS = CodeCompletionString::create(*Sink.Allocator, Chunks); switch (Kind) { case CodeCompletionResult::ResultKind::Declaration: { StringRef BriefComment; auto MaybeClangNode = AssociatedDecl->getClangNode(); if (MaybeClangNode) { if (auto *D = MaybeClangNode.getAsDecl()) { const auto &ClangContext = D->getASTContext(); if (const clang::RawComment *RC = ClangContext.getRawCommentForAnyRedecl(D)) BriefComment = RC->getBriefText(ClangContext); } } else { BriefComment = AssociatedDecl->getBriefComment(); } StringRef ModuleName; if (CurrentModule) { if (Sink.LastModule.first == CurrentModule.getOpaqueValue()) { ModuleName = Sink.LastModule.second; } else { if (auto *C = CurrentModule.dyn_cast()) { ModuleName = copyString(*Sink.Allocator, C->getFullModuleName()); } else { ModuleName = copyString( *Sink.Allocator, CurrentModule.get()->getName().str()); } Sink.LastModule.first = CurrentModule.getOpaqueValue(); Sink.LastModule.second = ModuleName; } } auto typeRelation = ExpectedTypeRelation; if (typeRelation == CodeCompletionResult::Unrelated) typeRelation = calculateMaxTypeRelationForDecl(AssociatedDecl, declTypeContext); if (typeRelation == CodeCompletionResult::Invalid) { IsNotRecommended = true; NotRecReason = CodeCompletionResult::NotRecommendedReason::TypeMismatch; } return new (*Sink.Allocator) CodeCompletionResult( SemanticContext, NumBytesToErase, CCS, AssociatedDecl, ModuleName, /*NotRecommended=*/IsNotRecommended, NotRecReason, copyString(*Sink.Allocator, BriefComment), copyAssociatedUSRs(*Sink.Allocator, AssociatedDecl), copyStringPairArray(*Sink.Allocator, CommentWords), typeRelation); } case CodeCompletionResult::ResultKind::Keyword: return new (*Sink.Allocator) CodeCompletionResult(KeywordKind, SemanticContext, NumBytesToErase, CCS, ExpectedTypeRelation); case CodeCompletionResult::ResultKind::BuiltinOperator: case CodeCompletionResult::ResultKind::Pattern: return new (*Sink.Allocator) CodeCompletionResult( Kind, SemanticContext, NumBytesToErase, CCS, ExpectedTypeRelation); case CodeCompletionResult::ResultKind::Literal: assert(LiteralKind.hasValue()); return new (*Sink.Allocator) CodeCompletionResult(*LiteralKind, SemanticContext, NumBytesToErase, CCS, ExpectedTypeRelation); } llvm_unreachable("Unhandled CodeCompletionResult in switch."); } void CodeCompletionResultBuilder::finishResult() { if (!Cancelled) Sink.Results.push_back(takeResult()); } MutableArrayRef CodeCompletionContext::takeResults() { // Copy pointers to the results. const size_t Count = CurrentResults.Results.size(); CodeCompletionResult **Results = CurrentResults.Allocator->Allocate(Count); std::copy(CurrentResults.Results.begin(), CurrentResults.Results.end(), Results); CurrentResults.Results.clear(); return MutableArrayRef(Results, Count); } Optional CodeCompletionString::getFirstTextChunkIndex( bool includeLeadingPunctuation) const { for (auto i : indices(getChunks())) { auto &C = getChunks()[i]; switch (C.getKind()) { using ChunkKind = Chunk::ChunkKind; case ChunkKind::Text: case ChunkKind::CallParameterName: case ChunkKind::CallParameterInternalName: case ChunkKind::GenericParameterName: case ChunkKind::LeftParen: case ChunkKind::LeftBracket: case ChunkKind::Equal: case ChunkKind::DeclAttrParamKeyword: case ChunkKind::DeclAttrKeyword: return i; case ChunkKind::Dot: case ChunkKind::ExclamationMark: case ChunkKind::QuestionMark: if (includeLeadingPunctuation) return i; continue; case ChunkKind::RightParen: case ChunkKind::RightBracket: case ChunkKind::LeftAngle: case ChunkKind::RightAngle: case ChunkKind::Ellipsis: case ChunkKind::Comma: case ChunkKind::Ampersand: case ChunkKind::Whitespace: case ChunkKind::AccessControlKeyword: case ChunkKind::OverrideKeyword: case ChunkKind::ThrowsKeyword: case ChunkKind::RethrowsKeyword: case ChunkKind::DeclIntroducer: case ChunkKind::CallParameterColon: case ChunkKind::DeclAttrParamColon: case ChunkKind::CallParameterType: case ChunkKind::CallParameterClosureType: case ChunkKind::OptionalBegin: case ChunkKind::CallParameterBegin: case ChunkKind::GenericParameterBegin: case ChunkKind::DynamicLookupMethodCallTail: case ChunkKind::OptionalMethodCallTail: case ChunkKind::TypeAnnotation: continue; case ChunkKind::BraceStmtWithCursor: llvm_unreachable("should have already extracted the text"); } } return None; } StringRef CodeCompletionString::getFirstTextChunk(bool includeLeadingPunctuation) const { Optional Idx = getFirstTextChunkIndex(includeLeadingPunctuation); if (Idx.hasValue()) return getChunks()[*Idx].getText(); return StringRef(); } void CodeCompletionString::getName(raw_ostream &OS) const { auto FirstTextChunk = getFirstTextChunkIndex(); int TextSize = 0; if (FirstTextChunk.hasValue()) { for (auto C : getChunks().slice(*FirstTextChunk)) { using ChunkKind = Chunk::ChunkKind; bool shouldPrint = !C.isAnnotation(); switch (C.getKind()) { case ChunkKind::TypeAnnotation: case ChunkKind::CallParameterClosureType: case ChunkKind::DeclAttrParamColon: case ChunkKind::OptionalMethodCallTail: continue; case ChunkKind::ThrowsKeyword: case ChunkKind::RethrowsKeyword: shouldPrint = true; // Even when they're annotations. break; default: break; } if (C.hasText() && shouldPrint) { TextSize += C.getText().size(); OS << C.getText(); } } } } void CodeCompletionContext::sortCompletionResults( MutableArrayRef Results) { struct ResultAndName { CodeCompletionResult *result; std::string name; }; // Caching the name of each field is important to avoid unnecessary calls to // CodeCompletionString::getName(). std::vector nameCache(Results.size()); for (unsigned i = 0, n = Results.size(); i < n; ++i) { auto *result = Results[i]; nameCache[i].result = result; llvm::raw_string_ostream OS(nameCache[i].name); result->getCompletionString()->getName(OS); OS.flush(); } // Sort nameCache, and then transform Results to return the pointers in order. std::sort(nameCache.begin(), nameCache.end(), [](const ResultAndName &LHS, const ResultAndName &RHS) { int Result = StringRef(LHS.name).compare_lower(RHS.name); // If the case insensitive comparison is equal, then secondary sort order // should be case sensitive. if (Result == 0) Result = LHS.name.compare(RHS.name); return Result < 0; }); std::transform(nameCache.begin(), nameCache.end(), Results.begin(), [](const ResultAndName &entry) { return entry.result; }); } namespace { class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks { CodeCompletionContext &CompletionContext; std::vector RequestedModules; CodeCompletionConsumer &Consumer; CodeCompletionExpr *CodeCompleteTokenExpr = nullptr; AssignExpr *AssignmentExpr; CompletionKind Kind = CompletionKind::None; Expr *ParsedExpr = nullptr; SourceLoc DotLoc; TypeLoc ParsedTypeLoc; DeclContext *CurDeclContext = nullptr; DeclAttrKind AttrKind; /// In situations when \c SyntaxKind hints or determines /// completions, i.e. a precedence group attribute, this /// can be set and used to control the code completion scenario. SyntaxKind SyntxKind; int AttrParamIndex; bool IsInSil = false; bool HasSpace = false; bool ShouldCompleteCallPatternAfterParen = true; bool PreferFunctionReferencesToCalls = false; Optional AttTargetDK; Optional ParentStmtKind; SmallVector ParsedKeywords; SourceLoc introducerLoc; std::vector> SubModuleNameVisibilityPairs; void addSuperKeyword(CodeCompletionResultSink &Sink) { auto *DC = CurDeclContext->getInnermostTypeContext(); if (!DC) return; auto *CD = DC->getSelfClassDecl(); if (!CD) return; Type ST = CD->getSuperclass(); if (ST.isNull() || ST->is()) return; CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::CurrentNominal, {}); Builder.setKeywordKind(CodeCompletionKeywordKind::kw_super); Builder.addTextChunk("super"); Builder.addTypeAnnotation(ST.getString()); } /// Set to true when we have delivered code completion results /// to the \c Consumer. bool DeliveredResults = false; Optional> typeCheckParsedExpr() { assert(ParsedExpr && "should have an expression"); // Figure out the kind of type-check we'll be performing. auto CheckKind = CompletionTypeCheckKind::Normal; if (Kind == CompletionKind::KeyPathExprObjC) CheckKind = CompletionTypeCheckKind::KeyPath; // If we've already successfully type-checked the expression for some // reason, just return the type. // FIXME: if it's ErrorType but we've already typechecked we shouldn't // typecheck again. rdar://21466394 if (CheckKind == CompletionTypeCheckKind::Normal && ParsedExpr->getType() && !ParsedExpr->getType()->is()) { auto refDecl = ParsedExpr->getReferencedDecl(); if (!refDecl) { if (auto apply = dyn_cast(ParsedExpr)) refDecl = apply->getFn()->getReferencedDecl(); } return std::make_pair(ParsedExpr->getType(), refDecl); } ConcreteDeclRef ReferencedDecl = nullptr; Expr *ModifiedExpr = ParsedExpr; if (auto T = getTypeOfCompletionContextExpr(P.Context, CurDeclContext, CheckKind, ModifiedExpr, ReferencedDecl)) { // FIXME: even though we don't apply the solution, the type checker may // modify the original expression. We should understand what effect that // may have on code completion. ParsedExpr = ModifiedExpr; return std::make_pair(*T, ReferencedDecl); } return None; } /// \returns true on success, false on failure. bool typecheckParsedType() { assert(ParsedTypeLoc.getTypeRepr() && "should have a TypeRepr"); return !performTypeLocChecking(P.Context, ParsedTypeLoc, CurDeclContext, false); } public: CodeCompletionCallbacksImpl(Parser &P, CodeCompletionContext &CompletionContext, CodeCompletionConsumer &Consumer) : CodeCompletionCallbacks(P), CompletionContext(CompletionContext), Consumer(Consumer) { } void completeExpr() override; void completeDotExpr(Expr *E, SourceLoc DotLoc) override; void completeStmtOrExpr(CodeCompletionExpr *E) override; void completePostfixExprBeginning(CodeCompletionExpr *E) override; void completeForEachSequenceBeginning(CodeCompletionExpr *E) override; void completePostfixExpr(Expr *E, bool hasSpace) override; void completePostfixExprParen(Expr *E, Expr *CodeCompletionE) override; void completeExprSuper(SuperRefExpr *SRE) override; void completeExprSuperDot(SuperRefExpr *SRE) override; void completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) override; void completeTypeDeclResultBeginning() override; void completeTypeSimpleBeginning() override; void completeTypeIdentifierWithDot(IdentTypeRepr *ITR) override; void completeTypeIdentifierWithoutDot(IdentTypeRepr *ITR) override; void completeCaseStmtKeyword() override; void completeCaseStmtBeginning() override; void completeCaseStmtDotPrefix() override; void completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) override; void completeDeclAttrParam(DeclAttrKind DK, int Index) override; void completeInPrecedenceGroup(SyntaxKind SK) override; void completeNominalMemberBeginning( SmallVectorImpl &Keywords, SourceLoc introducerLoc) override; void completeAccessorBeginning(CodeCompletionExpr *E) override; void completePoundAvailablePlatform() override; void completeImportDecl(std::vector> &Path) override; void completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) override; void completeAssignmentRHS(AssignExpr *E) override; void completeCallArg(CodeCompletionExpr *E) override; void completeReturnStmt(CodeCompletionExpr *E) override; void completeYieldStmt(CodeCompletionExpr *E, Optional yieldIndex) override; void completeAfterPoundExpr(CodeCompletionExpr *E, Optional ParentKind) override; void completeAfterPoundDirective() override; void completePlatformCondition() override; void completeGenericParams(TypeLoc TL) override; void completeAfterIfStmt(bool hasElse) override; void doneParsing() override; private: void addKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody); void deliverCompletionResults(); }; } // end anonymous namespace void CodeCompletionCallbacksImpl::completeExpr() { if (DeliveredResults) return; Parser::ParserPositionRAII RestorePosition(P); P.restoreParserPosition(ExprBeginPosition); // FIXME: implement fallback code completion. deliverCompletionResults(); } namespace { static bool isTopLevelContext(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."); } /// Whether funcType has a single argument (not including defaulted arguments) /// that is of type () -> (). static bool hasTrivialTrailingClosure(const FuncDecl *FD, AnyFunctionType *funcType) { SmallBitVector defaultMap = computeDefaultMap(funcType->getParams(), FD, /*level*/ FD->isInstanceMember() ? 1 : 0); if (defaultMap.size() - defaultMap.count() == 1) { auto param = funcType->getParams().back(); if (!param.isAutoClosure()) { if (auto Fn = param.getOldType()->getAs()) { return Fn->getParams().empty() && Fn->getResult()->isVoid(); } } } return false; } /// Build completions by doing visible decl lookup from a context. class CompletionLookup final : public swift::VisibleDeclConsumer { CodeCompletionResultSink &Sink; ASTContext &Ctx; LazyResolver *TypeResolver = nullptr; const DeclContext *CurrDeclContext; ClangImporter *Importer; CodeCompletionContext *CompletionContext; enum class LookupKind { ValueExpr, ValueInDeclContext, EnumElement, Type, TypeInDeclContext, ImportFromModule }; LookupKind Kind; /// Type of the user-provided expression for LookupKind::ValueExpr /// completions. Type ExprType; /// Whether the expr is of statically inferred metatype. bool IsStaticMetatype = false; /// User-provided base type for LookupKind::Type completions. Type BaseType; /// Expected types of the code completion expression. ExpectedTypeContext expectedTypeContext; bool HaveDot = false; bool IsUnwrappedOptional = false; SourceLoc DotLoc; bool NeedLeadingDot = false; bool NeedOptionalUnwrap = false; unsigned NumBytesToEraseForOptionalUnwrap = 0; bool HaveLParen = false; bool IsSuperRefExpr = false; bool IsSelfRefExpr = false; bool IsKeyPathExpr = false; bool IsSwiftKeyPathExpr = false; bool IsAfterSwiftKeyPathRoot = false; bool IsDynamicLookup = false; bool PreferFunctionReferencesToCalls = false; bool HaveLeadingSpace = false; bool IncludeInstanceMembers = false; /// True if we are code completing inside a static method. bool InsideStaticMethod = false; /// Innermost method that the code completion point is in. const AbstractFunctionDecl *CurrentMethod = nullptr; Optional ForcedSemanticContext = None; bool IsUnresolvedMember = false; public: bool FoundFunctionCalls = false; bool FoundFunctionsWithoutFirstKeyword = false; private: void foundFunction(const AbstractFunctionDecl *AFD) { FoundFunctionCalls = true; DeclName Name = AFD->getFullName(); auto ArgNames = Name.getArgumentNames(); if (ArgNames.empty()) return; if (ArgNames[0].empty()) FoundFunctionsWithoutFirstKeyword = true; } void 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; } void setClangDeclKeywords(const ValueDecl *VD, CommandWordsPairs &Pairs, CodeCompletionResultBuilder &Builder) { if (auto *CD = VD->getClangDecl()) { clang::comments::getClangDocKeyword(*Importer, CD, Pairs); } else { swift::markup::getSwiftDocKeyword(VD, Pairs); } Builder.addDeclDocCommentWords(llvm::makeArrayRef(Pairs)); } bool shouldUseFunctionReference(AbstractFunctionDecl *D) { if (PreferFunctionReferencesToCalls) return true; bool isImplicitlyCurriedIM = isImplicitlyCurriedInstanceMethod(D); for (auto expectedType : expectedTypeContext.possibleTypes) { if (expectedType && expectedType->lookThroughAllOptionalTypes() ->is() && calculateTypeRelationForDecl(D, expectedType, isImplicitlyCurriedIM, /*UseFuncResultType=*/false) >= CodeCompletionResult::ExpectedTypeRelation::Convertible) { return true; } } return false; } public: struct RequestedResultsTy { const ModuleDecl *TheModule; bool OnlyTypes; bool OnlyPrecedenceGroups; bool NeedLeadingDot; static RequestedResultsTy fromModule(const ModuleDecl *TheModule) { return { TheModule, false, false, false }; } RequestedResultsTy onlyTypes() const { return { TheModule, true, false, NeedLeadingDot }; } RequestedResultsTy onlyPrecedenceGroups() const { assert(!OnlyTypes && "onlyTypes() already includes precedence groups"); return { TheModule, false, true, false }; } RequestedResultsTy needLeadingDot(bool NeedDot) const { return { TheModule, OnlyTypes, OnlyPrecedenceGroups, NeedDot }; } static RequestedResultsTy toplevelResults() { return { nullptr, false, false, false }; } }; std::vector RequestedCachedResults; public: CompletionLookup(CodeCompletionResultSink &Sink, ASTContext &Ctx, const DeclContext *CurrDeclContext, CodeCompletionContext *CompletionContext = nullptr) : Sink(Sink), Ctx(Ctx), CurrDeclContext(CurrDeclContext), Importer(static_cast(CurrDeclContext->getASTContext(). getClangModuleLoader())), CompletionContext(CompletionContext) { (void)createTypeChecker(Ctx); TypeResolver = Ctx.getLazyResolver(); // 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(); } } void setHaveDot(SourceLoc DotLoc) { HaveDot = true; this->DotLoc = DotLoc; } void setIsUnwrappedOptional(bool value) { IsUnwrappedOptional = value; } void setIsStaticMetatype(bool value) { IsStaticMetatype = value; } void setExpectedTypes(ArrayRef Types, bool isSingleExpressionBody) { expectedTypeContext.isSingleExpressionBody = isSingleExpressionBody; expectedTypeContext.possibleTypes.clear(); expectedTypeContext.possibleTypes.reserve(Types.size()); for (auto T : Types) if (T) expectedTypeContext.possibleTypes.push_back(T); } CodeCompletionContext::TypeContextKind typeContextKind() const { if (expectedTypeContext.empty()) { return CodeCompletionContext::TypeContextKind::None; } else if (expectedTypeContext.isSingleExpressionBody) { return CodeCompletionContext::TypeContextKind::SingleExpressionBody; } else { return CodeCompletionContext::TypeContextKind::Required; } } bool needDot() const { return NeedLeadingDot; } void setHaveLParen(bool Value) { HaveLParen = Value; } void setIsSuperRefExpr() { IsSuperRefExpr = true; } void setIsSelfRefExpr(bool value) { IsSelfRefExpr = value; } void setIsKeyPathExpr() { IsKeyPathExpr = true; } void setIsSwiftKeyPathExpr(bool onRoot) { IsSwiftKeyPathExpr = true; IsAfterSwiftKeyPathRoot = onRoot; } void setIsDynamicLookup() { IsDynamicLookup = true; } void setPreferFunctionReferencesToCalls() { PreferFunctionReferencesToCalls = true; } void setHaveLeadingSpace(bool value) { HaveLeadingSpace = value; } void includeInstanceMembers() { IncludeInstanceMembers = true; } void addSubModuleNames(std::vector> &SubModuleNameVisibilityPairs) { for (auto &Pair : SubModuleNameVisibilityPairs) { CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind:: Declaration, SemanticContextKind::OtherModule, expectedTypeContext); auto MD = ModuleDecl::create(Ctx.getIdentifier(Pair.first), Ctx); Builder.setAssociatedDecl(MD); Builder.addTextChunk(MD->getNameStr()); Builder.addTypeAnnotation("Module"); if (Pair.second) Builder.setNotRecommended(CodeCompletionResult::NotRecommendedReason:: Redundant); } } void collectImportedModules(llvm::StringSet<> &ImportedModules) { ModuleDecl::ImportFilter ImportFilter; ImportFilter |= ModuleDecl::ImportFilterKind::Public; ImportFilter |= ModuleDecl::ImportFilterKind::Private; ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; SmallVector Imported; SmallVector FurtherImported; CurrDeclContext->getParentSourceFile()->getImportedModules(Imported, ImportFilter); while (!Imported.empty()) { ModuleDecl *MD = Imported.back().second; Imported.pop_back(); if (!ImportedModules.insert(MD->getNameStr()).second) continue; FurtherImported.clear(); MD->getImportedModules(FurtherImported, ModuleDecl::ImportFilterKind::Public); Imported.append(FurtherImported.begin(), FurtherImported.end()); for (auto SubMod : FurtherImported) { Imported.push_back(SubMod); } } } void addImportModuleNames() { // FIXME: Add user-defined swift modules SmallVector ModuleNames; // Collect clang module names. { SmallVector ClangModules; Ctx.getVisibleTopLevelClangModules(ClangModules); for (auto *M : ClangModules) { if (!M->isAvailable()) continue; if (M->getTopLevelModuleName().startswith("_")) continue; if (M->getTopLevelModuleName() == Ctx.SwiftShimsModuleName.str()) continue; ModuleNames.push_back(M->getTopLevelModuleName()); } } std::sort(ModuleNames.begin(), ModuleNames.end(), [](StringRef LHS, StringRef RHS) { return LHS.compare_lower(RHS) < 0; }); llvm::StringSet<> ImportedModules; collectImportedModules(ImportedModules); for (auto ModuleName : ModuleNames) { auto MD = ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx); CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::OtherModule, expectedTypeContext); Builder.setAssociatedDecl(MD); Builder.addTextChunk(MD->getNameStr()); Builder.addTypeAnnotation("Module"); // Imported modules are not recommended. if (ImportedModules.count(MD->getNameStr()) != 0) Builder.setNotRecommended( CodeCompletionResult::NotRecommendedReason::Redundant); } } SemanticContextKind getSemanticContext(const Decl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (ForcedSemanticContext) return *ForcedSemanticContext; if (IsUnresolvedMember) { if (isa(D)) { return SemanticContextKind::ExpressionSpecific; } } switch (Reason) { case DeclVisibilityKind::LocalVariable: case DeclVisibilityKind::FunctionParameter: case DeclVisibilityKind::GenericParameter: return SemanticContextKind::Local; case DeclVisibilityKind::MemberOfCurrentNominal: if (IsSuperRefExpr && CurrentMethod && CurrentMethod->getOverriddenDecl() == D) return SemanticContextKind::ExpressionSpecific; return SemanticContextKind::CurrentNominal; case DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal: case DeclVisibilityKind::MemberOfSuper: return SemanticContextKind::Super; case DeclVisibilityKind::MemberOfOutsideNominal: return SemanticContextKind::OutsideNominal; case DeclVisibilityKind::VisibleAtTopLevel: if (CurrDeclContext && D->getModuleContext() == CurrDeclContext->getParentModule()) { // Treat global variables from the same source file as local when // completing at top-level. if (isa(D) && isTopLevelContext(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, {}); } } llvm_unreachable("unhandled kind"); } void addValueBaseName(CodeCompletionResultBuilder &Builder, DeclBaseName Name) { auto NameStr = Name.userFacingName(); 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.addTextChunk(NameStr); } else { SmallString<16> buffer; Builder.addTextChunk(Builder.escapeKeyword(NameStr, true, buffer)); } } void addLeadingDot(CodeCompletionResultBuilder &Builder) { if (NeedOptionalUnwrap) { Builder.setNumBytesToErase(NumBytesToEraseForOptionalUnwrap); Builder.addQuestionMark(); Builder.addLeadingDot(); return; } if (needDot()) Builder.addLeadingDot(); } void addTypeAnnotation(CodeCompletionResultBuilder &Builder, Type T) { T = T->getReferenceStorageReferent(); if (T->isVoid()) { Builder.addTypeAnnotation("Void"); } else { PrintOptions PO; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; Builder.addTypeAnnotation(T.getString(PO)); } } void addTypeAnnotationForImplicitlyUnwrappedOptional( CodeCompletionResultBuilder &Builder, Type T, bool dynamicOrOptional = false) { 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 = "?"; } T = T->getReferenceStorageReferent(); PrintOptions PO; PO.PrintOptionalAsImplicitlyUnwrapped = true; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; Builder.addTypeAnnotation(T.getString(PO) + suffix); } /// For printing in code completion results, replace archetypes with /// protocol compositions. /// /// FIXME: Perhaps this should be an option in PrintOptions instead. Type eraseArchetypes(ModuleDecl *M, Type type, GenericSignature *genericSig) { if (!genericSig) return type; auto buildProtocolComposition = [&](ArrayRef protos) -> Type { SmallVector types; for (auto proto : protos) types.push_back(proto->getDeclaredInterfaceType()); return ProtocolCompositionType::get(M->getASTContext(), types, /*HasExplicitAnyObject=*/false); }; if (auto *genericFuncType = type->getAs()) { SmallVector erasedParams; for (const auto ¶m : genericFuncType->getParams()) { auto erasedTy = eraseArchetypes(M, param.getPlainType(), genericSig); erasedParams.emplace_back(erasedTy, param.getLabel(), param.getParameterFlags()); } return GenericFunctionType::get(genericSig, erasedParams, eraseArchetypes(M, genericFuncType->getResult(), genericSig), genericFuncType->getExtInfo()); } return type.transform([&](Type t) -> Type { // 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)) return t; auto protos = archetypeType->getConformsTo(); if (!protos.empty()) return buildProtocolComposition(protos); } if (t->isTypeParameter()) { auto protos = genericSig->getConformsTo(t); if (!protos.empty()) return buildProtocolComposition(protos); } return t; }); } Type getTypeOfMember(const ValueDecl *VD, Optional ExprType = None) { if (!ExprType) ExprType = this->ExprType; auto *M = CurrDeclContext->getParentModule(); auto *GenericSig = VD->getInnermostDeclContext() ->getGenericSignatureOfContext(); assert(VD->hasValidSignature()); Type T = VD->getInterfaceType(); 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; // For everything else, substitute in the base type. auto Subs = MaybeNominalType->getMemberSubstitutionMap(M, VD); // Pass in DesugarMemberTypes so that we see the actual // concrete type witnesses instead of type alias types. T = T.subst(Subs, (SubstFlags::DesugarMemberTypes | SubstFlags::UseErrorType)); } } return eraseArchetypes(M, T, GenericSig); } Type getAssociatedTypeType(const AssociatedTypeDecl *ATD) { Type BaseTy = BaseType; if (!BaseTy) BaseTy = ExprType; if (!BaseTy && CurrDeclContext) BaseTy = CurrDeclContext->getInnermostTypeContext() ->getDeclaredTypeInContext(); if (BaseTy) { BaseTy = BaseTy->getInOutObjectType()->getMetatypeInstanceType(); if (auto NTD = BaseTy->getAnyNominal()) { auto *Module = NTD->getParentModule(); auto Conformance = Module->lookupConformance( BaseTy, ATD->getProtocol()); if (Conformance && Conformance->isConcrete()) { return Conformance->getConcrete() ->getTypeWitness(const_cast(ATD), nullptr); } } } return Type(); } void addVarDeclRef(const VarDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (!VD->hasName() || !VD->isAccessibleFrom(CurrDeclContext) || VD->shouldHideFromEditor()) return; Identifier Name = VD->getName(); assert(!Name.empty() && "name should not be empty"); CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(VD, Reason, dynamicLookupInfo), expectedTypeContext); Builder.setAssociatedDecl(VD); addLeadingDot(Builder); addValueBaseName(Builder, Name); setClangDeclKeywords(VD, Pairs, Builder); if (!VD->hasValidSignature()) return; // Add a type annotation. Type VarType = getTypeOfMember(VD); if (Name != Ctx.Id_self && VD->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); } if (VD->getAttrs().hasAttribute()) addTypeAnnotationForImplicitlyUnwrappedOptional(Builder, VarType, DynamicOrOptional); else addTypeAnnotation(Builder, VarType); } static bool hasInterestingDefaultValues(const AbstractFunctionDecl *func) { if (!func) return false; for (auto param : *func->getParameters()) { switch (param->getDefaultArgumentKind()) { case DefaultArgumentKind::Normal: case DefaultArgumentKind::StoredProperty: case DefaultArgumentKind::Inherited: // FIXME: include this? return true; default: break; } } return false; } /// Build argument patterns for calling. Returns \c true if any content was /// added to \p Builder. If \p declParams is non-empty, the size must match /// with \p typeParams. bool addCallArgumentPatterns(CodeCompletionResultBuilder &Builder, ArrayRef typeParams, ArrayRef declParams, bool includeDefaultArgs = true) { assert(declParams.empty() || typeParams.size() == declParams.size()); bool modifiedBuilder = false; // Determine whether we should skip this argument because it is defaulted. auto shouldSkipArg = [&](const ParamDecl *PD) -> bool { switch (PD->getDefaultArgumentKind()) { case DefaultArgumentKind::None: return false; case DefaultArgumentKind::Normal: case DefaultArgumentKind::StoredProperty: case DefaultArgumentKind::Inherited: case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: return !includeDefaultArgs; case DefaultArgumentKind::File: case DefaultArgumentKind::Line: case DefaultArgumentKind::Column: case DefaultArgumentKind::Function: case DefaultArgumentKind::DSOHandle: // Skip parameters that are defaulted to source location or other // caller context information. Users typically don't want to specify // these parameters. return true; } llvm_unreachable("Unhandled DefaultArgumentKind in switch."); }; bool NeedComma = false; // Iterate over each parameter. for (unsigned i = 0; i != typeParams.size(); ++i) { auto &typeParam = typeParams[i]; Identifier argName; Identifier bodyName; bool isIUO = false; if (!declParams.empty()) { auto *PD = declParams[i]; if (shouldSkipArg(PD)) continue; argName = PD->getArgumentName(); bodyName = PD->getParameterName(); isIUO = PD->getAttrs().hasAttribute(); } else { isIUO = false; argName = typeParam.getLabel(); } bool isVariadic = typeParam.isVariadic(); bool isInOut = typeParam.isInOut(); bool isAutoclosure = typeParam.isAutoClosure(); Type paramTy = typeParam.getPlainType(); if (isVariadic) paramTy = ParamDecl::getVarargBaseTy(paramTy); if (NeedComma) Builder.addComma(); Builder.addCallParameter(argName, bodyName, paramTy, isVariadic, isInOut, isIUO, isAutoclosure); modifiedBuilder = true; NeedComma = true; } return modifiedBuilder; } /// Build argument patterns for calling. Returns \c true if any content was /// added to \p Builder. If \p Params is non-nullptr, \F bool addCallArgumentPatterns(CodeCompletionResultBuilder &Builder, const AnyFunctionType *AFT, const ParameterList *Params, bool includeDefaultArgs = true) { ArrayRef declParams; if (Params) declParams = Params->getArray(); return addCallArgumentPatterns(Builder, AFT->getParams(), declParams, includeDefaultArgs); } static void addThrows(CodeCompletionResultBuilder &Builder, const AnyFunctionType *AFT, const AbstractFunctionDecl *AFD) { if (AFD && AFD->getAttrs().hasAttribute()) Builder.addAnnotatedRethrows(); else if (AFT->throws()) Builder.addAnnotatedThrows(); } void addPoundAvailable(Optional ParentKind) { if (ParentKind != StmtKind::If && ParentKind != StmtKind::Guard) return; CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::ExpressionSpecific, expectedTypeContext); Builder.addTextChunk("available"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("Platform", /*IsVarArg=*/true); Builder.addComma(); Builder.addTextChunk("*"); Builder.addRightParen(); } void addPoundSelector(bool needPound) { // #selector is only available when the Objective-C runtime is. if (!Ctx.LangOpts.EnableObjCInterop) return; // After #, this is a very likely result. When just in a String context, // it's not. auto semanticContext = needPound ? SemanticContextKind::None : SemanticContextKind::ExpressionSpecific; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, semanticContext, expectedTypeContext); if (needPound) Builder.addTextChunk("#selector"); else Builder.addTextChunk("selector"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("@objc method", /*IsVarArg=*/false); Builder.addRightParen(); } void addPoundKeyPath(bool needPound) { // #keyPath is only available when the Objective-C runtime is. if (!Ctx.LangOpts.EnableObjCInterop) return; // After #, this is a very likely result. When just in a String context, // it's not. auto semanticContext = needPound ? SemanticContextKind::None : SemanticContextKind::ExpressionSpecific; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, semanticContext, expectedTypeContext); if (needPound) Builder.addTextChunk("#keyPath"); else Builder.addTextChunk("keyPath"); Builder.addLeftParen(); Builder.addSimpleTypedParameter("@objc property sequence", /*IsVarArg=*/false); Builder.addRightParen(); } SemanticContextKind getSemanticContextKind(const AbstractFunctionDecl *AFD) { // FIXME: to get the corect semantic context we need to know how lookup // would have found the declaration AFD. For now, just infer a reasonable // semantics. if (!AFD) return SemanticContextKind::CurrentModule; DeclContext *calleeDC = AFD->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() == CurrDeclContext->getParentModule()) return SemanticContextKind::CurrentModule; return SemanticContextKind::OtherModule; } void addFunctionCallPattern(const AnyFunctionType *AFT, const AbstractFunctionDecl *AFD = nullptr) { if (AFD) { auto genericSig = AFD->getInnermostDeclContext()->getGenericSignatureOfContext(); AFT = eraseArchetypes(CurrDeclContext->getParentModule(), const_cast(AFT), genericSig) ->castTo(); } // Add the pattern, possibly including any default arguments. auto addPattern = [&](ArrayRef declParams = {}, bool includeDefaultArgs = true) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, AFD ? CodeCompletionResult::ResultKind::Declaration : CodeCompletionResult::ResultKind::Pattern, getSemanticContextKind(AFD), expectedTypeContext); if (!HaveLParen) Builder.addLeftParen(); else Builder.addAnnotatedLeftParen(); if (AFD) { Builder.setAssociatedDecl(AFD); setClangDeclKeywords(AFD, Pairs, Builder); } addCallArgumentPatterns(Builder, AFT->getParams(), declParams, includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) Builder.addRightParen(); else Builder.addAnnotatedRightParen(); addThrows(Builder, AFT, AFD); if (AFD && AFD->getAttrs().hasAttribute()) addTypeAnnotationForImplicitlyUnwrappedOptional(Builder, AFT->getResult()); else addTypeAnnotation(Builder, AFT->getResult()); }; if (!AFD || !AFD->hasInterfaceType() || !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 (hasInterestingDefaultValues(AFD)) addPattern(AFD->getParameters()->getArray(), /*includeDefaultArgs=*/false); addPattern(AFD->getParameters()->getArray(), /*includeDefaultArgs=*/true); } } } bool isImplicitlyCurriedInstanceMethod(const AbstractFunctionDecl *FD) { switch (Kind) { case LookupKind::ValueExpr: return ExprType->is() && !FD->isStatic(); case LookupKind::ValueInDeclContext: if (InsideStaticMethod && FD->getDeclContext() == CurrentMethod->getDeclContext() && !FD->isStatic()) return true; if (auto Init = dyn_cast(CurrDeclContext)) return FD->getDeclContext() == Init->getParent() && !FD->isStatic(); return false; case LookupKind::EnumElement: case LookupKind::Type: case LookupKind::TypeInDeclContext: llvm_unreachable("cannot have a method call while doing a " "type completion"); case LookupKind::ImportFromModule: return false; } llvm_unreachable("Unhandled LookupKind in switch."); } void addMethodCall(const FuncDecl *FD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (FD->getName().empty()) return; foundFunction(FD); Identifier Name = FD->getName(); assert(!Name.empty() && "name should not be empty"); Type FunctionType = getTypeOfMember(FD); 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(); } bool trivialTrailingClosure = false; if (AFT && !IsImplicitlyCurriedInstanceMethod) trivialTrailingClosure = hasTrivialTrailingClosure(FD, AFT); // Add the method, possibly including any default arguments. auto addMethodImpl = [&](bool includeDefaultArgs = true, bool trivialTrailingClosure = false) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(FD, Reason, dynamicLookupInfo), expectedTypeContext); setClangDeclKeywords(FD, Pairs, Builder); Builder.setAssociatedDecl(FD); addLeadingDot(Builder); addValueBaseName(Builder, Name); if (IsDynamicLookup) Builder.addDynamicLookupMethodCallTail(); else if (FD->getAttrs().hasAttribute()) Builder.addOptionalMethodCallTail(); llvm::SmallString<32> TypeStr; if (!AFT) { llvm::raw_svector_ostream OS(TypeStr); FunctionType.print(OS); Builder.addTypeAnnotation(OS.str()); return; } if (IsImplicitlyCurriedInstanceMethod) { Builder.addLeftParen(); addCallArgumentPatterns(Builder, AFT->getParams(), {FD->getImplicitSelfDecl()}, includeDefaultArgs); Builder.addRightParen(); } else if (trivialTrailingClosure) { Builder.addBraceStmtWithCursor(" { code }"); addThrows(Builder, AFT, FD); } else { Builder.addLeftParen(); addCallArgumentPatterns(Builder, AFT, FD->getParameters(), includeDefaultArgs); Builder.addRightParen(); addThrows(Builder, AFT, FD); } Type ResultType = AFT->getResult(); // Build type annotation. { llvm::raw_svector_ostream OS(TypeStr); if (IsImplicitlyCurriedInstanceMethod) { auto *FnType = ResultType->castTo(); AnyFunctionType::printParams(FnType->getParams(), OS); ResultType = FnType->getResult(); OS << " -> "; } // What's left is the result type. if (ResultType->isVoid()) { OS << "Void"; } else { // As we did with parameters in addParamPatternFromFunction, // for regular methods we'll print '!' after implicitly // unwrapped optional results. bool IsIUO = !IsImplicitlyCurriedInstanceMethod && FD->getAttrs().hasAttribute(); PrintOptions PO; PO.OpaqueReturnTypePrinting = PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword; PO.PrintOptionalAsImplicitlyUnwrapped = IsIUO; ResultType.print(OS, PO); } } Builder.addTypeAnnotation(TypeStr); }; if (!AFT || IsImplicitlyCurriedInstanceMethod) { addMethodImpl(); } else { if (trivialTrailingClosure) addMethodImpl(/*includeDefaultArgs=*/false, /*trivialTrailingClosure=*/true); if (hasInterestingDefaultValues(FD)) addMethodImpl(/*includeDefaultArgs=*/false); addMethodImpl(/*includeDefaultArgs=*/true); } } void addConstructorCall(const ConstructorDecl *CD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, Optional BaseType, Optional Result, bool IsOnType = true, Identifier addName = Identifier()) { foundFunction(CD); Type MemberType = getTypeOfMember(CD, BaseType); 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 (MemberType->hasError() && addName.empty() && !needInit) return; // Add the constructor, possibly including any default arguments. auto addConstructorImpl = [&](bool includeDefaultArgs = true) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(CD, Reason, dynamicLookupInfo), expectedTypeContext); setClangDeclKeywords(CD, Pairs, Builder); Builder.setAssociatedDecl(CD); if (needInit) { assert(addName.empty()); addLeadingDot(Builder); Builder.addTextChunk("init"); } else if (!addName.empty()) { Builder.addTextChunk(addName.str()); } else { assert(!MemberType->hasError() && "will insert empty result"); } if (!ConstructorType) { addTypeAnnotation(Builder, MemberType); return; } if (!HaveLParen) Builder.addLeftParen(); else Builder.addAnnotatedLeftParen(); addCallArgumentPatterns(Builder, ConstructorType, CD->getParameters(), includeDefaultArgs); // The rparen matches the lparen here so that we insert both or neither. if (!HaveLParen) Builder.addRightParen(); else Builder.addAnnotatedRightParen(); addThrows(Builder, ConstructorType, CD); if (CD->getAttrs().hasAttribute()) { addTypeAnnotationForImplicitlyUnwrappedOptional( Builder, Result.hasValue() ? Result.getValue() : ConstructorType->getResult()); } else { addTypeAnnotation(Builder, Result.hasValue() ? Result.getValue() : ConstructorType->getResult()); } }; if (ConstructorType && hasInterestingDefaultValues(CD)) addConstructorImpl(/*includeDefaultArgs*/ false); addConstructorImpl(); } void addConstructorCallsForType(Type type, Identifier name, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (!Ctx.LangOpts.CodeCompleteInitsInPostfixExpr && !IsUnresolvedMember) return; assert(CurrDeclContext); SmallVector initializers; if (CurrDeclContext->lookupQualified(type, DeclBaseName::createConstructor(), NL_QualifiedDefault, TypeResolver, initializers)) { for (auto *init : initializers) { if (init->shouldHideFromEditor()) continue; if (IsUnresolvedMember && cast(init)->getFailability() == OTK_Optional) { continue; } addConstructorCall(cast(init), Reason, dynamicLookupInfo, type, None, /*IsOnType=*/true, name); } } } void 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)->getAs(); if (!subscriptType) return; CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(SD, Reason, dynamicLookupInfo), expectedTypeContext); Builder.setAssociatedDecl(SD); setClangDeclKeywords(SD, Pairs, Builder); // '\TyName#^TOKEN^#' requires leading dot. if (!HaveDot && IsAfterSwiftKeyPathRoot) Builder.addLeadingDot(); if (NeedOptionalUnwrap) { Builder.setNumBytesToErase(NumBytesToEraseForOptionalUnwrap); Builder.addQuestionMark(); } Builder.addLeftBracket(); addCallArgumentPatterns(Builder, subscriptType, SD->getIndices(), true); Builder.addRightBracket(); // Add a type annotation. Type resultTy = subscriptType->getResult(); if (IsDynamicLookup) { // Values of properties that were found on a AnyObject have // Optional type. resultTy = OptionalType::get(resultTy); } addTypeAnnotation(Builder, resultTy); } void addNominalTypeRef(const NominalTypeDecl *NTD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (IsUnresolvedMember) return; CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(NTD, Reason, dynamicLookupInfo), expectedTypeContext); Builder.setAssociatedDecl(NTD); setClangDeclKeywords(NTD, Pairs, Builder); addLeadingDot(Builder); Builder.addTextChunk(NTD->getName().str()); addTypeAnnotation(Builder, NTD->getDeclaredType()); } void addTypeAliasRef(const TypeAliasDecl *TAD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (IsUnresolvedMember) return; CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(TAD, Reason, dynamicLookupInfo), expectedTypeContext); Builder.setAssociatedDecl(TAD); setClangDeclKeywords(TAD, Pairs, Builder); addLeadingDot(Builder); Builder.addTextChunk(TAD->getName().str()); if (TAD->hasInterfaceType()) { auto underlyingType = TAD->getUnderlyingTypeLoc().getType(); if (underlyingType->hasError()) { Type parentType; if (auto nominal = TAD->getDeclContext()->getSelfNominalTypeDecl()) { parentType = nominal->getDeclaredInterfaceType(); } addTypeAnnotation( Builder, TypeAliasType::get(const_cast(TAD), parentType, SubstitutionMap(), underlyingType)); } else { addTypeAnnotation(Builder, underlyingType); } } } void addGenericTypeParamRef(const GenericTypeParamDecl *GP, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(GP, Reason, dynamicLookupInfo), expectedTypeContext); setClangDeclKeywords(GP, Pairs, Builder); Builder.setAssociatedDecl(GP); addLeadingDot(Builder); Builder.addTextChunk(GP->getName().str()); addTypeAnnotation(Builder, GP->getDeclaredInterfaceType()); } void addAssociatedTypeRef(const AssociatedTypeDecl *AT, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(AT, Reason, dynamicLookupInfo), expectedTypeContext); setClangDeclKeywords(AT, Pairs, Builder); Builder.setAssociatedDecl(AT); addLeadingDot(Builder); Builder.addTextChunk(AT->getName().str()); if (Type T = getAssociatedTypeType(AT)) addTypeAnnotation(Builder, T); } void addPrecedenceGroupRef(PrecedenceGroupDecl *PGD) { auto semanticContext = getSemanticContext(PGD, DeclVisibilityKind::VisibleAtTopLevel, {}); CodeCompletionResultBuilder builder( Sink, CodeCompletionResult::ResultKind::Declaration, semanticContext, {}); builder.addTextChunk(PGD->getName().str()); builder.setAssociatedDecl(PGD); }; void addEnumElementRef(const EnumElementDecl *EED, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, bool HasTypeContext) { if (!EED->hasName() || !EED->isAccessibleFrom(CurrDeclContext) || EED->shouldHideFromEditor()) return; CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, HasTypeContext ? SemanticContextKind::ExpressionSpecific : getSemanticContext(EED, Reason, dynamicLookupInfo), expectedTypeContext); Builder.setAssociatedDecl(EED); setClangDeclKeywords(EED, Pairs, Builder); addLeadingDot(Builder); addValueBaseName(Builder, EED->getName()); // Enum element is of function type; (Self.type) -> Self or // (Self.Type) -> (Args...) -> Self. Type EnumType = getTypeOfMember(EED); if (EnumType->is()) EnumType = EnumType->castTo()->getResult(); if (EnumType->is()) { Builder.addLeftParen(); addCallArgumentPatterns(Builder, EnumType->castTo(), EED->getParameterList()); Builder.addRightParen(); // Extract result as the enum type. EnumType = EnumType->castTo()->getResult(); } addTypeAnnotation(Builder, EnumType); } void addKeyword(StringRef Name, Type TypeAnnotation = Type(), SemanticContextKind SK = SemanticContextKind::None, CodeCompletionKeywordKind KeyKind = CodeCompletionKeywordKind::None, unsigned NumBytesToErase = 0) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SK, expectedTypeContext); addLeadingDot(Builder); Builder.addTextChunk(Name); Builder.setKeywordKind(KeyKind); if (TypeAnnotation) addTypeAnnotation(Builder, TypeAnnotation); if (NumBytesToErase > 0) Builder.setNumBytesToErase(NumBytesToErase); } void addKeyword(StringRef Name, StringRef TypeAnnotation, CodeCompletionKeywordKind KeyKind = CodeCompletionKeywordKind::None) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::None, expectedTypeContext); addLeadingDot(Builder); Builder.addTextChunk(Name); Builder.setKeywordKind(KeyKind); if (!TypeAnnotation.empty()) Builder.addTypeAnnotation(TypeAnnotation); } void addDeclAttrParamKeyword(StringRef Name, StringRef Annotation, bool NeedSpecify) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::None, expectedTypeContext); Builder.addDeclAttrParamKeyword(Name, Annotation, NeedSpecify); } void addDeclAttrKeyword(StringRef Name, StringRef Annotation) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::None, expectedTypeContext); Builder.addDeclAttrKeyword(Name, Annotation); } /// Add the compound function name for the given function. void addCompoundFunctionName(AbstractFunctionDecl *AFD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CommandWordsPairs Pairs; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, getSemanticContext(AFD, Reason, dynamicLookupInfo), expectedTypeContext); setClangDeclKeywords(AFD, Pairs, Builder); Builder.setAssociatedDecl(AFD); // Base name addLeadingDot(Builder); addValueBaseName(Builder, AFD->getBaseName()); // Add the argument labels. auto ArgLabels = AFD->getFullName().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(); } } // Implement swift::VisibleDeclConsumer. void foundDecl(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) override { if (D->shouldHideFromEditor()) return; if (IsKeyPathExpr && !KeyPathFilter(D, Reason)) return; if (IsSwiftKeyPathExpr && !SwiftKeyPathFilter(D, Reason)) return; if (!D->hasInterfaceType()) TypeResolver->resolveDeclSignature(D); else if (isa(D)) { // A TypeAliasDecl might have type set, but not the underlying type. TypeResolver->resolveDeclSignature(D); } switch (Kind) { case LookupKind::ValueExpr: if (auto *CD = dyn_cast(D)) { // Do we want compound function names here? if (shouldUseFunctionReference(CD)) { addCompoundFunctionName(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. Optional Result = None; 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, None, Result, /*isOnType*/ true); else if ((IsSelfRefExpr || IsSuperRefExpr || !Ty->is() || CD->isRequired()) && !HaveLParen) addConstructorCall(CD, Reason, dynamicLookupInfo, None, Result, /*isOnType*/ false); return; } if (!HaveLParen) { auto CDC = dyn_cast(CurrDeclContext); if (!CDC) return; // We do not want 'init' completions for 'self' in non-convenience // initializers and for 'super' in convenience initializers. if ((IsSelfRefExpr && CDC->isConvenienceInit()) || ((IsSuperRefExpr && !CDC->isConvenienceInit()))) addConstructorCall(CD, Reason, dynamicLookupInfo, None, None, /*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 (shouldUseFunctionReference(FD)) { addCompoundFunctionName(FD, Reason, dynamicLookupInfo); return; } addMethodCall(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); for (auto *protocol : GP->getConformingProtocols()) addConstructorCallsForType(protocol->getDeclaredInterfaceType(), 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; } 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 *TAD = dyn_cast(D)) { addTypeAliasRef(TAD, Reason, dynamicLookupInfo); return; } if (auto *GP = dyn_cast(D)) { addGenericTypeParamRef(GP, Reason, dynamicLookupInfo); return; } if (auto *AT = dyn_cast(D)) { addAssociatedTypeRef(AT, Reason, dynamicLookupInfo); return; } return; } } bool handleEnumElement(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (!D->hasInterfaceType()) TypeResolver->resolveDeclSignature(D); if (auto *EED = dyn_cast(D)) { addEnumElementRef(EED, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); return true; } else if (auto *ED = dyn_cast(D)) { llvm::DenseSet Elements; ED->getAllElements(Elements); for (auto *Ele : Elements) { if (!Ele->hasInterfaceType()) TypeResolver->resolveDeclSignature(Ele); addEnumElementRef(Ele, Reason, dynamicLookupInfo, /*HasTypeContext=*/true); } return true; } return false; } bool tryTupleExprCompletions(Type ExprType) { auto *TT = ExprType->getAs(); if (!TT) return false; unsigned Index = 0; for (auto TupleElt : TT->getElements()) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Pattern, SemanticContextKind::CurrentNominal, expectedTypeContext); addLeadingDot(Builder); if (TupleElt.hasName()) { Builder.addTextChunk(TupleElt.getName().str()); } else { llvm::SmallString<4> IndexStr; { llvm::raw_svector_ostream OS(IndexStr); OS << Index; } Builder.addTextChunk(IndexStr.str()); } addTypeAnnotation(Builder, TupleElt.getType()); Index++; } return true; } bool tryFunctionCallCompletions(Type ExprType, const ValueDecl *VD) { ExprType = ExprType->getRValueType(); if (auto AFT = ExprType->getAs()) { if (auto *AFD = dyn_cast_or_null(VD)) { addFunctionCallPattern(AFT, AFD); } else { addFunctionCallPattern(AFT); } return true; } return false; } bool tryModuleCompletions(Type ExprType) { if (auto MT = ExprType->getAs()) { ModuleDecl *M = MT->getModule(); if (CurrDeclContext->getParentModule() != M) { // Only use the cache if it is not the current module. RequestedCachedResults.push_back( RequestedResultsTy::fromModule(M).needLeadingDot(needDot())); return true; } } return false; } /// If the given ExprType is optional, this adds completions for the unwrapped /// type. /// /// \return true if the given type was Optional . bool 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, CurrDeclContext, TypeResolver, IncludeInstanceMembers); 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()) { NumBytesToEraseForOptionalUnwrap = Ctx.SourceMgr.getByteDistance( DotLoc, Ctx.SourceMgr.getCodeCompletionLoc()); } else { NumBytesToEraseForOptionalUnwrap = 0; } if (NumBytesToEraseForOptionalUnwrap <= CodeCompletionResult::MaxNumBytesToErase) { if (!tryTupleExprCompletions(Unwrapped)) { lookupVisibleMemberDecls(*this, Unwrapped, CurrDeclContext, TypeResolver, IncludeInstanceMembers); } } return true; } return false; } void getPostfixKeywordCompletions(Type ExprType, Expr *ParsedExpr) { 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 getValueExprCompletions(Type ExprType, ValueDecl *VD = nullptr) { 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 = OpenedArchetypeType::getAny(ExprType); if (WasOptional) ExprType = OptionalType::get(ExprType); // Handle special cases bool isIUO = VD && VD->getAttrs() .hasAttribute(); if (tryFunctionCallCompletions(ExprType, VD)) return; if (tryModuleCompletions(ExprType)) 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, CurrDeclContext, TypeResolver, IncludeInstanceMembers); } template void collectOperatorsFromMap(SourceFile::OperatorMap &map, bool includePrivate, std::vector &results) { for (auto &pair : map) { if (pair.second.getPointer() && (pair.second.getInt() || includePrivate)) { results.push_back(pair.second.getPointer()); } } } void collectOperatorsFrom(SourceFile *SF, std::vector &results) { bool includePrivate = CurrDeclContext->getParentSourceFile() == SF; collectOperatorsFromMap(SF->PrefixOperators, includePrivate, results); collectOperatorsFromMap(SF->PostfixOperators, includePrivate, results); collectOperatorsFromMap(SF->InfixOperators, includePrivate, results); } void collectOperatorsFrom(LoadedFile *F, std::vector &results) { SmallVector topLevelDecls; F->getTopLevelDecls(topLevelDecls); for (auto D : topLevelDecls) { if (auto op = dyn_cast(D)) results.push_back(op); } } std::vector collectOperators() { std::vector results; assert(CurrDeclContext); CurrDeclContext->getParentSourceFile()->forAllVisibleModules( [&](ModuleDecl::ImportedModule import) { for (auto fileUnit : import.second->getFiles()) { switch (fileUnit->getKind()) { case FileUnitKind::Builtin: case FileUnitKind::ClangModule: case FileUnitKind::DWARFModule: continue; case FileUnitKind::Source: collectOperatorsFrom(cast(fileUnit), results); break; case FileUnitKind::SerializedAST: collectOperatorsFrom(cast(fileUnit), results); break; } } }); return results; } void addPostfixBang(Type resultType) { CodeCompletionResultBuilder builder( Sink, CodeCompletionResult::ResultKind::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 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( Sink, CodeCompletionResult::ResultKind::Declaration, semanticContext, {}); // FIXME: handle variable amounts of space. if (HaveLeadingSpace) builder.setNumBytesToErase(1); builder.setAssociatedDecl(op); builder.addTextChunk(op->getName().str()); assert(resultType); addTypeAnnotation(builder, resultType); } void tryPostfixOperator(Expr *expr, PostfixOperatorDecl *op) { ConcreteDeclRef referencedDecl; FunctionType *funcTy = getTypeOfCompletionOperator( const_cast(CurrDeclContext), expr, op->getName(), DeclRefKind::PostfixOperator, referencedDecl); if (!funcTy) return; // TODO: Use referencedDecl (FuncDecl) instead of 'op' (OperatorDecl). addPostfixOperatorCompletion(op, funcTy->getResult()); } void addAssignmentOperator(Type RHSType, Type resultType) { CodeCompletionResultBuilder builder( Sink, CodeCompletionResult::ResultKind::BuiltinOperator, SemanticContextKind::None, {}); if (HaveLeadingSpace) builder.addAnnotatedWhitespace(" "); else builder.addWhitespace(" "); builder.addEqual(); builder.addWhitespace(" "); assert(RHSType && resultType); builder.addCallParameter(Identifier(), Identifier(), RHSType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); addTypeAnnotation(builder, resultType); } void 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( Sink, CodeCompletionResult::ResultKind::Declaration, semanticContext, {}); builder.setAssociatedDecl(op); if (HaveLeadingSpace) builder.addAnnotatedWhitespace(" "); else builder.addWhitespace(" "); builder.addTextChunk(op->getName().str()); builder.addWhitespace(" "); if (RHSType) builder.addCallParameter(Identifier(), Identifier(), RHSType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); if (resultType) addTypeAnnotation(builder, resultType); } void tryInfixOperatorCompletion(Expr *foldedExpr, InfixOperatorDecl *op) { ConcreteDeclRef referencedDecl; FunctionType *funcTy = getTypeOfCompletionOperator( const_cast(CurrDeclContext), foldedExpr, op->getName(), DeclRefKind::BinaryOperator, referencedDecl); if (!funcTy) return; Type lhsTy = funcTy->getParams()[0].getPlainType(); Type rhsTy = funcTy->getParams()[1].getPlainType(); Type resultTy = funcTy->getResult(); // Don't complete optional operators on non-optional types. if (!lhsTy->getRValueType()->getOptionalObjectType()) { // 'T ?? T' if (op->getName().str() == "??") return; // 'T == nil' if (auto NT = rhsTy->getNominalOrBoundGenericNominal()) if (NT->getName() == CurrDeclContext->getASTContext().Id_OptionalNilComparisonType) return; } // If the right-hand side and result type are both type parameters, we're // not providing a useful completion. if (resultTy->isTypeParameter() && rhsTy->isTypeParameter()) return; // TODO: Use referencedDecl (FuncDecl) instead of 'op' (OperatorDecl). addInfixOperatorCompletion(op, funcTy->getResult(), funcTy->getParams()[1].getPlainType()); } Expr *typeCheckLeadingSequence(Expr *LHS, ArrayRef leadingSequence) { if (leadingSequence.empty()) return LHS; SourceRange sequenceRange(leadingSequence.front()->getStartLoc(), LHS->getEndLoc()); auto *expr = findParsedExpr(CurrDeclContext, sequenceRange); if (!expr) return LHS; if (expr->getType() && !expr->getType()->hasError()) return expr; if (!typeCheckExpression(const_cast(CurrDeclContext), expr)) return expr; return LHS; } void getOperatorCompletions(Expr *LHS, ArrayRef leadingSequence) { Expr *foldedExpr = typeCheckLeadingSequence(LHS, leadingSequence); std::vector operators = collectOperators(); // FIXME: this always chooses the first operator with the given name. llvm::DenseSet seenPostfixOperators; llvm::DenseSet seenInfixOperators; for (auto op : operators) { switch (op->getKind()) { case DeclKind::PrefixOperator: // Don't insert prefix operators in postfix position. // FIXME: where should these get completed? break; case DeclKind::PostfixOperator: if (seenPostfixOperators.insert(op->getName()).second) tryPostfixOperator(LHS, cast(op)); break; case DeclKind::InfixOperator: if (seenInfixOperators.insert(op->getName()).second) tryInfixOperatorCompletion(foldedExpr, cast(op)); break; default: llvm_unreachable("unexpected operator kind"); } } if (leadingSequence.empty() && LHS->getType() && LHS->getType()->hasLValueType()) { addAssignmentOperator(LHS->getType()->getRValueType(), CurrDeclContext->getASTContext().TheEmptyTupleType); } // FIXME: unify this with the ?.member completions. if (auto T = LHS->getType()) if (auto ValueT = T->getRValueType()->getOptionalObjectType()) addPostfixBang(ValueT); } void addValueLiteralCompletions() { auto &context = CurrDeclContext->getASTContext(); auto *module = CurrDeclContext->getParentModule(); auto addFromProto = [&]( CodeCompletionLiteralKind kind, StringRef defaultTypeName, llvm::function_ref consumer, bool isKeyword = false) { CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal, SemanticContextKind::None, {}); builder.setLiteralKind(kind); consumer(builder); // Check for matching ExpectedTypes. auto *P = context.getProtocol(protocolForLiteralKind(kind)); bool foundConformance = false; for (auto T : expectedTypeContext.possibleTypes) { if (!T) continue; auto typeRelation = CodeCompletionResult::Identical; // 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; typeRelation = CodeCompletionResult::Convertible; } } // Check for conformance to the literal protocol. if (auto *NTD = T->getAnyNominal()) { SmallVector conformances; if (NTD->lookupConformance(module, P, conformances)) { foundConformance = true; addTypeAnnotation(builder, T); builder.setExpectedTypeRelation(typeRelation); } } } // Fallback to showing the default type. if (!foundConformance && !defaultTypeName.empty()) builder.addTypeAnnotation(defaultTypeName); }; // 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, "Int", [](Builder &builder) { builder.addTextChunk("0"); }); addFromProto(LK::BooleanLiteral, "Bool", [](Builder &builder) { builder.addTextChunk("true"); }, /*isKeyword=*/true); addFromProto(LK::BooleanLiteral, "Bool", [](Builder &builder) { builder.addTextChunk("false"); }, /*isKeyword=*/true); addFromProto(LK::NilLiteral, "", [](Builder &builder) { builder.addTextChunk("nil"); }, /*isKeyword=*/true); addFromProto(LK::StringLiteral, "String", [&](Builder &builder) { builder.addTextChunk("\""); builder.addSimpleNamedParameter("abc"); builder.addTextChunk("\""); }); addFromProto(LK::ArrayLiteral, "Array", [&](Builder &builder) { builder.addLeftBracket(); builder.addSimpleNamedParameter("values"); builder.addRightBracket(); }); addFromProto(LK::DictionaryLiteral, "Dictionary", [&](Builder &builder) { builder.addLeftBracket(); builder.addSimpleNamedParameter("key"); builder.addTextChunk(": "); builder.addSimpleNamedParameter("value"); builder.addRightBracket(); }); auto floatType = context.getFloatDecl()->getDeclaredType(); addFromProto(LK::ColorLiteral, "", [&](Builder &builder) { builder.addTextChunk("#colorLiteral"); builder.addLeftParen(); builder.addCallParameter(context.getIdentifier("red"), floatType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); builder.addComma(); builder.addCallParameter(context.getIdentifier("green"), floatType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); builder.addComma(); builder.addCallParameter(context.getIdentifier("blue"), floatType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); builder.addComma(); builder.addCallParameter(context.getIdentifier("alpha"), floatType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); builder.addRightParen(); }); auto stringType = context.getStringDecl()->getDeclaredType(); addFromProto(LK::ImageLiteral, "", [&](Builder &builder) { builder.addTextChunk("#imageLiteral"); builder.addLeftParen(); builder.addCallParameter(context.getIdentifier("resourceName"), stringType, /*IsVarArg*/ false, /*IsInOut*/ false, /*isIUO*/ false, /*isAutoClosure*/ false); builder.addRightParen(); }); // Add tuple completion (item, item). { CodeCompletionResultBuilder builder(Sink, CodeCompletionResult::Literal, SemanticContextKind::None, {}); builder.setLiteralKind(LK::Tuple); builder.addLeftParen(); builder.addSimpleNamedParameter("values"); builder.addRightParen(); for (auto T : expectedTypeContext.possibleTypes) { if (T && T->is() && !T->isVoid()) { addTypeAnnotation(builder, T); builder.setExpectedTypeRelation(CodeCompletionResult::Identical); break; } } } } struct FilteredDeclConsumer : public swift::VisibleDeclConsumer { swift::VisibleDeclConsumer &Consumer; DeclFilter Filter; FilteredDeclConsumer(swift::VisibleDeclConsumer &Consumer, DeclFilter Filter) : Consumer(Consumer), Filter(Filter) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Kind, DynamicLookupInfo dynamicLookupInfo) override { if (Filter(VD, Kind)) Consumer.foundDecl(VD, Kind, dynamicLookupInfo); } }; void getValueCompletionsInDeclContext(SourceLoc Loc, DeclFilter Filter = DefaultFilter, bool IncludeTopLevel = false, bool RequestCache = true, bool LiteralCompletions = true) { ExprType = Type(); Kind = LookupKind::ValueInDeclContext; NeedLeadingDot = false; FilteredDeclConsumer Consumer(*this, Filter); lookupVisibleDecls(Consumer, CurrDeclContext, TypeResolver, /*IncludeTopLevel=*/IncludeTopLevel, Loc); if (RequestCache) RequestedCachedResults.push_back(RequestedResultsTy::toplevelResults()); // Manually add any expected nominal types from imported modules so that // they get their expected type relation. Don't include protocols, since // they can't be initialized from the type name. // FIXME: this does not include types that conform to an expected protocol. // FIXME: this creates duplicate results. for (auto T : expectedTypeContext.possibleTypes) { if (auto NT = T->getAs()) { if (auto NTD = NT->getDecl()) { if (!isa(NTD) && NTD->getModuleContext() != CurrDeclContext->getParentModule()) { addNominalTypeRef(NT->getDecl(), DeclVisibilityKind::VisibleAtTopLevel, {}); } } } } 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 = std::any_of(expectedTypeContext.possibleTypes.begin(), expectedTypeContext.possibleTypes.end(), [](Type T) { if (auto *NTD = T->getAnyNominal()) return isa(NTD); return false; }); } if (LiteralCompletions) addValueLiteralCompletions(); // If the expected type is ObjectiveC.Selector, add #selector. If // it's String, add #keyPath. if (Ctx.LangOpts.EnableObjCInterop) { bool addedSelector = false; bool addedKeyPath = false; for (auto T : expectedTypeContext.possibleTypes) { T = T->lookThroughAllOptionalTypes(); if (auto structDecl = T->getStructOrBoundGenericStruct()) { if (!addedSelector && structDecl->getName() == Ctx.Id_Selector && structDecl->getParentModule()->getName() == Ctx.Id_ObjectiveC) { addPoundSelector(/*needPound=*/true); if (addedKeyPath) break; addedSelector = true; continue; } } if (!addedKeyPath && T->getAnyNominal() == Ctx.getStringDecl()) { addPoundKeyPath(/*needPound=*/true); if (addedSelector) break; addedKeyPath = true; continue; } } } } void getUnresolvedMemberCompletions(Type T) { if (!T->mayHaveMembers()) return; ModuleDecl *CurrModule = CurrDeclContext->getParentModule(); // 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) { if (VD->isOperator()) return false; if (!VD->hasInterfaceType()) { TypeResolver->resolveDeclSignature(VD); if (!VD->hasInterfaceType()) return false; } if (T->getOptionalObjectType() && VD->getModuleContext()->isStdlibModule()) { // In optional context, ignore '.init()', 'init(nilLiteral:)', if (isa(VD)) return false; // TODO: Ignore '.some()' and '.none' too *in expression // context*. They are useful in pattern context though. } // Enum element decls can always be referenced by implicit member // expression. if (isa(VD)) return true; // Only non-failable constructors are implicitly referenceable. if (auto CD = dyn_cast(VD)) { switch (CD->getFailability()) { case OTK_None: case OTK_ImplicitlyUnwrappedOptional: return true; case OTK_Optional: return false; } } // Otherwise, check the result type matches the contextual type. auto declTy = T->getTypeOfMember(CurrModule, VD); if (declTy->is()) return false; DeclContext *DC = const_cast(CurrDeclContext); // Member types can also be implicitly referenceable as long as it's // convertible to the contextual type. if (auto CD = dyn_cast(VD)) { declTy = declTy->getMetatypeInstanceType(); // Emit construction for the same type via typealias doesn't make sense // because we are emitting all `.init()`s. if (declTy->isEqual(T)) return false; return swift::isConvertibleTo(declTy, T, *DC); } // Only static member can be referenced. if (!VD->isStatic()) return false; if (isa(VD)) { // Strip '(Self.Type) ->' and parameters. declTy = declTy->castTo()->getResult(); declTy = declTy->castTo()->getResult(); } else if (auto FT = declTy->getAs()) { // The compiler accepts 'static var factory: () -> T' for implicit // member expression. // FIXME: This emits just 'factory'. We should emit 'factory()' instead. declTy = FT->getResult(); } return declTy->isEqual(T) || swift::isConvertibleTo(declTy, T, *DC); }); auto baseType = MetatypeType::get(T); llvm::SaveAndRestore SaveLook(Kind, LookupKind::ValueExpr); llvm::SaveAndRestore SaveType(ExprType, baseType); llvm::SaveAndRestore SaveUnresolved(IsUnresolvedMember, true); lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext, TypeResolver, /*includeInstanceMembers=*/false); } void getUnresolvedMemberCompletions(ArrayRef Types) { NeedLeadingDot = !HaveDot; for (auto T : Types) { if (!T) continue; if (auto objT = T->getOptionalObjectType()) { // If this is optional type, perform completion for the object type. // i.e. 'let _: Enum??? = .enumMember' is legal. getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes()); // Add 'nil' keyword with erasing '.' instruction. unsigned bytesToErase = 0; auto &SM = CurrDeclContext->getASTContext().SourceMgr; if (DotLoc.isValid()) bytesToErase = SM.getByteDistance(DotLoc, SM.getCodeCompletionLoc()); addKeyword("nil", T, SemanticContextKind::ExpressionSpecific, CodeCompletionKeywordKind::kw_nil, bytesToErase); } getUnresolvedMemberCompletions(T); } } void addArgNameCompletionResults(ArrayRef Names) { for (auto Name : Names) { CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::ExpressionSpecific, {}); Builder.addTextChunk(Name); Builder.addCallParameterColon(); Builder.addTypeAnnotation("Argument name"); } } void getTypeContextEnumElementCompletions(SourceLoc Loc) { llvm::SaveAndRestore ChangeLookupKind( Kind, LookupKind::EnumElement); NeedLeadingDot = !HaveDot; auto *Switch = cast_or_null( findNearestStmt(CurrDeclContext, Loc, StmtKind::Switch)); if (!Switch) return; auto Ty = Switch->getSubjectExpr()->getType(); if (!Ty) return; ExprType = Ty; auto *TheEnumDecl = dyn_cast_or_null(Ty->getAnyNominal()); if (!TheEnumDecl) return; for (auto Element : TheEnumDecl->getAllElements()) { foundDecl(Element, DeclVisibilityKind::MemberOfCurrentNominal, {}); } } void getTypeCompletions(Type BaseType) { Kind = LookupKind::Type; this->BaseType = BaseType; NeedLeadingDot = !HaveDot; lookupVisibleMemberDecls(*this, MetatypeType::get(BaseType), CurrDeclContext, TypeResolver, IncludeInstanceMembers); if (BaseType->isAnyExistentialType()) { addKeyword("Protocol", MetatypeType::get(BaseType)); addKeyword("Type", ExistentialMetatypeType::get(BaseType)); } else { addKeyword("Type", MetatypeType::get(BaseType)); } } static bool canUseAttributeOnDecl(DeclAttrKind DAK, bool IsInSil, Optional DK) { 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 (!DK.hasValue()) return true; return DeclAttribute::canAttributeAppearOnDeclKind(DAK, DK.getValue()); } void getAttributeDeclCompletions(bool IsInSil, Optional DK) { // FIXME: also include user-defined attribute keywords StringRef TargetName = "Declaration"; if (DK.hasValue()) { switch (DK.getValue()) { #define DECL(Id, ...) \ case DeclKind::Id: \ TargetName = #Id; \ break; #include "swift/AST/DeclNodes.def" } } std::string Description = TargetName.str() + " Attribute"; #define DECL_ATTR(KEYWORD, NAME, ...) \ if (canUseAttributeOnDecl(DAK_##NAME, IsInSil, DK)) \ addDeclAttrKeyword(#KEYWORD, Description); #include "swift/AST/Attr.def" } void getAttributeDeclParamCompletions(DeclAttrKind AttrKind, int ParamIndex) { if (AttrKind == DAK_Available) { if (ParamIndex == 0) { addDeclAttrParamKeyword("*", "Platform", false); #define AVAILABILITY_PLATFORM(X, PrettyName) \ addDeclAttrParamKeyword(#X, "Platform", false); #include "swift/AST/PlatformKinds.def" } else { addDeclAttrParamKeyword("unavailable", "", false); addDeclAttrParamKeyword("message", "Specify message", true); addDeclAttrParamKeyword("renamed", "Specify replacing name", true); addDeclAttrParamKeyword("introduced", "Specify version number", true); addDeclAttrParamKeyword("deprecated", "Specify version number", true); } } } void collectPrecedenceGroups() { assert(CurrDeclContext); auto M = CurrDeclContext->getParentModule(); if (M) { for (auto FU: M->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); } } CurrDeclContext->getParentSourceFile() ->forAllVisibleModules([&](ModuleDecl::ImportedModule Import) { auto Module = Import.second; if (Module == M) return; RequestedCachedResults.push_back( RequestedResultsTy::fromModule(Module).onlyPrecedenceGroups()); }); } void getPrecedenceGroupCompletions(SyntaxKind SK) { switch (SK) { case SyntaxKind::PrecedenceGroupAssociativity: addKeyword(getAssociativitySpelling(Associativity::None)); addKeyword(getAssociativitySpelling(Associativity::Left)); addKeyword(getAssociativitySpelling(Associativity::Right)); break; case SyntaxKind::PrecedenceGroupAssignment: addKeyword(getTokenText(tok::kw_false), Type(), SemanticContextKind::None, CodeCompletionKeywordKind::kw_false); addKeyword(getTokenText(tok::kw_true), Type(), SemanticContextKind::None, CodeCompletionKeywordKind::kw_true); break; case SyntaxKind::PrecedenceGroupAttributeList: addKeyword("associativity"); addKeyword("higherThan"); addKeyword("lowerThan"); addKeyword("assignment"); break; case SyntaxKind::PrecedenceGroupRelation: collectPrecedenceGroups(); break; default: llvm_unreachable("not a precedencegroup SyntaxKind"); } } void getPoundAvailablePlatformCompletions() { // The platform names should be identical to those in @available. getAttributeDeclParamCompletions(DAK_Available, 0); } void getTypeCompletionsInDeclContext(SourceLoc Loc) { Kind = LookupKind::TypeInDeclContext; lookupVisibleDecls(*this, CurrDeclContext, TypeResolver, /*IncludeTopLevel=*/false, Loc); RequestedCachedResults.push_back( RequestedResultsTy::toplevelResults().onlyTypes()); } void getToplevelCompletions(bool OnlyTypes) { Kind = OnlyTypes ? LookupKind::TypeInDeclContext : LookupKind::ValueInDeclContext; NeedLeadingDot = false; ModuleDecl *M = CurrDeclContext->getParentModule(); AccessFilteringDeclConsumer FilteringConsumer(CurrDeclContext, *this); M->lookupVisibleDecls({}, FilteringConsumer, NLKind::UnqualifiedLookup); } void getVisibleDeclsOfModule(const ModuleDecl *TheModule, ArrayRef AccessPath, bool ResultsHaveLeadingDot) { Kind = LookupKind::ImportFromModule; NeedLeadingDot = ResultsHaveLeadingDot; llvm::SmallVector, 1> LookupAccessPath; for (auto Piece : AccessPath) { LookupAccessPath.push_back( std::make_pair(Ctx.getIdentifier(Piece), SourceLoc())); } AccessFilteringDeclConsumer FilteringConsumer(CurrDeclContext, *this); TheModule->lookupVisibleDecls(LookupAccessPath, FilteringConsumer, NLKind::UnqualifiedLookup); llvm::SmallVector precedenceGroups; TheModule->getPrecedenceGroups(precedenceGroups); for (auto PGD: precedenceGroups) addPrecedenceGroupRef(PGD); } }; class CompletionOverrideLookup : public swift::VisibleDeclConsumer { CodeCompletionResultSink &Sink; ASTContext &Ctx; const DeclContext *CurrDeclContext; LazyResolver *TypeResolver; SmallVectorImpl &ParsedKeywords; SourceLoc introducerLoc; bool hasFuncIntroducer = false; bool hasVarIntroducer = false; bool hasTypealiasIntroducer = false; bool hasInitializerModifier = false; bool hasAccessModifier = false; bool hasOverride = false; bool hasOverridabilityModifier = false; bool hasStaticOrClass = false; public: CompletionOverrideLookup(CodeCompletionResultSink &Sink, ASTContext &Ctx, const DeclContext *CurrDeclContext, SmallVectorImpl &ParsedKeywords, SourceLoc introducerLoc) : Sink(Sink), Ctx(Ctx), CurrDeclContext(CurrDeclContext), ParsedKeywords(ParsedKeywords), introducerLoc(introducerLoc) { (void)createTypeChecker(Ctx); TypeResolver = Ctx.getLazyResolver(); hasFuncIntroducer = isKeywordSpecified("func"); hasVarIntroducer = isKeywordSpecified("var") || isKeywordSpecified("let"); hasTypealiasIntroducer = isKeywordSpecified("typealias"); hasInitializerModifier = isKeywordSpecified("required") || isKeywordSpecified("convenience"); hasAccessModifier = isKeywordSpecified("private") || isKeywordSpecified("fileprivate") || isKeywordSpecified("internal") || isKeywordSpecified("public") || isKeywordSpecified("open"); hasOverride = isKeywordSpecified("override"); hasOverridabilityModifier = isKeywordSpecified("final") || isKeywordSpecified("open"); hasStaticOrClass = isKeywordSpecified(getTokenText(tok::kw_class)) || isKeywordSpecified(getTokenText(tok::kw_static)); } bool isKeywordSpecified(StringRef Word) { return std::find(ParsedKeywords.begin(), ParsedKeywords.end(), Word) != ParsedKeywords.end(); } bool missingOverride(DeclVisibilityKind Reason) { return !hasOverride && Reason == DeclVisibilityKind::MemberOfSuper && !CurrDeclContext->getSelfProtocolDecl(); } void addAccessControl(const ValueDecl *VD, CodeCompletionResultBuilder &Builder) { assert(CurrDeclContext->getSelfNominalTypeDecl()); auto AccessOfContext = CurrDeclContext->getSelfNominalTypeDecl()->getFormalAccess(); auto Access = std::min(VD->getFormalAccess(), AccessOfContext); // Only emit 'public', not needed otherwise. if (Access >= AccessLevel::Public) Builder.addAccessControlKeyword(Access); } /// Return type if the result type if \p VD should be represented as opaque /// result type. TypeLoc getOpaqueResultTypeLoc(const ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { if (Reason != DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal) return nullptr; auto currTy = CurrDeclContext->getDeclaredTypeInContext(); if (!currTy) return nullptr; Type ResultT; if (auto *FD = dyn_cast(VD)) ResultT = FD->getResultInterfaceType(); else if (auto *SD = dyn_cast(VD)) ResultT = SD->getElementInterfaceType(); else if (auto *VarD = dyn_cast(VD)) ResultT = VarD->getInterfaceType(); else return nullptr; if (!ResultT->is()) // The result is not associatedtype. return nullptr; // If associatedtype doesn't have conformance/superclass constraint, we // can't use opaque type. auto assocTyD = ResultT->castTo()->getAssocType(); if (!assocTyD->getInherited().size()) return nullptr; // Try substitution to see if the associated type is resolved to concrete // type. auto substMap = currTy->getMemberSubstitutionMap( CurrDeclContext->getParentModule(), VD); ResultT = ResultT.subst(substMap, SubstFlags::UseErrorType); if (!ResultT || !ResultT->is()) // If resolved print it. return nullptr; return assocTyD->getInherited()[0]; } void addValueOverride(const ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo, CodeCompletionResultBuilder &Builder, bool hasDeclIntroducer) { class DeclPrinter : public StreamPrinter { TypeLoc OpaqueBaseTy; public: using StreamPrinter::StreamPrinter; Optional NameOffset; DeclPrinter(raw_ostream &OS, TypeLoc OpaqueBaseTy) : StreamPrinter(OS), OpaqueBaseTy(OpaqueBaseTy) {} void printDeclLoc(const Decl *D) override { if (!NameOffset.hasValue()) NameOffset = OS.tell(); } // As for FuncDecl, SubscriptDecl, and VarDecl, void printDeclResultTypePre(ValueDecl *VD, TypeLoc &TL) override { if (!OpaqueBaseTy.isNull()) { OS << "some "; TL = OpaqueBaseTy; } } }; llvm::SmallString<256> DeclStr; unsigned NameOffset = 0; { llvm::raw_svector_ostream OS(DeclStr); DeclPrinter Printer( OS, getOpaqueResultTypeLoc(VD, Reason, dynamicLookupInfo)); PrintOptions Options; if (auto transformType = CurrDeclContext->getDeclaredTypeInContext()) Options.setBaseType(transformType); Options.PrintImplicitAttrs = false; Options.ExclusiveAttrList.push_back(TAK_escaping); Options.ExclusiveAttrList.push_back(TAK_autoclosure); Options.PrintOverrideKeyword = false; Options.PrintPropertyAccessors = false; Options.PrintSubscriptAccessors = false; Options.PrintStaticKeyword = !hasStaticOrClass; VD->print(Printer, Options); NameOffset = Printer.NameOffset.getValue(); } if (!hasDeclIntroducer && !hasAccessModifier) addAccessControl(VD, Builder); if (missingOverride(Reason)) { if (!hasDeclIntroducer) Builder.addOverrideKeyword(); else { auto dist = Ctx.SourceMgr.getByteDistance( introducerLoc, Ctx.SourceMgr.getCodeCompletionLoc()); Builder.setNumBytesToErase(dist); Builder.addOverrideKeyword(); Builder.addDeclIntroducer(DeclStr.str().substr(0, NameOffset)); } } if (!hasDeclIntroducer) Builder.addDeclIntroducer(DeclStr.str().substr(0, NameOffset)); Builder.addTextChunk(DeclStr.str().substr(NameOffset)); } void addMethodOverride(const FuncDecl *FD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); Builder.setAssociatedDecl(FD); addValueOverride(FD, Reason, dynamicLookupInfo, Builder, hasFuncIntroducer); Builder.addBraceStmtWithCursor(); } void addVarOverride(const VarDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { // Overrides cannot use 'let', but if the 'override' keyword is specified // then the intention is clear, so provide the results anyway. The compiler // can then provide an error telling you to use 'var' instead. // If we don't need override then it's a protocol requirement, so show it. if (missingOverride(Reason) && hasVarIntroducer && isKeywordSpecified("let")) return; CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); Builder.setAssociatedDecl(VD); addValueOverride(VD, Reason, dynamicLookupInfo, Builder, hasVarIntroducer); } void addSubscriptOverride(const SubscriptDecl *SD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); Builder.setAssociatedDecl(SD); addValueOverride(SD, Reason, dynamicLookupInfo, Builder, false); Builder.addBraceStmtWithCursor(); } void addTypeAlias(const AssociatedTypeDecl *ATD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); Builder.setAssociatedDecl(ATD); if (!hasTypealiasIntroducer && !hasAccessModifier) addAccessControl(ATD, Builder); if (!hasTypealiasIntroducer) Builder.addDeclIntroducer("typealias "); Builder.addTextChunk(ATD->getName().str()); Builder.addTextChunk(" = "); Builder.addSimpleNamedParameter("Type"); } void addConstructor(const ConstructorDecl *CD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Declaration, SemanticContextKind::Super, {}); Builder.setAssociatedDecl(CD); if (!hasAccessModifier) addAccessControl(CD, Builder); if (missingOverride(Reason) && CD->isDesignatedInit() && !CD->isRequired()) Builder.addOverrideKeyword(); // Emit 'required' if we're in class context, 'required' is not specified, // and 1) this is a protocol conformance and the class is not final, or 2) // this is subclass and the initializer is marked as required. bool needRequired = false; auto C = CurrDeclContext->getSelfClassDecl(); if (C && !isKeywordSpecified("required")) { if (Reason == DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal && !C->isFinal()) needRequired = true; else if (Reason == DeclVisibilityKind::MemberOfSuper && CD->isRequired()) needRequired = true; } llvm::SmallString<256> DeclStr; if (needRequired) DeclStr += "required "; { llvm::raw_svector_ostream OS(DeclStr); PrintOptions Options; Options.PrintImplicitAttrs = false; Options.SkipAttributes = true; CD->print(OS, Options); } Builder.addTextChunk(DeclStr); Builder.addBraceStmtWithCursor(); } // Implement swift::VisibleDeclConsumer. void foundDecl(ValueDecl *D, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo) override { if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) return; if (D->shouldHideFromEditor()) return; if (D->isFinal() || // A 'class' member with an initial value cannot be overriden either. (D->isStatic() && D->getAttrs().hasAttribute())) return; if (!D->hasInterfaceType()) TypeResolver->resolveDeclSignature(D); bool hasIntroducer = hasFuncIntroducer || hasVarIntroducer || hasTypealiasIntroducer; if (hasStaticOrClass && !D->isStatic()) return; // As per the current convention, only instance members are // suggested if an introducer is not accompanied by a 'static' or // 'class' modifier. if (hasIntroducer && !hasStaticOrClass && D->isStatic()) return; if (auto *FD = dyn_cast(D)) { // We cannot override operators as members. if (FD->isBinaryOperator() || FD->isUnaryOperator()) return; // We cannot override individual accessors. if (isa(FD)) return; if (hasFuncIntroducer || (!hasIntroducer && !hasInitializerModifier)) addMethodOverride(FD, Reason, dynamicLookupInfo); return; } if (auto *VD = dyn_cast(D)) { if (hasVarIntroducer || (!hasIntroducer && !hasInitializerModifier)) addVarOverride(VD, Reason, dynamicLookupInfo); return; } if (auto *SD = dyn_cast(D)) { if (!hasIntroducer && !hasInitializerModifier) addSubscriptOverride(SD, Reason, dynamicLookupInfo); } if (auto *CD = dyn_cast(D)) { if (!isa(CD->getDeclContext())) return; if (hasIntroducer || hasOverride || hasOverridabilityModifier || hasStaticOrClass) return; if (CD->isRequired() || CD->isDesignatedInit()) addConstructor(CD, Reason, dynamicLookupInfo); return; } } void addDesignatedInitializers(NominalTypeDecl *NTD) { if (hasFuncIntroducer || hasVarIntroducer || hasTypealiasIntroducer || hasOverridabilityModifier || hasStaticOrClass) return; const auto *CD = dyn_cast(NTD); if (!CD) return; if (!CD->hasSuperclass()) return; CD = CD->getSuperclassDecl(); for (const auto *Member : CD->getMembers()) { const auto *Constructor = dyn_cast(Member); if (!Constructor) continue; if (Constructor->hasStubImplementation()) continue; if (Constructor->isDesignatedInit()) addConstructor(Constructor, DeclVisibilityKind::MemberOfSuper, {}); } } void addAssociatedTypes(NominalTypeDecl *NTD) { if (!hasTypealiasIntroducer && (hasFuncIntroducer || hasVarIntroducer || hasInitializerModifier || hasOverride || hasOverridabilityModifier || hasStaticOrClass)) return; for (auto Conformance : NTD->getAllConformances()) { auto Proto = Conformance->getProtocol(); if (!Proto->isAccessibleFrom(CurrDeclContext)) continue; for (auto Member : Proto->getMembers()) { auto *ATD = dyn_cast(Member); if (!ATD) continue; // FIXME: Also exclude the type alias that has already been specified. if (!Conformance->hasTypeWitness(ATD) || ATD->hasDefaultDefinitionType()) continue; addTypeAlias( ATD, DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal, {}); } } } void getOverrideCompletions(SourceLoc Loc) { if (!CurrDeclContext->isTypeContext()) return; if (isa(CurrDeclContext)) return; Type CurrTy = CurrDeclContext->getSelfTypeInContext(); auto *NTD = CurrDeclContext->getSelfNominalTypeDecl(); if (CurrTy && !CurrTy->is()) { // Look for overridable static members too. Type Meta = MetatypeType::get(CurrTy); lookupVisibleMemberDecls(*this, Meta, CurrDeclContext, TypeResolver, /*includeInstanceMembers=*/true); addDesignatedInitializers(NTD); addAssociatedTypes(NTD); } } }; } // end anonymous namespace static void addSelectorModifierKeywords(CodeCompletionResultSink &sink) { auto addKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) { CodeCompletionResultBuilder Builder( sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::None, {}); Builder.setKeywordKind(Kind); Builder.addTextChunk(Name); Builder.addCallParameterColon(); Builder.addSimpleTypedParameter("@objc property", /*IsVarArg=*/false); }; addKeyword("getter", CodeCompletionKeywordKind::None); addKeyword("setter", CodeCompletionKeywordKind::None); } void CodeCompletionCallbacksImpl::completeDotExpr(Expr *E, SourceLoc DotLoc) { assert(P.Tok.is(tok::code_complete)); // Don't produce any results in an enum element. if (InEnumElementRawValue) return; Kind = CompletionKind::DotExpr; if (ParseExprSelectorContext != ObjCSelectorContext::None) { PreferFunctionReferencesToCalls = true; CompleteExprSelectorContext = ParseExprSelectorContext; } ParsedExpr = E; this->DotLoc = DotLoc; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeStmtOrExpr(CodeCompletionExpr *E) { assert(P.Tok.is(tok::code_complete)); Kind = CompletionKind::StmtOrExpr; CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; } void CodeCompletionCallbacksImpl::completePostfixExprBeginning(CodeCompletionExpr *E) { assert(P.Tok.is(tok::code_complete)); // Don't produce any results in an enum element. if (InEnumElementRawValue) return; Kind = CompletionKind::PostfixExprBeginning; if (ParseExprSelectorContext != ObjCSelectorContext::None) { PreferFunctionReferencesToCalls = true; CompleteExprSelectorContext = ParseExprSelectorContext; if (CompleteExprSelectorContext == ObjCSelectorContext::MethodSelector) { addSelectorModifierKeywords(CompletionContext.getResultSink()); } } CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; } void CodeCompletionCallbacksImpl::completeForEachSequenceBeginning( CodeCompletionExpr *E) { assert(P.Tok.is(tok::code_complete)); Kind = CompletionKind::ForEachSequence; CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; } void CodeCompletionCallbacksImpl::completePostfixExpr(Expr *E, bool hasSpace) { assert(P.Tok.is(tok::code_complete)); // Don't produce any results in an enum element. if (InEnumElementRawValue) return; HasSpace = hasSpace; Kind = CompletionKind::PostfixExpr; if (ParseExprSelectorContext != ObjCSelectorContext::None) { PreferFunctionReferencesToCalls = true; CompleteExprSelectorContext = ParseExprSelectorContext; } ParsedExpr = E; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completePostfixExprParen(Expr *E, Expr *CodeCompletionE) { assert(P.Tok.is(tok::code_complete)); // Don't produce any results in an enum element. if (InEnumElementRawValue) return; Kind = CompletionKind::PostfixExprParen; ParsedExpr = E; CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = static_cast(CodeCompletionE); ShouldCompleteCallPatternAfterParen = true; if (Context.LangOpts.CodeCompleteCallPatternHeuristics) { // Lookahead one token to decide what kind of call completions to provide. // When it appears that there is already code for the call present, just // complete values and/or argument labels. Otherwise give the entire call // pattern. Token next = P.peekToken(); if (!next.isAtStartOfLine() && !next.is(tok::eof) && !next.is(tok::r_paren)) { ShouldCompleteCallPatternAfterParen = false; } } } void CodeCompletionCallbacksImpl::completeExprSuper(SuperRefExpr *SRE) { // Don't produce any results in an enum element. if (InEnumElementRawValue) return; Kind = CompletionKind::SuperExpr; if (ParseExprSelectorContext != ObjCSelectorContext::None) { PreferFunctionReferencesToCalls = true; CompleteExprSelectorContext = ParseExprSelectorContext; } ParsedExpr = SRE; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeExprSuperDot(SuperRefExpr *SRE) { // Don't produce any results in an enum element. if (InEnumElementRawValue) return; Kind = CompletionKind::SuperExprDot; if (ParseExprSelectorContext != ObjCSelectorContext::None) { PreferFunctionReferencesToCalls = true; CompleteExprSelectorContext = ParseExprSelectorContext; } ParsedExpr = SRE; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeExprKeyPath(KeyPathExpr *KPE, SourceLoc DotLoc) { Kind = (!KPE || KPE->isObjC()) ? CompletionKind::KeyPathExprObjC : CompletionKind::KeyPathExprSwift; ParsedExpr = KPE; this->DotLoc = DotLoc; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completePoundAvailablePlatform() { Kind = CompletionKind::PoundAvailablePlatform; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeTypeDeclResultBeginning() { Kind = CompletionKind::TypeDeclResultBeginning; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeTypeSimpleBeginning() { Kind = CompletionKind::TypeSimpleBeginning; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeDeclAttrParam(DeclAttrKind DK, int Index) { Kind = CompletionKind::AttributeDeclParen; AttrKind = DK; AttrParamIndex = Index; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeDeclAttrKeyword(Decl *D, bool Sil, bool Param) { Kind = CompletionKind::AttributeBegin; IsInSil = Sil; if (Param) { AttTargetDK = DeclKind::Param; } else if (D) { AttTargetDK = D->getKind(); } CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeInPrecedenceGroup(SyntaxKind SK) { assert(P.Tok.is(tok::code_complete)); SyntxKind = SK; Kind = CompletionKind::PrecedenceGroup; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeTypeIdentifierWithDot( IdentTypeRepr *ITR) { if (!ITR) { completeTypeSimpleBeginning(); return; } Kind = CompletionKind::TypeIdentifierWithDot; ParsedTypeLoc = TypeLoc(ITR); CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeTypeIdentifierWithoutDot( IdentTypeRepr *ITR) { assert(ITR); Kind = CompletionKind::TypeIdentifierWithoutDot; ParsedTypeLoc = TypeLoc(ITR); CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeCaseStmtKeyword() { Kind = CompletionKind::CaseStmtKeyword; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeCaseStmtBeginning() { assert(!InEnumElementRawValue); Kind = CompletionKind::CaseStmtBeginning; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeCaseStmtDotPrefix() { assert(!InEnumElementRawValue); Kind = CompletionKind::CaseStmtDotPrefix; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeImportDecl( std::vector> &Path) { Kind = CompletionKind::Import; CurDeclContext = P.CurDeclContext; DotLoc = Path.empty() ? SourceLoc() : Path.back().second; if (DotLoc.isInvalid()) return; auto Importer = static_cast(CurDeclContext->getASTContext(). getClangModuleLoader()); std::vector SubNames; Importer->collectSubModuleNames(Path, SubNames); ASTContext &Ctx = CurDeclContext->getASTContext(); for (StringRef Sub : SubNames) { Path.push_back(std::make_pair(Ctx.getIdentifier(Sub), SourceLoc())); SubModuleNameVisibilityPairs.push_back( std::make_pair(Sub.str(), Ctx.getLoadedModule(Path))); Path.pop_back(); } } void CodeCompletionCallbacksImpl::completeUnresolvedMember(CodeCompletionExpr *E, SourceLoc DotLoc) { Kind = CompletionKind::UnresolvedMember; CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; this->DotLoc = DotLoc; } void CodeCompletionCallbacksImpl::completeAssignmentRHS(AssignExpr *E) { AssignmentExpr = E; ParsedExpr = E->getDest(); CurDeclContext = P.CurDeclContext; Kind = CompletionKind::AssignmentRHS; } void CodeCompletionCallbacksImpl::completeCallArg(CodeCompletionExpr *E) { CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; Kind = CompletionKind::CallArg; } void CodeCompletionCallbacksImpl::completeReturnStmt(CodeCompletionExpr *E) { CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; Kind = CompletionKind::ReturnStmtExpr; } void CodeCompletionCallbacksImpl::completeYieldStmt(CodeCompletionExpr *E, Optional index) { CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; // TODO: use a different completion kind when completing without an index // in a multiple-value context. Kind = CompletionKind::YieldStmtExpr; } void CodeCompletionCallbacksImpl::completeAfterPoundExpr( CodeCompletionExpr *E, Optional ParentKind) { CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; Kind = CompletionKind::AfterPoundExpr; ParentStmtKind = ParentKind; } void CodeCompletionCallbacksImpl::completeAfterPoundDirective() { CurDeclContext = P.CurDeclContext; Kind = CompletionKind::AfterPoundDirective; } void CodeCompletionCallbacksImpl::completePlatformCondition() { CurDeclContext = P.CurDeclContext; Kind = CompletionKind::PlatformConditon; } void CodeCompletionCallbacksImpl::completeAfterIfStmt(bool hasElse) { CurDeclContext = P.CurDeclContext; if (hasElse) { Kind = CompletionKind::AfterIfStmtElse; } else { Kind = CompletionKind::StmtOrExpr; } } void CodeCompletionCallbacksImpl::completeGenericParams(TypeLoc TL) { CurDeclContext = P.CurDeclContext; Kind = CompletionKind::GenericParams; ParsedTypeLoc = TL; } void CodeCompletionCallbacksImpl::completeNominalMemberBeginning( SmallVectorImpl &Keywords, SourceLoc introducerLoc) { assert(!InEnumElementRawValue); this->introducerLoc = introducerLoc; ParsedKeywords.clear(); ParsedKeywords.append(Keywords.begin(), Keywords.end()); Kind = CompletionKind::NominalMemberBeginning; CurDeclContext = P.CurDeclContext; } void CodeCompletionCallbacksImpl::completeAccessorBeginning( CodeCompletionExpr *E) { Kind = CompletionKind::AccessorBeginning; CurDeclContext = P.CurDeclContext; CodeCompleteTokenExpr = E; } static bool isDynamicLookup(Type T) { return T->getRValueType()->isAnyObject(); } static bool isClangSubModule(ModuleDecl *TheModule) { if (auto ClangMod = TheModule->findUnderlyingClangModule()) return ClangMod->isSubModule(); return false; } static void addKeyword(CodeCompletionResultSink &Sink, StringRef Name, CodeCompletionKeywordKind Kind, StringRef TypeAnnotation = "") { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::None, {}); Builder.setKeywordKind(Kind); Builder.addTextChunk(Name); if (!TypeAnnotation.empty()) Builder.addTypeAnnotation(TypeAnnotation); } static void addDeclKeywords(CodeCompletionResultSink &Sink) { auto AddDeclKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind, Optional DAK) { if (Name == "let" || Name == "var") { // Treat keywords that could be the start of a pattern specially. return; } // Remove user inaccessible keywords. if (DAK.hasValue() && DeclAttribute::isUserInaccessible(*DAK)) return; addKeyword(Sink, Name, Kind); }; #define DECL_KEYWORD(kw) AddDeclKeyword(#kw, CodeCompletionKeywordKind::kw_##kw, None); #include "swift/Syntax/TokenKinds.def" // Context-sensitive keywords. auto AddCSKeyword = [&](StringRef Name, DeclAttrKind Kind) { AddDeclKeyword(Name, CodeCompletionKeywordKind::None, Kind); }; #define CONTEXTUAL_CASE(KW, CLASS) AddCSKeyword(#KW, DAK_##CLASS); #define CONTEXTUAL_DECL_ATTR(KW, CLASS, ...) CONTEXTUAL_CASE(KW, CLASS) #define CONTEXTUAL_DECL_ATTR_ALIAS(KW, CLASS) CONTEXTUAL_CASE(KW, CLASS) #define CONTEXTUAL_SIMPLE_DECL_ATTR(KW, CLASS, ...) CONTEXTUAL_CASE(KW, CLASS) #include #undef CONTEXTUAL_CASE } static void addStmtKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) { auto AddStmtKeyword = [&](StringRef Name, CodeCompletionKeywordKind Kind) { if (!MaybeFuncBody && Kind == CodeCompletionKeywordKind::kw_return) return; addKeyword(Sink, Name, Kind); }; #define STMT_KEYWORD(kw) AddStmtKeyword(#kw, CodeCompletionKeywordKind::kw_##kw); #include "swift/Syntax/TokenKinds.def" } static void addCaseStmtKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "case", CodeCompletionKeywordKind::kw_case); addKeyword(Sink, "default", CodeCompletionKeywordKind::kw_default); } static void addLetVarKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "let", CodeCompletionKeywordKind::kw_let); addKeyword(Sink, "var", CodeCompletionKeywordKind::kw_var); } static void addAccessorKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "get", CodeCompletionKeywordKind::None); addKeyword(Sink, "set", CodeCompletionKeywordKind::None); } static void addObserverKeywords(CodeCompletionResultSink &Sink) { addKeyword(Sink, "willSet", CodeCompletionKeywordKind::None); addKeyword(Sink, "didSet", CodeCompletionKeywordKind::None); } static void addExprKeywords(CodeCompletionResultSink &Sink) { // Expr keywords. addKeyword(Sink, "try", CodeCompletionKeywordKind::kw_try); addKeyword(Sink, "try!", CodeCompletionKeywordKind::kw_try); addKeyword(Sink, "try?", CodeCompletionKeywordKind::kw_try); // FIXME: The pedantically correct way to find the type is to resolve the // Swift.StringLiteralType type. addKeyword(Sink, "#function", CodeCompletionKeywordKind::pound_function, "String"); addKeyword(Sink, "#file", CodeCompletionKeywordKind::pound_file, "String"); // Same: Swift.IntegerLiteralType. addKeyword(Sink, "#line", CodeCompletionKeywordKind::pound_line, "Int"); addKeyword(Sink, "#column", CodeCompletionKeywordKind::pound_column, "Int"); addKeyword(Sink, "#dsohandle", CodeCompletionKeywordKind::pound_dsohandle, "UnsafeMutableRawPointer"); } static void addOpaqueTypeKeyword(CodeCompletionResultSink &Sink) { addKeyword(Sink, "some", CodeCompletionKeywordKind::None, "some"); } static void addAnyTypeKeyword(CodeCompletionResultSink &Sink) { addKeyword(Sink, "Any", CodeCompletionKeywordKind::None, "Any"); } void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody) { switch (Kind) { case CompletionKind::None: case CompletionKind::DotExpr: case CompletionKind::AttributeDeclParen: case CompletionKind::AttributeBegin: case CompletionKind::PoundAvailablePlatform: case CompletionKind::Import: case CompletionKind::UnresolvedMember: case CompletionKind::CallArg: case CompletionKind::AfterPoundExpr: case CompletionKind::AfterPoundDirective: case CompletionKind::PlatformConditon: case CompletionKind::GenericParams: case CompletionKind::KeyPathExprObjC: case CompletionKind::KeyPathExprSwift: case CompletionKind::PrecedenceGroup: break; case CompletionKind::AccessorBeginning: { // TODO: Omit already declared or mutally exclusive accessors. // E.g. If 'get' is already declared, emit 'set' only. addAccessorKeywords(Sink); // Only 'var' for non-protocol context can have 'willSet' and 'didSet'. assert(ParsedDecl); VarDecl *var = dyn_cast(ParsedDecl); if (auto accessor = dyn_cast(ParsedDecl)) var = dyn_cast(accessor->getStorage()); if (var && !var->getDeclContext()->getSelfProtocolDecl()) addObserverKeywords(Sink); if (!isa(ParsedDecl)) break; MaybeFuncBody = true; LLVM_FALLTHROUGH; } case CompletionKind::StmtOrExpr: addDeclKeywords(Sink); addStmtKeywords(Sink, MaybeFuncBody); LLVM_FALLTHROUGH; case CompletionKind::AssignmentRHS: case CompletionKind::ReturnStmtExpr: case CompletionKind::YieldStmtExpr: case CompletionKind::PostfixExprBeginning: case CompletionKind::ForEachSequence: addSuperKeyword(Sink); addLetVarKeywords(Sink); addExprKeywords(Sink); addAnyTypeKeyword(Sink); break; case CompletionKind::CaseStmtKeyword: addCaseStmtKeywords(Sink); break; case CompletionKind::PostfixExpr: case CompletionKind::PostfixExprParen: case CompletionKind::SuperExpr: case CompletionKind::SuperExprDot: case CompletionKind::CaseStmtBeginning: case CompletionKind::CaseStmtDotPrefix: case CompletionKind::TypeIdentifierWithDot: case CompletionKind::TypeIdentifierWithoutDot: break; case CompletionKind::TypeDeclResultBeginning: if (!isa(CurDeclContext)) if (CurDeclContext->isTypeContext() || (ParsedDecl && isa(ParsedDecl))) addOpaqueTypeKeyword(Sink); LLVM_FALLTHROUGH; case CompletionKind::TypeSimpleBeginning: addAnyTypeKeyword(Sink); break; case CompletionKind::NominalMemberBeginning: { bool HasDeclIntroducer = llvm::find_if(ParsedKeywords, [this](const StringRef kw) { return llvm::StringSwitch(kw) .Case("associatedtype", true) .Case("class", !CurDeclContext || !isa(CurDeclContext)) .Case("deinit", true) .Case("enum", true) .Case("extension", true) .Case("func", true) .Case("import", true) .Case("init", true) .Case("let", true) .Case("operator", true) .Case("precedencegroup", true) .Case("protocol", true) .Case("struct", true) .Case("subscript", true) .Case("typealias", true) .Case("var", true) .Default(false); }) != ParsedKeywords.end(); if (!HasDeclIntroducer) { addDeclKeywords(Sink); addLetVarKeywords(Sink); } break; } case CompletionKind::AfterIfStmtElse: addKeyword(Sink, "if", CodeCompletionKeywordKind::kw_if); break; } } static void addPoundDirectives(CodeCompletionResultSink &Sink) { auto addWithName = [&](StringRef name, CodeCompletionKeywordKind K, llvm::function_ref consumer = nullptr) { CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::Keyword, SemanticContextKind::None, {}); Builder.addTextChunk(name); Builder.setKeywordKind(K); if (consumer) consumer(Builder); }; addWithName("sourceLocation", CodeCompletionKeywordKind::pound_sourceLocation, [&] (CodeCompletionResultBuilder &Builder) { Builder.addLeftParen(); Builder.addTextChunk("file"); Builder.addCallParameterColon(); Builder.addSimpleTypedParameter("String"); Builder.addComma(); Builder.addTextChunk("line"); Builder.addCallParameterColon(); Builder.addSimpleTypedParameter("Int"); Builder.addRightParen(); }); addWithName("warning", CodeCompletionKeywordKind::pound_warning, [&] (CodeCompletionResultBuilder &Builder) { Builder.addLeftParen(); Builder.addTextChunk("\""); Builder.addSimpleNamedParameter("message"); Builder.addTextChunk("\""); Builder.addRightParen(); }); addWithName("error", CodeCompletionKeywordKind::pound_error, [&] (CodeCompletionResultBuilder &Builder) { Builder.addLeftParen(); Builder.addTextChunk("\""); Builder.addSimpleNamedParameter("message"); Builder.addTextChunk("\""); Builder.addRightParen(); }); addWithName("if ", CodeCompletionKeywordKind::pound_if, [&] (CodeCompletionResultBuilder &Builder) { Builder.addSimpleNamedParameter("condition"); }); // FIXME: These directives are only valid in conditional completion block. addWithName("elseif ", CodeCompletionKeywordKind::pound_elseif, [&] (CodeCompletionResultBuilder &Builder) { Builder.addSimpleNamedParameter("condition"); }); addWithName("else", CodeCompletionKeywordKind::pound_else); addWithName("endif", CodeCompletionKeywordKind::pound_endif); } /// Add platform conditions used in '#if' and '#elseif' directives. static void addPlatformConditions(CodeCompletionResultSink &Sink) { auto addWithName = [&](StringRef Name, llvm::function_ref consumer) { CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Pattern, SemanticContextKind::ExpressionSpecific, {}); Builder.addTextChunk(Name); Builder.addLeftParen(); consumer(Builder); Builder.addRightParen(); }; addWithName("os", [](CodeCompletionResultBuilder &Builder) { Builder.addSimpleNamedParameter("name"); }); addWithName("arch", [](CodeCompletionResultBuilder &Builder) { Builder.addSimpleNamedParameter("name"); }); addWithName("canImport", [](CodeCompletionResultBuilder &Builder) { Builder.addSimpleNamedParameter("module"); }); addWithName("targetEnvironment", [](CodeCompletionResultBuilder &Builder) { Builder.addTextChunk("simulator"); }); addWithName("swift", [](CodeCompletionResultBuilder &Builder) { Builder.addTextChunk(">="); Builder.addSimpleNamedParameter("version"); }); addWithName("swift", [](CodeCompletionResultBuilder &Builder) { Builder.addTextChunk("<"); Builder.addSimpleNamedParameter("version"); }); addWithName("compiler", [](CodeCompletionResultBuilder &Builder) { Builder.addTextChunk(">="); Builder.addSimpleNamedParameter("version"); }); addWithName("compiler", [](CodeCompletionResultBuilder &Builder) { Builder.addTextChunk("<"); Builder.addSimpleNamedParameter("version"); }); addKeyword(Sink, "true", CodeCompletionKeywordKind::kw_true, "Bool"); addKeyword(Sink, "false", CodeCompletionKeywordKind::kw_false, "Bool"); } /// Add flags specified by '-D' to completion results. static void addConditionalCompilationFlags(ASTContext &Ctx, CodeCompletionResultSink &Sink) { for (auto Flag : Ctx.LangOpts.getCustomConditionalCompilationFlags()) { // TODO: Should we filter out some flags? CodeCompletionResultBuilder Builder( Sink, CodeCompletionResult::ResultKind::Keyword, SemanticContextKind::ExpressionSpecific, {}); Builder.addTextChunk(Flag); } } void CodeCompletionCallbacksImpl::doneParsing() { CompletionContext.CodeCompletionKind = Kind; if (Kind == CompletionKind::None) { return; } bool MaybeFuncBody = true; if (CurDeclContext) { auto *CD = CurDeclContext->getLocalContext(); if (!CD || CD->getContextKind() == DeclContextKind::Initializer || CD->getContextKind() == DeclContextKind::TopLevelCodeDecl) MaybeFuncBody = false; } // Add keywords even if type checking fails completely. addKeywords(CompletionContext.getResultSink(), MaybeFuncBody); if (auto *DC = dyn_cast_or_null(ParsedDecl)) { if (DC->isChildContextOf(CurDeclContext)) CurDeclContext = DC; } typeCheckContextUntil( CurDeclContext, CurDeclContext->getASTContext().SourceMgr.getCodeCompletionLoc()); Optional ExprType; ConcreteDeclRef ReferencedDecl = nullptr; if (ParsedExpr) { if (auto *checkedExpr = findParsedExpr(CurDeclContext, ParsedExpr->getSourceRange())) { ParsedExpr = checkedExpr; } if (auto typechecked = typeCheckParsedExpr()) { ExprType = typechecked->first; ReferencedDecl = typechecked->second; ParsedExpr->setType(*ExprType); } if (!ExprType && Kind != CompletionKind::PostfixExprParen && Kind != CompletionKind::CallArg && Kind != CompletionKind::KeyPathExprObjC) return; } if (!ParsedTypeLoc.isNull() && !typecheckParsedType()) return; CompletionLookup Lookup(CompletionContext.getResultSink(), P.Context, CurDeclContext, &CompletionContext); if (ExprType) { Lookup.setIsStaticMetatype(ParsedExpr->isStaticallyDerivedMetatype()); } if (auto *DRE = dyn_cast_or_null(ParsedExpr)) { Lookup.setIsSelfRefExpr(DRE->getDecl()->getFullName() == Context.Id_self); } if (isInsideObjCSelector()) Lookup.includeInstanceMembers(); if (PreferFunctionReferencesToCalls) Lookup.setPreferFunctionReferencesToCalls(); auto DoPostfixExprBeginning = [&] (){ SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); Lookup.getValueCompletionsInDeclContext(Loc); }; switch (Kind) { case CompletionKind::None: llvm_unreachable("should be already handled"); return; case CompletionKind::DotExpr: { Lookup.setHaveDot(DotLoc); if (isDynamicLookup(*ExprType)) Lookup.setIsDynamicLookup(); Lookup.getPostfixKeywordCompletions(*ExprType, ParsedExpr); if (isa(ParsedExpr) || isa(ParsedExpr)) Lookup.setIsUnwrappedOptional(true); ExprContextInfo ContextInfo(CurDeclContext, ParsedExpr); Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); break; } case CompletionKind::KeyPathExprSwift: { auto KPE = dyn_cast(ParsedExpr); auto BGT = (*ExprType)->getAs(); if (!KPE || !BGT || BGT->getGenericArgs().size() != 2) break; assert(!KPE->isObjC()); if (DotLoc.isValid()) Lookup.setHaveDot(DotLoc); bool OnRoot = !KPE->getComponents().front().isValid(); Lookup.setIsSwiftKeyPathExpr(OnRoot); Type baseType = BGT->getGenericArgs()[OnRoot ? 0 : 1]; if (OnRoot && baseType->is()) { // Infer the root type of the keypath from the context type. ExprContextInfo ContextInfo(CurDeclContext, ParsedExpr); for (auto T : ContextInfo.getPossibleTypes()) { if (auto unwrapped = T->getOptionalObjectType()) T = unwrapped; if (!T->getAnyNominal() || !T->getAnyNominal()->getKeyPathTypeKind() || T->hasUnresolvedType() || !T->is()) continue; // Use the first KeyPath context type found. baseType = T->castTo()->getGenericArgs()[0]; break; } } if (!OnRoot && KPE->getComponents().back().getKind() == KeyPathExpr::Component::Kind::OptionalWrap) { // KeyPath expr with '?' (e.g. '\Ty.[0].prop?.another'). // Althogh expected type is optional, we should unwrap it because it's // unwrapped. baseType = baseType->getOptionalObjectType(); } Lookup.getValueExprCompletions(baseType); break; } case CompletionKind::StmtOrExpr: case CompletionKind::ForEachSequence: case CompletionKind::PostfixExprBeginning: { ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); DoPostfixExprBeginning(); break; } case CompletionKind::PostfixExpr: { Lookup.setHaveLeadingSpace(HasSpace); if (isDynamicLookup(*ExprType)) Lookup.setIsDynamicLookup(); Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); Lookup.getOperatorCompletions(ParsedExpr, leadingSequenceExprs); Lookup.getPostfixKeywordCompletions(*ExprType, ParsedExpr); break; } case CompletionKind::PostfixExprParen: { Lookup.setHaveLParen(true); ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); if (ShouldCompleteCallPatternAfterParen) { ExprContextInfo ParentContextInfo(CurDeclContext, ParsedExpr); Lookup.setExpectedTypes(ParentContextInfo.getPossibleTypes(), ParentContextInfo.isSingleExpressionBody()); if (ExprType && ((*ExprType)->is() || (*ExprType)->is())) { Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); } else { for (auto &typeAndDecl : ContextInfo.getPossibleCallees()) Lookup.tryFunctionCallCompletions(typeAndDecl.first, typeAndDecl.second); } } else { // Add argument labels, then fallthrough to get values. Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); } if (!Lookup.FoundFunctionCalls || (Lookup.FoundFunctionCalls && Lookup.FoundFunctionsWithoutFirstKeyword)) { Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); Lookup.setHaveLParen(false); DoPostfixExprBeginning(); } break; } case CompletionKind::SuperExpr: { Lookup.setIsSuperRefExpr(); Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); break; } case CompletionKind::SuperExprDot: { Lookup.setIsSuperRefExpr(); Lookup.setHaveDot(SourceLoc()); Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); break; } case CompletionKind::KeyPathExprObjC: { if (DotLoc.isValid()) Lookup.setHaveDot(DotLoc); Lookup.setIsKeyPathExpr(); Lookup.includeInstanceMembers(); if (ExprType) { if (isDynamicLookup(*ExprType)) Lookup.setIsDynamicLookup(); Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl()); } else { SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); Lookup.getValueCompletionsInDeclContext(Loc, KeyPathFilter, false, true, false); } break; } case CompletionKind::TypeDeclResultBeginning: case CompletionKind::TypeSimpleBeginning: { Lookup.getTypeCompletionsInDeclContext( P.Context.SourceMgr.getCodeCompletionLoc()); break; } case CompletionKind::TypeIdentifierWithDot: { Lookup.setHaveDot(SourceLoc()); Lookup.getTypeCompletions(ParsedTypeLoc.getType()); break; } case CompletionKind::TypeIdentifierWithoutDot: { Lookup.getTypeCompletions(ParsedTypeLoc.getType()); break; } case CompletionKind::CaseStmtBeginning: { SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); Lookup.getValueCompletionsInDeclContext(Loc); Lookup.getTypeContextEnumElementCompletions(Loc); break; } case CompletionKind::CaseStmtDotPrefix: { Lookup.setHaveDot(SourceLoc()); SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); Lookup.getTypeContextEnumElementCompletions(Loc); break; } case CompletionKind::NominalMemberBeginning: { CompletionOverrideLookup OverrideLookup(CompletionContext.getResultSink(), P.Context, CurDeclContext, ParsedKeywords, introducerLoc); OverrideLookup.getOverrideCompletions(SourceLoc()); break; } case CompletionKind::AccessorBeginning: { if (isa(ParsedDecl)) { ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); DoPostfixExprBeginning(); } break; } case CompletionKind::AttributeBegin: { Lookup.getAttributeDeclCompletions(IsInSil, AttTargetDK); break; } case CompletionKind::AttributeDeclParen: { Lookup.getAttributeDeclParamCompletions(AttrKind, AttrParamIndex); break; } case CompletionKind::PoundAvailablePlatform: { Lookup.getPoundAvailablePlatformCompletions(); break; } case CompletionKind::Import: { if (DotLoc.isValid()) Lookup.addSubModuleNames(SubModuleNameVisibilityPairs); else Lookup.addImportModuleNames(); break; } case CompletionKind::UnresolvedMember: { Lookup.setHaveDot(DotLoc); ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); Lookup.getUnresolvedMemberCompletions(ContextInfo.getPossibleTypes()); break; } case CompletionKind::AssignmentRHS : { SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); if (auto destType = ParsedExpr->getType()) Lookup.setExpectedTypes(destType->getRValueType(), /*isSingleExpressionBody*/ false); Lookup.getValueCompletionsInDeclContext(Loc, DefaultFilter); break; } case CompletionKind::CallArg : { ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr); if (!ContextInfo.getPossibleNames().empty()) { Lookup.addArgNameCompletionResults(ContextInfo.getPossibleNames()); break; } Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(), ContextInfo.isSingleExpressionBody()); DoPostfixExprBeginning(); break; } case CompletionKind::ReturnStmtExpr : { SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); Lookup.setExpectedTypes(getReturnTypeFromContext(CurDeclContext), /*isSingleExpressionBody*/ false); Lookup.getValueCompletionsInDeclContext(Loc); break; } case CompletionKind::YieldStmtExpr: { SourceLoc Loc = P.Context.SourceMgr.getCodeCompletionLoc(); if (auto FD = dyn_cast(CurDeclContext)) { if (FD->isCoroutine()) { // TODO: handle multi-value yields. Lookup.setExpectedTypes(FD->getStorage()->getValueInterfaceType(), /*isSingleExpressionBody*/ false); } } Lookup.getValueCompletionsInDeclContext(Loc); break; } case CompletionKind::AfterPoundExpr: { Lookup.addPoundAvailable(ParentStmtKind); Lookup.addPoundSelector(/*needPound=*/false); Lookup.addPoundKeyPath(/*needPound=*/false); break; } case CompletionKind::AfterPoundDirective: { addPoundDirectives(CompletionContext.getResultSink()); // FIXME: Add pound expressions (e.g. '#selector()') if it's at statements // position. break; } case CompletionKind::PlatformConditon: { addPlatformConditions(CompletionContext.getResultSink()); addConditionalCompilationFlags(CurDeclContext->getASTContext(), CompletionContext.getResultSink()); break; } case CompletionKind::GenericParams: if (auto GT = ParsedTypeLoc.getType()->getAnyGeneric()) { if (auto Params = GT->getGenericParams()) { for (auto GP : Params->getParams()) { Lookup.addGenericTypeParamRef( GP, DeclVisibilityKind::GenericParameter, {}); } } } break; case CompletionKind::PrecedenceGroup: Lookup.getPrecedenceGroupCompletions(SyntxKind); break; case CompletionKind::AfterIfStmtElse: case CompletionKind::CaseStmtKeyword: // Handled earlier by keyword completions. break; } for (auto &Request: Lookup.RequestedCachedResults) { // Use the current SourceFile as the DeclContext so that we can use it to // perform qualified lookup, and to get the correct visibility for // @testable imports. const SourceFile &SF = P.SF; llvm::DenseSet ImportsSeen; auto handleImport = [&](ModuleDecl::ImportedModule Import) { ModuleDecl *TheModule = Import.second; ModuleDecl::AccessPathTy Path = Import.first; if (TheModule->getFiles().empty()) return; // Clang submodules are ignored and there's no lookup cost involved, // so just ignore them and don't put the empty results in the cache // because putting a lot of objects in the cache will push out // other lookups. if (isClangSubModule(TheModule)) return; std::vector AccessPath; for (auto Piece : Path) { AccessPath.push_back(Piece.first.str()); } StringRef ModuleFilename = TheModule->getModuleFilename(); // ModuleFilename can be empty if something strange happened during // module loading, for example, the module file is corrupted. if (!ModuleFilename.empty()) { auto &Ctx = TheModule->getASTContext(); CodeCompletionCache::Key K{ ModuleFilename, TheModule->getName().str(), AccessPath, Request.NeedLeadingDot, SF.hasTestableOrPrivateImport( AccessLevel::Internal, TheModule, SourceFile::ImportQueryKind::TestableOnly), SF.hasTestableOrPrivateImport( AccessLevel::Internal, TheModule, SourceFile::ImportQueryKind::PrivateOnly), Ctx.LangOpts.CodeCompleteInitsInPostfixExpr}; using PairType = llvm::DenseSet>::iterator; std::pair Result = ImportsSeen.insert(K); if (!Result.second) return; // already handled. RequestedModules.push_back({std::move(K), TheModule, Request.OnlyTypes, Request.OnlyPrecedenceGroups}); } }; if (Request.TheModule) { // FIXME: actually check imports. const_cast(Request.TheModule) ->forAllVisibleModules({}, handleImport); } else { // Add results from current module. Lookup.getToplevelCompletions(Request.OnlyTypes); // Add results for all imported modules. ModuleDecl::ImportFilter ImportFilter; ImportFilter |= ModuleDecl::ImportFilterKind::Public; ImportFilter |= ModuleDecl::ImportFilterKind::Private; ImportFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly; SmallVector Imports; auto *SF = CurDeclContext->getParentSourceFile(); SF->getImportedModules(Imports, ImportFilter); for (auto Imported : Imports) { ModuleDecl *TheModule = Imported.second; ModuleDecl::AccessPathTy AccessPath = Imported.first; TheModule->forAllVisibleModules(AccessPath, handleImport); } } Lookup.RequestedCachedResults.clear(); } CompletionContext.typeContextKind = Lookup.typeContextKind(); deliverCompletionResults(); } void CodeCompletionCallbacksImpl::deliverCompletionResults() { // Use the current SourceFile as the DeclContext so that we can use it to // perform qualified lookup, and to get the correct visibility for // @testable imports. DeclContext *DCForModules = &P.SF; Consumer.handleResultsAndModules(CompletionContext, RequestedModules, DCForModules); RequestedModules.clear(); DeliveredResults = true; } void PrintingCodeCompletionConsumer::handleResults( MutableArrayRef Results) { unsigned NumResults = 0; for (auto Result : Results) { if (!IncludeKeywords && Result->getKind() == CodeCompletionResult::Keyword) continue; NumResults++; } if (NumResults == 0) return; OS << "Begin completions, " << NumResults << " items\n"; for (auto Result : Results) { if (!IncludeKeywords && Result->getKind() == CodeCompletionResult::Keyword) continue; Result->print(OS); llvm::SmallString<64> Name; llvm::raw_svector_ostream NameOs(Name); Result->getCompletionString()->getName(NameOs); OS << "; name=" << Name; StringRef comment = Result->getBriefDocComment(); if (IncludeComments && !comment.empty()) { OS << "; comment=" << comment; } OS << "\n"; } OS << "End completions\n"; } namespace { class CodeCompletionCallbacksFactoryImpl : public CodeCompletionCallbacksFactory { CodeCompletionContext &CompletionContext; CodeCompletionConsumer &Consumer; public: CodeCompletionCallbacksFactoryImpl(CodeCompletionContext &CompletionContext, CodeCompletionConsumer &Consumer) : CompletionContext(CompletionContext), Consumer(Consumer) {} CodeCompletionCallbacks *createCodeCompletionCallbacks(Parser &P) override { return new CodeCompletionCallbacksImpl(P, CompletionContext, Consumer); } }; } // end anonymous namespace CodeCompletionCallbacksFactory * swift::ide::makeCodeCompletionCallbacksFactory( CodeCompletionContext &CompletionContext, CodeCompletionConsumer &Consumer) { return new CodeCompletionCallbacksFactoryImpl(CompletionContext, Consumer); } void swift::ide::lookupCodeCompletionResultsFromModule( CodeCompletionResultSink &targetSink, const ModuleDecl *module, ArrayRef accessPath, bool needLeadingDot, const DeclContext *currDeclContext) { CompletionLookup Lookup(targetSink, module->getASTContext(), currDeclContext); Lookup.getVisibleDeclsOfModule(module, accessPath, needLeadingDot); } void swift::ide::copyCodeCompletionResults(CodeCompletionResultSink &targetSink, CodeCompletionResultSink &sourceSink, bool onlyTypes, bool onlyPrecedenceGroups) { // We will be adding foreign results (from another sink) into TargetSink. // TargetSink should have an owning pointer to the allocator that keeps the // results alive. targetSink.ForeignAllocators.push_back(sourceSink.Allocator); if (onlyTypes) { std::copy_if(sourceSink.Results.begin(), sourceSink.Results.end(), std::back_inserter(targetSink.Results), [](CodeCompletionResult *R) -> bool { if (R->getKind() != CodeCompletionResult::Declaration) return false; switch(R->getAssociatedDeclKind()) { case CodeCompletionDeclKind::PrecedenceGroup: case CodeCompletionDeclKind::Module: case CodeCompletionDeclKind::Class: case CodeCompletionDeclKind::Struct: case CodeCompletionDeclKind::Enum: case CodeCompletionDeclKind::Protocol: case CodeCompletionDeclKind::TypeAlias: case CodeCompletionDeclKind::AssociatedType: case CodeCompletionDeclKind::GenericTypeParam: return true; case CodeCompletionDeclKind::EnumElement: case CodeCompletionDeclKind::Constructor: case CodeCompletionDeclKind::Destructor: case CodeCompletionDeclKind::Subscript: case CodeCompletionDeclKind::StaticMethod: case CodeCompletionDeclKind::InstanceMethod: case CodeCompletionDeclKind::PrefixOperatorFunction: case CodeCompletionDeclKind::PostfixOperatorFunction: case CodeCompletionDeclKind::InfixOperatorFunction: case CodeCompletionDeclKind::FreeFunction: case CodeCompletionDeclKind::StaticVar: case CodeCompletionDeclKind::InstanceVar: case CodeCompletionDeclKind::LocalVar: case CodeCompletionDeclKind::GlobalVar: return false; } llvm_unreachable("Unhandled CodeCompletionDeclKind in switch."); }); } else if (onlyPrecedenceGroups) { std::copy_if(sourceSink.Results.begin(), sourceSink.Results.end(), std::back_inserter(targetSink.Results), [](CodeCompletionResult *R) -> bool { return R->getAssociatedDeclKind() == CodeCompletionDeclKind::PrecedenceGroup; }); } else { targetSink.Results.insert(targetSink.Results.end(), sourceSink.Results.begin(), sourceSink.Results.end()); } } void SimpleCachingCodeCompletionConsumer::handleResultsAndModules( CodeCompletionContext &context, ArrayRef requestedModules, DeclContext *DCForModules) { for (auto &R : requestedModules) { // FIXME(thread-safety): lock the whole AST context. We might load a // module. llvm::Optional V = context.Cache.get(R.Key); if (!V.hasValue()) { // No cached results found. Fill the cache. V = context.Cache.createValue(); lookupCodeCompletionResultsFromModule( (*V)->Sink, R.TheModule, R.Key.AccessPath, R.Key.ResultsHaveLeadingDot, DCForModules); context.Cache.set(R.Key, *V); } assert(V.hasValue()); copyCodeCompletionResults(context.getResultSink(), (*V)->Sink, R.OnlyTypes, R.OnlyPrecedenceGroups); } handleResults(context.takeResults()); }