@@ -112,10 +112,10 @@ enum FloatingRank {
112
112
Ibm128Rank
113
113
};
114
114
115
- /// \returns location that is relevant when searching for Doc comments related
116
- /// to \p D.
117
- static SourceLocation getDeclLocForCommentSearch(const Decl *D,
118
- SourceManager &SourceMgr) {
115
+ /// \returns The locations that are relevant when searching for Doc comments
116
+ /// related to \p D.
117
+ static SmallVector< SourceLocation, 2>
118
+ getDeclLocsForCommentSearch(const Decl *D, SourceManager &SourceMgr) {
119
119
assert(D);
120
120
121
121
// User can not attach documentation to implicit declarations.
@@ -167,115 +167,48 @@ static SourceLocation getDeclLocForCommentSearch(const Decl *D,
167
167
isa<TemplateTemplateParmDecl>(D))
168
168
return {};
169
169
170
+ SmallVector<SourceLocation, 2> Locations;
170
171
// Find declaration location.
171
172
// For Objective-C declarations we generally don't expect to have multiple
172
173
// declarators, thus use declaration starting location as the "declaration
173
174
// location".
174
175
// For all other declarations multiple declarators are used quite frequently,
175
176
// so we use the location of the identifier as the "declaration location".
177
+ SourceLocation BaseLocation;
176
178
if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
177
- isa<ObjCPropertyDecl>(D) ||
178
- isa<RedeclarableTemplateDecl>(D) ||
179
+ isa<ObjCPropertyDecl>(D) || isa<RedeclarableTemplateDecl>(D) ||
179
180
isa<ClassTemplateSpecializationDecl>(D) ||
180
181
// Allow association with Y across {} in `typedef struct X {} Y`.
181
182
isa<TypedefDecl>(D))
182
- return D->getBeginLoc();
183
+ BaseLocation = D->getBeginLoc();
184
+ else
185
+ BaseLocation = D->getLocation();
183
186
184
- const SourceLocation DeclLoc = D->getLocation();
185
- if (DeclLoc.isMacroID()) {
186
- // There are (at least) three types of macros we care about here.
187
- //
188
- // 1. Macros that are used in the definition of a type outside the macro,
189
- // with a comment attached at the macro call site.
190
- // ```
191
- // #define MAKE_NAME(Foo) Name##Foo
192
- //
193
- // /// Comment is here, where we use the macro.
194
- // struct MAKE_NAME(Foo) {
195
- // int a;
196
- // int b;
197
- // };
198
- // ```
199
- // 2. Macros that define whole things along with the comment.
200
- // ```
201
- // #define MAKE_METHOD(name) \
202
- // /** Comment is here, inside the macro. */ \
203
- // void name() {}
204
- //
205
- // struct S {
206
- // MAKE_METHOD(f)
207
- // }
208
- // ```
209
- // 3. Macros that both declare a type and name a decl outside the macro.
210
- // ```
211
- // /// Comment is here, where we use the macro.
212
- // typedef NS_ENUM(NSInteger, Size) {
213
- // SizeWidth,
214
- // SizeHeight
215
- // };
216
- // ```
217
- // In this case NS_ENUM declares am enum type, and uses the same name for
218
- // the typedef declaration that appears outside the macro. The comment
219
- // here should be applied to both declarations inside and outside the
220
- // macro.
221
- //
222
- // We have found a Decl name that comes from inside a macro, but
223
- // Decl::getLocation() returns the place where the macro is being called.
224
- // If the declaration (and not just the name) resides inside the macro,
225
- // then we want to map Decl::getLocation() into the macro to where the
226
- // declaration and its attached comment (if any) were written.
227
- //
228
- // This mapping into the macro is done by mapping the location to its
229
- // spelling location, however even if the declaration is inside a macro,
230
- // the name's spelling can come from a macro argument (case 2 above). In
231
- // this case mapping the location to the spelling location finds the
232
- // argument's position (at `f` in MAKE_METHOD(`f`) above), which is not
233
- // where the declaration and its comment are located.
234
- //
235
- // To avoid this issue, we make use of Decl::getBeginLocation() instead.
236
- // While the declaration's position is where the name is written, the
237
- // comment is always attached to the begining of the declaration, not to
238
- // the name.
239
- //
240
- // In the first case, the begin location of the decl is outside the macro,
241
- // at the location of `typedef`. This is where the comment is found as
242
- // well. The begin location is not inside a macro, so it's spelling
243
- // location is the same.
244
- //
245
- // In the second case, the begin location of the decl is the call to the
246
- // macro, at `MAKE_METHOD`. However its spelling location is inside the
247
- // the macro at the location of `void`. This is where the comment is found
248
- // again.
249
- //
250
- // In the third case, there's no correct single behaviour. We want to use
251
- // the comment outside the macro for the definition that's inside the macro.
252
- // There is also a definition outside the macro, and we want the comment to
253
- // apply to both. The cases we care about here is NS_ENUM() and
254
- // NS_OPTIONS(). In general, if an enum is defined inside a macro, we should
255
- // try to find the comment there.
256
-
257
- // This is handling case 3 for NS_ENUM() and NS_OPTIONS(), which define
258
- // enum types inside the macro.
259
- if (isa<EnumDecl>(D)) {
260
- SourceLocation MacroCallLoc = SourceMgr.getExpansionLoc(DeclLoc);
261
- if (auto BufferRef =
262
- SourceMgr.getBufferOrNone(SourceMgr.getFileID(MacroCallLoc));
263
- BufferRef.has_value()) {
264
- llvm::StringRef buffer = BufferRef->getBuffer().substr(
265
- SourceMgr.getFileOffset(MacroCallLoc));
266
- if (buffer.starts_with("NS_ENUM(") ||
267
- buffer.starts_with("NS_OPTIONS(")) {
268
- // We want to use the comment on the call to NS_ENUM and NS_OPTIONS
269
- // macros for the types defined inside the macros, which is at the
270
- // expansion location.
271
- return MacroCallLoc;
272
- }
273
- }
187
+ if (!D->getLocation().isMacroID()) {
188
+ Locations.emplace_back(BaseLocation);
189
+ } else {
190
+ const auto *DeclCtx = D->getDeclContext();
191
+
192
+ // When encountering definitions generated from a macro (that are not
193
+ // contained by another declaration in the macro) we need to try and find
194
+ // the comment at the location of the expansion but if there is no comment
195
+ // there we should retry to see if there is a comment inside the macro as
196
+ // well. To this end we return first BaseLocation to first look at the
197
+ // expansion site, the second value is the spelling location of the
198
+ // beginning of the declaration defined inside the macro.
199
+ if (!(DeclCtx &&
200
+ Decl::castFromDeclContext(DeclCtx)->getLocation().isMacroID())) {
201
+ Locations.emplace_back(SourceMgr.getExpansionLoc(BaseLocation));
274
202
}
275
- return SourceMgr.getSpellingLoc(D->getBeginLoc());
203
+
204
+ // We use Decl::getBeginLoc() and not just BaseLocation here to ensure that
205
+ // we don't refer to the macro argument location at the expansion site (this
206
+ // can happen if the name's spelling is provided via macro argument), and
207
+ // always to the declaration itself.
208
+ Locations.emplace_back(SourceMgr.getSpellingLoc(D->getBeginLoc()));
276
209
}
277
210
278
- return DeclLoc ;
211
+ return Locations ;
279
212
}
280
213
281
214
RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
@@ -357,30 +290,36 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
357
290
}
358
291
359
292
RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
360
- const SourceLocation DeclLoc = getDeclLocForCommentSearch (D, SourceMgr);
293
+ const auto DeclLocs = getDeclLocsForCommentSearch (D, SourceMgr);
361
294
362
- // If the declaration doesn't map directly to a location in a file, we
363
- // can't find the comment.
364
- if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
365
- return nullptr;
295
+ for (const auto DeclLoc : DeclLocs) {
296
+ // If the declaration doesn't map directly to a location in a file, we
297
+ // can't find the comment.
298
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
299
+ continue;
366
300
367
- if (ExternalSource && !CommentsLoaded) {
368
- ExternalSource->ReadComments();
369
- CommentsLoaded = true;
370
- }
301
+ if (ExternalSource && !CommentsLoaded) {
302
+ ExternalSource->ReadComments();
303
+ CommentsLoaded = true;
304
+ }
371
305
372
- if (Comments.empty())
373
- return nullptr ;
306
+ if (Comments.empty())
307
+ continue ;
374
308
375
- const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
376
- if (!File.isValid()) {
377
- return nullptr;
309
+ const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
310
+ if (!File.isValid())
311
+ continue;
312
+
313
+ const auto CommentsInThisFile = Comments.getCommentsInFile(File);
314
+ if (!CommentsInThisFile || CommentsInThisFile->empty())
315
+ continue;
316
+
317
+ if (RawComment *Comment =
318
+ getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile))
319
+ return Comment;
378
320
}
379
- const auto CommentsInThisFile = Comments.getCommentsInFile(File);
380
- if (!CommentsInThisFile || CommentsInThisFile->empty())
381
- return nullptr;
382
321
383
- return getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile) ;
322
+ return nullptr ;
384
323
}
385
324
386
325
void ASTContext::addComment(const RawComment &RC) {
@@ -584,27 +523,29 @@ void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
584
523
// declaration, but also comments that *follow* the declaration -- thanks to
585
524
// the lookahead in the lexer: we've consumed the semicolon and looked
586
525
// ahead through comments.
587
-
588
526
for (const Decl *D : Decls) {
589
527
assert(D);
590
528
if (D->isInvalidDecl())
591
529
continue;
592
530
593
531
D = &adjustDeclToTemplate(*D);
594
532
595
- const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
596
-
597
- if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
598
- continue;
599
-
600
533
if (DeclRawComments.count(D) > 0)
601
534
continue;
602
535
603
- if (RawComment *const DocComment =
604
- getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile)) {
605
- cacheRawCommentForDecl(*D, *DocComment);
606
- comments::FullComment *FC = DocComment->parse(*this, PP, D);
607
- ParsedComments[D->getCanonicalDecl()] = FC;
536
+ const auto DeclLocs = getDeclLocsForCommentSearch(D, SourceMgr);
537
+
538
+ for (const auto DeclLoc : DeclLocs) {
539
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
540
+ continue;
541
+
542
+ if (RawComment *const DocComment = getRawCommentForDeclNoCacheImpl(
543
+ D, DeclLoc, *CommentsInThisFile)) {
544
+ cacheRawCommentForDecl(*D, *DocComment);
545
+ comments::FullComment *FC = DocComment->parse(*this, PP, D);
546
+ ParsedComments[D->getCanonicalDecl()] = FC;
547
+ break;
548
+ }
608
549
}
609
550
}
610
551
}
0 commit comments