Skip to content

Commit

Permalink
[CodeCompletion] Support completion for macro roles and the 'names:' …
Browse files Browse the repository at this point in the history
…argument label

rdar://108163121
  • Loading branch information
ahoppen committed Apr 26, 2023
1 parent 5526852 commit e4ddd96
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 13 deletions.
5 changes: 5 additions & 0 deletions include/swift/AST/MacroDeclaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,13 @@ enum class MacroRole: uint32_t {
/// A freestanding macro that expands to expressions, statements and
/// declarations in a code block.
CodeItem = 0x80,

// NOTE: When adding a new macro role, also add it to `getAllMacroRoles`.
};

/// Returns an enumeratable list of all macro roles.
std::vector<MacroRole> getAllMacroRoles();

/// The contexts in which a particular macro declaration can be used.
using MacroRoles = OptionSet<MacroRole>;

Expand Down
3 changes: 2 additions & 1 deletion include/swift/IDE/CompletionLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {

void getAttributeDeclCompletions(bool IsInSil, Optional<DeclKind> DK);

void getAttributeDeclParamCompletions(DeclAttrKind AttrKind, int ParamIndex);
void getAttributeDeclParamCompletions(CustomSyntaxAttributeKind AttrKind,
int ParamIndex);

void getTypeAttributeKeywordCompletions();

Expand Down
11 changes: 10 additions & 1 deletion include/swift/Parse/IDEInspectionCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ enum class ObjCSelectorContext {
SetterSelector
};

/// Attributes that have syntax which can't be modelled using a function call.
/// This can't be \c DeclAttrKind because '@freestandig' and '@attached' have
/// the same attribute kind but take different macro roles as arguemnts.
enum class CustomSyntaxAttributeKind {
Available,
FreestandingMacro,
AttachedMacro,
};

/// Parser's interface to code completion.
class CodeCompletionCallbacks {
protected:
Expand Down Expand Up @@ -185,7 +194,7 @@ class CodeCompletionCallbacks {

/// Complete the parameters in attribute, for instance, version specifier for
/// @available.
virtual void completeDeclAttrParam(DeclAttrKind DK, int Index) {};
virtual void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index){};

/// Complete 'async' and 'throws' at effects specifier position.
virtual void completeEffectsSpecifier(bool hasAsync, bool hasThrows) {};
Expand Down
8 changes: 8 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10049,6 +10049,14 @@ BuiltinTupleDecl::BuiltinTupleDecl(Identifier Name, DeclContext *Parent)
: NominalTypeDecl(DeclKind::BuiltinTuple, Parent, Name, SourceLoc(),
ArrayRef<InheritedEntry>(), nullptr) {}

std::vector<MacroRole> swift::getAllMacroRoles() {
return {
MacroRole::Expression, MacroRole::Declaration, MacroRole::Accessor,
MacroRole::MemberAttribute, MacroRole::Member, MacroRole::Peer,
MacroRole::Conformance, MacroRole::CodeItem,
};
}

StringRef swift::getMacroRoleString(MacroRole role) {
switch (role) {
case MacroRole::Expression:
Expand Down
8 changes: 4 additions & 4 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
SourceLoc DotLoc;
TypeLoc ParsedTypeLoc;
DeclContext *CurDeclContext = nullptr;
DeclAttrKind AttrKind;
CustomSyntaxAttributeKind AttrKind;

/// When the code completion token occurs in a custom attribute, the attribute
/// it occurs in. Used so we can complete inside the attribute even if it's
Expand Down Expand Up @@ -270,7 +270,7 @@ class CodeCompletionCallbacksImpl : public CodeCompletionCallbacks,
void completeCaseStmtKeyword() override;
void completeCaseStmtBeginning(CodeCompletionExpr *E) override;
void completeDeclAttrBeginning(bool Sil, bool isIndependent) override;
void completeDeclAttrParam(DeclAttrKind DK, int Index) override;
void completeDeclAttrParam(CustomSyntaxAttributeKind DK, int Index) override;
void completeEffectsSpecifier(bool hasAsync, bool hasThrows) override;
void completeInPrecedenceGroup(
CodeCompletionCallbacks::PrecedenceGroupCompletionKind SK) override;
Expand Down Expand Up @@ -456,8 +456,8 @@ void CodeCompletionCallbacksImpl::completeTypeSimpleBeginning() {
CurDeclContext = P.CurDeclContext;
}

void CodeCompletionCallbacksImpl::completeDeclAttrParam(DeclAttrKind DK,
int Index) {
void CodeCompletionCallbacksImpl::completeDeclAttrParam(
CustomSyntaxAttributeKind DK, int Index) {
Kind = CompletionKind::AttributeDeclParen;
AttrKind = DK;
AttrParamIndex = Index;
Expand Down
31 changes: 27 additions & 4 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3004,9 +3004,10 @@ void CompletionLookup::getAttributeDeclCompletions(bool IsInSil,
#include "swift/AST/Attr.def"
}

void CompletionLookup::getAttributeDeclParamCompletions(DeclAttrKind AttrKind,
int ParamIndex) {
if (AttrKind == DAK_Available) {
void CompletionLookup::getAttributeDeclParamCompletions(
CustomSyntaxAttributeKind AttrKind, int ParamIndex) {
switch (AttrKind) {
case CustomSyntaxAttributeKind::Available:
if (ParamIndex == 0) {
addDeclAttrParamKeyword("*", "Platform", false);

Expand All @@ -3022,6 +3023,28 @@ void CompletionLookup::getAttributeDeclParamCompletions(DeclAttrKind AttrKind,
addDeclAttrParamKeyword("introduced", "Specify version number", true);
addDeclAttrParamKeyword("deprecated", "Specify version number", true);
}
break;
case CustomSyntaxAttributeKind::FreestandingMacro:
case CustomSyntaxAttributeKind::AttachedMacro:
switch (ParamIndex) {
case 0:
for (auto role : getAllMacroRoles()) {
bool isRoleSupported = isMacroSupported(role, Ctx);
if (AttrKind == CustomSyntaxAttributeKind::FreestandingMacro) {
isRoleSupported &= isFreestandingMacro(role);
} else if (AttrKind == CustomSyntaxAttributeKind::AttachedMacro) {
isRoleSupported &= isAttachedMacro(role);
}
if (isRoleSupported) {
addDeclAttrParamKeyword(getMacroRoleString(role), "", false);
}
}
break;
case 1:
addDeclAttrParamKeyword("names", "Specify declared names", true);
break;
}
break;
}
}

Expand Down Expand Up @@ -3096,7 +3119,7 @@ void CompletionLookup::getPrecedenceGroupCompletions(
void CompletionLookup::getPoundAvailablePlatformCompletions() {

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

void CompletionLookup::getSelfTypeCompletionInDeclContext(
Expand Down
25 changes: 22 additions & 3 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
diagnose(ArgumentLoc, diag::attr_availability_expected_option, AttrName)
.highlight(SourceRange(ArgumentLoc));
if (Tok.is(tok::code_complete) && CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(DAK_Available,
ParamIndex);
CodeCompletionCallbacks->completeDeclAttrParam(
CustomSyntaxAttributeKind::Available, ParamIndex);
consumeToken(tok::code_complete);
} else {
consumeIf(tok::identifier);
Expand Down Expand Up @@ -940,7 +940,8 @@ bool Parser::parseAvailability(
if (!Tok.is(tok::identifier) &&
!(Tok.isAnyOperator() && Tok.getText() == "*")) {
if (Tok.is(tok::code_complete) && CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(DAK_Available, 0);
CodeCompletionCallbacks->completeDeclAttrParam(
CustomSyntaxAttributeKind::Available, 0);
consumeToken(tok::code_complete);
}
diagnose(Tok.getLoc(), diag::attr_availability_platform, AttrName)
Expand Down Expand Up @@ -2220,6 +2221,24 @@ Parser::parseMacroRoleAttribute(
[&] {
ParserStatus status;

if (Tok.is(tok::code_complete)) {
consumeIf(tok::code_complete);
status.setHasCodeCompletionAndIsError();
CustomSyntaxAttributeKind attributeKind =
isAttached ? CustomSyntaxAttributeKind::AttachedMacro
: CustomSyntaxAttributeKind::FreestandingMacro;
if (!sawRole) {
sawRole = true;
if (CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(attributeKind, 0);
}
} else if (!sawNames) {
if (CodeCompletionCallbacks) {
CodeCompletionCallbacks->completeDeclAttrParam(attributeKind, 1);
}
}
}

// Parse the argment label, if there is one.
Identifier fieldName;
SourceLoc fieldNameLoc;
Expand Down
26 changes: 26 additions & 0 deletions test/IDE/complete_macro_attribute.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t/output


@freestanding(#^FREESTANDING_ROLE^#)
macro FreestandingMacro

// FREESTANDING_ROLE: Begin completions, 2 items
// FREESTANDING_ROLE-DAG: Keyword/None: expression; name=expression
// FREESTANDING_ROLE-DAG: Keyword/None: declaration; name=declaration

@attached(#^ATTACHED_ROLE^#)
macro AttachedMacro

// ATTACHED_ROLE: Begin completions, 5 items
// ATTACHED_ROLE-DAG: Keyword/None: accessor; name=accessor
// ATTACHED_ROLE-DAG: Keyword/None: memberAttribute; name=memberAttribute
// ATTACHED_ROLE-DAG: Keyword/None: member; name=member
// ATTACHED_ROLE-DAG: Keyword/None: peer; name=peer
// ATTACHED_ROLE-DAG: Keyword/None: conformance; name=conformance

@freestanding(declaration, #^NAMES_POSITION^#)
macro FreestandingDeclarationMacro

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

0 comments on commit e4ddd96

Please sign in to comment.