Files
swift-mirror/include/swift/IDE/CodeCompletion.h
John McCall 7a4aeed570 Implement generalized accessors using yield-once coroutines.
For now, the accessors have been underscored as `_read` and `_modify`.
I'll prepare an evolution proposal for this feature which should allow
us to remove the underscores or, y'know, rename them to `purple` and
`lettuce`.

`_read` accessors do not make any effort yet to avoid copying the
value being yielded.  I'll work on it in follow-up patches.

Opaque accesses to properties and subscripts defined with `_modify`
accessors will use an inefficient `materializeForSet` pattern that
materializes the value to a temporary instead of accessing it in-place.
That will be fixed by migrating to `modify` over `materializeForSet`,
which is next up after the `read` optimizations.

SIL ownership verification doesn't pass yet for the test cases here
because of a general fault in SILGen where borrows can outlive their
borrowed value due to being cleaned up on the general cleanup stack
when the borrowed value is cleaned up on the formal-access stack.
Michael, Andy, and I discussed various ways to fix this, but it seems
clear to me that it's not in any way specific to coroutine accesses.

rdar://35399664
2018-07-23 18:59:58 -04:00

921 lines
29 KiB
C++

//===--- CodeCompletion.h - Routines for code completion --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IDE_CODECOMPLETION_H
#define SWIFT_IDE_CODECOMPLETION_H
#include "swift/AST/Identifier.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/TrailingObjects.h"
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace swift {
class CodeCompletionCallbacksFactory;
class Decl;
class DeclContext;
class ModuleDecl;
namespace ide {
class CodeCompletionCache;
class CodeCompletionContext;
class CodeCompletionResultBuilder;
struct RequestedCachedModule;
/// \brief A routine to remove code completion tokens from code completion
/// tests.
///
/// \code
/// code-completion-token:
/// '#^' identifier '^#'
/// \endcode
///
/// \param Input test source code.
/// \param TokenName names the token whose position should be returned in
/// \p CompletionOffset.
/// \param CompletionOffset set to ~0U on error, or to a 0-based byte offset on
/// success.
///
/// \returns test source code without any code completion tokens.
std::string removeCodeCompletionTokens(StringRef Input,
StringRef TokenName,
unsigned *CompletionOffset);
namespace detail {
class CodeCompletionStringChunk {
friend class swift::ide::CodeCompletionResultBuilder;
public:
enum class ChunkKind {
/// "open", "public", "internal", "fileprivate", or "private".
AccessControlKeyword,
/// such as @"availability".
DeclAttrKeyword,
/// such as "unavailable" etc. for @available.
DeclAttrParamKeyword,
/// The "override" keyword.
OverrideKeyword,
/// The "throws" keyword.
ThrowsKeyword,
/// The "rethrows" keyword.
RethrowsKeyword,
/// The keyword part of a declaration before the name, like "func".
DeclIntroducer,
/// Normal text chunk.
Text,
/// The first chunk of an optional substring that continues until
/// \c NestingLevel decreases.
OptionalBegin,
/// Punctuation.
LeftParen,
RightParen,
LeftBracket,
RightBracket,
LeftAngle,
RightAngle,
Dot,
Ellipsis,
Comma,
ExclamationMark,
QuestionMark,
Ampersand,
Equal,
Whitespace,
/// The first chunk of a substring that describes the parameter for a
/// generic type.
GenericParameterBegin,
/// Generic type parameter name.
GenericParameterName,
/// The first chunk of a substring that describes the parameter for a
/// function call.
CallParameterBegin,
/// Function call parameter name.
CallParameterName,
/// Function call parameter internal / local name. If the parameter has no
/// formal API name, it can still have a local name which can be useful
/// for display purposes.
///
/// This chunk should not be inserted into the editor buffer.
CallParameterInternalName,
/// A colon between parameter name and value. Should be inserted in the
/// editor buffer if the preceding CallParameterName was inserted.
CallParameterColon,
/// A colon between parameter name and value. Used in decl attribute.
DeclAttrParamColon,
/// Required parameter type.
CallParameterType,
/// Desugared closure parameter type. This can be used to get the
/// closure type if CallParameterType is a NameAliasType.
CallParameterClosureType,
/// A placeholder for \c ! or \c ? in a call to a method found by dynamic
/// lookup.
///
/// The default spelling is \c !, but clients may render it as \c ? if
/// desired.
DynamicLookupMethodCallTail,
/// A placeholder for \c ! or \c ? in a call to an optional method.
///
/// The default spelling is \c !, but clients may render it as \c ? if
/// desired.
OptionalMethodCallTail,
/// Specifies the type of the whole entity that is returned in this code
/// completion result. For example, for variable references it is the
/// variable type, for function calls it is the return type.
///
/// This chunk should not be inserted into the editor buffer.
TypeAnnotation,
/// A brace statement -- left brace and right brace. The preferred
/// position to put the cursor after the completion result is inserted
/// into the editor buffer is between the braces.
///
/// The spelling is always "{}", but clients may choose to insert newline
/// and indentation in between.
BraceStmtWithCursor,
};
static bool chunkStartsNestedGroup(ChunkKind Kind) {
return Kind == ChunkKind::CallParameterBegin ||
Kind == ChunkKind::GenericParameterBegin ||
Kind == ChunkKind::OptionalBegin;
}
static bool chunkHasText(ChunkKind Kind) {
return Kind == ChunkKind::AccessControlKeyword ||
Kind == ChunkKind::OverrideKeyword ||
Kind == ChunkKind::ThrowsKeyword ||
Kind == ChunkKind::RethrowsKeyword ||
Kind == ChunkKind::DeclAttrKeyword ||
Kind == ChunkKind::DeclIntroducer ||
Kind == ChunkKind::Text ||
Kind == ChunkKind::LeftParen ||
Kind == ChunkKind::RightParen ||
Kind == ChunkKind::LeftBracket ||
Kind == ChunkKind::RightBracket ||
Kind == ChunkKind::LeftAngle ||
Kind == ChunkKind::RightAngle ||
Kind == ChunkKind::Dot ||
Kind == ChunkKind::Ellipsis ||
Kind == ChunkKind::Comma ||
Kind == ChunkKind::ExclamationMark ||
Kind == ChunkKind::QuestionMark ||
Kind == ChunkKind::Ampersand ||
Kind == ChunkKind::Equal ||
Kind == ChunkKind::Whitespace ||
Kind == ChunkKind::CallParameterName ||
Kind == ChunkKind::CallParameterInternalName ||
Kind == ChunkKind::CallParameterColon ||
Kind == ChunkKind::DeclAttrParamColon ||
Kind == ChunkKind::DeclAttrParamKeyword ||
Kind == ChunkKind::CallParameterType ||
Kind == ChunkKind::CallParameterClosureType ||
Kind == ChunkKind::GenericParameterName ||
Kind == ChunkKind::DynamicLookupMethodCallTail ||
Kind == ChunkKind::OptionalMethodCallTail ||
Kind == ChunkKind::TypeAnnotation ||
Kind == ChunkKind::BraceStmtWithCursor;
}
private:
unsigned Kind : 8;
unsigned NestingLevel : 8;
/// \brief If true, then this chunk is an annotation that is included only
/// for exposition and may not be inserted in the editor buffer.
unsigned IsAnnotation : 1;
StringRef Text;
CodeCompletionStringChunk(ChunkKind Kind, unsigned NestingLevel, StringRef Text,
bool isAnnotation)
: Kind(unsigned(Kind)), NestingLevel(NestingLevel),
IsAnnotation(isAnnotation), Text(Text) {
assert(chunkHasText(Kind));
}
CodeCompletionStringChunk(ChunkKind Kind, unsigned NestingLevel,
bool isAnnotation)
: Kind(unsigned(Kind)), NestingLevel(NestingLevel),
IsAnnotation(isAnnotation) {
assert(!chunkHasText(Kind));
}
void setIsAnnotation() {
IsAnnotation = 1;
}
public:
ChunkKind getKind() const {
return ChunkKind(Kind);
}
bool is(ChunkKind K) const { return getKind() == K; }
unsigned getNestingLevel() const {
return NestingLevel;
}
bool isAnnotation() const {
return IsAnnotation;
}
bool hasText() const { return chunkHasText(getKind()); }
StringRef getText() const {
assert(hasText());
return Text;
}
bool endsPreviousNestedGroup(unsigned GroupNestingLevel) const {
return NestingLevel < GroupNestingLevel ||
(NestingLevel == GroupNestingLevel && chunkStartsNestedGroup(getKind()));
}
static CodeCompletionStringChunk createWithText(ChunkKind Kind,
unsigned NestingLevel,
StringRef Text,
bool isAnnotation = false) {
return CodeCompletionStringChunk(Kind, NestingLevel, Text, isAnnotation);
}
static CodeCompletionStringChunk createSimple(ChunkKind Kind,
unsigned NestingLevel,
bool isAnnotation = false) {
return CodeCompletionStringChunk(Kind, NestingLevel, isAnnotation);
}
};
} // end namespace detail
/// \brief A structured representation of a code completion string.
class alignas(detail::CodeCompletionStringChunk) CodeCompletionString final :
private llvm::TrailingObjects<CodeCompletionString,
detail::CodeCompletionStringChunk> {
friend class CodeCompletionResultBuilder;
friend TrailingObjects;
public:
using Chunk = detail::CodeCompletionStringChunk;
private:
unsigned NumChunks : 16;
CodeCompletionString(ArrayRef<Chunk> Chunks);
public:
/// Creates a \c CodeCompletionString from a list of \c Chunks.
///
/// \note The caller must ensure any text inside \c Chunks will outlive this
/// object, typically by storing them inside a \c CodeCompletionResultSink.
static CodeCompletionString *create(llvm::BumpPtrAllocator &Allocator,
ArrayRef<Chunk> Chunks);
ArrayRef<Chunk> getChunks() const {
return {getTrailingObjects<Chunk>(), NumChunks};
}
StringRef getFirstTextChunk(bool includeLeadingPunctuation = false) const;
Optional<unsigned>
getFirstTextChunkIndex(bool includeLeadingPunctuation = false) const;
/// Concatenates all text chunks considered part of the name to \p OS.
void getName(raw_ostream &OS) const;
/// Print a debug representation of the code completion string to \p OS.
void print(raw_ostream &OS) const;
void dump() const;
};
/// \brief Describes the origin of the code completion result.
///
/// This enum is ordered from the contexts that are "nearest" to the code
/// completion point to "outside" contexts.
enum class SemanticContextKind {
/// Used in cases when the concept of semantic context is not applicable.
None,
/// \brief This is a highly-likely expression-context-specific completion
/// result. This description is intentionally vague: this is a catch-all
/// category for all heuristics for highly-likely results.
///
/// For example, the name of an overridden superclass member inside a nominal
/// member function has ExpressionSpecific context:
/// \code
/// class Base {
/// init() {}
/// init(a: Int) {}
/// func foo() {}
/// func bar() {}
/// }
/// class Derived {
/// init() {
/// super. // init() -- ExpressionSpecific
/// // init(a: Int) -- Super
/// }
///
/// func foo() {
/// super. // foo() -- ExpressionSpecific
/// // bar() -- Super
/// }
/// }
/// \endcode
ExpressionSpecific,
/// A declaration from the same function.
Local,
/// A declaration found in the immediately enclosing nominal decl.
CurrentNominal,
/// A declaration found in the superclass of the immediately enclosing
/// nominal decl.
Super,
/// A declaration found in the non-immediately enclosing nominal decl.
///
/// For example, 'Foo' is visible at (1) because of this.
/// \code
/// struct A {
/// typealias Foo = Int
/// struct B {
/// func foo() {
/// // (1)
/// }
/// }
/// }
/// \endcode
OutsideNominal,
/// A declaration from the current module.
CurrentModule,
/// A declaration imported from other module.
OtherModule,
};
/// The declaration kind of a code completion result, if it is a declaration.
enum class CodeCompletionDeclKind {
Module,
Class,
Struct,
Enum,
EnumElement,
Protocol,
AssociatedType,
TypeAlias,
GenericTypeParam,
Constructor,
Destructor,
Subscript,
StaticMethod,
InstanceMethod,
PrefixOperatorFunction,
PostfixOperatorFunction,
InfixOperatorFunction,
FreeFunction,
StaticVar,
InstanceVar,
LocalVar,
GlobalVar,
PrecedenceGroup,
};
enum class CodeCompletionLiteralKind {
ArrayLiteral,
BooleanLiteral,
ColorLiteral,
DictionaryLiteral,
IntegerLiteral,
ImageLiteral,
NilLiteral,
StringLiteral,
Tuple,
};
enum class CodeCompletionOperatorKind {
None,
Unknown,
Bang, // !
NotEq, // !=
NotEqEq, // !==
Modulo, // %
ModuloEq, // %=
Amp, // &
AmpAmp, // &&
AmpStar, // &*
AmpPlus, // &+
AmpMinus, // &-
AmpEq, // &=
LParen, // ( -- not really an operator, but treated as one in some cases.
Star, // *
StarEq, // *=
Plus, // +
PlusEq, // +=
Minus, // -
MinusEq, // -=
Dot, // .
DotDotDot, // ...
DotDotLess, // ..<
Slash, // /
SlashEq, // /=
Less, // <
LessLess, // <<
LessLessEq, // <<=
LessEq, // <=
Eq, // =
EqEq, // ==
EqEqEq, // ===
Greater, // >
GreaterEq, // >=
GreaterGreater, // >>
GreaterGreaterEq, // >>=
QuestionDot, // ?.
Caret, // ^
CaretEq, // ^=
Pipe, // |
PipeEq, // |=
PipePipe, // ||
TildeEq, // ~=
};
enum class CodeCompletionKeywordKind {
None,
#define KEYWORD(X) kw_##X,
#define POUND_KEYWORD(X) pound_##X,
#include "swift/Syntax/TokenKinds.def"
};
enum class CompletionKind {
None,
Import,
UnresolvedMember,
DotExpr,
StmtOrExpr,
PostfixExprBeginning,
PostfixExpr,
PostfixExprParen,
SuperExpr,
SuperExprDot,
KeyPathExpr,
KeyPathExprDot,
TypeSimpleBeginning,
TypeIdentifierWithDot,
TypeIdentifierWithoutDot,
CaseStmtBeginning,
CaseStmtDotPrefix,
NominalMemberBeginning,
AttributeBegin,
AttributeDeclParen,
PoundAvailablePlatform,
AssignmentRHS,
CallArg,
ReturnStmtExpr,
YieldStmtExpr,
ForEachSequence,
AfterPound,
AfterIfStmtElse,
GenericParams,
SwiftKeyPath,
};
/// \brief A single code completion result.
class CodeCompletionResult {
friend class CodeCompletionResultBuilder;
public:
enum ResultKind {
Declaration,
Keyword,
Pattern,
Literal,
BuiltinOperator,
};
/// Describes the relationship between the type of the completion results and
/// the expected type at the code completion position.
enum ExpectedTypeRelation {
/// The relationship of the result's type to the expected type is not
/// invalid, not convertible, and not identical.
Unrelated,
/// The result's type is invalid at the expected position.
Invalid,
/// The result's type is convertible to the type of the expected.
Convertible,
/// The result's type is identical to the type of the expected.
Identical,
};
enum NotRecommendedReason {
Redundant,
TypeMismatch,
Deprecated,
NoReason,
};
private:
unsigned Kind : 3;
unsigned AssociatedKind : 8;
unsigned KnownOperatorKind : 6;
unsigned SemanticContext : 3;
unsigned NotRecommended : 1;
unsigned NotRecReason : 3;
/// The number of bytes to the left of the code completion point that
/// should be erased first if this completion string is inserted in the
/// editor buffer.
unsigned NumBytesToErase : 7;
public:
static const unsigned MaxNumBytesToErase = 127;
private:
CodeCompletionString *CompletionString;
StringRef ModuleName;
StringRef BriefDocComment;
ArrayRef<StringRef> AssociatedUSRs;
ArrayRef<std::pair<StringRef, StringRef>> DocWords;
unsigned TypeDistance : 3;
public:
/// Constructs a \c Pattern, \c Keyword or \c BuiltinOperator result.
///
/// \note The caller must ensure \c CodeCompletionString outlives this result.
CodeCompletionResult(ResultKind Kind, SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
ExpectedTypeRelation TypeDistance = Unrelated,
CodeCompletionOperatorKind KnownOperatorKind =
CodeCompletionOperatorKind::None)
: Kind(Kind), KnownOperatorKind(unsigned(KnownOperatorKind)),
SemanticContext(unsigned(SemanticContext)), NotRecommended(false),
NotRecReason(NotRecommendedReason::NoReason),
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
TypeDistance(TypeDistance) {
assert(Kind != Declaration && "use the other constructor");
assert(CompletionString);
if (isOperator() && KnownOperatorKind == CodeCompletionOperatorKind::None)
this->KnownOperatorKind =
(unsigned)getCodeCompletionOperatorKind(CompletionString);
assert(!isOperator() ||
getOperatorKind() != CodeCompletionOperatorKind::None);
AssociatedKind = 0;
}
/// Constructs a \c Keyword result.
///
/// \note The caller must ensure \c CodeCompletionString outlives this result.
CodeCompletionResult(CodeCompletionKeywordKind Kind,
SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
ExpectedTypeRelation TypeDistance = Unrelated)
: Kind(Keyword), KnownOperatorKind(0),
SemanticContext(unsigned(SemanticContext)), NotRecommended(false),
NotRecReason(NotRecommendedReason::NoReason),
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
TypeDistance(TypeDistance) {
assert(CompletionString);
AssociatedKind = static_cast<unsigned>(Kind);
}
/// Constructs a \c Literal result.
///
/// \note The caller must ensure \c CodeCompletionString outlives this result.
CodeCompletionResult(CodeCompletionLiteralKind LiteralKind,
SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
ExpectedTypeRelation TypeDistance)
: Kind(Literal), KnownOperatorKind(0),
SemanticContext(unsigned(SemanticContext)), NotRecommended(false),
NotRecReason(NotRecommendedReason::NoReason),
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
TypeDistance(TypeDistance) {
AssociatedKind = static_cast<unsigned>(LiteralKind);
assert(CompletionString);
}
/// Constructs a \c Declaration result.
///
/// \note The caller must ensure \c CodeCompletionString and any StringRef
/// arguments outlive this result, typically by storing them in the same
/// \c CodeCompletionResultSink as the result itself.
CodeCompletionResult(SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
const Decl *AssociatedDecl, StringRef ModuleName,
bool NotRecommended,
CodeCompletionResult::NotRecommendedReason NotRecReason,
StringRef BriefDocComment,
ArrayRef<StringRef> AssociatedUSRs,
ArrayRef<std::pair<StringRef, StringRef>> DocWords,
enum ExpectedTypeRelation TypeDistance)
: Kind(ResultKind::Declaration), KnownOperatorKind(0),
SemanticContext(unsigned(SemanticContext)),
NotRecommended(NotRecommended), NotRecReason(NotRecReason),
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
ModuleName(ModuleName), BriefDocComment(BriefDocComment),
AssociatedUSRs(AssociatedUSRs), DocWords(DocWords),
TypeDistance(TypeDistance) {
assert(AssociatedDecl && "should have a decl");
AssociatedKind = unsigned(getCodeCompletionDeclKind(AssociatedDecl));
assert(CompletionString);
if (isOperator())
KnownOperatorKind =
(unsigned)getCodeCompletionOperatorKind(CompletionString);
assert(!isOperator() ||
getOperatorKind() != CodeCompletionOperatorKind::None);
}
// FIXME:
CodeCompletionResult(SemanticContextKind SemanticContext,
unsigned NumBytesToErase,
CodeCompletionString *CompletionString,
CodeCompletionDeclKind DeclKind, StringRef ModuleName,
bool NotRecommended,
CodeCompletionResult::NotRecommendedReason NotRecReason,
StringRef BriefDocComment,
ArrayRef<StringRef> AssociatedUSRs,
ArrayRef<std::pair<StringRef, StringRef>> DocWords,
CodeCompletionOperatorKind KnownOperatorKind)
: Kind(ResultKind::Declaration),
KnownOperatorKind(unsigned(KnownOperatorKind)),
SemanticContext(unsigned(SemanticContext)),
NotRecommended(NotRecommended), NotRecReason(NotRecReason),
NumBytesToErase(NumBytesToErase), CompletionString(CompletionString),
ModuleName(ModuleName), BriefDocComment(BriefDocComment),
AssociatedUSRs(AssociatedUSRs), DocWords(DocWords) {
AssociatedKind = static_cast<unsigned>(DeclKind);
assert(CompletionString);
TypeDistance = ExpectedTypeRelation::Unrelated;
assert(!isOperator() ||
getOperatorKind() != CodeCompletionOperatorKind::None);
}
ResultKind getKind() const { return static_cast<ResultKind>(Kind); }
CodeCompletionDeclKind getAssociatedDeclKind() const {
assert(getKind() == Declaration);
return static_cast<CodeCompletionDeclKind>(AssociatedKind);
}
CodeCompletionLiteralKind getLiteralKind() const {
assert(getKind() == Literal);
return static_cast<CodeCompletionLiteralKind>(AssociatedKind);
}
CodeCompletionKeywordKind getKeywordKind() const {
assert(getKind() == Keyword);
return static_cast<CodeCompletionKeywordKind>(AssociatedKind);
}
bool isOperator() const {
if (getKind() != Declaration)
return getKind() == BuiltinOperator;
switch (getAssociatedDeclKind()) {
case CodeCompletionDeclKind::PrefixOperatorFunction:
case CodeCompletionDeclKind::PostfixOperatorFunction:
case CodeCompletionDeclKind::InfixOperatorFunction:
return true;
default:
return false;
}
}
CodeCompletionOperatorKind getOperatorKind() const {
assert(isOperator());
return static_cast<CodeCompletionOperatorKind>(KnownOperatorKind);
}
ExpectedTypeRelation getExpectedTypeRelation() const {
return static_cast<ExpectedTypeRelation>(TypeDistance);
}
NotRecommendedReason getNotRecommendedReason() const {
return static_cast<NotRecommendedReason>(NotRecReason);
}
SemanticContextKind getSemanticContext() const {
return static_cast<SemanticContextKind>(SemanticContext);
}
bool isNotRecommended() const {
return NotRecommended;
}
unsigned getNumBytesToErase() const {
return NumBytesToErase;
}
CodeCompletionString *getCompletionString() const {
return CompletionString;
}
StringRef getModuleName() const { return ModuleName; }
StringRef getBriefDocComment() const {
return BriefDocComment;
}
ArrayRef<StringRef> getAssociatedUSRs() const {
return AssociatedUSRs;
}
ArrayRef<std::pair<StringRef, StringRef>> getDeclKeywords() const {
return DocWords;
}
/// Print a debug representation of the code completion result to \p OS.
void print(raw_ostream &OS) const;
void dump() const;
static CodeCompletionDeclKind getCodeCompletionDeclKind(const Decl *D);
static CodeCompletionOperatorKind
getCodeCompletionOperatorKind(StringRef name);
static CodeCompletionOperatorKind
getCodeCompletionOperatorKind(CodeCompletionString *str);
};
struct CodeCompletionResultSink {
using AllocatorPtr = std::shared_ptr<llvm::BumpPtrAllocator>;
/// The allocator used to allocate results "native" to this sink.
AllocatorPtr Allocator;
/// Allocators that keep alive "foreign" results imported into this sink from
/// other sinks.
std::vector<AllocatorPtr> ForeignAllocators;
std::vector<CodeCompletionResult *> Results;
/// A single-element cache for module names stored in Allocator, keyed by a
/// clang::Module * or swift::ModuleDecl *.
std::pair<void *, StringRef> LastModule;
CodeCompletionResultSink()
: Allocator(std::make_shared<llvm::BumpPtrAllocator>()) {}
};
class CodeCompletionContext {
friend class CodeCompletionResultBuilder;
/// \brief A set of current completion results, not yet delivered to the
/// consumer.
CodeCompletionResultSink CurrentResults;
public:
CodeCompletionCache &Cache;
CompletionKind CodeCompletionKind = CompletionKind::None;
bool HasExpectedTypeRelation = false;
/// Whether there may be members that can use implicit member syntax,
/// e.g. `x = .foo`.
bool MayUseImplicitMemberExpr = false;
CodeCompletionContext(CodeCompletionCache &Cache)
: Cache(Cache) {}
/// \brief Allocate a string owned by the code completion context.
StringRef copyString(StringRef Str);
/// \brief Return current code completion results.
MutableArrayRef<CodeCompletionResult *> takeResults();
/// \brief Sort code completion results in an implementation-defined order
/// in place.
static void sortCompletionResults(
MutableArrayRef<CodeCompletionResult *> Results);
CodeCompletionResultSink &getResultSink() {
return CurrentResults;
}
};
/// \brief An abstract base class for consumers of code completion results.
/// \see \c SimpleCachingCodeCompletionConsumer.
class CodeCompletionConsumer {
public:
virtual ~CodeCompletionConsumer() {}
virtual void
handleResultsAndModules(CodeCompletionContext &context,
ArrayRef<RequestedCachedModule> requestedModules,
DeclContext *DCForModules) = 0;
};
/// A simplified code completion consumer interface that clients can use to get
/// CodeCompletionResults with automatic caching of top-level completions from
/// imported modules.
struct SimpleCachingCodeCompletionConsumer : public CodeCompletionConsumer {
// Implement the CodeCompletionConsumer interface.
void handleResultsAndModules(CodeCompletionContext &context,
ArrayRef<RequestedCachedModule> requestedModules,
DeclContext *DCForModules) override;
/// Clients should override this method to receive \p Results.
virtual void handleResults(
MutableArrayRef<CodeCompletionResult *> Results) = 0;
};
/// \brief A code completion result consumer that prints the results to a
/// \c raw_ostream.
class PrintingCodeCompletionConsumer
: public SimpleCachingCodeCompletionConsumer {
llvm::raw_ostream &OS;
bool IncludeKeywords;
bool IncludeComments;
public:
PrintingCodeCompletionConsumer(llvm::raw_ostream &OS,
bool IncludeKeywords = true,
bool IncludeComments = true)
: OS(OS),
IncludeKeywords(IncludeKeywords),
IncludeComments(IncludeComments) {}
void handleResults(MutableArrayRef<CodeCompletionResult *> Results) override;
};
/// \brief Create a factory for code completion callbacks.
CodeCompletionCallbacksFactory *
makeCodeCompletionCallbacksFactory(CodeCompletionContext &CompletionContext,
CodeCompletionConsumer &Consumer);
/// Lookup the top-level code completions from \p module and store them in
/// \p targetSink.
///
/// Results are looked up as if in \p currDeclContext, which may be null.
void lookupCodeCompletionResultsFromModule(CodeCompletionResultSink &targetSink,
const ModuleDecl *module,
ArrayRef<std::string> accessPath,
bool needLeadingDot,
const DeclContext *currDeclContext);
/// Copy code completion results from \p sourceSink to \p targetSink, possibly
/// restricting by \p onlyTypes.
void copyCodeCompletionResults(CodeCompletionResultSink &targetSink,
CodeCompletionResultSink &sourceSink,
bool onlyTypes);
} // end namespace ide
} // end namespace swift
template <> struct llvm::DenseMapInfo<swift::ide::CodeCompletionKeywordKind> {
using Kind = swift::ide::CodeCompletionKeywordKind;
static Kind getEmptyKey() { return Kind(~0u); }
static Kind getTombstoneKey() { return Kind(~1u); }
static unsigned getHashValue(const Kind &Val) { return unsigned(Val); }
static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; }
};
template <> struct llvm::DenseMapInfo<swift::ide::CodeCompletionLiteralKind> {
using Kind = swift::ide::CodeCompletionLiteralKind;
static Kind getEmptyKey() { return Kind(~0u); }
static Kind getTombstoneKey() { return Kind(~1u); }
static unsigned getHashValue(const Kind &Val) { return unsigned(Val); }
static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; }
};
template <> struct llvm::DenseMapInfo<swift::ide::CodeCompletionDeclKind> {
using Kind = swift::ide::CodeCompletionDeclKind;
static Kind getEmptyKey() { return Kind(~0u); }
static Kind getTombstoneKey() { return Kind(~1u); }
static unsigned getHashValue(const Kind &Val) { return unsigned(Val); }
static bool isEqual(const Kind &LHS, const Kind &RHS) { return LHS == RHS; }
};
#endif // SWIFT_IDE_CODECOMPLETION_H