Skip to content

Commit 7da537c

Browse files
authored
Merge pull request swiftlang#37520 from rintaro/ide-completion-typeattr-rdar44917341
[CodeCompletion] Complete type attributes
2 parents a9948e2 + 5096ab7 commit 7da537c

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

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

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

@@ -5836,6 +5853,11 @@ void CodeCompletionCallbacksImpl::completeForEachPatternBeginning(
58365853
ParsedKeywords.emplace_back("await");
58375854
}
58385855

5856+
void CodeCompletionCallbacksImpl::completeTypeAttrBeginning() {
5857+
CurDeclContext = P.CurDeclContext;
5858+
Kind = CompletionKind::TypeAttrBeginning;
5859+
}
5860+
58395861
static bool isDynamicLookup(Type T) {
58405862
return T->getRValueType()->isAnyObject();
58415863
}
@@ -5970,6 +5992,7 @@ void CodeCompletionCallbacksImpl::addKeywords(CodeCompletionResultSink &Sink,
59705992
case CompletionKind::KeyPathExprSwift:
59715993
case CompletionKind::PrecedenceGroup:
59725994
case CompletionKind::StmtLabel:
5995+
case CompletionKind::TypeAttrBeginning:
59735996
break;
59745997

59755998
case CompletionKind::EffectsSpecifier: {
@@ -6988,6 +7011,15 @@ void CodeCompletionCallbacksImpl::doneParsing() {
69887011
Lookup.getStmtLabelCompletions(Loc, ParentStmtKind == StmtKind::Continue);
69897012
break;
69907013
}
7014+
case CompletionKind::TypeAttrBeginning: {
7015+
Lookup.getTypeAttributeKeywordCompletions();
7016+
7017+
// Type names at attribute position after '@'.
7018+
Lookup.getTypeCompletionsInDeclContext(
7019+
P.Context.SourceMgr.getCodeCompletionLoc());
7020+
break;
7021+
7022+
}
69917023
case CompletionKind::AfterIfStmtElse:
69927024
case CompletionKind::CaseStmtKeyword:
69937025
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
@@ -2817,6 +2817,7 @@ bool Parser::canParseCustomAttribute() {
28172817

28182818
ParserResult<CustomAttr> Parser::parseCustomAttribute(
28192819
SourceLoc atLoc, PatternBindingInitializer *&initContext) {
2820+
assert(Tok.is(tok::identifier));
28202821
SyntaxContext->setCreateSyntax(SyntaxKind::CustomAttribute);
28212822

28222823
// Parse a custom attribute.
@@ -3054,7 +3055,7 @@ bool Parser::canParseTypeAttribute() {
30543055
TypeAttributes attrs; // ignored
30553056
PatternBindingInitializer *initContext = nullptr;
30563057
return !parseTypeAttribute(attrs, /*atLoc=*/SourceLoc(), initContext,
3057-
/*justChecking*/ true);
3058+
/*justChecking*/ true).isError();
30583059
}
30593060

30603061
/// Parses the '@differentiable' type attribute argument (no argument list,
@@ -3213,16 +3214,28 @@ bool Parser::parseConventionAttributeInternal(
32133214
/// \param justChecking - if true, we're just checking whether we
32143215
/// canParseTypeAttribute; don't emit any diagnostics, and there's
32153216
/// no need to actually record the attribute
3216-
bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
3217-
PatternBindingInitializer *&initContext,
3218-
bool justChecking) {
3217+
ParserStatus Parser::parseTypeAttribute(TypeAttributes &Attributes,
3218+
SourceLoc AtLoc,
3219+
PatternBindingInitializer *&initContext,
3220+
bool justChecking) {
32193221
// If this not an identifier, the attribute is malformed.
32203222
if (Tok.isNot(tok::identifier) &&
32213223
// These are keywords that we accept as attribute names.
32223224
Tok.isNot(tok::kw_in) && Tok.isNot(tok::kw_inout)) {
3225+
3226+
if (Tok.is(tok::code_complete)) {
3227+
if (!justChecking) {
3228+
if (CodeCompletion) {
3229+
CodeCompletion->completeTypeAttrBeginning();
3230+
}
3231+
}
3232+
consumeToken(tok::code_complete);
3233+
return makeParserCodeCompletionStatus();
3234+
}
3235+
32233236
if (!justChecking)
32243237
diagnose(Tok, diag::expected_attribute_name);
3225-
return true;
3238+
return makeParserError();
32263239
}
32273240

32283241
// Determine which attribute it is, and diagnose it if unknown.
@@ -3250,7 +3263,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
32503263
if (declAttrID != DAK_Count) {
32513264
// This is a valid decl attribute so they should have put it on the decl
32523265
// instead of the type.
3253-
if (justChecking) return true;
3266+
if (justChecking) return makeParserError();
32543267

32553268
// If this is the first attribute, and if we are on a simple decl, emit a
32563269
// fixit to move the attribute. Otherwise, we don't have the location of
@@ -3285,21 +3298,22 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
32853298
backtrack.cancelBacktrack();
32863299
}
32873300

3288-
return true;
3301+
return makeParserError();
32893302
}
32903303

32913304
// If we're just checking, try to parse now.
32923305
if (justChecking)
3293-
return !canParseCustomAttribute();
3306+
return canParseCustomAttribute() ? makeParserSuccess()
3307+
: makeParserError();
32943308

32953309
// Parse as a custom attribute.
32963310
auto customAttrResult = parseCustomAttribute(AtLoc, initContext);
32973311
if (customAttrResult.isParseErrorOrHasCompletion())
3298-
return true;
3312+
return customAttrResult;
32993313

33003314
if (auto attr = customAttrResult.get())
33013315
Attributes.addCustomAttr(attr);
3302-
return false;
3316+
return makeParserSuccess();
33033317
}
33043318

33053319
// Ok, it is a valid attribute, eat it, and then process it.
@@ -3313,19 +3327,19 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33133327
if (failedToParse) {
33143328
if (Tok.is(tok::r_paren))
33153329
consumeToken();
3316-
return true;
3330+
return makeParserError();
33173331
}
33183332
}
33193333

33203334
// In just-checking mode, we only need to consume the tokens, and we don't
33213335
// want to do any other analysis.
33223336
if (justChecking)
3323-
return false;
3337+
return makeParserSuccess();
33243338

33253339
// Diagnose duplicated attributes.
33263340
if (Attributes.has(attr)) {
33273341
diagnose(AtLoc, diag::duplicate_attribute, /*isModifier=*/false);
3328-
return false;
3342+
return makeParserSuccess();
33293343
}
33303344

33313345
// Handle any attribute-specific processing logic.
@@ -3347,7 +3361,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33473361
case TAK_objc_metatype:
33483362
if (!isInSILMode()) {
33493363
diagnose(AtLoc, diag::only_allowed_in_sil, Text);
3350-
return false;
3364+
return makeParserSuccess();
33513365
}
33523366
break;
33533367

@@ -3356,27 +3370,27 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
33563370
case TAK_sil_unowned:
33573371
if (!isInSILMode()) {
33583372
diagnose(AtLoc, diag::only_allowed_in_sil, Text);
3359-
return false;
3373+
return makeParserSuccess();
33603374
}
33613375

33623376
if (Attributes.hasOwnership()) {
33633377
diagnose(AtLoc, diag::duplicate_attribute, /*isModifier*/false);
3364-
return false;
3378+
return makeParserSuccess();
33653379
}
33663380
break;
33673381

33683382
// 'inout' attribute.
33693383
case TAK_inout:
33703384
if (!isInSILMode()) {
33713385
diagnose(AtLoc, diag::inout_not_attribute);
3372-
return false;
3386+
return makeParserSuccess();
33733387
}
33743388
break;
33753389

33763390
case TAK_opened: {
33773391
if (!isInSILMode()) {
33783392
diagnose(AtLoc, diag::only_allowed_in_sil, "opened");
3379-
return false;
3393+
return makeParserSuccess();
33803394
}
33813395

33823396
// Parse the opened existential ID string in parens
@@ -3410,7 +3424,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
34103424
Attributes.differentiabilityKind = DifferentiabilityKind::Normal;
34113425
if (parseDifferentiableTypeAttributeArgument(
34123426
*this, Attributes, /*emitDiagnostics=*/!justChecking))
3413-
return true;
3427+
return makeParserError();
34143428
// Only 'reverse' is supported today.
34153429
// TODO: Change this to an error once clients have migrated to 'reverse'.
34163430
if (Attributes.differentiabilityKind == DifferentiabilityKind::Normal) {
@@ -3432,31 +3446,31 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
34323446
auto beginLoc = Tok.getLoc();
34333447
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
34343448
diagnose(Tok, diag::attr_expected_lparen, "_opaqueReturnTypeOf", false);
3435-
return true;
3449+
return makeParserError();
34363450
}
34373451

34383452
if (!Tok.is(tok::string_literal)) {
34393453
diagnose(Tok, diag::opened_attribute_id_value);
3440-
return true;
3454+
return makeParserError();
34413455
}
34423456
auto mangling = Tok.getText().slice(1, Tok.getText().size() - 1);
34433457
consumeToken(tok::string_literal);
34443458

34453459
if (!Tok.is(tok::comma)) {
34463460
diagnose(Tok, diag::attr_expected_comma, "_opaqueReturnTypeOf", false);
3447-
return true;
3461+
return makeParserError();
34483462
}
34493463
consumeToken(tok::comma);
34503464

34513465
if (!Tok.is(tok::integer_literal)) {
34523466
diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf");
3453-
return true;
3467+
return makeParserError();
34543468
}
34553469

34563470
unsigned index;
34573471
if (Tok.getText().getAsInteger(10, index)) {
34583472
diagnose(Tok, diag::attr_expected_string_literal, "_opaqueReturnTypeOf");
3459-
return true;
3473+
return makeParserError();
34603474
}
34613475
consumeToken(tok::integer_literal);
34623476

@@ -3471,7 +3485,7 @@ bool Parser::parseTypeAttribute(TypeAttributes &Attributes, SourceLoc AtLoc,
34713485
}
34723486

34733487
Attributes.setAttr(attr, AtLoc);
3474-
return false;
3488+
return makeParserSuccess();
34753489
}
34763490

34773491
/// \verbatim
@@ -3705,9 +3719,10 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes,
37053719
/// '@' attribute
37063720
/// '@' attribute attribute-list-clause
37073721
/// \endverbatim
3708-
bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
3709-
SourceLoc &SpecifierLoc,
3710-
TypeAttributes &Attributes) {
3722+
ParserStatus
3723+
Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
3724+
SourceLoc &SpecifierLoc,
3725+
TypeAttributes &Attributes) {
37113726
PatternBindingInitializer *initContext = nullptr;
37123727
Specifier = ParamDecl::Specifier::Default;
37133728
while (Tok.is(tok::kw_inout) ||
@@ -3731,21 +3746,23 @@ bool Parser::parseTypeAttributeListPresent(ParamDecl::Specifier &Specifier,
37313746
SpecifierLoc = consumeToken();
37323747
}
37333748

3749+
ParserStatus status;
37343750
SyntaxParsingContext AttrListCtx(SyntaxContext, SyntaxKind::AttributeList);
37353751
while (Tok.is(tok::at_sign)) {
37363752
// Ignore @substituted in SIL mode and leave it for the type parser.
37373753
if (isInSILMode() && peekToken().getText() == "substituted")
3738-
return false;
3754+
return status;
37393755

37403756
if (Attributes.AtLoc.isInvalid())
37413757
Attributes.AtLoc = Tok.getLoc();
37423758
SyntaxParsingContext AttrCtx(SyntaxContext, SyntaxKind::Attribute);
37433759
SourceLoc AtLoc = consumeToken();
3744-
if (parseTypeAttribute(Attributes, AtLoc, initContext))
3745-
return true;
3760+
status |= parseTypeAttribute(Attributes, AtLoc, initContext);
3761+
if (status.isError())
3762+
return status;
37463763
}
37473764

3748-
return false;
3765+
return status;
37493766
}
37503767

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

0 commit comments

Comments
 (0)