Skip to content

Commit 78b4e85

Browse files
committed
[IDE] Complete unowned, nonisolated, access-control parameter
1 parent 673d6a1 commit 78b4e85

File tree

3 files changed

+101
-22
lines changed

3 files changed

+101
-22
lines changed

include/swift/Parse/IDEInspectionCallbacks.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@ enum class ObjCSelectorContext {
2929
SetterSelector
3030
};
3131

32-
/// Attributes that have syntax which can't be modelled using a function call.
33-
/// This can't be \c DeclAttrKind because '@freestandig' and '@attached' have
32+
/// Parameterized attributes that have code completion.
33+
/// This can't be \c DeclAttrKind because '@freestanding' and '@attached' have
3434
/// the same attribute kind but take different macro roles as arguemnts.
3535
enum class ParameterizedDeclAttributeKind {
36+
AccessControl,
37+
Nonisolated,
38+
Unowned,
3639
Available,
3740
FreestandingMacro,
3841
AttachedMacro,

lib/IDE/CompletionLookup.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -3105,6 +3105,16 @@ void CompletionLookup::getAttributeDeclCompletions(bool IsInSil,
31053105
void CompletionLookup::getAttributeDeclParamCompletions(
31063106
ParameterizedDeclAttributeKind AttrKind, int ParamIndex, bool HasLabel) {
31073107
switch (AttrKind) {
3108+
case ParameterizedDeclAttributeKind::Unowned:
3109+
addDeclAttrParamKeyword("safe", /*Parameters=*/{}, "", false);
3110+
addDeclAttrParamKeyword("unsafe", /*Parameters=*/{}, "", false);
3111+
break;
3112+
case ParameterizedDeclAttributeKind::Nonisolated:
3113+
addDeclAttrParamKeyword("unsafe", /*Parameters=*/{}, "", false);
3114+
break;
3115+
case ParameterizedDeclAttributeKind::AccessControl:
3116+
addDeclAttrParamKeyword("set", /*Parameters=*/{}, "", false);
3117+
break;
31083118
case ParameterizedDeclAttributeKind::Available:
31093119
if (ParamIndex == 0) {
31103120
addDeclAttrParamKeyword("*", /*Parameters=*/{}, "Platform", false);

lib/Parse/ParseDecl.cpp

+86-20
Original file line numberDiff line numberDiff line change
@@ -2473,8 +2473,9 @@ Parser::parseMacroRoleAttribute(
24732473
/// \returns \c None if an error was diagnosed; \c Identifier() if the argument list was permissibly
24742474
/// omitted; the identifier written by the user otherwise.
24752475
static std::optional<Identifier> parseSingleAttrOptionImpl(
2476-
Parser &P, SourceLoc Loc, SourceRange &AttrRange, StringRef AttrName,
2477-
DeclAttrKind DK, bool allowOmitted, DiagRef nonIdentifierDiagnostic) {
2476+
Parser &P, SourceLoc Loc, SourceRange &AttrRange, StringRef AttrName, DeclAttrKind DK,
2477+
ParserStatus &Status, bool allowOmitted, DiagRef nonIdentifierDiagnostic,
2478+
llvm::function_ref<void()> codeCompletionCallback = {}) {
24782479
SWIFT_DEFER {
24792480
AttrRange = SourceRange(Loc, P.PreviousLoc);
24802481
};
@@ -2484,19 +2485,32 @@ static std::optional<Identifier> parseSingleAttrOptionImpl(
24842485
if (allowOmitted)
24852486
return Identifier();
24862487

2488+
Status.setIsParseError();
24872489
P.diagnose(Loc, diag::attr_expected_lparen, AttrName, isDeclModifier);
24882490
return std::nullopt;
24892491
}
24902492

24912493
P.consumeAttributeLParen();
2494+
2495+
if (P.Tok.is(tok::code_complete)) {
2496+
Status.setHasCodeCompletion();
2497+
codeCompletionCallback();
2498+
}
24922499

24932500
StringRef parsedName = P.Tok.getText();
24942501
if (!P.consumeIf(tok::identifier)) {
2502+
Status.setIsParseError();
24952503
P.diagnose(Loc, nonIdentifierDiagnostic);
24962504
return std::nullopt;
24972505
}
24982506

2507+
if (P.Tok.is(tok::code_complete)) {
2508+
Status.setHasCodeCompletion();
2509+
codeCompletionCallback();
2510+
}
2511+
24992512
if (!P.consumeIf(tok::r_paren)) {
2513+
Status.setIsParseError();
25002514
P.diagnose(Loc, diag::attr_expected_rparen, AttrName, isDeclModifier);
25012515
return std::nullopt;
25022516
}
@@ -2590,11 +2604,11 @@ ParserResult<LifetimeAttr> Parser::parseLifetimeAttribute(SourceLoc atLoc,
25902604
/// \returns \c None if an error was diagnosed; \c Identifier() if the argument list was permissibly
25912605
/// omitted; the identifier written by the user otherwise.
25922606
static std::optional<Identifier>
2593-
parseSingleAttrOptionIdentifier(Parser &P, SourceLoc Loc,
2607+
parseSingleAttrOptionIdentifier(Parser &P, SourceLoc Loc, ParserStatus &Status,
25942608
SourceRange &AttrRange, StringRef AttrName,
25952609
DeclAttrKind DK, bool allowOmitted = false) {
25962610
return parseSingleAttrOptionImpl(
2597-
P, Loc, AttrRange, AttrName, DK, allowOmitted,
2611+
P, Loc, AttrRange, AttrName, DK, Status, allowOmitted,
25982612
{diag::attr_expected_option_identifier, {AttrName}});
25992613
}
26002614

@@ -2616,13 +2630,17 @@ template <typename R>
26162630
static std::optional<R>
26172631
parseSingleAttrOption(Parser &P, SourceLoc Loc, SourceRange &AttrRange,
26182632
StringRef AttrName, DeclAttrKind DK,
2633+
ParserStatus& Status,
26192634
ArrayRef<std::pair<Identifier, R>> options,
2620-
std::optional<R> valueIfOmitted = std::nullopt) {
2635+
std::optional<R> valueIfOmitted = std::nullopt,
2636+
llvm::function_ref<void()> codeCompletionCallback = {}) {
26212637
auto parsedIdentifier = parseSingleAttrOptionImpl(
2622-
P, Loc, AttrRange,AttrName, DK,
2638+
P, Loc, AttrRange, AttrName, DK, Status,
26232639
/*allowOmitted=*/valueIfOmitted.has_value(),
26242640
{diag::attr_expected_option_such_as,
2625-
{AttrName, options.front().first.str()}});
2641+
{AttrName, options.front().first.str()}},
2642+
codeCompletionCallback);
2643+
26262644
if (!parsedIdentifier)
26272645
return std::nullopt;
26282646

@@ -2755,8 +2773,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
27552773
}
27562774

27572775
case DeclAttrKind::Inline: {
2776+
ParserStatus optionStatus;
27582777
auto kind = parseSingleAttrOption<InlineKind>(
2759-
*this, Loc, AttrRange, AttrName, DK, {
2778+
*this, Loc, AttrRange, AttrName, DK, optionStatus, {
27602779
{ Context.Id_never, InlineKind::Never },
27612780
{ Context.Id__always, InlineKind::Always }
27622781
});
@@ -2770,8 +2789,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
27702789
}
27712790

27722791
case DeclAttrKind::Optimize: {
2792+
ParserStatus optionStatus;
27732793
auto optMode = parseSingleAttrOption<OptimizationMode>(
2774-
*this, Loc, AttrRange, AttrName, DK, {
2794+
*this, Loc, AttrRange, AttrName, DK, optionStatus, {
27752795
{ Context.Id_speed, OptimizationMode::ForSpeed },
27762796
{ Context.Id_size, OptimizationMode::ForSize },
27772797
{ Context.Id_none, OptimizationMode::NoOptimization }
@@ -2786,8 +2806,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
27862806
}
27872807

27882808
case DeclAttrKind::Exclusivity: {
2809+
ParserStatus optionStatus;
27892810
auto mode = parseSingleAttrOption<ExclusivityAttr::Mode>(
2790-
*this, Loc, AttrRange, AttrName, DK, {
2811+
*this, Loc, AttrRange, AttrName, DK, optionStatus, {
27912812
{ Context.Id_checked, ExclusivityAttr::Mode::Checked },
27922813
{ Context.Id_unchecked, ExclusivityAttr::Mode::Unchecked }
27932814
});
@@ -2807,11 +2828,19 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
28072828

28082829
if (Kind == ReferenceOwnership::Unowned) {
28092830
// Parse an optional specifier after unowned.
2831+
ParserStatus optionStatus;
28102832
Kind = parseSingleAttrOption<ReferenceOwnership>(
2811-
*this, Loc, AttrRange, AttrName, DK, {
2833+
*this, Loc, AttrRange, AttrName, DK, optionStatus, {
28122834
{ Context.Id_unsafe, ReferenceOwnership::Unmanaged },
28132835
{ Context.Id_safe, ReferenceOwnership::Unowned }
2814-
}, ReferenceOwnership::Unowned)
2836+
}, ReferenceOwnership::Unowned,
2837+
[&] () {
2838+
if (CodeCompletionCallbacks) {
2839+
CodeCompletionCallbacks->completeDeclAttrParam(
2840+
ParameterizedDeclAttributeKind::Unowned, 0, false);
2841+
consumeToken(tok::code_complete);
2842+
}
2843+
})
28152844
// Recover from errors by going back to Unowned.
28162845
.value_or(ReferenceOwnership::Unowned);
28172846
}
@@ -2827,8 +2856,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
28272856
}
28282857

28292858
case DeclAttrKind::NonSendable: {
2859+
ParserStatus optionStatus;
28302860
auto kind = parseSingleAttrOption<NonSendableKind>(
2831-
*this, Loc, AttrRange, AttrName, DK, {
2861+
*this, Loc, AttrRange, AttrName, DK, optionStatus, {
28322862
{ Context.Id_assumed, NonSendableKind::Assumed }
28332863
}, NonSendableKind::Specific);
28342864
if (!kind)
@@ -2882,11 +2912,34 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
28822912

28832913
consumeAttributeLParen();
28842914

2915+
if (Tok.is(tok::code_complete) && CodeCompletionCallbacks) {
2916+
CodeCompletionCallbacks->completeDeclAttrParam(
2917+
ParameterizedDeclAttributeKind::AccessControl, 0, false);
2918+
consumeToken(tok::code_complete);
2919+
}
2920+
28852921
// Parse the subject.
28862922
if (Tok.isContextualKeyword("set")) {
28872923
consumeToken();
28882924
} else {
28892925
diagnose(Loc, diag::attr_access_expected_set, AttrName);
2926+
2927+
const Token &Tok2 = peekToken();
2928+
2929+
if (CodeCompletionCallbacks) {
2930+
if (Tok.is(tok::code_complete)) {
2931+
CodeCompletionCallbacks->completeDeclAttrParam(
2932+
ParameterizedDeclAttributeKind::AccessControl, 0, false);
2933+
consumeToken(tok::code_complete);
2934+
} else if (Tok2.is(tok::code_complete) && Tok.is(tok::identifier) &&
2935+
!Tok.isContextualDeclKeyword()) {
2936+
consumeToken(tok::identifier);
2937+
CodeCompletionCallbacks->completeDeclAttrParam(
2938+
ParameterizedDeclAttributeKind::AccessControl, 0, false);
2939+
consumeToken(tok::code_complete);
2940+
}
2941+
}
2942+
28902943
// Minimal recovery: if there's a single token and then an r_paren,
28912944
// consume them both. If there's just an r_paren, consume that.
28922945
if (!consumeIf(tok::r_paren)) {
@@ -3155,8 +3208,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
31553208

31563209
case DeclAttrKind::SwiftNativeObjCRuntimeBase: {
31573210
SourceRange range;
3158-
auto name = parseSingleAttrOptionIdentifier(*this, Loc, range, AttrName,
3159-
DK);
3211+
ParserStatus optionStatus;
3212+
auto name = parseSingleAttrOptionIdentifier(*this, Loc, optionStatus, range,
3213+
AttrName, DK);
31603214
if (!name)
31613215
return makeParserSuccess();
31623216

@@ -3448,7 +3502,8 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
34483502
}
34493503
case DeclAttrKind::ObjCImplementation: {
34503504
SourceRange range;
3451-
auto name = parseSingleAttrOptionIdentifier(*this, Loc, range, AttrName, DK,
3505+
ParserStatus optionStatus;
3506+
auto name = parseSingleAttrOptionIdentifier(*this, Loc, optionStatus, range, AttrName, DK,
34523507
/*allowOmitted=*/true);
34533508
if (!name)
34543509
return makeParserSuccess();
@@ -3460,8 +3515,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
34603515
}
34613516
case DeclAttrKind::ObjCRuntimeName: {
34623517
SourceRange range;
3518+
ParserStatus optionStatus;
34633519
auto name =
3464-
parseSingleAttrOptionIdentifier(*this, Loc, range, AttrName, DK);
3520+
parseSingleAttrOptionIdentifier(*this, Loc, optionStatus, range, AttrName, DK);
34653521
if (!name)
34663522
return makeParserSuccess();
34673523

@@ -3618,8 +3674,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
36183674

36193675
case DeclAttrKind::ProjectedValueProperty: {
36203676
SourceRange range;
3677+
ParserStatus optionStatus;
36213678
auto name =
3622-
parseSingleAttrOptionIdentifier(*this, Loc, range, AttrName, DK);
3679+
parseSingleAttrOptionIdentifier(*this, Loc, optionStatus, range, AttrName, DK);
36233680
if (!name)
36243681
return makeParserSuccess();
36253682

@@ -3719,9 +3776,17 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
37193776
case DeclAttrKind::Nonisolated: {
37203777
std::optional<bool> isUnsafe(false);
37213778
if (EnableParameterizedNonisolated) {
3779+
ParserStatus optionStatus;
37223780
isUnsafe =
37233781
parseSingleAttrOption<bool>(*this, Loc, AttrRange, AttrName, DK,
3724-
{{Context.Id_unsafe, true}}, *isUnsafe);
3782+
optionStatus, {{Context.Id_unsafe, true}},
3783+
*isUnsafe, [&] () {
3784+
if (CodeCompletionCallbacks) {
3785+
CodeCompletionCallbacks->completeDeclAttrParam(
3786+
ParameterizedDeclAttributeKind::Nonisolated, 0, false);
3787+
consumeToken(tok::code_complete);
3788+
}
3789+
});
37253790
if (!isUnsafe) {
37263791
return makeParserSuccess();
37273792
}
@@ -3920,8 +3985,9 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
39203985
}
39213986

39223987
case DeclAttrKind::Execution: {
3988+
ParserStatus optionStatus;
39233989
auto behavior = parseSingleAttrOption<ExecutionKind>(
3924-
*this, Loc, AttrRange, AttrName, DK,
3990+
*this, Loc, AttrRange, AttrName, DK, optionStatus,
39253991
{{Context.Id_concurrent, ExecutionKind::Concurrent},
39263992
{Context.Id_caller, ExecutionKind::Caller}});
39273993
if (!behavior)

0 commit comments

Comments
 (0)