Skip to content

Commit 584cc87

Browse files
committed
[Completion] Only provide macro completions when they are valid
Only return macros that are valid in their current position, ie. an attached macro is not valid on a nominal. Also return freestanding expression macros in code block item position and handle the new freestanding code item macros. Resolves rdar://105563583.
1 parent 3e3a98f commit 584cc87

16 files changed

+506
-225
lines changed

include/swift/IDE/CodeCompletionCache.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,7 @@ class OnDiskCodeCompletionCache {
116116
struct RequestedCachedModule {
117117
CodeCompletionCache::Key Key;
118118
const ModuleDecl *TheModule;
119-
bool OnlyTypes;
120-
bool OnlyPrecedenceGroups;
121-
bool OnlyMacros;
119+
CodeCompletionFilter Filter;
122120
};
123121

124122
} // end namespace ide

include/swift/IDE/CodeCompletionResult.h

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,39 @@ enum class CodeCompletionResultKind : uint8_t {
316316
MAX_VALUE = BuiltinOperator
317317
};
318318

319+
enum class CodeCompletionMacroRole : uint8_t {
320+
Expression = 1 << 0,
321+
Declaration = 1 << 1,
322+
CodeItem = 1 << 2,
323+
AttachedVar = 1 << 3,
324+
AttachedContext = 1 << 4,
325+
AttachedDecl = 1 << 5,
326+
};
327+
using CodeCompletionMacroRoles = OptionSet<CodeCompletionMacroRole>;
328+
329+
enum class CodeCompletionFilterFlag : uint16_t {
330+
Expr = 1 << 0,
331+
Type = 1 << 1,
332+
PrecedenceGroup = 1 << 2,
333+
Module = 1 << 3,
334+
ExpressionMacro = 1 << 4,
335+
DeclarationMacro = 1 << 5,
336+
CodeItemMacro = 1 << 6,
337+
AttachedVarMacro = 1 << 7,
338+
AttachedContextMacro = 1 << 8,
339+
AttachedDeclMacro = 1 << 9,
340+
};
341+
using CodeCompletionFilter = OptionSet<CodeCompletionFilterFlag>;
342+
343+
CodeCompletionMacroRoles getCompletionMacroRoles(const Decl *D);
344+
345+
CodeCompletionMacroRoles
346+
getCompletionMacroRoles(OptionSet<CustomAttributeKind> kinds);
347+
348+
CodeCompletionMacroRoles getCompletionMacroRoles(CodeCompletionFilter filter);
349+
350+
CodeCompletionFilter getCompletionFilter(CodeCompletionMacroRoles roles);
351+
319352
/// The parts of a \c CodeCompletionResult that are not dependent on the context
320353
/// it appears in and can thus be cached.
321354
class ContextFreeCodeCompletionResult {
@@ -334,6 +367,8 @@ class ContextFreeCodeCompletionResult {
334367
CodeCompletionOperatorKind KnownOperatorKind : 6;
335368
static_assert(int(CodeCompletionOperatorKind::MAX_VALUE) < 1 << 6, "");
336369

370+
CodeCompletionMacroRoles DeclMacroRoles;
371+
337372
bool IsSystem : 1;
338373
bool IsAsync : 1;
339374
/// Whether the result has been annotated as having an async alternative that
@@ -359,17 +394,18 @@ class ContextFreeCodeCompletionResult {
359394
NullTerminatedStringRef NameForDiagnostics;
360395

361396
public:
362-
/// Memberwise initializer. \p AssociatedKInd is opaque and will be
397+
/// Memberwise initializer. \p AssociatedKind is opaque and will be
363398
/// interpreted based on \p Kind. If \p KnownOperatorKind is \c None and the
364399
/// completion item is an operator, it will be determined based on the
365-
/// compleiton string.
400+
/// completion string.
366401
///
367-
/// \note The caller must ensure that the \p CompleitonString and all the
402+
/// \note The caller must ensure that the \p CompletionString and all the
368403
/// \c Ref types outlive this result, typically by storing them in the same
369404
/// \c CodeCompletionResultSink as the result itself.
370405
ContextFreeCodeCompletionResult(
371406
CodeCompletionResultKind Kind, uint8_t AssociatedKind,
372-
CodeCompletionOperatorKind KnownOperatorKind, bool IsSystem, bool IsAsync,
407+
CodeCompletionOperatorKind KnownOperatorKind,
408+
CodeCompletionMacroRoles DeclMacroRoles, bool IsSystem, bool IsAsync,
373409
bool HasAsyncAlternative, CodeCompletionString *CompletionString,
374410
NullTerminatedStringRef ModuleName,
375411
NullTerminatedStringRef BriefDocComment,
@@ -380,8 +416,9 @@ class ContextFreeCodeCompletionResult {
380416
NullTerminatedStringRef DiagnosticMessage,
381417
NullTerminatedStringRef FilterName,
382418
NullTerminatedStringRef NameForDiagnostics)
383-
: Kind(Kind), KnownOperatorKind(KnownOperatorKind), IsSystem(IsSystem),
384-
IsAsync(IsAsync), HasAsyncAlternative(HasAsyncAlternative),
419+
: Kind(Kind), KnownOperatorKind(KnownOperatorKind),
420+
DeclMacroRoles(DeclMacroRoles), IsSystem(IsSystem), IsAsync(IsAsync),
421+
HasAsyncAlternative(HasAsyncAlternative),
385422
CompletionString(CompletionString), ModuleName(ModuleName),
386423
BriefDocComment(BriefDocComment), AssociatedUSRs(AssociatedUSRs),
387424
ResultType(ResultType), NotRecommended(NotRecommended),
@@ -488,6 +525,10 @@ class ContextFreeCodeCompletionResult {
488525
return KnownOperatorKind;
489526
}
490527

528+
CodeCompletionMacroRoles getMacroRoles() const {
529+
return DeclMacroRoles;
530+
}
531+
491532
bool isSystem() const { return IsSystem; };
492533

493534
bool isAsync() const { return IsAsync; };

include/swift/IDE/CodeCompletionResultType.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ enum class CustomAttributeKind : uint8_t {
2828
ResultBuilder = 1 << 1,
2929
/// A type that can be used as a global actor.
3030
GlobalActor = 1 << 2,
31-
/// A macro can be used as a custom attribute.
32-
Macro = 1 << 3,
31+
/// A macro that can be used on variables or subscripts.
32+
VarMacro = 1 << 3,
33+
/// A macro that can be used on any type context.
34+
ContextMacro = 1 << 4,
35+
/// A macro that can be used on any declaration.
36+
DeclMacro = 1 << 5,
3337
};
3438

3539
/// The expected contextual type(s) for code-completion.

include/swift/IDE/CompletionLookup.h

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
137137
bool IsUnwrappedOptional = false;
138138
SourceLoc DotLoc;
139139
bool NeedLeadingDot = false;
140-
bool NeedLeadingMacroPound = false;
141140

142141
bool NeedOptionalUnwrap = false;
143142
unsigned NumBytesToEraseForOptionalUnwrap = 0;
@@ -186,53 +185,27 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
186185
public:
187186
struct RequestedResultsTy {
188187
const ModuleDecl *TheModule;
189-
bool OnlyTypes;
190-
bool OnlyPrecedenceGroups;
191-
bool OnlyMacros;
188+
CodeCompletionFilter Filter;
192189
bool NeedLeadingDot;
193-
bool NeedPound;
194-
bool IncludeModuleQualifier;
195190

196-
static RequestedResultsTy fromModule(const ModuleDecl *TheModule) {
197-
return {TheModule, false, false, false, false, false, true};
191+
static RequestedResultsTy fromModule(const ModuleDecl *mod,
192+
CodeCompletionFilter filter) {
193+
return {mod, filter, /*NeedLeadingDot=*/false};
198194
}
199195

200-
RequestedResultsTy onlyTypes() const {
201-
return {TheModule, true, false, false, NeedLeadingDot, false,
202-
IncludeModuleQualifier};
196+
static RequestedResultsTy topLevelResults(CodeCompletionFilter filter) {
197+
return {nullptr, filter, /*NeedLeadingDot=*/false};
203198
}
204199

205-
RequestedResultsTy onlyPrecedenceGroups() const {
206-
assert(!OnlyTypes && "onlyTypes() already includes precedence groups");
207-
return {TheModule, false, true, false, false, false, true};
208-
}
209-
210-
RequestedResultsTy onlyMacros(bool needPound) const {
211-
return {TheModule, false, false, true, false, needPound, false};
212-
}
213-
214-
RequestedResultsTy needLeadingDot(bool NeedDot) const {
215-
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, OnlyMacros, NeedDot,
216-
NeedPound, IncludeModuleQualifier};
217-
}
218-
219-
RequestedResultsTy withModuleQualifier(bool IncludeModule) const {
220-
return {TheModule, OnlyTypes, OnlyPrecedenceGroups, OnlyMacros,
221-
NeedLeadingDot, NeedPound, IncludeModule};
222-
}
223-
224-
static RequestedResultsTy toplevelResults() {
225-
return {nullptr, false, false, false, false, true, true};
200+
RequestedResultsTy needLeadingDot(bool needDot) const {
201+
return {TheModule, Filter, needDot};
226202
}
227203

228204
friend bool operator==(const RequestedResultsTy &LHS,
229205
const RequestedResultsTy &RHS) {
230-
return LHS.TheModule == RHS.TheModule && LHS.OnlyTypes == RHS.OnlyTypes &&
231-
LHS.OnlyPrecedenceGroups == RHS.OnlyPrecedenceGroups &&
232-
LHS.OnlyMacros == RHS.OnlyMacros &&
233-
LHS.NeedLeadingDot == RHS.NeedLeadingDot &&
234-
LHS.NeedPound == RHS.NeedPound &&
235-
LHS.IncludeModuleQualifier == RHS.IncludeModuleQualifier;
206+
return LHS.TheModule == RHS.TheModule &&
207+
LHS.Filter.containsOnly(RHS.Filter) &&
208+
LHS.NeedLeadingDot == RHS.NeedLeadingDot;
236209
}
237210
};
238211

@@ -524,7 +497,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
524497
Type ExprType, const ValueDecl *VD,
525498
Optional<SemanticContextKind> SemanticContext = None);
526499

527-
bool tryModuleCompletions(Type ExprType, bool TypesOnly = false);
500+
bool tryModuleCompletions(Type ExprType, CodeCompletionFilter Filter);
528501

529502
/// If the given ExprType is optional, this adds completions for the unwrapped
530503
/// type.
@@ -562,7 +535,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
562535

563536
void addObjCPoundKeywordCompletions(bool needPound);
564537

565-
void getMacroCompletions(bool needPound);
538+
void getMacroCompletions(CodeCompletionMacroRoles roles);
566539

567540
struct FilteredDeclConsumer : public swift::VisibleDeclConsumer {
568541
swift::VisibleDeclConsumer &Consumer;
@@ -626,7 +599,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
626599
void getTypeCompletionsInDeclContext(SourceLoc Loc,
627600
bool ModuleQualifier = true);
628601

629-
void getToplevelCompletions(bool OnlyTypes, bool OnlyMacros);
602+
void getToplevelCompletions(CodeCompletionFilter Filter);
630603

631604
void lookupExternalModuleDecls(const ModuleDecl *TheModule,
632605
ArrayRef<std::string> AccessPath,
@@ -645,18 +618,15 @@ using RequestedResultsTy = swift::ide::CompletionLookup::RequestedResultsTy;
645618
template <>
646619
struct DenseMapInfo<RequestedResultsTy> {
647620
static inline RequestedResultsTy getEmptyKey() {
648-
return {DenseMapInfo<swift::ModuleDecl *>::getEmptyKey(), false, false,
649-
false, false, false, false};
621+
return {DenseMapInfo<swift::ModuleDecl *>::getEmptyKey(), {}, false};
650622
}
651623
static inline RequestedResultsTy getTombstoneKey() {
652-
return {DenseMapInfo<swift::ModuleDecl *>::getTombstoneKey(), false, false,
653-
false, false, false, false};
624+
return {DenseMapInfo<swift::ModuleDecl *>::getTombstoneKey(), {}, false};
654625
}
655626
static unsigned getHashValue(const RequestedResultsTy &Val) {
656627
return hash_combine(
657628
DenseMapInfo<swift::ModuleDecl *>::getHashValue(Val.TheModule),
658-
Val.OnlyTypes, Val.OnlyPrecedenceGroups, Val.OnlyMacros,
659-
Val.NeedLeadingDot, Val.NeedPound, Val.IncludeModuleQualifier);
629+
Val.Filter.toRaw(), Val.NeedLeadingDot);
660630
}
661631
static bool isEqual(const RequestedResultsTy &LHS,
662632
const RequestedResultsTy &RHS) {

lib/IDE/AfterPoundExprCompletion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ void AfterPoundExprCompletion::deliverResults(
5252
/*expectsNonVoid=*/true);
5353
Lookup.addPoundAvailable(ParentStmtKind);
5454
Lookup.addObjCPoundKeywordCompletions(/*needPound=*/false);
55-
Lookup.getMacroCompletions(/*needPound=*/false);
55+
Lookup.getMacroCompletions(CodeCompletionMacroRole::Expression);
5656
}
5757

5858
deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);

lib/IDE/CodeCompletion.cpp

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,22 +1130,6 @@ static void addPoundDirectives(CodeCompletionResultSink &Sink) {
11301130
Builder.addSimpleTypedParameter("Int");
11311131
Builder.addRightParen();
11321132
});
1133-
addWithName("warning", CodeCompletionKeywordKind::pound_warning,
1134-
[&] (CodeCompletionResultBuilder &Builder) {
1135-
Builder.addLeftParen();
1136-
Builder.addTextChunk("\"");
1137-
Builder.addSimpleNamedParameter("message");
1138-
Builder.addTextChunk("\"");
1139-
Builder.addRightParen();
1140-
});
1141-
addWithName("error", CodeCompletionKeywordKind::pound_error,
1142-
[&] (CodeCompletionResultBuilder &Builder) {
1143-
Builder.addLeftParen();
1144-
Builder.addTextChunk("\"");
1145-
Builder.addSimpleNamedParameter("message");
1146-
Builder.addTextChunk("\"");
1147-
Builder.addRightParen();
1148-
});
11491133

11501134
addWithName("if ", CodeCompletionKeywordKind::pound_if,
11511135
[&] (CodeCompletionResultBuilder &Builder) {
@@ -1352,11 +1336,10 @@ void swift::ide::deliverCompletionResults(
13521336
std::pair<PairType, bool> Result = ImportsSeen.insert(K);
13531337
if (!Result.second)
13541338
return; // already handled.
1355-
RequestedModules.push_back({std::move(K), TheModule,
1356-
Request.OnlyTypes, Request.OnlyPrecedenceGroups, Request.OnlyMacros});
1339+
RequestedModules.push_back({std::move(K), TheModule, Request.Filter});
13571340

13581341
auto TheModuleName = TheModule->getName();
1359-
if (Request.IncludeModuleQualifier &&
1342+
if (Request.Filter.contains(CodeCompletionFilterFlag::Module) &&
13601343
(!Lookup.isHiddenModuleName(TheModuleName) ||
13611344
explictlyImportedModules.contains(TheModule)) &&
13621345
seenModuleNames.insert(TheModuleName).second)
@@ -1371,11 +1354,11 @@ void swift::ide::deliverCompletionResults(
13711354
}
13721355
} else {
13731356
// Add results from current module.
1374-
Lookup.getToplevelCompletions(Request.OnlyTypes, Request.OnlyMacros);
1357+
Lookup.getToplevelCompletions(Request.Filter);
13751358

13761359
// Add the qualifying module name
13771360
auto curModule = SF.getParentModule();
1378-
if (Request.IncludeModuleQualifier &&
1361+
if (Request.Filter.contains(CodeCompletionFilterFlag::Module) &&
13791362
seenModuleNames.insert(curModule->getName()).second)
13801363
Lookup.addModuleName(curModule);
13811364

@@ -1790,15 +1773,35 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17901773
default:
17911774
break;
17921775
}
1793-
}
1794-
if (!ExpectedCustomAttributeKinds) {
1776+
1777+
switch (*AttTargetDK) {
1778+
case DeclKind::Var:
1779+
case DeclKind::Subscript:
1780+
ExpectedCustomAttributeKinds |= CustomAttributeKind::VarMacro;
1781+
break;
1782+
case DeclKind::Struct:
1783+
case DeclKind::Class:
1784+
case DeclKind::Protocol:
1785+
case DeclKind::Enum:
1786+
case DeclKind::Extension:
1787+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ContextMacro;
1788+
break;
1789+
default:
1790+
break;
1791+
}
1792+
if (*AttTargetDK != DeclKind::Param) {
1793+
ExpectedCustomAttributeKinds |= CustomAttributeKind::DeclMacro;
1794+
}
1795+
} else {
17951796
// If we don't know on which decl kind we are completing, suggest all
17961797
// attribute kinds.
17971798
ExpectedCustomAttributeKinds |= CustomAttributeKind::PropertyWrapper;
17981799
ExpectedCustomAttributeKinds |= CustomAttributeKind::ResultBuilder;
17991800
ExpectedCustomAttributeKinds |= CustomAttributeKind::GlobalActor;
1801+
ExpectedCustomAttributeKinds |= CustomAttributeKind::VarMacro;
1802+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ContextMacro;
1803+
ExpectedCustomAttributeKinds |= CustomAttributeKind::DeclMacro;
18001804
}
1801-
ExpectedCustomAttributeKinds |= CustomAttributeKind::Macro;
18021805

18031806
Lookup.setExpectedTypes(/*Types=*/{},
18041807
/*isImplicitSingleExpressionReturn=*/false,
@@ -1814,8 +1817,11 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
18141817
P.Context.SourceMgr.getIDEInspectionTargetLoc());
18151818

18161819
// Macro name at attribute position after '@'.
1817-
Lookup.getToplevelCompletions(
1818-
/*OnlyTypes=*/false, /*OnlyMacros=*/true);
1820+
CodeCompletionMacroRoles macroRoles =
1821+
getCompletionMacroRoles(ExpectedCustomAttributeKinds);
1822+
if (macroRoles) {
1823+
Lookup.getMacroCompletions(macroRoles);
1824+
}
18191825
break;
18201826
}
18211827
case CompletionKind::AttributeDeclParen: {
@@ -1968,6 +1974,15 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
19681974

19691975
case CompletionKind::AfterPoundDirective: {
19701976
addPoundDirectives(CompletionContext.getResultSink());
1977+
1978+
CodeCompletionMacroRoles roles;
1979+
if (!CurDeclContext || !CurDeclContext->isTypeContext()) {
1980+
roles |= CodeCompletionMacroRole::Expression;
1981+
roles |= CodeCompletionMacroRole::CodeItem;
1982+
}
1983+
roles |= CodeCompletionMacroRole::Declaration;
1984+
Lookup.getMacroCompletions(roles);
1985+
19711986
// FIXME: Add pound expressions (e.g. '#selector()') if it's at statements
19721987
// position.
19731988
break;

0 commit comments

Comments
 (0)