blob: 391f8b5dbe58002b71a3c31875450def951e161b [file] [log] [blame]
//===--- 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/ImportCache.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/SourceFile.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/CodeCompletionResultPrinter.h"
#include "swift/IDE/Utils.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Sema/IDETypeChecking.h"
#include "swift/Sema/CodeCompletionTypeChecking.h"
#include "swift/Syntax/SyntaxKind.h"
#include "swift/Strings.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 <algorithm>
#include <string>
using namespace swift;
using namespace ide;
using CommandWordsPairs = std::vector<std::pair<StringRef, StringRef>>;
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<StringRef>& 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<std::pair<StringRef, StringRef>> Content;
std::vector<StringRef> ViewedText;
std::vector<StringRef> Words;
StringRef Key;
bool isKeyViewed(StringRef K) {
return std::find(ViewedText.begin(), ViewedText.end(), K) != ViewedText.end();
}
public:
WordPairsArrangedViewer(ArrayRef<std::pair<StringRef, StringRef>> 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<StringRef, ArrayRef<StringRef>> 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<ClangCommentExtractor> {
CommandWordsPairs &Words;
const CommandTraits &Traits;
std::vector<const Comment *> 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<TextComment>(*CIT)) {
auto Text = TC->getText();
std::vector<StringRef> 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<StringRef> 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)
return;
SwiftDocWordExtractor Extractor(Words);
for (auto Part : DC->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<bool(ValueDecl *, DeclVisibilityKind)>;
static bool DefaultFilter(ValueDecl* VD, DeclVisibilityKind Kind) {
return true;
}
static bool KeyPathFilter(ValueDecl* decl, DeclVisibilityKind) {
return isa<TypeDecl>(decl) ||
(isa<VarDecl>(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;
}
llvm::StringRef swift::ide::copyString(llvm::BumpPtrAllocator &Allocator,
llvm::StringRef Str) {
char *Buffer = Allocator.Allocate<char>(Str.size());
std::copy(Str.begin(), Str.end(), Buffer);
return llvm::StringRef(Buffer, Str.size());
}
const char *swift::ide::copyCString(llvm::BumpPtrAllocator &Allocator,
llvm::StringRef Str) {
char *Buffer = Allocator.Allocate<char>(Str.size() + 1);
std::copy(Str.begin(), Str.end(), Buffer);
Buffer[Str.size()] = '\0';
return Buffer;
}
CodeCompletionString::CodeCompletionString(ArrayRef<Chunk> Chunks) {
std::uninitialized_copy(Chunks.begin(), Chunks.end(),
getTrailingObjects<Chunk>());
NumChunks = Chunks.size();
}
CodeCompletionString *CodeCompletionString::create(llvm::BumpPtrAllocator &Allocator,
ArrayRef<Chunk> Chunks) {
void *CCSMem = Allocator.Allocate(totalSizeToAlloc<Chunk>(Chunks.size()),
alignof(CodeCompletionString));
return new (CCSMem) CodeCompletionString(Chunks);
}
void CodeCompletionString::print(raw_ostream &OS) const {
unsigned PrevNestingLevel = 0;
auto chunks = getChunks();
for (auto I = chunks.begin(), E = chunks.end(); I != E; ++I) {
bool AnnotatedTextChunk = false;
if (I->getNestingLevel() < PrevNestingLevel) {
OS << "#}";
}
switch (I->getKind()) {
using ChunkKind = Chunk::ChunkKind;
case ChunkKind::AccessControlKeyword:
case ChunkKind::DeclAttrKeyword:
case ChunkKind::DeclAttrParamKeyword:
case ChunkKind::OverrideKeyword:
case ChunkKind::EffectsSpecifierKeyword:
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:
case ChunkKind::Keyword:
case ChunkKind::Attribute:
case ChunkKind::BaseName:
case ChunkKind::TypeIdSystem:
case ChunkKind::TypeIdUser:
AnnotatedTextChunk = I->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 (I->getKind() == ChunkKind::CallParameterInternalName)
OS << "(";
else if (I->getKind() == ChunkKind::CallParameterClosureType)
OS << "##";
for (char Ch : I->getText()) {
if (Ch == '\n')
OS << "\\n";
else
OS << Ch;
}
if (AnnotatedTextChunk)
OS << "']";
else if (I->getKind() == ChunkKind::CallParameterInternalName)
OS << ")";
break;
case ChunkKind::OptionalBegin:
case ChunkKind::CallParameterBegin:
case ChunkKind::CallParameterTypeBegin:
case ChunkKind::GenericParameterBegin:
OS << "{#";
break;
case ChunkKind::DynamicLookupMethodCallTail:
case ChunkKind::OptionalMethodCallTail:
OS << I->getText();
break;
case ChunkKind::TypeAnnotationBegin: {
OS << "[#";
++I;
auto level = I->getNestingLevel();
for (; I != E && !I->endsPreviousNestedGroup(level); ++I)
if (I->hasText())
OS << I->getText();
--I;
OS << "#]";
continue;
}
case ChunkKind::TypeAnnotation:
OS << "[#";
OS << I->getText();
OS << "#]";
break;
case ChunkKind::CallParameterClosureExpr:
OS << " {" << I->getText() << "|}";
break;
case ChunkKind::BraceStmtWithCursor:
OS << " {|}";
break;
}
PrevNestingLevel = I->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<VarDecl>(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<FuncDecl>(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");
}
bool CodeCompletionResult::getDeclIsSystem(const Decl *D) {
return D->getModuleContext()->isSystemModule();
}
void CodeCompletionResult::printPrefix(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 (IsSystem)
Prefix.append("/IsSystem");
if (NumBytesToErase != 0) {
Prefix.append("/Erase[");
Prefix.append(Twine(NumBytesToErase).str());
Prefix.append("]");
}
switch (getExpectedTypeRelation()) {
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::NotApplicable:
case ExpectedTypeRelation::Unknown:
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;
}
void CodeCompletionResult::dump() const {
printPrefix(llvm::errs());
CompletionString->print(llvm::errs());
llvm::errs() << "\n";
}
void CodeCompletionResultBuilder::withNestedGroup(
CodeCompletionString::Chunk::ChunkKind Kind,
llvm::function_ref<void()> body) {
++CurrentNestingLevel;
addSimpleChunk(Kind);
body();
--CurrentNestingLevel;
}
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) {
ModuleDecl *MD = D->getModuleContext();
// If this is an underscored cross-import overlay, map it to the underlying
// module that declares it instead.
if (ModuleDecl *Declaring = MD->getDeclaringModuleIfCrossImportOverlay())
MD = Declaring;
CurrentModule = MD;
}
if (D->getAttrs().getDeprecated(D->getASTContext()))
setNotRecommended(CodeCompletionResult::Deprecated);
}
namespace {
class AnnotatedTypePrinter : public ASTPrinter {
using ChunkKind = CodeCompletionString::Chunk::ChunkKind;
CodeCompletionResultBuilder &Builder;
SmallString<16> Buffer;
ChunkKind CurrChunkKind = ChunkKind::Text;
ChunkKind NextChunkKind = ChunkKind::Text;
Optional<ChunkKind> getChunkKindForPrintNameContext(PrintNameContext context) {
switch (context) {
case PrintNameContext::Keyword:
return ChunkKind::Keyword;
case PrintNameContext::Attribute:
return ChunkKind::Attribute;
default:
return None;
}
}
void flush() {
if (Buffer.empty())
return;
Builder.addChunkWithText(CurrChunkKind, Buffer);
Buffer.clear();
}
public:
AnnotatedTypePrinter(CodeCompletionResultBuilder &Builder) : Builder(Builder) {}
~AnnotatedTypePrinter() {
// Flush the remainings.
flush();
}
void printText(StringRef Text) override {
if (CurrChunkKind != NextChunkKind) {
// If the next desired kind is different from the current buffer, flush
// the current buffer.
flush();
CurrChunkKind = NextChunkKind;
}
Buffer.append(Text);
}
void printTypeRef(
Type T, const TypeDecl *TD, Identifier Name,
PrintNameContext NameContext = PrintNameContext::Normal) override {
NextChunkKind = TD->getModuleContext()->isSystemModule()
? ChunkKind::TypeIdSystem
: ChunkKind::TypeIdUser;
ASTPrinter::printTypeRef(T, TD, Name, NameContext);
NextChunkKind = ChunkKind::Text;
}
void printNamePre(PrintNameContext context) override {
if (auto Kind = getChunkKindForPrintNameContext(context))
NextChunkKind = *Kind;
}
void printNamePost(PrintNameContext context) override {
if (auto Kind = getChunkKindForPrintNameContext(context))
NextChunkKind = ChunkKind::Text;
}
};
} // namespcae
void CodeCompletionResultBuilder::addCallParameter(Identifier Name,
Identifier LocalName,
Type Ty,
Type ContextTy,
bool IsVarArg,
bool IsInOut,
bool IsIUO,
bool isAutoClosure,
bool useUnderscoreLabel,
bool isLabeledTrailingClosure) {
++CurrentNestingLevel;
using ChunkKind = CodeCompletionString::Chunk::ChunkKind;
addSimpleChunk(ChunkKind::CallParameterBegin);
if (shouldAnnotateResults()) {
if (!Name.empty() || !LocalName.empty()) {
llvm::SmallString<16> EscapedKeyword;
if (!Name.empty()) {
addChunkWithText(
CodeCompletionString::Chunk::ChunkKind::CallParameterName,
escapeKeyword(Name.str(), false, EscapedKeyword));
if (!LocalName.empty() && Name != LocalName) {
addChunkWithTextNoCopy(ChunkKind::Text, " ");
getLastChunk().setIsAnnotation();
addChunkWithText(ChunkKind::CallParameterInternalName,
escapeKeyword(LocalName.str(), false, EscapedKeyword));
getLastChunk().setIsAnnotation();
}
} else {
assert(!LocalName.empty());
addChunkWithTextNoCopy(ChunkKind::CallParameterName, "_");
getLastChunk().setIsAnnotation();
addChunkWithTextNoCopy(ChunkKind::Text, " ");
getLastChunk().setIsAnnotation();
addChunkWithText(ChunkKind::CallParameterInternalName,
escapeKeyword(LocalName.str(), false, EscapedKeyword));
}
addChunkWithTextNoCopy(ChunkKind::CallParameterColon, ": ");
}
} else {
if (!Name.empty()) {
llvm::SmallString<16> EscapedKeyword;
addChunkWithText(
CodeCompletionString::Chunk::ChunkKind::CallParameterName,
escapeKeyword(Name.str(), false, EscapedKeyword));
addChunkWithTextNoCopy(
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
} else if (useUnderscoreLabel) {
addChunkWithTextNoCopy(
CodeCompletionString::Chunk::ChunkKind::CallParameterName, "_");
addChunkWithTextNoCopy(
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
} else if (!LocalName.empty()) {
// Use local (non-API) parameter name if we have nothing else.
llvm::SmallString<16> EscapedKeyword;
addChunkWithText(
CodeCompletionString::Chunk::ChunkKind::CallParameterInternalName,
escapeKeyword(LocalName.str(), false, EscapedKeyword));
addChunkWithTextNoCopy(
CodeCompletionString::Chunk::ChunkKind::CallParameterColon, ": ");
}
}
// 'inout' arguments are printed specially.
if (IsInOut) {
addChunkWithTextNoCopy(
CodeCompletionString::Chunk::ChunkKind::Ampersand, "&");
Ty = Ty->getInOutObjectType();
}
// If the parameter is of the type @autoclosure ()->output, then the
// code completion should show the parameter of the output type
// instead of the function type ()->output.
if (isAutoClosure) {
// 'Ty' may be ErrorType.
if (auto funcTy = Ty->getAs<FunctionType>())
Ty = funcTy->getResult();
}
PrintOptions PO;
PO.SkipAttributes = true;
PO.PrintOptionalAsImplicitlyUnwrapped = IsIUO;
PO.OpaqueReturnTypePrinting =
PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword;
if (ContextTy)
PO.setBaseType(ContextTy);
if (shouldAnnotateResults()) {
withNestedGroup(ChunkKind::CallParameterTypeBegin, [&]() {
AnnotatedTypePrinter printer(*this);
Ty->print(printer, PO);
});
} else {
std::string TypeName = Ty->getString(PO);
addChunkWithText(ChunkKind::CallParameterType, TypeName);
}
// Look through optional types and type aliases to find out if we have
// function type.
Ty = Ty->lookThroughAllOptionalTypes();
if (auto AFT = Ty->getAs<AnyFunctionType>()) {
// If this is a closure type, add ChunkKind::CallParameterClosureType or
// ChunkKind::CallParameterClosureExpr for labeled trailing closures.
PrintOptions PO;
PO.PrintFunctionRepresentationAttrs =
PrintOptions::FunctionRepresentationMode::None;
PO.SkipAttributes = true;
PO.OpaqueReturnTypePrinting =
PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword;
if (ContextTy)
PO.setBaseType(ContextTy);
if (isLabeledTrailingClosure) {
// Expand the closure body.
SmallString<32> buffer;
llvm::raw_svector_ostream OS(buffer);
bool firstParam = true;
for (const auto &param : AFT->getParams()) {
if (!firstParam)
OS << ", ";
firstParam = false;
if (param.hasLabel()) {
OS << param.getLabel();
} else {
OS << "<#";
if (param.isInOut())
OS << "inout ";
OS << param.getPlainType()->getString(PO);
if (param.isVariadic())
OS << "...";
OS << "#>";
}
}
if (!firstParam)
OS << " in";
addChunkWithText(
CodeCompletionString::Chunk::ChunkKind::CallParameterClosureExpr,
OS.str());
} else {
// Add the closure type.
addChunkWithText(
CodeCompletionString::Chunk::ChunkKind::CallParameterClosureType,
AFT->getString(PO));
}
}
if (IsVarArg)
addEllipsis();
--CurrentNestingLevel;
}
void CodeCompletionResultBuilder::addTypeAnnotation(Type T, PrintOptions PO,
StringRef suffix) {
T = T->getReferenceStorageReferent();
// Replace '()' with 'Void'.
if (T->isVoid())
T = T->getASTContext().getVoidDecl()->getDeclaredInterfaceType();
if (shouldAnnotateResults()) {
withNestedGroup(CodeCompletionString::Chunk::ChunkKind::TypeAnnotationBegin,
[&]() {
AnnotatedTypePrinter printer(*this);
T->print(printer, PO);
if (!suffix.empty())
printer.printText(suffix);
});
} else {
auto str = T.getString(PO);
if (!suffix.empty())
str += suffix.str();
addTypeAnnotation(str);
}
}
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<AbstractTypeParamDecl>(VD) && !isa<AssociatedTypeDecl>(VD))
return false;
if (isa<ParamDecl>(VD))
return false;
if (isa<ModuleDecl>(VD))
return false;
if (VD->hasClangNode() && !VD->getClangDecl())
return false;
return true;
}
template <typename FnTy>
static void walkValueDeclAndOverriddenDecls(const Decl *D, const FnTy &Fn) {
if (auto *VD = dyn_cast<ValueDecl>(D)) {
Fn(VD);
walkOverriddenDecls(VD, Fn);
}
}
ArrayRef<StringRef> copyAssociatedUSRs(llvm::BumpPtrAllocator &Allocator,
const Decl *D) {
llvm::SmallVector<StringRef, 4> USRs;
walkValueDeclAndOverriddenDecls(D, [&](llvm::PointerUnion<const ValueDecl*,
const clang::NamedDecl*> OD) {
llvm::SmallString<128> SS;
bool Ignored = true;
if (auto *OVD = OD.dyn_cast<const ValueDecl*>()) {
if (shouldCopyAssociatedUSRForDecl(OVD)) {
llvm::raw_svector_ostream OS(SS);
Ignored = printValueDeclUSR(OVD, OS);
}
} else if (auto *OND = OD.dyn_cast<const clang::NamedDecl*>()) {
Ignored = clang::index::generateUSRForDecl(OND, SS);
}
if (!Ignored)
USRs.push_back(copyString(Allocator, SS));
});
if (!USRs.empty())
return copyArray(Allocator, ArrayRef<StringRef>(USRs));
return ArrayRef<StringRef>();
}
static CodeCompletionResult::ExpectedTypeRelation
calculateTypeRelation(Type Ty, Type ExpectedTy, const DeclContext *DC) {
if (Ty.isNull() || ExpectedTy.isNull() ||
Ty->is<ErrorType>() ||
ExpectedTy->is<ErrorType>())
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;
bool isAny = false;
isAny |= ExpectedTy->isAny();
isAny |= ExpectedTy->is<ArchetypeType>() &&
!ExpectedTy->castTo<ArchetypeType>()->hasRequirements();
if (!isAny && isConvertibleTo(Ty, ExpectedTy, /*openArchetypes=*/true,
*const_cast<DeclContext *>(DC)))
return CodeCompletionResult::ExpectedTypeRelation::Convertible;
}
if (auto FT = Ty->getAs<AnyFunctionType>()) {
if (FT->getResult()->isVoid())
return CodeCompletionResult::ExpectedTypeRelation::Invalid;
}
return CodeCompletionResult::ExpectedTypeRelation::Unrelated;
}
static CodeCompletionResult::ExpectedTypeRelation
calculateMaxTypeRelation(Type Ty, const ExpectedTypeContext &typeContext,
const DeclContext *DC) {
if (typeContext.empty())
return CodeCompletionResult::ExpectedTypeRelation::Unknown;
if (auto funcTy = Ty->getAs<AnyFunctionType>())
Ty = funcTy->removeArgumentLabels(1);
auto Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated;
for (auto expectedTy : 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.isImplicitSingleExpressionReturn && expectedTy->isVoid())
continue;
Result = std::max(Result, calculateTypeRelation(Ty, expectedTy, DC));
// Map invalid -> unrelated when in a single-expression body, since the
// input may be incomplete.
if (typeContext.isImplicitSingleExpressionReturn &&
Result == CodeCompletionResult::ExpectedTypeRelation::Invalid)
Result = CodeCompletionResult::ExpectedTypeRelation::Unrelated;
}
return Result;
}
CodeCompletionOperatorKind
CodeCompletionResult::getCodeCompletionOperatorKind(StringRef name) {
using CCOK = CodeCompletionOperatorKind;
using OpPair = std::pair<StringRef, CCOK>;
// 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<const clang::Module *>()) {
ModuleName = copyString(*Sink.Allocator, C->getFullModuleName());
} else {
ModuleName = copyString(
*Sink.Allocator,
CurrentModule.get<const swift::ModuleDecl *>()->getName().str());
}
Sink.LastModule.first = CurrentModule.getOpaqueValue();
Sink.LastModule.second = ModuleName;
}
}
return new (*Sink.Allocator) CodeCompletionResult(
SemanticContext, NumBytesToErase, CCS, AssociatedDecl, ModuleName,
/*NotRecommended=*/IsNotRecommended, NotRecReason,
copyString(*Sink.Allocator, BriefComment),
copyAssociatedUSRs(*Sink.Allocator, AssociatedDecl),
copyArray(*Sink.Allocator, CommentWords), ExpectedTypeRelation);
}
case CodeCompletionResult::ResultKind::Keyword:
return new (*Sink.Allocator)
CodeCompletionResult(
KeywordKind, SemanticContext, NumBytesToErase,
CCS, ExpectedTypeRelation,
copyString(*Sink.Allocator, BriefDocComment));
case CodeCompletionResult::ResultKind::BuiltinOperator:
case CodeCompletionResult::ResultKind::Pattern:
return new (*Sink.Allocator) CodeCompletionResult(
Kind, SemanticContext, NumBytesToErase, CCS, ExpectedTypeRelation,
CodeCompletionOperatorKind::None,
copyString(*Sink.Allocator, BriefDocComment));
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<CodeCompletionResult *> CodeCompletionContext::takeResults() {
// Copy pointers to the results.
const size_t Count = CurrentResults.Results.size();
CodeCompletionResult **Results =
CurrentResults.Allocator->Allocate<CodeCompletionResult *>(Count);
std::copy(CurrentResults.Results.begin(), CurrentResults.Results.end(),
Results);
CurrentResults.Results.clear();
return MutableArrayRef<CodeCompletionResult *>(Results, Count);
}
Optional<unsigned> 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:
case ChunkKind::Keyword:
case ChunkKind::Attribute:
case ChunkKind::BaseName:
case ChunkKind::TypeIdSystem:
case ChunkKind::TypeIdUser:
case ChunkKind::CallParameterBegin:
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::EffectsSpecifierKeyword:
case ChunkKind::DeclIntroducer:
case ChunkKind::CallParameterColon:
case ChunkKind::CallParameterTypeBegin:
case ChunkKind::DeclAttrParamColon:
case ChunkKind::CallParameterType:
case ChunkKind::CallParameterClosureType:
case ChunkKind::CallParameterClosureExpr:
case ChunkKind::OptionalBegin:
case ChunkKind::GenericParameterBegin:
case ChunkKind::DynamicLookupMethodCallTail:
case ChunkKind::OptionalMethodCallTail:
case ChunkKind::TypeAnnotation:
case ChunkKind::TypeAnnotationBegin:
continue;
case ChunkKind::BraceStmtWithCursor:
llvm_unreachable("should have already extracted the text");
}
}
return None;
}
StringRef
CodeCompletionString::getFirstTextChunk(bool includeLeadingPunctuation) const {
Optional<unsigned> 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()) {
auto chunks = getChunks().slice(*FirstTextChunk);
for (auto i = chunks.begin(), e = chunks.end(); i != e; ++i) {
using ChunkKind = Chunk::ChunkKind;
bool shouldPrint = !i->isAnnotation();
switch (i->getKind()) {
case ChunkKind::TypeAnnotation:
case ChunkKind::CallParameterClosureType:
case ChunkKind::CallParameterClosureExpr:
case ChunkKind::DeclAttrParamColon:
case ChunkKind::OptionalMethodCallTail:
continue;
case ChunkKind::TypeAnnotationBegin: {
auto level = i->getNestingLevel();
do { ++i; } while (i != e && !i->endsPreviousNestedGroup(level));
--i;
continue;
}
case ChunkKind::EffectsSpecifierKeyword:
shouldPrint = true; // Even when they're annotations.
break;
default:
break;
}
if (i->hasText() && shouldPrint) {
TextSize += i->getText().size();
OS << i->getText();
}
}
}
}
void CodeCompletionContext::sortCompletionResults(
MutableArrayRef<CodeCompletionResult *> 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<ResultAndName> 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;
CodeCompletionConsumer &Consumer;
CodeCompletionExpr *CodeCompleteTokenExpr = nullptr;
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;
bool AttTargetIsIndependent = false;
bool IsAtStartOfLine = false;
Optional<DeclKind> AttTargetDK;
Optional<StmtKind> ParentStmtKind;
SmallVector<StringRef, 3> ParsedKeywords;
SourceLoc introducerLoc;
std::vector<std::pair<std::string, bool>> 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<ErrorType>())
return;
CodeCompletionResultBuilder Builder(Sink,
CodeCompletionResult::ResultKind::Keyword,
SemanticContextKind::CurrentNominal,
{});
Builder.setKeywordKind(CodeCompletionKeywordKind::kw_super);
Builder.addKeyword("super");
Builder.addTypeAnnotation(ST, PrintOptions());
}
Optional<std::pair<Type, ConcreteDeclRef>> 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<ErrorType>()) {
return getReferencedDecl(ParsedExpr);
}
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");
if (ParsedTypeLoc.wasValidated() && !ParsedTypeLoc.isError()) {
return true;
}
const auto ty = swift::performTypeResolution(
ParsedTypeLoc.getTypeRepr(), P.Context,
/*isSILMode=*/false,
/*isSILType=*/false,
CurDeclContext->getGenericEnvironmentOfContext(),
/*GenericParams=*/nullptr,
CurDeclContext,
/*ProduceDiagnostics=*/false);
ParsedTypeLoc.setType(ty);
if (!ParsedTypeLoc.isError()) {
return true;
}
// It doesn't type check as a type, so see if it's a qualifying module name.
if (auto *ITR = dyn_cast<IdentTypeRepr>(ParsedTypeLoc.getTypeRepr())) {
const auto &componentRange = ITR->getComponentRange();
// If it has more than one component, it can't be a module name.
if (std::distance(componentRange.begin(), componentRange.end()) != 1)
return false;
const auto &component = componentRange.front();
ImportPath::Module::Builder builder(
component->getNameRef().getBaseIdentifier(),
component->getLoc());
if (auto Module = Context.getLoadedModule(builder.get()))
ParsedTypeLoc.setType(ModuleType::get(Module));
return true;
}
return false;
}
public:
CodeCompletionCallbacksImpl(Parser &P,
CodeCompletionContext &CompletionContext,
CodeCompletionConsumer &Consumer)
: CodeCompletionCallbacks(P), CompletionContext(CompletionContext),
Consumer(Consumer) {
}
void setAttrTargetDeclKind(Optional<DeclKind> DK) override {
if (DK == DeclKind::PatternBinding)
DK = DeclKind::Var;
else if (DK == DeclKind::Param)
// For params, consider the attribute is always for the decl.
AttTargetIsIndependent = false;
if (!AttTargetIsIndependent)
AttTargetDK = DK;
}
void completeDotExpr(CodeCompletionExpr *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 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(CodeCompletionExpr *E) override;
void completeDeclAttrBeginning(bool Sil, bool isIndependent) override;
void completeDeclAttrParam(DeclAttrKind DK, int Index) override;
void completeEffectsSpecifier(bool hasAsync, bool hasThrows) override;
void completeInPrecedenceGroup(SyntaxKind SK) override;
void completeNominalMemberBeginning(
SmallVectorImpl<StringRef> &Keywords, SourceLoc introducerLoc) override;
void completeAccessorBeginning(CodeCompletionExpr *E) override;
void completePoundAvailablePlatform() override;
void completeImportDecl(ImportPath::Builder &Path) override;
void completeUnresolvedMember(CodeCompletionExpr *E,
SourceLoc DotLoc) override;
void completeCallArg(CodeCompletionExpr *E, bool isFirst) override;
void completeLabeledTrailingClosure(CodeCompletionExpr *E,
bool isAtStartOfLine) override;
bool canPerformCompleteLabeledTrailingClosure() const override {
return true;
}
void completeReturnStmt(CodeCompletionExpr *E) override;
void completeYieldStmt(CodeCompletionExpr *E,
Optional<unsigned> yieldIndex) override;
void completeAfterPoundExpr(CodeCompletionExpr *E,
Optional<StmtKind> ParentKind) override;
void completeAfterPoundDirective() override;
void completePlatformCondition() override;
void completeGenericRequirement() override;
void completeAfterIfStmt(bool hasElse) override;
void completeStmtLabel(StmtKind ParentKind) override;
void doneParsing() override;
private:
void addKeywords(CodeCompletionResultSink &Sink, bool MaybeFuncBody);
bool trySolverCompletion(bool MaybeFuncBody);
};
} // end anonymous namespace
namespace {
static bool isTopLevelSubcontext(const DeclContext *DC) {
for (; DC && DC->isLocalContext(); DC = DC->getParent()) {
switch (DC->getContextKind()) {
case DeclContextKind::TopLevelCodeDecl:
return true;
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::SubscriptDecl:
case DeclContextKind::EnumElementDecl:
return false;
default:
continue;
}
}
return false;
}
static KnownProtocolKind
protocolForLiteralKind(CodeCompletionLiteralKind kind) {
switch (kind) {
case CodeCompletionLiteralKind::ArrayLiteral:
return KnownProtocolKind::ExpressibleByArrayLiteral;
case CodeCompletionLiteralKind::BooleanLiteral:
return KnownProtocolKind::ExpressibleByBooleanLiteral;
case CodeCompletionLiteralKind::ColorLiteral:
return KnownProtocolKind::ExpressibleByColorLiteral;
case CodeCompletionLiteralKind::ImageLiteral:
return KnownProtocolKind::ExpressibleByImageLiteral;
case CodeCompletionLiteralKind::DictionaryLiteral:
return KnownProtocolKind::ExpressibleByDictionaryLiteral;
case CodeCompletionLiteralKind::IntegerLiteral:
return KnownProtocolKind::ExpressibleByIntegerLiteral;
case CodeCompletionLiteralKind::NilLiteral:
return KnownProtocolKind::ExpressibleByNilLiteral;
case CodeCompletionLiteralKind::StringLiteral:
return KnownProtocolKind::ExpressibleByUnicodeScalarLiteral;
case CodeCompletionLiteralKind::Tuple:
llvm_unreachable("no such protocol kind");
}
llvm_unreachable("Unhandled CodeCompletionLiteralKind in switch.");
}
static Type
defaultTypeLiteralKind(CodeCompletionLiteralKind kind, ASTContext &Ctx) {
switch (kind) {
case CodeCompletionLiteralKind::BooleanLiteral:
return Ctx.getBoolDecl()->getDeclaredInterfaceType();
case CodeCompletionLiteralKind::IntegerLiteral:
return Ctx.getIntDecl()->getDeclaredInterfaceType();
case CodeCompletionLiteralKind::StringLiteral:
return Ctx.getStringDecl()->getDeclaredInterfaceType();
case CodeCompletionLiteralKind::ArrayLiteral:
return Ctx.getArrayDecl()->getDeclaredType();
case CodeCompletionLiteralKind::DictionaryLiteral:
return Ctx.getDictionaryDecl()->getDeclaredType();
case CodeCompletionLiteralKind::NilLiteral:
case CodeCompletionLiteralKind::ColorLiteral:
case CodeCompletionLiteralKind::ImageLiteral:
case CodeCompletionLiteralKind::Tuple:
return Type();
}
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) {
ParameterListInfo paramInfo(funcType->getParams(), FD,
/*skipCurriedSelf*/ FD->hasCurriedSelf());
if (paramInfo.size() - paramInfo.numNonDefaultedParameters() == 1) {
auto param = funcType->getParams().back();
if (!param.isAutoClosure()) {
if (auto Fn = param.getOldType()->getAs<AnyFunctionType>()) {
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;
const DeclContext *CurrDeclContext;
ModuleDecl *CurrModule;
ClangImporter *Importer;
CodeCompletionContext *CompletionContext;
enum class LookupKind {
ValueExpr,
ValueInDeclContext,
EnumElement,
Type,
TypeInDeclContext,
ImportFromModule,
GenericRequirement,
};
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 CheckForDuplicates = false;
llvm::DenseSet<std::pair<const Decl *, Type>> PreviouslySeen;
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<SemanticContextKind> ForcedSemanticContext = None;
bool IsUnresolvedMember = false;
public:
bool FoundFunctionCalls = false;
bool FoundFunctionsWithoutFirstKeyword = false;
private:
void foundFunction(const AbstractFunctionDecl *AFD) {
FoundFunctionCalls = true;
const DeclName Name = AFD->getName();
auto ArgNames = Name.getArgumentNames();
if (ArgNames.empty())
return;
if (ArgNames[0].empty())
FoundFunctionsWithoutFirstKeyword = true;
}
void 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));
}
/// Returns \c true if \p TAD is usable as a first type of a requirement in
/// \c where clause for a context.
/// \p selfTy must be a \c Self type of the context.
static bool canBeUsedAsRequirementFirstType(Type selfTy, TypeAliasDecl *TAD) {
auto T = TAD->getDeclaredInterfaceType();
auto subMap = selfTy->getMemberSubstitutionMap(TAD->getParentModule(), TAD);
T = T.subst(subMap)->getCanonicalType();
ArchetypeType *archeTy = T->getAs<ArchetypeType>();
if (!archeTy)
return false;
archeTy = archeTy->getRoot();
// For protocol, the 'archeTy' should match with the 'baseTy' which is the
// dynamic 'Self' type of the protocol. For nominal decls, 'archTy' should
// be one of the generic params in 'selfTy'. Search 'archeTy' in 'baseTy'.
return selfTy.findIf([&](Type T) { return archeTy->isEqual(T); });
}
public:
struct RequestedResultsTy {
const ModuleDecl *TheModule;
bool OnlyTypes;
bool OnlyPrecedenceGroups;
bool NeedLeadingDot;
bool IncludeModuleQualifier;
static RequestedResultsTy fromModule(const ModuleDecl *TheModule) {
return { TheModule, false, false, false, true };
}
RequestedResultsTy onlyTypes() const {
return { TheModule, true, false, NeedLeadingDot, IncludeModuleQualifier };
}
RequestedResultsTy onlyPrecedenceGroups() const {
assert(!OnlyTypes && "onlyTypes() already includes precedence groups");
return { TheModule, false, true, false, true };
}
RequestedResultsTy needLeadingDot(bool NeedDot) const {
return {
TheModule, OnlyTypes, OnlyPrecedenceGroups, NeedDot,
IncludeModuleQualifier
};
}
RequestedResultsTy withModuleQualifier(bool IncludeModule) const {
return {
TheModule, OnlyTypes, OnlyPrecedenceGroups, NeedLeadingDot,
IncludeModule
};
}
static RequestedResultsTy toplevelResults() {
return { nullptr, false, false, false, true };
}
};
std::vector<RequestedResultsTy> RequestedCachedResults;
public:
CompletionLookup(CodeCompletionResultSink &Sink,
ASTContext &Ctx,
const DeclContext *CurrDeclContext,
CodeCompletionContext *CompletionContext = nullptr)
: Sink(Sink), Ctx(Ctx), CurrDeclContext(CurrDeclContext),
CurrModule(CurrDeclContext ? CurrDeclContext->getParentModule()
: nullptr),
Importer(static_cast<ClangImporter *>(CurrDeclContext->getASTContext().
getClangModuleLoader())),
CompletionContext(CompletionContext) {
// Determine if we are doing code completion inside a static method.
if (CurrDeclContext) {
CurrentMethod = CurrDeclContext->getInnermostMethodContext();
if (auto *FD = dyn_cast_or_null<FuncDecl>(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<Type> Types,
bool isImplicitSingleExpressionReturn,
bool preferNonVoid = false) {
expectedTypeContext.isImplicitSingleExpressionReturn =
isImplicitSingleExpressionReturn;
expectedTypeContext.preferNonVoid = preferNonVoid;
expectedTypeContext.possibleTypes.clear();
expectedTypeContext.possibleTypes.reserve(Types.size());
for (auto T : Types)
if (T)
expectedTypeContext.possibleTypes.push_back(T);
}
void setIdealExpectedType(Type Ty) {
expectedTypeContext.idealType = Ty;
}
CodeCompletionContext::TypeContextKind typeContextKind() const {
if (expectedTypeContext.empty() && !expectedTypeContext.preferNonVoid) {
return CodeCompletionContext::TypeContextKind::None;
} else if (expectedTypeContext.isImplicitSingleExpressionReturn) {
return CodeCompletionContext::TypeContextKind::SingleExpressionBody;
} else {
return CodeCompletionContext::TypeContextKind::Required;
}
}
bool needDot() const {
return NeedLeadingDot;
}
void setHaveLParen(bool Value) {
HaveLParen = Value;
}
void setIsSuperRefExpr(bool Value = true) {
IsSuperRefExpr = Value;
}
void setIsSelfRefExpr(bool value) { IsSelfRefExpr = value; }
void setIsKeyPathExpr() {
IsKeyPathExpr = true;
}
void shouldCheckForDuplicates(bool value = true) {
CheckForDuplicates = value;
}
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<std::pair<std::string, bool>>
&SubModuleNameVisibilityPairs) {
for (auto &Pair : SubModuleNameVisibilityPairs) {
CodeCompletionResultBuilder Builder(Sink,
CodeCompletionResult::ResultKind::
Declaration,
SemanticContextKind::None,
expectedTypeContext);
auto MD = ModuleDecl::create(Ctx.getIdentifier(Pair.first), Ctx);
Builder.setAssociatedDecl(MD);
Builder.addBaseName(MD->getNameStr());
Builder.addTypeAnnotation("Module");
if (Pair.second)
Builder.setNotRecommended(CodeCompletionResult::NotRecommendedReason::
Redundant);
}
}
void collectImportedModules(llvm::StringSet<> &ImportedModules) {
SmallVector<ImportedModule, 16> Imported;
SmallVector<ImportedModule, 16> FurtherImported;
CurrDeclContext->getParentSourceFile()->getImportedModules(
Imported,
{ModuleDecl::ImportFilterKind::Exported,
ModuleDecl::ImportFilterKind::Default,
ModuleDecl::ImportFilterKind::ImplementationOnly});
while (!Imported.empty()) {
ModuleDecl *MD = Imported.back().importedModule;
Imported.pop_back();
if (!ImportedModules.insert(MD->getNameStr()).second)
continue;
FurtherImported.clear();
MD->getImportedModules(FurtherImported,
ModuleDecl::ImportFilterKind::Exported);
Imported.append(FurtherImported.begin(), FurtherImported.end());
}
}
void addModuleName(
ModuleDecl *MD,
Optional<CodeCompletionResult::NotRecommendedReason> R = None) {
// Don't add underscored cross-import overlay modules.
if (MD->getDeclaringModuleIfCrossImportOverlay())
return;
CodeCompletionResultBuilder Builder(
Sink,
CodeCompletionResult::ResultKind::Declaration,
SemanticContextKind::None,
expectedTypeContext);
Builder.setAssociatedDecl(MD);
Builder.addBaseName(MD->getNameStr());
Builder.addTypeAnnotation("Module");
if (R)
Builder.setNotRecommended(*R);
}
void addImportModuleNames() {
SmallVector<Identifier, 0> ModuleNames;
Ctx.getVisibleTopLevelModuleNames(ModuleNames);
llvm::StringSet<> ImportedModules;
collectImportedModules(ImportedModules);
auto mainModuleName = CurrModule->getName();
for (auto ModuleName : ModuleNames) {
if (ModuleName.str().startswith("_") ||
ModuleName == mainModuleName ||
ModuleName == Ctx.SwiftShimsModuleName ||
ModuleName.str() == SWIFT_ONONE_SUPPORT)
continue;
auto MD = ModuleDecl::create(ModuleName, Ctx);
Optional<CodeCompletionResult::NotRecommendedReason> Reason = None;
// Imported modules are not recommended.
if (ImportedModules.count(MD->getNameStr()) != 0)
Reason = CodeCompletionResult::NotRecommendedReason::Redundant;
addModuleName(MD, Reason);
}
}
SemanticContextKind getSemanticContext(const Decl *D,
DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo) {
if (ForcedSemanticContext)
return *ForcedSemanticContext;
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::MemberOfProtocolConformedToByCurrentNominal:
case DeclVisibilityKind::MemberOfSuper:
return SemanticContextKind::Super;
case DeclVisibilityKind::MemberOfOutsideNominal:
return SemanticContextKind::OutsideNominal;
case DeclVisibilityKind::VisibleAtTopLevel:
if (CurrDeclContext && D->getModuleContext() == CurrModule) {
// Treat global variables from the same source file as local when
// completing at top-level.
if (isa<VarDecl>(D) && isTopLevelSubcontext(CurrDeclContext) &&
D->getDeclContext()->getParentSourceFile() ==
CurrDeclContext->getParentSourceFile()) {
return SemanticContextKind::Local;
} else {
return SemanticContextKind::CurrentModule;
}
} else {
return SemanticContextKind::OtherModule;
}
case DeclVisibilityKind::DynamicLookup:
switch (dynamicLookupInfo.getKind()) {
case DynamicLookupInfo::None:
llvm_unreachable("invalid DynamicLookupInfo::Kind for dynamic lookup");
case DynamicLookupInfo::AnyObject:
// AnyObject results can come from different modules, including the
// current module, but we always assign them the OtherModule semantic
// context. These declarations are uniqued by signature, so it is
// totally random (determined by the hash function) which of the
// equivalent declarations (across multiple modules) we will get.
return SemanticContextKind::OtherModule;
case DynamicLookupInfo::KeyPathDynamicMember:
// Use the visibility of the underlying declaration.
// FIXME: KeyPath<AnyObject, U> !?!?
assert(dynamicLookupInfo.getKeyPathDynamicMember().originalVisibility !=
DeclVisibilityKind::DynamicLookup);
return getSemanticContext(
D, dynamicLookupInfo.getKeyPathDynamicMember().originalVisibility,
{});
}
case DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal:
llvm_unreachable("should not see this kind");
}
llvm_unreachable("unhandled kind");
}
bool isUnresolvedMemberIdealType(Type Ty) {
assert(Ty);
if (!IsUnresolvedMember)
return false;
Type idealTy = expectedTypeContext.idealType;
if (!idealTy)
return false;
/// Consider optional object type is the ideal.
/// For exmaple:
/// enum MyEnum { case foo, bar }
/// func foo(_: MyEnum?)
/// fooo(.<HERE>)
/// Prefer '.foo' and '.bar' over '.some' and '.none'.
idealTy = idealTy->lookThroughAllOptionalTypes();
return idealTy->isEqual(Ty);
}
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.addBaseName(NameStr);
} else {
SmallString<16> buffer;
Builder.addBaseName(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,
GenericSignature genericSig = GenericSignature()) {
PrintOptions PO;
PO.OpaqueReturnTypePrinting =
PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword;
if (auto typeContext = CurrDeclContext->getInnermostTypeContext())
PO.setBaseType(typeContext->getDeclaredTypeInContext());
Builder.addTypeAnnotation(eraseArchetypes(T, genericSig), PO);
Builder.setExpectedTypeRelation(
calculateMaxTypeRelation(T, expectedTypeContext, CurrDeclContext));
}
void addTypeAnnotationForImplicitlyUnwrappedOptional(
CodeCompletionResultBuilder &Builder, Type T,
GenericSignature genericSig = GenericSignature(),
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 = "?";
}
PrintOptions PO;
PO.PrintOptionalAsImplicitlyUnwrapped = true;
PO.OpaqueReturnTypePrinting =
PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword;
if (auto typeContext = CurrDeclContext->getInnermostTypeContext())
PO.setBaseType(typeContext->getDeclaredTypeInContext());
Builder.addTypeAnnotation(eraseArchetypes(T, genericSig), PO, suffix);
Builder.setExpectedTypeRelation(
calculateMaxTypeRelation(T, expectedTypeContext, CurrDeclContext));
}
/// For printing in code completion results, replace archetypes with
/// protocol compositions.
///
/// FIXME: Perhaps this should be an option in PrintOptions instead.
Type eraseArchetypes(Type type, GenericSignature genericSig) {
if (!genericSig)
return type;
auto buildProtocolComposition = [&](ArrayRef<ProtocolDecl *> protos) -> Type {
SmallVector<Type, 2> types;
for (auto proto : protos)
types.push_back(proto->getDeclaredInterfaceType());
return ProtocolCompositionType::get(Ctx, types,
/*HasExplicitAnyObject=*/false);
};
if (auto *genericFuncType = type->getAs<GenericFunctionType>()) {
SmallVector<AnyFunctionType::Param, 8> erasedParams;
for (const auto &param : genericFuncType->getParams()) {
auto erasedTy = eraseArchetypes(param.getPlainType(), genericSig);
erasedParams.emplace_back(erasedTy, param.getLabel(),
param.getParameterFlags());
}
return GenericFunctionType::get(genericSig,
erasedParams,
eraseArchetypes(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<ArchetypeType>()) {
// Don't erase opaque archetype.
if (isa<OpaqueTypeArchetypeType>(archetypeType))
return t;
auto protos = archetypeType->getConformsTo();
if (!protos.empty())
return buildProtocolComposition(protos);
}
if (t->isTypeParameter()) {
const auto protos = genericSig->getRequiredProtocols(t);
if (!protos.empty())
return buildProtocolComposition(protos);
}
return t;
});
}
Type getTypeOfMember(const ValueDecl *VD,
DynamicLookupInfo dynamicLookupInfo) {
switch (dynamicLookupInfo.getKind()) {
case DynamicLookupInfo::None:
return getTypeOfMember(VD, this->ExprType);
case DynamicLookupInfo::AnyObject:
return getTypeOfMember(VD, Type());
case DynamicLookupInfo::KeyPathDynamicMember: {
auto &keyPathInfo = dynamicLookupInfo.getKeyPathDynamicMember();
// Map the result of VD to keypath member lookup results.
// Given:
// struct Wrapper<T> {
// subscript<U>(dynamicMember: KeyPath<T, U>) -> Wrapped<U> { get }
// }
// struct Circle {
// var center: Point { get }
// var radius: Length { get }
// }
//
// Consider 'Wrapper<Circle>.center'.
// 'VD' is 'Circle.center' decl.
// 'keyPathInfo.subscript' is 'Wrapper<T>.subscript' decl.
// 'keyPathInfo.baseType' is 'Wrapper<Circle>' type.
// FIXME: Handle nested keypath member lookup.
// i.e. cases where 'ExprType' != 'keyPathInfo.baseType'.
auto *SD = keyPathInfo.subscript;
const auto elementTy = SD->getElementInterfaceType();
if (!elementTy->hasTypeParameter())
return elementTy;
// Map is:
// { τ_0_0(T) => Circle
// τ_1_0(U) => U }
auto subs = keyPathInfo.baseType->getMemberSubstitutions(SD);
// If the keyPath result type has type parameters, that might affect the
// subscript result type.
auto keyPathResultTy = getResultTypeOfKeypathDynamicMember(SD)->
mapTypeOutOfContext();
if (keyPathResultTy->hasTypeParameter()) {
auto keyPathRootTy = getRootTypeOfKeypathDynamicMember(SD).
subst(QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(CurrModule));
// The result type of the VD.
// i.e. 'Circle.center' => 'Point'.
auto innerResultTy = getTypeOfMember(VD, keyPathRootTy);
if (auto paramTy = keyPathResultTy->getAs<GenericTypeParamType>()) {
// Replace keyPath result type in the map with the inner result type.
// i.e. Make the map as:
// { τ_0_0(T) => Circle
// τ_1_0(U) => Point }
auto key =
paramTy->getCanonicalType()->castTo<GenericTypeParamType>();
subs[key] = innerResultTy;
} else {
// FIXME: Handle the case where the KeyPath result is generic.
// e.g. 'subscript<U>(dynamicMember: KeyPath<T, Box<U>>) -> Bag<U>'
// For now, just return the inner type.
return innerResultTy;
}
}
// Substitute the element type of the subscript using modified map.
// i.e. 'Wrapped<U>' => 'Wrapped<Point>'.
return elementTy.subst(QueryTypeSubstitutionMap{subs},
LookUpConformanceInModule(CurrModule));
}
}
llvm_unreachable("Unhandled DynamicLookupInfo Kind in switch");
}
Type getTypeOfMember(const ValueDecl *VD, Type ExprType) {
Type T = VD->getInterfaceType();
assert(!T.isNull());
if (ExprType) {
Type ContextTy = VD->getDeclContext()->getDeclaredInterfaceType();
if (ContextTy) {
// Look through lvalue types and metatypes
Type MaybeNominalType = ExprType->getRValueType();
if (auto Metatype = MaybeNominalType->getAs<MetatypeType>())
MaybeNominalType = Metatype->getInstanceType();
if (auto SelfType = MaybeNominalType->getAs<DynamicSelfType>())
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(CurrModule, VD);
// Pass in DesugarMemberTypes so that we see the actual
// concrete type witnesses instead of type alias types.
T = T.subst(Subs, SubstFlags::DesugarMemberTypes);
}
}
return T;
}
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.isConcrete()) {
return Conformance.getConcrete()->getTypeWitness(
const_cast<AssociatedTypeDecl *>(ATD));
}
}
}
return Type();
}
void addVarDeclRef(const VarDecl *VD, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo) {
if (!VD->hasName())
return;
const Identifier Name = VD->getName();
assert(!Name.empty() && "name should not be empty");
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);
// "not recommended" in its own getter.
if (Kind == LookupKind::ValueInDeclContext) {
if (auto accessor = dyn_cast<AccessorDecl>(CurrDeclContext)) {
if (accessor->getStorage() == VD && accessor->isGetter())
Builder.setNotRecommended(CodeCompletionResult::NoReason);
}
}
if (!VD->hasInterfaceType())
return;
// Add a type annotation.
Type VarType = getTypeOfMember(VD, dynamicLookupInfo);
if (auto *PD = dyn_cast<ParamDecl>(VD)) {
if (Name != Ctx.Id_self && PD->isInOut()) {
// It is useful to show inout for function parameters.
// But for 'self' it is just noise.
VarType = InOutType::get(VarType);
}
}
auto DynamicOrOptional =
IsDynamicLookup || VD->getAttrs().hasAttribute<OptionalAttr>();
if (DynamicOrOptional) {
// Values of properties that were found on a AnyObject have
// Optional<T> type. Same applies to optional members.
VarType = OptionalType::get(VarType);
}
auto genericSig =
VD->getInnermostDeclContext()->getGenericSignatureOfContext();
if (VD->isImplicitlyUnwrappedOptional())
addTypeAnnotationForImplicitlyUnwrappedOptional(
Builder, VarType, genericSig, DynamicOrOptional);
else
addTypeAnnotation(Builder, VarType, genericSig);
if (isUnresolvedMemberIdealType(VarType))
Builder.setSemanticContext(SemanticContextKind::ExpressionSpecific);
}
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<AnyFunctionType::Param> typeParams,
ArrayRef<const ParamDecl *> declParams,
GenericSignature genericSig,
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;
#define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \
case DefaultArgumentKind::NAME:
#include "swift/AST/MagicIdentifierKinds.def"
// 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->isImplicitlyUnwrappedOptional();
} 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();
Type contextTy;
if (auto typeContext = CurrDeclContext->getInnermostTypeContext())
contextTy = typeContext->getDeclaredTypeInContext();
Builder.addCallParameter(argName, bodyName,
eraseArchetypes(paramTy, genericSig), contextTy,
isVariadic, isInOut, isIUO, isAutoclosure,
/*useUnderscoreLabel=*/false,
/*isLabeledTrailingClosure=*/false);
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,
GenericSignature genericSig,
bool includeDefaultArgs = true) {
ArrayRef<const ParamDecl *> declParams;
if (Params)
declParams = Params->getArray();
return addCallArgumentPatterns(Builder, AFT->getParams(), declParams,
genericSig, includeDefaultArgs);
}
static void addEffectsSpecifiers(CodeCompletionResultBuilder &Builder,
const AnyFunctionType *AFT,
const AbstractFunctionDecl *AFD) {
assert(AFT != nullptr);
// 'async'.
if ((AFD && AFD->hasAsync()) || AFT->isAsync())
Builder.addAnnotatedAsync();
// 'throws' or 'rethrows'.
if (AFD && AFD->getAttrs().hasAttribute<RethrowsAttr>())
Builder.addAnnotatedRethrows();
else if (AFT->isThrowing())
Builder.addAnnotatedThrows();
}
void addPoundAvailable(Optional<StmtKind> ParentKind) {
if (ParentKind != StmtKind::If && ParentKind != StmtKind::Guard)
return;
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResult::ResultKind::Keyword,
SemanticContextKind::ExpressionSpecific, expectedTypeContext);
Builder.addBaseName("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;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResult::ResultKind::Keyword,
SemanticContextKind::None, {});
if (needPound)
Builder.addTextChunk("#selector");
else
Builder.addTextChunk("selector");
Builder.addLeftParen();
Builder.addSimpleTypedParameter("@objc method", /*IsVarArg=*/false);
Builder.addRightParen();
Builder.addTypeAnnotation("Selector");
// This function is called only if the context type is 'Selector'.
Builder.setExpectedTypeRelation(
CodeCompletionResult::ExpectedTypeRelation::Identical);
}
void addPoundKeyPath(bool needPound) {
// #keyPath is only available when the Objective-C runtime is.
if (!Ctx.LangOpts.EnableObjCInterop) return;
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResult::ResultKind::Keyword,
SemanticContextKind::None, {});
if (needPound)
Builder.addTextChunk("#keyPath");
else
Builder.addTextChunk("keyPath");
Builder.addLeftParen();
Builder.addSimpleTypedParameter("@objc property sequence",
/*IsVarArg=*/false);
Builder.addRightParen();
Builder.addTypeAnnotation("String");
// This function is called only if the context type is 'String'.
Builder.setExpectedTypeRelation(
CodeCompletionResult::ExpectedTypeRelation::Identical);
}
SemanticContextKind getSemanticContextKind(const ValueDecl *VD) {
// FIXME: to get the corect semantic context we need to know how lookup
// would have found the VD. For now, just infer a reasonable semantics.
if (!VD)
return SemanticContextKind::CurrentModule;
DeclContext *calleeDC = VD->getDeclContext();
if (calleeDC->isTypeContext())
// FIXME: We should distinguish CurrentNominal and Super. We need to
// propagate the base type to do that.
return SemanticContextKind::CurrentNominal;
if (calleeDC->isLocalContext())
return SemanticContextKind::Local;
if (calleeDC->getParentModule() == CurrModule)
return SemanticContextKind::CurrentModule;
return SemanticContextKind::OtherModule;
}
void addSubscriptCallPattern(
const AnyFunctionType *AFT, const SubscriptDecl *SD,
const Optional<SemanticContextKind> SemanticContext = None) {
foundFunction(AFT);
GenericSignature genericSig;
if (SD)
genericSig = SD->getGenericSignatureOfContext();
CommandWordsPairs Pairs;
CodeCompletionResultBuilder Builder(
Sink,
SD ? CodeCompletionResult::ResultKind::Declaration
: CodeCompletionResult::ResultKind::Pattern,
SemanticContext ? *SemanticContext : getSemanticContextKind(SD),
expectedTypeContext);
if (SD) {
Builder.setAssociatedDecl(SD);
setClangDeclKeywords(SD, Pairs, Builder);
}
if (!HaveLParen)
Builder.addLeftBracket();
else
Builder.addAnnotatedLeftBracket();
ArrayRef<const ParamDecl *> declParams;
if (SD)
declParams = SD->getIndices()->getArray();
addCallArgumentPatterns(Builder, AFT->getParams(), declParams, genericSig);
if (!HaveLParen)
Builder.