@@ -3215,16 +3215,61 @@ void CompletionLookup::getTypeCompletionsInDeclContext(SourceLoc Loc,
3215
3215
RequestedCachedResults.insert (RequestedResultsTy::topLevelResults (filter));
3216
3216
}
3217
3217
3218
+ namespace {
3219
+
3220
+ // / A \c VisibleDeclConsumer that stores all decls that are found and is able
3221
+ // / to forward the to another \c VisibleDeclConsumer later.
3222
+ class StoringDeclConsumer : public VisibleDeclConsumer {
3223
+ struct FoundDecl {
3224
+ ValueDecl *VD;
3225
+ DeclVisibilityKind Reason;
3226
+ DynamicLookupInfo DynamicLookupInfo;
3227
+ };
3228
+
3229
+ std::vector<FoundDecl> FoundDecls;
3230
+
3231
+ void foundDecl (ValueDecl *VD, DeclVisibilityKind Reason,
3232
+ DynamicLookupInfo DynamicLookupInfo = {}) override {
3233
+ FoundDecls.push_back ({VD, Reason, DynamicLookupInfo});
3234
+ }
3235
+
3236
+ public:
3237
+ // / Call \c foundDecl for every declaration that this consumer has found.
3238
+ void forward (VisibleDeclConsumer &Consumer) {
3239
+ for (auto &FoundDecl : FoundDecls) {
3240
+ Consumer.foundDecl (FoundDecl.VD , FoundDecl.Reason ,
3241
+ FoundDecl.DynamicLookupInfo );
3242
+ }
3243
+ }
3244
+ };
3245
+
3246
+ } // namespace
3247
+
3218
3248
void CompletionLookup::getToplevelCompletions (CodeCompletionFilter Filter) {
3219
3249
Kind = (Filter - CodeCompletionFilterFlag::Module)
3220
3250
.containsOnly (CodeCompletionFilterFlag::Type)
3221
3251
? LookupKind::TypeInDeclContext
3222
3252
: LookupKind::ValueInDeclContext;
3223
3253
NeedLeadingDot = false ;
3224
3254
3255
+ // If we have 'addinitstotoplevel' enabled, calling `foundDecl` on `this`
3256
+ // can cause macros to get expanded, which can then cause new members ot get
3257
+ // added to 'TopLevelValues', invalidating iterator over `TopLevelDecls` in
3258
+ // `SourceLookupCache::lookupVisibleDecls`.
3259
+ //
3260
+ // Technically `foundDecl` should not expand macros or discover new top level
3261
+ // members in any way because those newly discovered decls will not be added
3262
+ // to the code completion results. However, it's preferrable to miss results
3263
+ // than to silently invalidate a collection, resulting in hard-to-diagnose
3264
+ // crashes.
3265
+ // Thus, store all the decls found by `CurrModule->lookupVisibleDecls` in a
3266
+ // vector first and only call `this->foundDecl` once we have left the
3267
+ // iteration loop over `TopLevelDecls`.
3268
+ StoringDeclConsumer StoringConsumer;
3269
+
3225
3270
UsableFilteringDeclConsumer UsableFilteringConsumer (
3226
3271
Ctx.SourceMgr , CurrDeclContext, Ctx.SourceMgr .getIDEInspectionTargetLoc (),
3227
- * this );
3272
+ StoringConsumer );
3228
3273
AccessFilteringDeclConsumer AccessFilteringConsumer (CurrDeclContext,
3229
3274
UsableFilteringConsumer);
3230
3275
@@ -3243,6 +3288,8 @@ void CompletionLookup::getToplevelCompletions(CodeCompletionFilter Filter) {
3243
3288
3244
3289
CurrModule->lookupVisibleDecls ({}, FilteringConsumer,
3245
3290
NLKind::UnqualifiedLookup);
3291
+
3292
+ StoringConsumer.forward (*this );
3246
3293
}
3247
3294
3248
3295
void CompletionLookup::lookupExternalModuleDecls (
0 commit comments