@@ -112,10 +112,10 @@ enum FloatingRank {
112112 Ibm128Rank
113113};
114114
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) {
119119 assert(D);
120120
121121 // User can not attach documentation to implicit declarations.
@@ -167,115 +167,48 @@ static SourceLocation getDeclLocForCommentSearch(const Decl *D,
167167 isa<TemplateTemplateParmDecl>(D))
168168 return {};
169169
170+ SmallVector<SourceLocation, 2> Locations;
170171 // Find declaration location.
171172 // For Objective-C declarations we generally don't expect to have multiple
172173 // declarators, thus use declaration starting location as the "declaration
173174 // location".
174175 // For all other declarations multiple declarators are used quite frequently,
175176 // so we use the location of the identifier as the "declaration location".
177+ SourceLocation BaseLocation;
176178 if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
177- isa<ObjCPropertyDecl>(D) ||
178- isa<RedeclarableTemplateDecl>(D) ||
179+ isa<ObjCPropertyDecl>(D) || isa<RedeclarableTemplateDecl>(D) ||
179180 isa<ClassTemplateSpecializationDecl>(D) ||
180181 // Allow association with Y across {} in `typedef struct X {} Y`.
181182 isa<TypedefDecl>(D))
182- return D->getBeginLoc();
183+ BaseLocation = D->getBeginLoc();
184+ else
185+ BaseLocation = D->getLocation();
183186
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));
274202 }
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()));
276209 }
277210
278- return DeclLoc ;
211+ return Locations ;
279212}
280213
281214RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
@@ -357,30 +290,36 @@ RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
357290}
358291
359292RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
360- const SourceLocation DeclLoc = getDeclLocForCommentSearch (D, SourceMgr);
293+ const auto DeclLocs = getDeclLocsForCommentSearch (D, SourceMgr);
361294
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;
366300
367- if (ExternalSource && !CommentsLoaded) {
368- ExternalSource->ReadComments();
369- CommentsLoaded = true;
370- }
301+ if (ExternalSource && !CommentsLoaded) {
302+ ExternalSource->ReadComments();
303+ CommentsLoaded = true;
304+ }
371305
372- if (Comments.empty())
373- return nullptr ;
306+ if (Comments.empty())
307+ continue ;
374308
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;
378320 }
379- const auto CommentsInThisFile = Comments.getCommentsInFile(File);
380- if (!CommentsInThisFile || CommentsInThisFile->empty())
381- return nullptr;
382321
383- return getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile) ;
322+ return nullptr ;
384323}
385324
386325void ASTContext::addComment(const RawComment &RC) {
@@ -584,27 +523,29 @@ void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
584523 // declaration, but also comments that *follow* the declaration -- thanks to
585524 // the lookahead in the lexer: we've consumed the semicolon and looked
586525 // ahead through comments.
587-
588526 for (const Decl *D : Decls) {
589527 assert(D);
590528 if (D->isInvalidDecl())
591529 continue;
592530
593531 D = &adjustDeclToTemplate(*D);
594532
595- const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
596-
597- if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
598- continue;
599-
600533 if (DeclRawComments.count(D) > 0)
601534 continue;
602535
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+ }
608549 }
609550 }
610551}
0 commit comments