Skip to content

Commit 31dee1c

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 31dee1c

16 files changed

+508
-208
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: 45 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 MacroRoles;
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 MacroRoles, 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+
MacroRoles(MacroRoles), 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,8 @@ class ContextFreeCodeCompletionResult {
488525
return KnownOperatorKind;
489526
}
490527

528+
CodeCompletionMacroRoles getMacroRoles() const { return MacroRoles; }
529+
491530
bool isSystem() const { return IsSystem; };
492531

493532
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: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,8 @@ static void addPoundDirectives(CodeCompletionResultSink &Sink) {
11301130
Builder.addSimpleTypedParameter("Int");
11311131
Builder.addRightParen();
11321132
});
1133+
1134+
#ifndef SWIFT_SWIFT_PARSER
11331135
addWithName("warning", CodeCompletionKeywordKind::pound_warning,
11341136
[&] (CodeCompletionResultBuilder &Builder) {
11351137
Builder.addLeftParen();
@@ -1146,6 +1148,7 @@ static void addPoundDirectives(CodeCompletionResultSink &Sink) {
11461148
Builder.addTextChunk("\"");
11471149
Builder.addRightParen();
11481150
});
1151+
#endif
11491152

11501153
addWithName("if ", CodeCompletionKeywordKind::pound_if,
11511154
[&] (CodeCompletionResultBuilder &Builder) {
@@ -1352,11 +1355,10 @@ void swift::ide::deliverCompletionResults(
13521355
std::pair<PairType, bool> Result = ImportsSeen.insert(K);
13531356
if (!Result.second)
13541357
return; // already handled.
1355-
RequestedModules.push_back({std::move(K), TheModule,
1356-
Request.OnlyTypes, Request.OnlyPrecedenceGroups, Request.OnlyMacros});
1358+
RequestedModules.push_back({std::move(K), TheModule, Request.Filter});
13571359

13581360
auto TheModuleName = TheModule->getName();
1359-
if (Request.IncludeModuleQualifier &&
1361+
if (Request.Filter.contains(CodeCompletionFilterFlag::Module) &&
13601362
(!Lookup.isHiddenModuleName(TheModuleName) ||
13611363
explictlyImportedModules.contains(TheModule)) &&
13621364
seenModuleNames.insert(TheModuleName).second)
@@ -1371,11 +1373,11 @@ void swift::ide::deliverCompletionResults(
13711373
}
13721374
} else {
13731375
// Add results from current module.
1374-
Lookup.getToplevelCompletions(Request.OnlyTypes, Request.OnlyMacros);
1376+
Lookup.getToplevelCompletions(Request.Filter);
13751377

13761378
// Add the qualifying module name
13771379
auto curModule = SF.getParentModule();
1378-
if (Request.IncludeModuleQualifier &&
1380+
if (Request.Filter.contains(CodeCompletionFilterFlag::Module) &&
13791381
seenModuleNames.insert(curModule->getName()).second)
13801382
Lookup.addModuleName(curModule);
13811383

@@ -1790,15 +1792,35 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
17901792
default:
17911793
break;
17921794
}
1793-
}
1794-
if (!ExpectedCustomAttributeKinds) {
1795+
1796+
switch (*AttTargetDK) {
1797+
case DeclKind::Var:
1798+
case DeclKind::Subscript:
1799+
ExpectedCustomAttributeKinds |= CustomAttributeKind::VarMacro;
1800+
break;
1801+
case DeclKind::Struct:
1802+
case DeclKind::Class:
1803+
case DeclKind::Protocol:
1804+
case DeclKind::Enum:
1805+
case DeclKind::Extension:
1806+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ContextMacro;
1807+
break;
1808+
default:
1809+
break;
1810+
}
1811+
if (*AttTargetDK != DeclKind::Param) {
1812+
ExpectedCustomAttributeKinds |= CustomAttributeKind::DeclMacro;
1813+
}
1814+
} else {
17951815
// If we don't know on which decl kind we are completing, suggest all
17961816
// attribute kinds.
17971817
ExpectedCustomAttributeKinds |= CustomAttributeKind::PropertyWrapper;
17981818
ExpectedCustomAttributeKinds |= CustomAttributeKind::ResultBuilder;
17991819
ExpectedCustomAttributeKinds |= CustomAttributeKind::GlobalActor;
1820+
ExpectedCustomAttributeKinds |= CustomAttributeKind::VarMacro;
1821+
ExpectedCustomAttributeKinds |= CustomAttributeKind::ContextMacro;
1822+
ExpectedCustomAttributeKinds |= CustomAttributeKind::DeclMacro;
18001823
}
1801-
ExpectedCustomAttributeKinds |= CustomAttributeKind::Macro;
18021824

18031825
Lookup.setExpectedTypes(/*Types=*/{},
18041826
/*isImplicitSingleExpressionReturn=*/false,
@@ -1814,8 +1836,11 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
18141836
P.Context.SourceMgr.getIDEInspectionTargetLoc());
18151837

18161838
// Macro name at attribute position after '@'.
1817-
Lookup.getToplevelCompletions(
1818-
/*OnlyTypes=*/false, /*OnlyMacros=*/true);
1839+
CodeCompletionMacroRoles macroRoles =
1840+
getCompletionMacroRoles(ExpectedCustomAttributeKinds);
1841+
if (macroRoles) {
1842+
Lookup.getMacroCompletions(macroRoles);
1843+
}
18191844
break;
18201845
}
18211846
case CompletionKind::AttributeDeclParen: {
@@ -1968,6 +1993,15 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
19681993

19691994
case CompletionKind::AfterPoundDirective: {
19701995
addPoundDirectives(CompletionContext.getResultSink());
1996+
1997+
CodeCompletionMacroRoles roles;
1998+
if (!CurDeclContext || !CurDeclContext->isTypeContext()) {
1999+
roles |= CodeCompletionMacroRole::Expression;
2000+
roles |= CodeCompletionMacroRole::CodeItem;
2001+
}
2002+
roles |= CodeCompletionMacroRole::Declaration;
2003+
Lookup.getMacroCompletions(roles);
2004+
19712005
// FIXME: Add pound expressions (e.g. '#selector()') if it's at statements
19722006
// position.
19732007
break;

lib/IDE/CodeCompletionCache.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ CodeCompletionCache::~CodeCompletionCache() {}
104104
/// This should be incremented any time we commit a change to the format of the
105105
/// cached results. This isn't expected to change very often.
106106
static constexpr uint32_t onDiskCompletionCacheVersion =
107-
10; // Store if decl has an async alternative
107+
11; // Added macro roles
108108

109109
/// Deserializes CodeCompletionResults from \p in and stores them in \p V.
110110
/// \see writeCacheModule.
@@ -230,6 +230,7 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
230230
auto kind = static_cast<CodeCompletionResultKind>(*cursor++);
231231
auto associatedKind = static_cast<uint8_t>(*cursor++);
232232
auto opKind = static_cast<CodeCompletionOperatorKind>(*cursor++);
233+
auto roles = CodeCompletionMacroRoles(*cursor++);
233234
auto notRecommended =
234235
static_cast<ContextFreeNotRecommendedReason>(*cursor++);
235236
auto diagSeverity =
@@ -266,7 +267,7 @@ static bool readCachedModule(llvm::MemoryBuffer *in,
266267

267268
ContextFreeCodeCompletionResult *result =
268269
new (*V.Allocator) ContextFreeCodeCompletionResult(
269-
kind, associatedKind, opKind, isSystem, isAsync,
270+
kind, associatedKind, opKind, roles, isSystem, isAsync,
270271
hasAsyncAlternative, string, moduleName, briefDocComment,
271272
makeArrayRef(assocUSRs).copy(*V.Allocator),
272273
CodeCompletionResultType(resultTypes), notRecommended, diagSeverity,
@@ -423,6 +424,7 @@ static void writeCachedModule(llvm::raw_ostream &out,
423424
} else {
424425
LE.write(static_cast<uint8_t>(CodeCompletionOperatorKind::None));
425426
}
427+
LE.write(static_cast<uint8_t>(R->getMacroRoles().toRaw()));
426428
LE.write(static_cast<uint8_t>(R->getNotRecommendedReason()));
427429
LE.write(static_cast<uint8_t>(R->getDiagnosticSeverity()));
428430
LE.write(static_cast<uint8_t>(R->isSystem()));

0 commit comments

Comments
 (0)