Skip to content

Commit 15fa94d

Browse files
authored
Merge pull request #37537 from rintaro/5.5-ide-completion-typeattr-rdar44917341
[5.5][CodeCompletion] Complete type attributes
2 parents dc34c13 + e57bca0 commit 15fa94d

File tree

8 files changed

+151
-48
lines changed

8 files changed

+151
-48
lines changed

include/swift/IDE/CodeCompletion.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ enum class CompletionKind {
562562
PrecedenceGroup,
563563
StmtLabel,
564564
ForEachPatternBeginning,
565+
TypeAttrBeginning,
565566
};
566567

567568
/// A single code completion result.

include/swift/Parse/CodeCompletionCallbacks.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ class CodeCompletionCallbacks {
234234
virtual
235235
void completeForEachPatternBeginning(bool hasTry, bool hasAwait) {};
236236

237+
virtual void completeTypeAttrBeginning() {};
238+
237239
/// Signals that the AST for the all the delayed-parsed code was
238240
/// constructed. No \c complete*() callbacks will be done after this.
239241
virtual void doneParsing() = 0;

include/swift/Parse/Parser.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,28 +1090,27 @@ class Parser {
10901090
bool parseVersionTuple(llvm::VersionTuple &Version, SourceRange &Range,
10911091
const Diagnostic &D);
10921092

1093-
bool parseTypeAttributeList(ParamDecl::Specifier &Specifier,
1094-
SourceLoc &SpecifierLoc,
1095-
TypeAttributes &Attributes) {
1093+
ParserStatus parseTypeAttributeList(ParamDecl::Specifier &Specifier,
1094+
SourceLoc &SpecifierLoc,
1095+
TypeAttributes &Attributes) {
10961096
if (Tok.isAny(tok::at_sign, tok::kw_inout) ||
10971097
(Tok.is(tok::identifier) &&
10981098
(Tok.getRawText().equals("__shared") ||
10991099
Tok.getRawText().equals("__owned"))))
11001100
return parseTypeAttributeListPresent(Specifier, SpecifierLoc, Attributes);
1101-
return false;
1101+
return makeParserSuccess();
11021102
}
1103-
bool parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
1104-
SourceLoc &SpecifierLoc,
1105-
TypeAttributes &Attributes);
1103+
ParserStatus parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
1104+
SourceLoc &SpecifierLoc,
1105+
TypeAttributes &Attributes);
11061106

11071107
bool parseConventionAttributeInternal(bool justChecking,
11081108
TypeAttributes::Convention &convention);
11091109

1110-
bool parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
1111-
PatternBindingInitializer *&initContext,
1112-
bool justChecking = false);
1113-
1114-
1110+
ParserStatus parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
1111+
PatternBindingInitializer *&initContext,
1112+
bool justChecking = false);
1113+
11151114
ParserResult<ImportDecl> parseDeclImport(ParseDeclOptions Flags,
11161115
DeclAttributes &Attributes);
11171116
ParserStatus parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,

lib/IDE/CodeCompletion.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks {
16701670
void completeAfterIfStmt(bool hasElse) override;
16711671
void completeStmtLabel(StmtKind ParentKind) override;
16721672
void completeForEachPatternBeginning(bool hasTry, bool hasAwait) override;
1673+
void completeTypeAttrBeginning() override;
16731674

16741675
void doneParsing() override;
16751676

@@ -4702,6 +4703,22 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
47024703
}
47034704
}
47044705

4706+
void getTypeAttributeKeywordCompletions() {
4707+
auto addTypeAttr = [&](StringRef Name) {
4708+
CodeCompletionResultBuilder Builder(
4709+
Sink,
4710+
CodeCompletionResult::ResultKind::Keyword,
4711+
SemanticContextKind::None, expectedTypeContext);
4712+
Builder.addAttributeKeyword(Name, "Type Attribute");
4713+
};
4714+
addTypeAttr("autoclosure");
4715+
addTypeAttr("convention(swift)");
4716+
addTypeAttr("convention(block)");
4717+
addTypeAttr("convention(c)");
4718+
addTypeAttr("convention(thin)");
4719+
addTypeAttr("escaping");
4720+
}
4721+
47054722
void collectPrecedenceGroups() {
47064723
assert(CurrDeclContext);
47074724

@@ -5835,6 +5852,11 @@ void CodeCompletionCallbacksImpl::completeForEachPatternBeginning(
58355852
ParsedKeywords.emplace_back("await");
58365853
}
58375854

5855+
void CodeCompletionCallbacksImpl::completeTypeAttrBeginning() {
5856+
CurDeclContext = P.CurDeclContext;
5857+
Kind = CompletionKind::TypeAttrBeginning;
5858+
}
5859+
58385860
static bool isDynamicLookup(Type T) {
58395861
return T->getRValueType()->isAnyObject();
58405862
}
@@ -5969,6 +5991,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
59695991
case CompletionKind::KeyPathExprSwift:
59705992
case CompletionKind::PrecedenceGroup:
59715993
case CompletionKind::StmtLabel:
5994+
case CompletionKind::TypeAttrBeginning:
59725995
break;
59735996

59745997
case CompletionKind::EffectsSpecifier: {
@@ -6987,6 +7010,15 @@ void CodeCompletionCallbacksImpl::doneParsing() {
69877010
Lookup.getStmtLabelCompletions(Loc, ParentStmtKind == StmtKind::Continue);
69887011
break;
69897012
}
7013+
case CompletionKind::TypeAttrBeginning: {
7014+
Lookup.getTypeAttributeKeywordCompletions();
7015+
7016+
// Type names at attribute position after '@'.
7017+
Lookup.getTypeCompletionsInDeclContext(
7018+
P.Context.SourceMgr.getCodeCompletionLoc());
7019+
break;
7020+
7021+
}
69907022
case CompletionKind::AfterIfStmtElse:
69917023
case CompletionKind::CaseStmtKeyword:
69927024
case CompletionKind::EffectsSpecifier:

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,12 @@ class CodeCompletionResultBuilder {
360360
addTypeAnnotation(Annotation);
361361
}
362362

363+
void addAttributeKeyword(StringRef Name, StringRef Annotation) {
364+
addChunkWithText(CodeCompletionString::Chunk::ChunkKind::Attribute, Name);
365+
if (!Annotation.empty())
366+
addTypeAnnotation(Annotation);
367+
}
368+
363369
StringRef escapeKeyword(StringRef Word, bool escapeAllKeywords,
364370
llvm::SmallString<16> &EscapedKeyword) {
365371
EscapedKeyword.clear();

lib/Parse/ParseDecl.cpp

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,6 +2856,7 @@ bool Parser::canParseCustomAttribute() {
28562856

28572857
ParserResult<CustomAttr> Parser::parseCustomAttribute(
28582858
SourceLoc atLoc, PatternBindingInitializer *&initContext) {
2859+
assert(Tok.is(tok::identifier));
28592860
SyntaxContext->setCreateSyntax(SyntaxKind::CustomAttribute);
28602861

28612862
// Parse a custom attribute.
@@ -3093,7 +3094,7 @@ bool Parser::canParseTypeAttribute() {
30933094
TypeAttributes attrs; // ignored
30943095
PatternBindingInitializer *initContext = nullptr;
30953096
return !parseTypeAttribute(attrs, /*atLoc=*/SourceLoc(), initContext,
3096-
/*justChecking*/ true);
3097+
/*justChecking*/ true).isError();
30973098
}
30983099

30993100
/// Parses the '@differentiable' type attribute argument (no argument list,
@@ -3252,16 +3253,28 @@ bool Parser::parseConventionAttributeInternal(
32523253
/// \param justChecking - if true, we're just checking whether we
32533254
/// canParseTypeAttribute; don't emit any diagnostics, and there's
32543255
/// no need to actually record the attribute
3255-
bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
3256-
PatternBindingInitializer *&initContext,
3257-
bool justChecking) {
3256+
ParserStatus Parser::parseTypeAttribute(TypeAttributes &Attributes,
3257+
SourceLoc AtLoc,
3258+
PatternBindingInitializer *&initContext,
3259+
bool justChecking) {
32583260
// If this not an identifier, the attribute is malformed.
32593261
if (Tok.isNot(tok::identifier) &&
32603262
// These are keywords that we accept as attribute names.
32613263
Tok.isNot(tok::kw_in) && Tok.isNot(tok::kw_inout)) {
3264+
3265+
if (Tok.is(tok::code_complete)) {
3266+
if (!justChecking) {
3267+
if (CodeCompletion) {
3268+
CodeCompletion->completeTypeAttrBeginning();
3269+
}
3270+
}
3271+
consumeToken(tok::code_complete);
3272+
return makeParserCodeCompletionStatus();
3273+
}
3274+
32623275
if (!justChecking)
32633276
diagnose(Tok, diag::expected_attribute_name);
3264-
return true;
3277+
return makeParserError();
32653278
}
32663279

32673280
// Determine which attribute it is, and diagnose it if unknown.
@@ -3289,7 +3302,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
32893302
if (declAttrID != DAK_Count) {
32903303
// This is a valid decl attribute so they should have put it on the decl
32913304
// instead of the type.
3292-
if (justChecking) return true;
3305+
if (justChecking) return makeParserError();
32933306

32943307
// If this is the first attribute, and if we are on a simple decl, emit a
32953308
// fixit to move the attribute. Otherwise, we don't have the location of
@@ -3324,21 +3337,22 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33243337
backtrack.cancelBacktrack();
33253338
}
33263339

3327-
return true;
3340+
return makeParserError();
33283341
}
33293342

33303343
// If we're just checking, try to parse now.
33313344
if (justChecking)
3332-
return !canParseCustomAttribute();
3345+
return canParseCustomAttribute() ? makeParserSuccess()
3346+
: makeParserError();
33333347

33343348
// Parse as a custom attribute.
33353349
auto customAttrResult = parseCustomAttribute(AtLoc, initContext);
33363350
if (customAttrResult.isParseErrorOrHasCompletion())
3337-
return true;
3351+
return customAttrResult;
33383352

33393353
if (auto attr = customAttrResult.get())
33403354
Attributes.addCustomAttr(attr);
3341-
return false;
3355+
return makeParserSuccess();
33423356
}
33433357

33443358
// Ok, it is a valid attribute, eat it, and then process it.
@@ -3352,19 +3366,19 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33523366
if (failedToParse) {
33533367
if (Tok.is(tok::r_paren))
33543368
consumeToken();
3355-
return true;
3369+
return makeParserError();
33563370
}
33573371
}
33583372

33593373
// In just-checking mode, we only need to consume the tokens, and we don't
33603374
// want to do any other analysis.
33613375
if (justChecking)
3362-
return false;
3376+
return makeParserSuccess();
33633377

33643378
// Diagnose duplicated attributes.
33653379
if (Attributes.has(attr)) {
33663380
diagnose(AtLoc, diag::duplicate_attribute, /*isModifier=*/false);
3367-
return false;
3381+
return makeParserSuccess();
33683382
}
33693383

33703384
// Handle any attribute-specific processing logic.
@@ -3386,7 +3400,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33863400
case TAK_objc_metatype:
33873401
if (!isInSILMode()) {
33883402
diagnose(AtLoc, diag::only_allowed_in_sil, Text);
3389-
return false;
3403+
return makeParserSuccess();
33903404
}
33913405
break;
33923406

@@ -3395,27 +3409,27 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33953409
case TAK_sil_unowned:
33963410
if (!isInSILMode()) {
33973411
diagnose(AtLoc, diag::only_allowed_in_sil, Text);
3398-
return false;
3412+
return makeParserSuccess();
33993413
}
34003414

34013415
if (Attributes.hasOwnership()) {
34023416
diagnose(AtLoc, diag::duplicate_attribute, /*isModifier*/false);
3403-
return false;
3417+
return makeParserSuccess();
34043418
}
34053419
break;
34063420

34073421
// 'inout' attribute.
34083422
case TAK_inout:
34093423
if (!isInSILMode()) {
34103424
diagnose(AtLoc, diag::inout_not_attribute);
3411-
return false;
3425+
return makeParserSuccess();
34123426
}
34133427
break;
34143428

34153429
case TAK_opened: {
34163430
if (!isInSILMode()) {
34173431
diagnose(AtLoc, diag::only_allowed_in_sil, "opened");
3418-
return false;
3432+
return makeParserSuccess();
34193433
}
34203434

34213435
// Parse the opened existential ID string in parens
@@ -3449,7 +3463,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
34493463
Attributes.differentiabilityKind = DifferentiabilityKind::Normal;
34503464
if (parseDifferentiableTypeAttributeArgument(
34513465
*this, Attributes, /*emitDiagnostics=*/!justChecking))
3452-
return true;
3466+
return makeParserError();
34533467
// Only 'reverse' is supported today.
34543468
// TODO: Change this to an error once clients have migrated to 'reverse'.
34553469
if (Attributes.differentiabilityKind == DifferentiabilityKind::Normal) {
@@ -3471,31 +3485,31 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
34713485
auto beginLoc = Tok.getLoc();
34723486
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
34733487
diagnose(Tok, diag::attr_expected_lparen, "_opaqueReturnTypeOf", false);
3474-
return true;
3488+
return makeParserError();
34753489
}
34763490

34773491
if (!Tok.is(tok::string_literal)) {
34783492
diagnose(Tok, diag::opened_attribute_id_value);
3479-
return true;
3493+
return makeParserError();
34803494
}
34813495
auto mangling = Tok.getText().slice(1, Tok.getText().size() - 1);
34823496
consumeToken(tok::string_literal);
34833497

34843498
if (!Tok.is(tok::comma)) {
34853499
diagnose(Tok, diag::attr_expected_comma, "_opaqueReturnTypeOf", false);
3486-
return true;
3500+
return makeParserError();
34873501
}
34883502
consumeToken(tok::comma);
34893503

34903504
if (!Tok.is(tok::integer_literal)) {
34913505
diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf");
3492-
return true;
3506+
return makeParserError();
34933507
}
34943508

34953509
unsigned index;
34963510
if (Tok.getText().getAsInteger(10, index)) {
34973511
diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf");
3498-
return true;
3512+
return makeParserError();
34993513
}
35003514
consumeToken(tok::integer_literal);
35013515

@@ -3510,7 +3524,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
35103524
}
35113525

35123526
Attributes.setAttr(attr, AtLoc);
3513-
return false;
3527+
return makeParserSuccess();
35143528
}
35153529

35163530
/// \verbatim
@@ -3744,9 +3758,10 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes,
37443758
/// '@' attribute
37453759
/// '@' attribute attribute-list-clause
37463760
/// \endverbatim
3747-
bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
3748-
SourceLoc &SpecifierLoc,
3749-
TypeAttributes &Attributes) {
3761+
ParserStatus
3762+
Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
3763+
SourceLoc &SpecifierLoc,
3764+
TypeAttributes &Attributes) {
37503765
PatternBindingInitializer *initContext = nullptr;
37513766
Specifier = ParamDecl::Specifier::Default;
37523767
while (Tok.is(tok::kw_inout) ||
@@ -3770,21 +3785,23 @@ bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
37703785
SpecifierLoc = consumeToken();
37713786
}
37723787

3788+
ParserStatus status;
37733789
SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList);
37743790
while (Tok.is(tok::at_sign)) {
37753791
// Ignore @substituted in SIL mode and leave it for the type parser.
37763792
if (isInSILMode() && peekToken().getText() == "substituted")
3777-
return false;
3793+
return status;
37783794

37793795
if (Attributes.AtLoc.isInvalid())
37803796
Attributes.AtLoc = Tok.getLoc();
37813797
SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute);
37823798
SourceLoc AtLoc = consumeToken();
3783-
if (parseTypeAttribute(Attributes, AtLoc, initContext))
3784-
return true;
3799+
status |= parseTypeAttribute(Attributes, AtLoc, initContext);
3800+
if (status.isError())
3801+
return status;
37853802
}
37863803

3787-
return false;
3804+
return status;
37883805
}
37893806

37903807
static bool isStartOfOperatorDecl(const Token &Tok, const Token &Tok2) {

0 commit comments

Comments
 (0)