@@ -84,7 +84,7 @@ translateDeclToContext(clang::NamedDecl *decl) {
84
84
// If this typedef is merely a restatement of a tag declaration's type,
85
85
// return the result for that tag.
86
86
if (auto tag = typedefName->getUnderlyingType ()->getAsTagDecl ())
87
- return translateDeclToContext (tag);
87
+ return translateDeclToContext (const_cast <clang::TagDecl *>( tag) );
88
88
89
89
// Otherwise, this must be a typedef mapped to a strong type.
90
90
return std::make_pair (SwiftLookupTable::ContextKind::Typedef,
@@ -105,13 +105,8 @@ SwiftLookupTable::translateContext(EffectiveClangContext context) {
105
105
return std::make_pair (ContextKind::TranslationUnit, StringRef ());
106
106
107
107
// Tag declaration context.
108
- if (auto tag = dyn_cast<clang::TagDecl>(dc)) {
109
- if (tag->getIdentifier ())
110
- return std::make_pair (ContextKind::Tag, tag->getName ());
111
- if (auto typedefDecl = tag->getTypedefNameForAnonDecl ())
112
- return std::make_pair (ContextKind::Tag, typedefDecl->getName ());
113
- return None;
114
- }
108
+ if (auto tag = dyn_cast<clang::TagDecl>(dc))
109
+ return translateDeclToContext (const_cast <clang::TagDecl *>(tag));
115
110
116
111
// Objective-C class context.
117
112
if (auto objcClass = dyn_cast<clang::ObjCInterfaceDecl>(dc))
@@ -130,10 +125,8 @@ SwiftLookupTable::translateContext(EffectiveClangContext context) {
130
125
131
126
case EffectiveClangContext::UnresolvedContext:
132
127
// Resolve the context.
133
- if (auto decl = resolveContext (context.getUnresolvedName ())) {
134
- if (auto context = translateDeclToContext (decl))
135
- return context;
136
- }
128
+ if (auto decl = resolveContext (context.getUnresolvedName ()))
129
+ return translateDeclToContext (decl);
137
130
138
131
return None;
139
132
}
@@ -167,6 +160,66 @@ void SwiftLookupTable::addCategory(clang::ObjCCategoryDecl *category) {
167
160
Categories.push_back (category);
168
161
}
169
162
163
+ bool SwiftLookupTable::resolveUnresolvedEntries (
164
+ SmallVectorImpl<SingleEntry> &unresolved) {
165
+ // Common case: nothing left to resolve.
166
+ unresolved.clear ();
167
+ if (UnresolvedEntries.empty ()) return false ;
168
+
169
+ // Reprocess each of the unresolved entries to see if it can be
170
+ // resolved now that we're done. This occurs when a swift_name'd
171
+ // entity becomes a member of an entity that follows it in the
172
+ // translation unit, e.g., given:
173
+ //
174
+ // \code
175
+ // typedef enum FooSomeEnumeration __attribute__((Foo.SomeEnum)) {
176
+ // ...
177
+ // } FooSomeEnumeration;
178
+ //
179
+ // typedef struct Foo {
180
+ //
181
+ // } Foo;
182
+ // \endcode
183
+ //
184
+ // FooSomeEnumeration belongs inside "Foo", but we haven't actually
185
+ // seen "Foo" yet. Therefore, we will reprocess FooSomeEnumeration
186
+ // at the end, once "Foo" is available. There are several reasons
187
+ // this loop can execute:
188
+ //
189
+ // * Import-as-member places an entity inside of an another entity
190
+ // that comes later in the translation unit. The number of
191
+ // iterations that can be caused by this is bounded by the nesting
192
+ // depth. (At present, that depth is limited to 2).
193
+ //
194
+ // * An erroneous import-as-member will cause an extra iteration at
195
+ // the end, so that the loop can detect that nothing changed and
196
+ // return a failure.
197
+ while (true ) {
198
+ // Take the list of unresolved entries to process.
199
+ auto prevNumUnresolvedEntries = UnresolvedEntries.size ();
200
+ auto currentUnresolved = std::move (UnresolvedEntries);
201
+ UnresolvedEntries.clear ();
202
+
203
+ // Process each of the currently-unresolved entries.
204
+ for (const auto &entry : currentUnresolved)
205
+ addEntry (std::get<0 >(entry), std::get<1 >(entry), std::get<2 >(entry));
206
+
207
+ // Are we done?
208
+ if (UnresolvedEntries.empty ()) return false ;
209
+
210
+ // If nothing changed, fail: something is unresolvable, and the
211
+ // caller should complain.
212
+ if (UnresolvedEntries.size () == prevNumUnresolvedEntries) {
213
+ for (const auto &entry : UnresolvedEntries)
214
+ unresolved.push_back (std::get<1 >(entry));
215
+ return true ;
216
+ }
217
+
218
+ // Something got resolved, so loop again.
219
+ assert (UnresolvedEntries.size () < prevNumUnresolvedEntries);
220
+ }
221
+ }
222
+
170
223
// / Determine whether the entry is a global declaration that is being
171
224
// / mapped as a member of a particular type or extension thereof.
172
225
// /
@@ -237,7 +290,19 @@ void SwiftLookupTable::addEntry(DeclName name, SingleEntry newEntry,
237
290
238
291
// Translate the context.
239
292
auto contextOpt = translateContext (effectiveContext);
240
- if (!contextOpt) return ;
293
+ if (!contextOpt) {
294
+ // If is is a declaration with a swift_name attribute, we might be
295
+ // able to resolve this later.
296
+ if (auto decl = newEntry.dyn_cast <clang::NamedDecl *>()) {
297
+ if (decl->hasAttr <clang::SwiftNameAttr>()) {
298
+ UnresolvedEntries.push_back (
299
+ std::make_tuple (name, newEntry, effectiveContext));
300
+ }
301
+ }
302
+
303
+ return ;
304
+ }
305
+
241
306
auto context = *contextOpt;
242
307
243
308
// If this is a global imported as a member, record is as such.
0 commit comments