Skip to content
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

[CodeCompletion] Support completion for macro roles and the 'names:' argument label #65427

Merged
merged 3 commits into from
Apr 29, 2023
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
2 changes: 1 addition & 1 deletion include/swift/AST/DiagnosticsCommon.def
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ ERROR(unknown_attribute,none,
NOTE(in_macro_expansion,none,
"in expansion of macro %0 here", (DeclName))
ERROR(macro_experimental,none,
"%0 macros are an experimental feature that is not enabled (%1)",
"%0 macros are an experimental feature that is not enabled %select{|(%1)}1",
(StringRef, StringRef))
ERROR(ambiguous_macro_reference,none,
"ambiguous reference to macro %0", (DeclName))
Expand Down
8 changes: 8 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 All @@ -83,6 +88,9 @@ bool isAttachedMacro(MacroRoles contexts);

MacroRoles getAttachedMacroRoles();

/// Checks if the macro is supported or guarded behind an experimental flag.
bool isMacroSupported(MacroRole role, ASTContext &ctx);

enum class MacroIntroducedDeclNameKind {
Named,
Overloaded,
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
13 changes: 7 additions & 6 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,9 +1019,10 @@ class Parser {
PatternBindingInitializer *initContext);

/// Parse the optional modifiers before a declaration.
bool parseDeclModifierList(DeclAttributes &Attributes, SourceLoc &StaticLoc,
StaticSpellingKind &StaticSpelling,
bool isFromClangAttribute = false);
ParserStatus parseDeclModifierList(DeclAttributes &Attributes,
SourceLoc &StaticLoc,
StaticSpellingKind &StaticSpelling,
bool isFromClangAttribute = false);

/// Parse an availability attribute of the form
/// @available(*, introduced: 1.0, deprecated: 3.1).
Expand Down Expand Up @@ -1133,9 +1134,9 @@ class Parser {
ParserResult<CustomAttr> parseCustomAttribute(
SourceLoc atLoc, PatternBindingInitializer *&initContext);

bool parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
DeclAttrKind DK,
bool isFromClangAttribute = false);
ParserStatus parseNewDeclAttribute(DeclAttributes &Attributes,
SourceLoc AtLoc, DeclAttrKind DK,
bool isFromClangAttribute = false);

/// Parse a version tuple of the form x[.y[.z]]. Returns true if there was
/// an error parsing.
Expand Down
23 changes: 23 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10091,6 +10091,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 Expand Up @@ -10182,6 +10190,21 @@ MacroRoles swift::getAttachedMacroRoles() {
return attachedMacroRoles;
}

bool swift::isMacroSupported(MacroRole role, ASTContext &ctx) {
switch (role) {
case MacroRole::Expression:
case MacroRole::Declaration:
case MacroRole::Accessor:
case MacroRole::MemberAttribute:
case MacroRole::Member:
case MacroRole::Peer:
case MacroRole::Conformance:
Comment on lines +10195 to +10201
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not really matter, but there is "feature" flag for each macro roles e.g. CodeItemMacros, FreestandingMacros. Do we want to use them here perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I am using it for codeItem but I should also use them for freestanding declaration (and all the others even if the feature flags are off), you are right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, putting those behind a feature flag failed because then we can’t compile the stdlib anymore. I suspect that the issue is that the features are only enabled if we have swiftSwiftParser but we don’t have that yet while building the stdlib during bootstrapping. I just reverted it to always enable non-codeItem macros – freestanding declaration macros don’t have a feature flag (rdar://108637367).

return true;
case MacroRole::CodeItem:
return ctx.LangOpts.hasFeature(Feature::CodeItemMacros);
}
}

void MissingDecl::forEachMacroExpandedDecl(MacroExpandedDeclCallback callback) {
auto macroRef = unexpandedMacro.macroRef;
auto *baseDecl = unexpandedMacro.baseDecl;
Expand Down
8 changes: 5 additions & 3 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7658,9 +7658,11 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
} else {
SourceLoc staticLoc;
StaticSpellingKind staticSpelling;
hadError = parser.parseDeclModifierList(
MappedDecl->getAttrs(), staticLoc, staticSpelling,
/*isFromClangAttribute=*/true);
hadError = parser
.parseDeclModifierList(MappedDecl->getAttrs(), staticLoc,
staticSpelling,
/*isFromClangAttribute=*/true)
.isError();
}

if (hadError) {
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
Loading