Skip to content

[5.9][CodeComplete] Offer completions for the names: argument of a macro declaration #65569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/swift/AST/MacroDeclaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,14 @@ enum class MacroIntroducedDeclNameKind {
Prefixed,
Suffixed,
Arbitrary,

// NOTE: When adding a new name kind, also add it to
// `getAllMacroIntroducedDeclNameKinds`.
};

/// Returns an enumeratable list of all macro introduced decl name kinds.
std::vector<MacroIntroducedDeclNameKind> getAllMacroIntroducedDeclNameKinds();

/// Whether a macro-introduced name of this kind requires an argument.
bool macroIntroducedNameRequiresArgument(MacroIntroducedDeclNameKind kind);

Expand Down
6 changes: 3 additions & 3 deletions include/swift/IDE/CompletionLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
CodeCompletionKeywordKind KeyKind = CodeCompletionKeywordKind::None,
CodeCompletionFlair flair = {});

void addDeclAttrParamKeyword(StringRef Name, StringRef Annotation,
bool NeedSpecify);
void addDeclAttrParamKeyword(StringRef Name, ArrayRef<StringRef> Parameters,
StringRef Annotation, bool NeedSpecify);

void addDeclAttrKeyword(StringRef Name, StringRef Annotation);

Expand Down Expand Up @@ -586,7 +586,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
void getAttributeDeclCompletions(bool IsInSil, Optional<DeclKind> DK);

void getAttributeDeclParamCompletions(CustomSyntaxAttributeKind AttrKind,
int ParamIndex);
int ParamIndex, bool HasLabel);

void getTypeAttributeKeywordCompletions();

Expand Down
5 changes: 4 additions & 1 deletion include/swift/Parse/IDEInspectionCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ class CodeCompletionCallbacks {

/// Complete the parameters in attribute, for instance, version specifier for
/// @available.
virtual void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index){};
/// If `HasLabel` is `true`, then the argument already has a label specified,
/// e.g. we're completing after `names: ` in a macro declaration.
virtual void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index,
bool HasLabel){};

/// Complete 'async' and 'throws' at effects specifier position.
virtual void completeEffectsSpecifier(bool hasAsync, bool hasThrows) {};
Expand Down
11 changes: 11 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10137,6 +10137,17 @@ StringRef swift::getMacroRoleString(MacroRole role) {
}
}

std::vector<MacroIntroducedDeclNameKind>
swift::getAllMacroIntroducedDeclNameKinds() {
return {
MacroIntroducedDeclNameKind::Named,
MacroIntroducedDeclNameKind::Overloaded,
MacroIntroducedDeclNameKind::Prefixed,
MacroIntroducedDeclNameKind::Suffixed,
MacroIntroducedDeclNameKind::Arbitrary,
};
}

bool swift::macroIntroducedNameRequiresArgument(
MacroIntroducedDeclNameKind kind
) {
Expand Down
10 changes: 7 additions & 3 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
CodeCompletionCallbacks::PrecedenceGroupCompletionKind SyntxKind;

int AttrParamIndex;
bool AttrParamHasLabel;
bool IsInSil = false;
bool HasSpace = false;
bool ShouldCompleteCallPatternAfterParen = true;
Expand Down Expand Up @@ -270,7 +271,8 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
void completeCaseStmtKeyword() override;
void completeCaseStmtBeginning(CodeCompletionExpr *E) override;
void completeDeclAttrBeginning(bool Sil, bool isIndependent) override;
void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index) override;
void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index,
bool HasLabel) override;
void completeEffectsSpecifier(bool hasAsync, bool hasThrows) override;
void completeInPrecedenceGroup(
CodeCompletionCallbacks::PrecedenceGroupCompletionKind SK) override;
Expand Down Expand Up @@ -457,10 +459,11 @@ void CodeCompletionCallbacksImpl::completeTypeSimpleBeginning() {
}

void CodeCompletionCallbacksImpl::completeDeclAttrParam(
CustomSyntaxAttributeKind DK, int Index) {
CustomSyntaxAttributeKind DK, int Index, bool HasLabel) {
Kind = CompletionKind::AttributeDeclParen;
AttrKind = DK;
AttrParamIndex = Index;
AttrParamHasLabel = HasLabel;
CurDeclContext = P.CurDeclContext;
}

Expand Down Expand Up @@ -1844,7 +1847,8 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
break;
}
case CompletionKind::AttributeDeclParen: {
Lookup.getAttributeDeclParamCompletions(AttrKind, AttrParamIndex);
Lookup.getAttributeDeclParamCompletions(AttrKind, AttrParamIndex,
AttrParamHasLabel);
break;
}
case CompletionKind::PoundAvailablePlatform: {
Expand Down
11 changes: 9 additions & 2 deletions lib/IDE/CodeCompletionResultBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,17 @@ class CodeCompletionResultBuilder {
addChunkWithTextNoCopy(CodeCompletionString::Chunk::ChunkKind::Equal, "=");
}

void addDeclAttrParamKeyword(StringRef Name, StringRef Annotation,
bool NeedSpecify) {
void addDeclAttrParamKeyword(StringRef Name, ArrayRef<StringRef> Parameters,
StringRef Annotation, bool NeedSpecify) {
addChunkWithText(CodeCompletionString::Chunk::ChunkKind::
DeclAttrParamKeyword, Name);
if (!Parameters.empty()) {
addLeftParen();
for (auto Parameter : Parameters) {
addSimpleNamedParameter(Parameter);
}
addRightParen();
}
if (NeedSpecify)
addChunkWithText(CodeCompletionString::Chunk::ChunkKind::
DeclAttrParamColon, ": ");
Expand Down
47 changes: 34 additions & 13 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1850,11 +1850,12 @@ void CompletionLookup::addKeyword(StringRef Name, StringRef TypeAnnotation,
}

void CompletionLookup::addDeclAttrParamKeyword(StringRef Name,
ArrayRef<StringRef> Parameters,
StringRef Annotation,
bool NeedSpecify) {
CodeCompletionResultBuilder Builder(Sink, CodeCompletionResultKind::Keyword,
SemanticContextKind::None);
Builder.addDeclAttrParamKeyword(Name, Annotation, NeedSpecify);
Builder.addDeclAttrParamKeyword(Name, Parameters, Annotation, NeedSpecify);
}

void CompletionLookup::addDeclAttrKeyword(StringRef Name,
Expand Down Expand Up @@ -3012,23 +3013,27 @@ void CompletionLookup::getAttributeDeclCompletions(bool IsInSil,
}

void CompletionLookup::getAttributeDeclParamCompletions(
CustomSyntaxAttributeKind AttrKind, int ParamIndex) {
CustomSyntaxAttributeKind AttrKind, int ParamIndex, bool HasLabel) {
switch (AttrKind) {
case CustomSyntaxAttributeKind::Available:
if (ParamIndex == 0) {
addDeclAttrParamKeyword("*", "Platform", false);
addDeclAttrParamKeyword("*", /*Parameters=*/{}, "Platform", false);

#define AVAILABILITY_PLATFORM(X, PrettyName) \
addDeclAttrParamKeyword(swift::platformString(PlatformKind::X), "Platform", \
false);
addDeclAttrParamKeyword(swift::platformString(PlatformKind::X), \
/*Parameters=*/{}, "Platform", false);
#include "swift/AST/PlatformKinds.def"

} else {
addDeclAttrParamKeyword("unavailable", "", false);
addDeclAttrParamKeyword("message", "Specify message", true);
addDeclAttrParamKeyword("renamed", "Specify replacing name", true);
addDeclAttrParamKeyword("introduced", "Specify version number", true);
addDeclAttrParamKeyword("deprecated", "Specify version number", true);
addDeclAttrParamKeyword("unavailable", /*Parameters=*/{}, "", false);
addDeclAttrParamKeyword("message", /*Parameters=*/{}, "Specify message",
true);
addDeclAttrParamKeyword("renamed", /*Parameters=*/{},
"Specify replacing name", true);
addDeclAttrParamKeyword("introduced", /*Parameters=*/{},
"Specify version number", true);
addDeclAttrParamKeyword("deprecated", /*Parameters=*/{},
"Specify version number", true);
}
break;
case CustomSyntaxAttributeKind::FreestandingMacro:
Expand All @@ -3043,12 +3048,27 @@ void CompletionLookup::getAttributeDeclParamCompletions(
isRoleSupported &= isAttachedMacro(role);
}
if (isRoleSupported) {
addDeclAttrParamKeyword(getMacroRoleString(role), "", false);
addDeclAttrParamKeyword(getMacroRoleString(role), /*Parameters=*/{},
/*Annotation=*/"", /*NeedsSpecify=*/false);
}
}
break;
case 1:
addDeclAttrParamKeyword("names", "Specify declared names", true);
if (HasLabel) {
for (auto kind : getAllMacroIntroducedDeclNameKinds()) {
auto name = getMacroIntroducedDeclNameString(kind);
SmallVector<StringRef, 1> Parameters;
if (macroIntroducedNameRequiresArgument(kind)) {
Parameters = {"name"};
}
addDeclAttrParamKeyword(name, Parameters, /*Annotation=*/"",
/*NeedsSpecify=*/false);
}
} else {
addDeclAttrParamKeyword("names", /*Parameters=*/{},
"Specify declared names",
/*NeedsSpecify=*/true);
}
break;
}
break;
Expand Down Expand Up @@ -3126,7 +3146,8 @@ void CompletionLookup::getPrecedenceGroupCompletions(
void CompletionLookup::getPoundAvailablePlatformCompletions() {

// The platform names should be identical to those in @available.
getAttributeDeclParamCompletions(CustomSyntaxAttributeKind::Available, 0);
getAttributeDeclParamCompletions(CustomSyntaxAttributeKind::Available, 0,
/*HasLabel=*/false);
}

void CompletionLookup::getSelfTypeCompletionInDeclContext(
Expand Down
38 changes: 25 additions & 13 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,8 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
.highlight(SourceRange(ArgumentLoc));
if (Tok.is(tok::code_complete) && CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(
CustomSyntaxAttributeKind::Available, ParamIndex);
CustomSyntaxAttributeKind::Available, ParamIndex,
/*HasLabel=*/false);
consumeToken(tok::code_complete);
} else {
consumeIf(tok::identifier);
Expand Down Expand Up @@ -941,7 +942,7 @@ bool Parser::parseAvailability(
!(Tok.isAnyOperator() && Tok.getText() == "*")) {
if (Tok.is(tok::code_complete) && CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(
CustomSyntaxAttributeKind::Available, 0);
CustomSyntaxAttributeKind::Available, 0, /*HasLabel=*/false);
consumeToken(tok::code_complete);
}
diagnose(Tok.getLoc(), diag::attr_availability_platform, AttrName)
Expand Down Expand Up @@ -2185,6 +2186,14 @@ Optional<MacroRole> getMacroRole(StringRef roleName) {
.Default(None);
}

static CustomSyntaxAttributeKind getCustomSyntaxAttributeKind(bool isAttached) {
if (isAttached) {
return CustomSyntaxAttributeKind::AttachedMacro;
} else {
return CustomSyntaxAttributeKind::FreestandingMacro;
}
}

ParserResult<MacroRoleAttr>
Parser::parseMacroRoleAttribute(
MacroSyntax syntax, SourceLoc AtLoc, SourceLoc Loc)
Expand Down Expand Up @@ -2221,20 +2230,18 @@ Parser::parseMacroRoleAttribute(
[&] {
ParserStatus status;

if (Tok.is(tok::code_complete)) {
consumeIf(tok::code_complete);
if (consumeIf(tok::code_complete)) {
status.setHasCodeCompletionAndIsError();
CustomSyntaxAttributeKind attributeKind =
isAttached ? CustomSyntaxAttributeKind::AttachedMacro
: CustomSyntaxAttributeKind::FreestandingMacro;
if (!sawRole) {
sawRole = true;
if (this->CodeCompletionCallbacks) {
this->CodeCompletionCallbacks->completeDeclAttrParam(attributeKind, 0);
this->CodeCompletionCallbacks->completeDeclAttrParam(
getCustomSyntaxAttributeKind(isAttached), 0, /*HasLabel=*/false);
}
} else if (!sawNames) {
if (this->CodeCompletionCallbacks) {
this->CodeCompletionCallbacks->completeDeclAttrParam(attributeKind, 1);
this->CodeCompletionCallbacks->completeDeclAttrParam(
getCustomSyntaxAttributeKind(isAttached), 1, /*HasLabel=*/false);
}
}
}
Expand Down Expand Up @@ -2309,10 +2316,15 @@ Parser::parseMacroRoleAttribute(
// Parse the introduced name kind.
Identifier introducedNameKind;
SourceLoc introducedNameKindLoc;
if (parseIdentifier(
introducedNameKind, introducedNameKindLoc,
diag::macro_attribute_unknown_argument_form,
/*diagnoseDollarPrefix=*/true)) {
if (consumeIf(tok::code_complete)) {
status.setHasCodeCompletionAndIsError();
if (this->CodeCompletionCallbacks) {
this->CodeCompletionCallbacks->completeDeclAttrParam(
getCustomSyntaxAttributeKind(isAttached), 1, /*HasLabel=*/true);
}
} else if (parseIdentifier(introducedNameKind, introducedNameKindLoc,
diag::macro_attribute_unknown_argument_form,
/*diagnoseDollarPrefix=*/true)) {
status.setIsParseError();
return status;
}
Expand Down
10 changes: 10 additions & 0 deletions test/IDE/complete_macro_attribute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,13 @@ macro FreestandingDeclarationMacro

// NAMES_POSITION: Begin completions, 1 item
// NAMES_POSITION-DAG: Keyword/None: names: [#Specify declared names#]; name=names

@attached(member, names: #^NAMES_ARGUMENT^#)

// NAMES_ARGUMENT: Begin completions, 5 items
// NAMES_ARGUMENT-DAG: Keyword/None: named({#(name)#}); name=named()
// NAMES_ARGUMENT-DAG: Keyword/None: overloaded; name=overloaded
// NAMES_ARGUMENT-DAG: Keyword/None: prefixed({#(name)#}); name=prefixed()
// NAMES_ARGUMENT-DAG: Keyword/None: suffixed({#(name)#}); name=suffixed()
// NAMES_ARGUMENT-DAG: Keyword/None: arbitrary; name=arbitrary