[Completion] Only complete @unchecked et al in inheritance clauses

Add a case for completing type attributes in
inheritance clause position, and limit the
completion of `@unchecked`, `@preconcurrency`, and
`@retroactive` to that case.
This commit is contained in:
Hamish Knight
2024-07-02 10:02:14 +01:00
parent 42f563d6d8
commit ec597c82fa
11 changed files with 97 additions and 23 deletions

View File

@@ -229,6 +229,7 @@ enum class CompletionKind : uint8_t {
StmtLabel,
ForEachPatternBeginning,
TypeAttrBeginning,
TypeAttrInheritanceBeginning,
OptionalBinding,
/// Completion after `~` in an inheritance clause.

View File

@@ -605,7 +605,7 @@ public:
void getAttributeDeclParamCompletions(CustomSyntaxAttributeKind AttrKind,
int ParamIndex, bool HasLabel);
void getTypeAttributeKeywordCompletions();
void getTypeAttributeKeywordCompletions(CompletionKind completionKind);
void collectPrecedenceGroups();

View File

@@ -288,6 +288,8 @@ public:
virtual void completeTypeAttrBeginning() {};
virtual void completeTypeAttrInheritanceBeginning() {};
virtual void completeOptionalBinding(){};
virtual void completeWithoutConstraintType(){};

View File

@@ -1398,6 +1398,8 @@ public:
/// Whether the type is for a closure attribute.
CustomAttribute,
/// A type in an inheritance clause.
InheritanceClause,
};
ParserResult<TypeRepr> parseTypeScalar(
@@ -1455,6 +1457,7 @@ public:
ParserResult<TypeRepr> parseTypeDotted(ParserResult<TypeRepr> Base);
struct ParsedTypeAttributeList {
ParseTypeReason ParseReason;
ParamDecl::Specifier Specifier = ParamDecl::Specifier::Default;
SourceLoc SpecifierLoc;
SourceLoc IsolatedLoc;
@@ -1463,6 +1466,8 @@ public:
SmallVector<TypeOrCustomAttr> Attributes;
SmallVector<LifetimeDependenceSpecifier> lifetimeDependenceSpecifiers;
ParsedTypeAttributeList(ParseTypeReason reason) : ParseReason(reason) {}
/// Main entry point for parsing.
///
/// Inline we just have the fast path of failing to match. We call slowParse
@@ -1484,7 +1489,7 @@ public:
};
ParserStatus parseTypeAttribute(TypeOrCustomAttr &result, SourceLoc AtLoc,
SourceLoc AtEndLoc,
SourceLoc AtEndLoc, ParseTypeReason reason,
PatternBindingInitializer *&initContext,
bool justChecking = false);

View File

@@ -303,6 +303,7 @@ public:
void completeStmtLabel(StmtKind ParentKind) override;
void completeForEachPatternBeginning(bool hasTry, bool hasAwait) override;
void completeTypeAttrBeginning() override;
void completeTypeAttrInheritanceBeginning() override;
void completeOptionalBinding() override;
void completeWithoutConstraintType() override;
@@ -655,6 +656,11 @@ void CodeCompletionCallbacksImpl::completeTypeAttrBeginning() {
Kind = CompletionKind::TypeAttrBeginning;
}
void CodeCompletionCallbacksImpl::completeTypeAttrInheritanceBeginning() {
CurDeclContext = P.CurDeclContext;
Kind = CompletionKind::TypeAttrInheritanceBeginning;
}
bool swift::ide::isDynamicLookup(Type T) {
return T->getRValueType()->isAnyObject();
}
@@ -983,6 +989,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
case CompletionKind::PrecedenceGroup:
case CompletionKind::StmtLabel:
case CompletionKind::TypeAttrBeginning:
case CompletionKind::TypeAttrInheritanceBeginning:
case CompletionKind::OptionalBinding:
case CompletionKind::WithoutConstraintType:
break;
@@ -1931,14 +1938,14 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
Lookup.getStmtLabelCompletions(Loc, ParentStmtKind == StmtKind::Continue);
break;
}
case CompletionKind::TypeAttrBeginning: {
Lookup.getTypeAttributeKeywordCompletions();
case CompletionKind::TypeAttrBeginning:
case CompletionKind::TypeAttrInheritanceBeginning: {
Lookup.getTypeAttributeKeywordCompletions(Kind);
// Type names at attribute position after '@'.
Lookup.getTypeCompletionsInDeclContext(
P.Context.SourceMgr.getIDEInspectionTargetLoc());
break;
}
case CompletionKind::OptionalBinding: {
SourceLoc Loc = P.Context.SourceMgr.getIDEInspectionTargetLoc();

View File

@@ -3132,8 +3132,20 @@ void CompletionLookup::getAttributeDeclParamCompletions(
}
}
void CompletionLookup::getTypeAttributeKeywordCompletions() {
auto addTypeAttr = [&](StringRef Name) {
void CompletionLookup::getTypeAttributeKeywordCompletions(
CompletionKind completionKind) {
auto addTypeAttr = [&](TypeAttrKind Kind, StringRef Name) {
if (completionKind != CompletionKind::TypeAttrInheritanceBeginning) {
switch (Kind) {
case TypeAttrKind::Retroactive:
case TypeAttrKind::Preconcurrency:
case TypeAttrKind::Unchecked:
// These attributes are only available in inheritance clasuses.
return;
default:
break;
}
}
CodeCompletionResultBuilder Builder = makeResultBuilder(
CodeCompletionResultKind::Keyword, SemanticContextKind::None);
Builder.addAttributeKeyword(Name, "Type Attribute");
@@ -3142,17 +3154,17 @@ void CompletionLookup::getTypeAttributeKeywordCompletions() {
// Add simple user-accessible attributes.
#define SIL_TYPE_ATTR(SPELLING, C)
#define SIMPLE_SIL_TYPE_ATTR(SPELLING, C)
#define SIMPLE_TYPE_ATTR(SPELLING, C) \
if (!TypeAttribute::isUserInaccessible(TypeAttrKind::C)) \
addTypeAttr(#SPELLING);
#define SIMPLE_TYPE_ATTR(SPELLING, C) \
if (!TypeAttribute::isUserInaccessible(TypeAttrKind::C)) \
addTypeAttr(TypeAttrKind::C, #SPELLING);
#include "swift/AST/TypeAttr.def"
// Add non-simple cases.
addTypeAttr("convention(swift)");
addTypeAttr("convention(block)");
addTypeAttr("convention(c)");
addTypeAttr("convention(thin)");
addTypeAttr("isolated(any)");
addTypeAttr(TypeAttrKind::Convention, "convention(swift)");
addTypeAttr(TypeAttrKind::Convention, "convention(block)");
addTypeAttr(TypeAttrKind::Convention, "convention(c)");
addTypeAttr(TypeAttrKind::Convention, "convention(thin)");
addTypeAttr(TypeAttrKind::Isolated, "isolated(any)");
}
void CompletionLookup::collectPrecedenceGroups() {

View File

@@ -4483,7 +4483,8 @@ bool Parser::canParseTypeAttribute() {
TypeOrCustomAttr result; // ignored
PatternBindingInitializer *initContext = nullptr;
return !parseTypeAttribute(result, /*atLoc=*/SourceLoc(),
/*atEndLoc=*/SourceLoc(), initContext,
/*atEndLoc=*/SourceLoc(),
ParseTypeReason::Unspecified, initContext,
/*justChecking*/ true)
.isError();
}
@@ -4684,6 +4685,7 @@ bool Parser::parseUUIDString(UUID &uuid, Diag<> diagnostic, bool justChecking) {
/// no need to actually record the attribute
ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
SourceLoc AtLoc, SourceLoc AtEndLoc,
ParseTypeReason reason,
PatternBindingInitializer *&initContext,
bool justChecking) {
if (AtEndLoc != Tok.getLoc()) {
@@ -4699,7 +4701,14 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
if (Tok.is(tok::code_complete)) {
if (!justChecking) {
if (CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeTypeAttrBeginning();
switch (reason) {
case ParseTypeReason::InheritanceClause:
CodeCompletionCallbacks->completeTypeAttrInheritanceBeginning();
break;
default:
CodeCompletionCallbacks->completeTypeAttrBeginning();
break;
}
}
}
consumeToken(tok::code_complete);
@@ -5525,7 +5534,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
TypeOrCustomAttr result;
SourceLoc AtEndLoc = Tok.getRange().getEnd();
SourceLoc AtLoc = P.consumeToken();
status |= P.parseTypeAttribute(result, AtLoc, AtEndLoc, initContext);
status |=
P.parseTypeAttribute(result, AtLoc, AtEndLoc, ParseReason, initContext);
if (status.isError())
return status;
if (result)
@@ -6806,7 +6816,8 @@ ParserStatus Parser::parseInheritance(
continue;
}
auto ParsedTypeResult = parseType();
auto ParsedTypeResult =
parseType(diag::expected_type, ParseTypeReason::InheritanceClause);
Status |= ParsedTypeResult;
// Record the type if its a single type.

View File

@@ -159,7 +159,7 @@ SourceLoc Parser::tryCompleteFunctionParamTypeBeginning() {
// Skip over any starting parameter specifiers.
{
CancellableBacktrackingScope backtrack(*this);
ParsedTypeAttributeList attrs;
ParsedTypeAttributeList attrs(ParseTypeReason::Unspecified);
attrs.parse(*this);
if (!Tok.is(tok::code_complete))
return SourceLoc();

View File

@@ -396,9 +396,15 @@ ParserResult<TypeRepr> Parser::parseTypeScalar(
ParserStatus status;
// Parse attributes.
ParsedTypeAttributeList parsedAttributeList;
ParsedTypeAttributeList parsedAttributeList(reason);
status |= parsedAttributeList.parse(*this);
// If we have a completion, create an ErrorType.
if (status.hasCodeCompletion()) {
auto *ET = ErrorTypeRepr::create(Context, PreviousLoc);
return makeParserCodeCompletionResult<TypeRepr>(ET);
}
// Parse generic parameters in SIL mode.
GenericParamList *generics = nullptr;
SourceLoc substitutedLoc;

View File

@@ -1126,7 +1126,8 @@ bool SILParser::parseSILType(SILType &Result,
}
// Parse attributes.
Parser::ParsedTypeAttributeList parsedAttrs;
Parser::ParsedTypeAttributeList parsedAttrs(
Parser::ParseTypeReason::Unspecified);
parsedAttrs.parse(P);
// Global functions are implicitly @convention(thin) if not specified otherwise.

View File

@@ -1,16 +1,45 @@
// RUN: %batch-code-completion
// TYPEATTR-NOT: myIntValue
// TYPEATTR-NOT: Type Attribute
// TYPEATTR-DAG: Keyword/None: autoclosure[#Type Attribute#]; name=autoclosure
// TYPEATTR-DAG: Keyword/None: convention(swift)[#Type Attribute#]; name=convention(swift)
// TYPEATTR-DAG: Keyword/None: convention(block)[#Type Attribute#]; name=convention(block)
// TYPEATTR-DAG: Keyword/None: convention(c)[#Type Attribute#]; name=convention(c)
// TYPEATTR-DAG: Keyword/None: convention(thin)[#Type Attribute#]; name=convention(thin)
// TYPEATTR-DAG: Keyword/None: escaping[#Type Attribute#]; name=escaping
// TYPEATTR-DAG: Keyword/None: isolated(any)[#Type Attribute#]; name=isolated(any)
// TYPEATTR-DAG: Keyword/None: noDerivative[#Type Attribute#]; name=noDerivative
// TYPEATTR-DAG: Keyword/None: Sendable[#Type Attribute#]; name=Sendable
// TYPEATTR-NOT: Type Attribute
// TYPEATTR-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
// TYPEATTR-NOT: Type Attribute
// TYPEATTR-NOT: myIntValue
struct MyStruct {}
// TYPEATTR_INHERIT-DAG: Keyword/None: autoclosure[#Type Attribute#]; name=autoclosure
// TYPEATTR_INHERIT-DAG: Keyword/None: convention(swift)[#Type Attribute#]; name=convention(swift)
// TYPEATTR_INHERIT-DAG: Keyword/None: convention(block)[#Type Attribute#]; name=convention(block)
// TYPEATTR_INHERIT-DAG: Keyword/None: convention(c)[#Type Attribute#]; name=convention(c)
// TYPEATTR_INHERIT-DAG: Keyword/None: convention(thin)[#Type Attribute#]; name=convention(thin)
// TYPEATTR_INHERIT-DAG: Keyword/None: escaping[#Type Attribute#]; name=escaping
// TYPEATTR_INHERIT-DAG: Keyword/None: isolated(any)[#Type Attribute#]; name=isolated(any)
// TYPEATTR_INHERIT-DAG: Keyword/None: noDerivative[#Type Attribute#]; name=noDerivative
// TYPEATTR_INHERIT-DAG: Keyword/None: Sendable[#Type Attribute#]; name=Sendable
//
// TYPEATTR_INHERIT-DAG: Keyword/None: retroactive[#Type Attribute#]; name=retroactive
// TYPEATTR_INHERIT-DAG: Keyword/None: unchecked[#Type Attribute#]; name=unchecked
// TYPEATTR_INHERIT-DAG: Keyword/None: preconcurrency[#Type Attribute#]; name=preconcurrency
struct MyStruct : @#^STRUCT_INHERIT?check=TYPEATTR_INHERIT^# {}
class C : @#^CLASS_INHERIT?check=TYPEATTR_INHERIT^#,
Array<@#^GENERIC_ARG_INHERIT?check=TYPEATTR^#>,
@unchecked @#^CLASS_INHERIT2?check=TYPEATTR_INHERIT^# {}
extension C : @#^EXT_INHERIT1?check=TYPEATTR_INHERIT^# {}
protocol P : @#^PROTO_INHERIT?check=TYPEATTR_INHERIT^# {}
extension C : P, @#^EXT_INHERIT2?check=TYPEATTR_INHERIT^# {}
var myIntValue: Int = 1