File: | clang/lib/AST/Comment.cpp |
Warning: | line 383, column 14 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- Comment.cpp - Comment AST node implementation --------------------===// | ||||
2 | // | ||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
6 | // | ||||
7 | //===----------------------------------------------------------------------===// | ||||
8 | |||||
9 | #include "clang/AST/Comment.h" | ||||
10 | #include "clang/AST/ASTContext.h" | ||||
11 | #include "clang/AST/Decl.h" | ||||
12 | #include "clang/AST/DeclObjC.h" | ||||
13 | #include "clang/AST/DeclTemplate.h" | ||||
14 | #include "clang/Basic/CharInfo.h" | ||||
15 | #include "llvm/Support/ErrorHandling.h" | ||||
16 | #include <type_traits> | ||||
17 | |||||
18 | namespace clang { | ||||
19 | namespace comments { | ||||
20 | |||||
21 | // Check that no comment class has a non-trival destructor. They are allocated | ||||
22 | // with a BumpPtrAllocator and therefore their destructor is not executed. | ||||
23 | #define ABSTRACT_COMMENT(COMMENT) | ||||
24 | #define COMMENT(CLASS, PARENT) \ | ||||
25 | static_assert(std::is_trivially_destructible<CLASS>::value, \ | ||||
26 | #CLASS " should be trivially destructible!"); | ||||
27 | #include "clang/AST/CommentNodes.inc" | ||||
28 | #undef COMMENT | ||||
29 | #undef ABSTRACT_COMMENT | ||||
30 | |||||
31 | // DeclInfo is also allocated with a BumpPtrAllocator. | ||||
32 | static_assert(std::is_trivially_destructible<DeclInfo>::value, | ||||
33 | "DeclInfo should be trivially destructible!"); | ||||
34 | |||||
35 | const char *Comment::getCommentKindName() const { | ||||
36 | switch (getCommentKind()) { | ||||
37 | case NoCommentKind: return "NoCommentKind"; | ||||
38 | #define ABSTRACT_COMMENT(COMMENT) | ||||
39 | #define COMMENT(CLASS, PARENT) \ | ||||
40 | case CLASS##Kind: \ | ||||
41 | return #CLASS; | ||||
42 | #include "clang/AST/CommentNodes.inc" | ||||
43 | #undef COMMENT | ||||
44 | #undef ABSTRACT_COMMENT | ||||
45 | } | ||||
46 | llvm_unreachable("Unknown comment kind!")::llvm::llvm_unreachable_internal("Unknown comment kind!", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 46); | ||||
47 | } | ||||
48 | |||||
49 | namespace { | ||||
50 | struct good {}; | ||||
51 | struct bad {}; | ||||
52 | |||||
53 | template <typename T> | ||||
54 | good implements_child_begin_end(Comment::child_iterator (T::*)() const) { | ||||
55 | return good(); | ||||
56 | } | ||||
57 | |||||
58 | LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__)) | ||||
59 | static inline bad implements_child_begin_end( | ||||
60 | Comment::child_iterator (Comment::*)() const) { | ||||
61 | return bad(); | ||||
62 | } | ||||
63 | |||||
64 | #define ASSERT_IMPLEMENTS_child_begin(function) \ | ||||
65 | (void) good(implements_child_begin_end(function)) | ||||
66 | |||||
67 | LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__)) | ||||
68 | static inline void CheckCommentASTNodes() { | ||||
69 | #define ABSTRACT_COMMENT(COMMENT) | ||||
70 | #define COMMENT(CLASS, PARENT) \ | ||||
71 | ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \ | ||||
72 | ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end); | ||||
73 | #include "clang/AST/CommentNodes.inc" | ||||
74 | #undef COMMENT | ||||
75 | #undef ABSTRACT_COMMENT | ||||
76 | } | ||||
77 | |||||
78 | #undef ASSERT_IMPLEMENTS_child_begin | ||||
79 | |||||
80 | } // end unnamed namespace | ||||
81 | |||||
82 | Comment::child_iterator Comment::child_begin() const { | ||||
83 | switch (getCommentKind()) { | ||||
84 | case NoCommentKind: llvm_unreachable("comment without a kind")::llvm::llvm_unreachable_internal("comment without a kind", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 84); | ||||
85 | #define ABSTRACT_COMMENT(COMMENT) | ||||
86 | #define COMMENT(CLASS, PARENT) \ | ||||
87 | case CLASS##Kind: \ | ||||
88 | return static_cast<const CLASS *>(this)->child_begin(); | ||||
89 | #include "clang/AST/CommentNodes.inc" | ||||
90 | #undef COMMENT | ||||
91 | #undef ABSTRACT_COMMENT | ||||
92 | } | ||||
93 | llvm_unreachable("Unknown comment kind!")::llvm::llvm_unreachable_internal("Unknown comment kind!", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 93); | ||||
94 | } | ||||
95 | |||||
96 | Comment::child_iterator Comment::child_end() const { | ||||
97 | switch (getCommentKind()) { | ||||
98 | case NoCommentKind: llvm_unreachable("comment without a kind")::llvm::llvm_unreachable_internal("comment without a kind", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 98); | ||||
99 | #define ABSTRACT_COMMENT(COMMENT) | ||||
100 | #define COMMENT(CLASS, PARENT) \ | ||||
101 | case CLASS##Kind: \ | ||||
102 | return static_cast<const CLASS *>(this)->child_end(); | ||||
103 | #include "clang/AST/CommentNodes.inc" | ||||
104 | #undef COMMENT | ||||
105 | #undef ABSTRACT_COMMENT | ||||
106 | } | ||||
107 | llvm_unreachable("Unknown comment kind!")::llvm::llvm_unreachable_internal("Unknown comment kind!", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 107); | ||||
108 | } | ||||
109 | |||||
110 | bool TextComment::isWhitespaceNoCache() const { | ||||
111 | for (StringRef::const_iterator I = Text.begin(), E = Text.end(); | ||||
112 | I != E; ++I) { | ||||
113 | if (!clang::isWhitespace(*I)) | ||||
114 | return false; | ||||
115 | } | ||||
116 | return true; | ||||
117 | } | ||||
118 | |||||
119 | bool ParagraphComment::isWhitespaceNoCache() const { | ||||
120 | for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) { | ||||
121 | if (const TextComment *TC = dyn_cast<TextComment>(*I)) { | ||||
122 | if (!TC->isWhitespace()) | ||||
123 | return false; | ||||
124 | } else | ||||
125 | return false; | ||||
126 | } | ||||
127 | return true; | ||||
128 | } | ||||
129 | |||||
130 | static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) { | ||||
131 | TypeLoc TL = SrcTL.IgnoreParens(); | ||||
132 | |||||
133 | // Look through attribute types. | ||||
134 | if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>()) | ||||
135 | return AttributeTL.getModifiedLoc(); | ||||
136 | // Look through qualified types. | ||||
137 | if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) | ||||
138 | return QualifiedTL.getUnqualifiedLoc(); | ||||
139 | // Look through pointer types. | ||||
140 | if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) | ||||
141 | return PointerTL.getPointeeLoc().getUnqualifiedLoc(); | ||||
142 | // Look through reference types. | ||||
143 | if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>()) | ||||
144 | return ReferenceTL.getPointeeLoc().getUnqualifiedLoc(); | ||||
145 | // Look through adjusted types. | ||||
146 | if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>()) | ||||
147 | return ATL.getOriginalLoc(); | ||||
148 | if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>()) | ||||
149 | return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc(); | ||||
150 | if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>()) | ||||
151 | return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc(); | ||||
152 | if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>()) | ||||
153 | return ETL.getNamedTypeLoc(); | ||||
154 | |||||
155 | return TL; | ||||
156 | } | ||||
157 | |||||
158 | static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) { | ||||
159 | TypeLoc PrevTL; | ||||
160 | while (PrevTL != TL) { | ||||
161 | PrevTL = TL; | ||||
162 | TL = lookThroughTypedefOrTypeAliasLocs(TL); | ||||
163 | } | ||||
164 | |||||
165 | if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { | ||||
166 | ResFTL = FTL; | ||||
167 | return true; | ||||
168 | } | ||||
169 | |||||
170 | if (TemplateSpecializationTypeLoc STL = | ||||
171 | TL.getAs<TemplateSpecializationTypeLoc>()) { | ||||
172 | // If we have a typedef to a template specialization with exactly one | ||||
173 | // template argument of a function type, this looks like std::function, | ||||
174 | // boost::function, or other function wrapper. Treat these typedefs as | ||||
175 | // functions. | ||||
176 | if (STL.getNumArgs() != 1) | ||||
177 | return false; | ||||
178 | TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0); | ||||
179 | if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type) | ||||
180 | return false; | ||||
181 | TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo(); | ||||
182 | TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); | ||||
183 | if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { | ||||
184 | ResFTL = FTL; | ||||
185 | return true; | ||||
186 | } | ||||
187 | } | ||||
188 | |||||
189 | return false; | ||||
190 | } | ||||
191 | |||||
192 | const char *ParamCommandComment::getDirectionAsString(PassDirection D) { | ||||
193 | switch (D) { | ||||
194 | case ParamCommandComment::In: | ||||
195 | return "[in]"; | ||||
196 | case ParamCommandComment::Out: | ||||
197 | return "[out]"; | ||||
198 | case ParamCommandComment::InOut: | ||||
199 | return "[in,out]"; | ||||
200 | } | ||||
201 | llvm_unreachable("unknown PassDirection")::llvm::llvm_unreachable_internal("unknown PassDirection", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 201); | ||||
202 | } | ||||
203 | |||||
204 | void DeclInfo::fill() { | ||||
205 | assert
, "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 205, __PRETTY_FUNCTION__)); | ||||
206 | |||||
207 | // Set defaults. | ||||
208 | Kind = OtherKind; | ||||
209 | TemplateKind = NotTemplate; | ||||
210 | IsObjCMethod = false; | ||||
211 | IsInstanceMethod = false; | ||||
212 | IsClassMethod = false; | ||||
213 | ParamVars = None; | ||||
214 | TemplateParameters = nullptr; | ||||
215 | |||||
216 | if (!CommentDecl) { | ||||
217 | // If there is no declaration, the defaults is our only guess. | ||||
218 | IsFilled = true; | ||||
219 | return; | ||||
220 | } | ||||
221 | CurrentDecl = CommentDecl; | ||||
222 | |||||
223 | Decl::Kind K = CommentDecl->getKind(); | ||||
224 | switch (K) { | ||||
225 | default: | ||||
226 | // Defaults are should be good for declarations we don't handle explicitly. | ||||
227 | break; | ||||
228 | case Decl::Function: | ||||
229 | case Decl::CXXMethod: | ||||
230 | case Decl::CXXConstructor: | ||||
231 | case Decl::CXXDestructor: | ||||
232 | case Decl::CXXConversion: { | ||||
233 | const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); | ||||
234 | Kind = FunctionKind; | ||||
235 | ParamVars = FD->parameters(); | ||||
236 | ReturnType = FD->getReturnType(); | ||||
237 | unsigned NumLists = FD->getNumTemplateParameterLists(); | ||||
238 | if (NumLists != 0) { | ||||
239 | TemplateKind = TemplateSpecialization; | ||||
240 | TemplateParameters = | ||||
241 | FD->getTemplateParameterList(NumLists - 1); | ||||
242 | } | ||||
243 | |||||
244 | if (K == Decl::CXXMethod || K == Decl::CXXConstructor || | ||||
245 | K == Decl::CXXDestructor || K == Decl::CXXConversion) { | ||||
246 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); | ||||
247 | IsInstanceMethod = MD->isInstance(); | ||||
248 | IsClassMethod = !IsInstanceMethod; | ||||
249 | } | ||||
250 | break; | ||||
251 | } | ||||
252 | case Decl::ObjCMethod: { | ||||
253 | const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); | ||||
254 | Kind = FunctionKind; | ||||
255 | ParamVars = MD->parameters(); | ||||
256 | ReturnType = MD->getReturnType(); | ||||
257 | IsObjCMethod = true; | ||||
258 | IsInstanceMethod = MD->isInstanceMethod(); | ||||
259 | IsClassMethod = !IsInstanceMethod; | ||||
260 | break; | ||||
261 | } | ||||
262 | case Decl::FunctionTemplate: { | ||||
263 | const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); | ||||
264 | Kind = FunctionKind; | ||||
265 | TemplateKind = Template; | ||||
266 | const FunctionDecl *FD = FTD->getTemplatedDecl(); | ||||
267 | ParamVars = FD->parameters(); | ||||
268 | ReturnType = FD->getReturnType(); | ||||
269 | TemplateParameters = FTD->getTemplateParameters(); | ||||
270 | break; | ||||
271 | } | ||||
272 | case Decl::ClassTemplate: { | ||||
273 | const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); | ||||
274 | Kind = ClassKind; | ||||
275 | TemplateKind = Template; | ||||
276 | TemplateParameters = CTD->getTemplateParameters(); | ||||
277 | break; | ||||
278 | } | ||||
279 | case Decl::ClassTemplatePartialSpecialization: { | ||||
280 | const ClassTemplatePartialSpecializationDecl *CTPSD = | ||||
281 | cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); | ||||
282 | Kind = ClassKind; | ||||
283 | TemplateKind = TemplatePartialSpecialization; | ||||
284 | TemplateParameters = CTPSD->getTemplateParameters(); | ||||
285 | break; | ||||
286 | } | ||||
287 | case Decl::ClassTemplateSpecialization: | ||||
288 | Kind = ClassKind; | ||||
289 | TemplateKind = TemplateSpecialization; | ||||
290 | break; | ||||
291 | case Decl::Record: | ||||
292 | case Decl::CXXRecord: | ||||
293 | Kind = ClassKind; | ||||
294 | break; | ||||
295 | case Decl::Var: | ||||
296 | case Decl::Field: | ||||
297 | case Decl::EnumConstant: | ||||
298 | case Decl::ObjCIvar: | ||||
299 | case Decl::ObjCAtDefsField: | ||||
300 | case Decl::ObjCProperty: { | ||||
301 | const TypeSourceInfo *TSI; | ||||
302 | if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl)) | ||||
303 | TSI = VD->getTypeSourceInfo(); | ||||
304 | else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl)) | ||||
305 | TSI = PD->getTypeSourceInfo(); | ||||
306 | else | ||||
307 | TSI = nullptr; | ||||
308 | if (TSI) { | ||||
309 | TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); | ||||
310 | FunctionTypeLoc FTL; | ||||
311 | if (getFunctionTypeLoc(TL, FTL)) { | ||||
312 | ParamVars = FTL.getParams(); | ||||
313 | ReturnType = FTL.getReturnLoc().getType(); | ||||
314 | } | ||||
315 | } | ||||
316 | Kind = VariableKind; | ||||
317 | break; | ||||
318 | } | ||||
319 | case Decl::Namespace: | ||||
320 | Kind = NamespaceKind; | ||||
321 | break; | ||||
322 | case Decl::TypeAlias: | ||||
323 | case Decl::Typedef: { | ||||
324 | Kind = TypedefKind; | ||||
325 | // If this is a typedef / using to something we consider a function, extract | ||||
326 | // arguments and return type. | ||||
327 | const TypeSourceInfo *TSI = | ||||
328 | K == Decl::Typedef | ||||
329 | ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo() | ||||
330 | : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo(); | ||||
331 | if (!TSI) | ||||
332 | break; | ||||
333 | TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); | ||||
334 | FunctionTypeLoc FTL; | ||||
335 | if (getFunctionTypeLoc(TL, FTL)) { | ||||
336 | Kind = FunctionKind; | ||||
337 | ParamVars = FTL.getParams(); | ||||
338 | ReturnType = FTL.getReturnLoc().getType(); | ||||
339 | } | ||||
340 | break; | ||||
341 | } | ||||
342 | case Decl::TypeAliasTemplate: { | ||||
343 | const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); | ||||
344 | Kind = TypedefKind; | ||||
345 | TemplateKind = Template; | ||||
346 | TemplateParameters = TAT->getTemplateParameters(); | ||||
347 | TypeAliasDecl *TAD = TAT->getTemplatedDecl(); | ||||
348 | if (!TAD) | ||||
349 | break; | ||||
350 | |||||
351 | const TypeSourceInfo *TSI = TAD->getTypeSourceInfo(); | ||||
352 | if (!TSI) | ||||
353 | break; | ||||
354 | TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); | ||||
355 | FunctionTypeLoc FTL; | ||||
356 | if (getFunctionTypeLoc(TL, FTL)) { | ||||
357 | Kind = FunctionKind; | ||||
358 | ParamVars = FTL.getParams(); | ||||
359 | ReturnType = FTL.getReturnLoc().getType(); | ||||
360 | } | ||||
361 | break; | ||||
362 | } | ||||
363 | case Decl::Enum: | ||||
364 | Kind = EnumKind; | ||||
365 | break; | ||||
366 | } | ||||
367 | |||||
368 | IsFilled = true; | ||||
369 | } | ||||
370 | |||||
371 | StringRef ParamCommandComment::getParamName(const FullComment *FC) const { | ||||
372 | assert(isParamIndexValid())((isParamIndexValid()) ? static_cast<void> (0) : __assert_fail ("isParamIndexValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 372, __PRETTY_FUNCTION__)); | ||||
373 | if (isVarArgParam()) | ||||
374 | return "..."; | ||||
375 | return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); | ||||
376 | } | ||||
377 | |||||
378 | StringRef TParamCommandComment::getParamName(const FullComment *FC) const { | ||||
379 | assert(isPositionValid())((isPositionValid()) ? static_cast<void> (0) : __assert_fail ("isPositionValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/lib/AST/Comment.cpp" , 379, __PRETTY_FUNCTION__)); | ||||
| |||||
380 | const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; | ||||
381 | for (unsigned i = 0, e = getDepth(); i != e; ++i) { | ||||
382 | if (i == e-1) | ||||
383 | return TPL->getParam(getIndex(i))->getName(); | ||||
| |||||
384 | const NamedDecl *Param = TPL->getParam(getIndex(i)); | ||||
385 | if (const TemplateTemplateParmDecl *TTP = | ||||
386 | dyn_cast<TemplateTemplateParmDecl>(Param)) | ||||
387 | TPL = TTP->getTemplateParameters(); | ||||
388 | } | ||||
389 | return ""; | ||||
390 | } | ||||
391 | |||||
392 | } // end namespace comments | ||||
393 | } // end namespace clang | ||||
394 |
1 | //===--- Comment.h - Comment AST nodes --------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines comment AST nodes. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CLANG_AST_COMMENT_H |
14 | #define LLVM_CLANG_AST_COMMENT_H |
15 | |
16 | #include "clang/AST/CommentCommandTraits.h" |
17 | #include "clang/AST/DeclObjC.h" |
18 | #include "clang/AST/Type.h" |
19 | #include "clang/Basic/SourceLocation.h" |
20 | #include "llvm/ADT/ArrayRef.h" |
21 | #include "llvm/ADT/StringRef.h" |
22 | |
23 | namespace clang { |
24 | class Decl; |
25 | class ParmVarDecl; |
26 | class TemplateParameterList; |
27 | |
28 | namespace comments { |
29 | class FullComment; |
30 | |
31 | /// Describes the syntax that was used in a documentation command. |
32 | /// |
33 | /// Exact values of this enumeration are important because they used to select |
34 | /// parts of diagnostic messages. Audit diagnostics before changing or adding |
35 | /// a new value. |
36 | enum CommandMarkerKind { |
37 | /// Command started with a backslash character: |
38 | /// \code |
39 | /// \foo |
40 | /// \endcode |
41 | CMK_Backslash = 0, |
42 | |
43 | /// Command started with an 'at' character: |
44 | /// \code |
45 | /// @foo |
46 | /// \endcode |
47 | CMK_At = 1 |
48 | }; |
49 | |
50 | /// Any part of the comment. |
51 | /// Abstract class. |
52 | class Comment { |
53 | protected: |
54 | /// Preferred location to show caret. |
55 | SourceLocation Loc; |
56 | |
57 | /// Source range of this AST node. |
58 | SourceRange Range; |
59 | |
60 | class CommentBitfields { |
61 | friend class Comment; |
62 | |
63 | /// Type of this AST node. |
64 | unsigned Kind : 8; |
65 | }; |
66 | enum { NumCommentBits = 8 }; |
67 | |
68 | class InlineContentCommentBitfields { |
69 | friend class InlineContentComment; |
70 | |
71 | unsigned : NumCommentBits; |
72 | |
73 | /// True if there is a newline after this inline content node. |
74 | /// (There is no separate AST node for a newline.) |
75 | unsigned HasTrailingNewline : 1; |
76 | }; |
77 | enum { NumInlineContentCommentBits = NumCommentBits + 1 }; |
78 | |
79 | class TextCommentBitfields { |
80 | friend class TextComment; |
81 | |
82 | unsigned : NumInlineContentCommentBits; |
83 | |
84 | /// True if \c IsWhitespace field contains a valid value. |
85 | mutable unsigned IsWhitespaceValid : 1; |
86 | |
87 | /// True if this comment AST node contains only whitespace. |
88 | mutable unsigned IsWhitespace : 1; |
89 | }; |
90 | enum { NumTextCommentBits = NumInlineContentCommentBits + 2 }; |
91 | |
92 | class InlineCommandCommentBitfields { |
93 | friend class InlineCommandComment; |
94 | |
95 | unsigned : NumInlineContentCommentBits; |
96 | |
97 | unsigned RenderKind : 3; |
98 | |
99 | unsigned CommandID : CommandInfo::NumCommandIDBits; |
100 | }; |
101 | enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 3 + |
102 | CommandInfo::NumCommandIDBits }; |
103 | |
104 | class HTMLTagCommentBitfields { |
105 | friend class HTMLTagComment; |
106 | |
107 | unsigned : NumInlineContentCommentBits; |
108 | |
109 | /// True if we found that this tag is malformed in some way. |
110 | unsigned IsMalformed : 1; |
111 | }; |
112 | enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 }; |
113 | |
114 | class HTMLStartTagCommentBitfields { |
115 | friend class HTMLStartTagComment; |
116 | |
117 | unsigned : NumHTMLTagCommentBits; |
118 | |
119 | /// True if this tag is self-closing (e. g., <br />). This is based on tag |
120 | /// spelling in comment (plain <br> would not set this flag). |
121 | unsigned IsSelfClosing : 1; |
122 | }; |
123 | enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 }; |
124 | |
125 | class ParagraphCommentBitfields { |
126 | friend class ParagraphComment; |
127 | |
128 | unsigned : NumCommentBits; |
129 | |
130 | /// True if \c IsWhitespace field contains a valid value. |
131 | mutable unsigned IsWhitespaceValid : 1; |
132 | |
133 | /// True if this comment AST node contains only whitespace. |
134 | mutable unsigned IsWhitespace : 1; |
135 | }; |
136 | enum { NumParagraphCommentBits = NumCommentBits + 2 }; |
137 | |
138 | class BlockCommandCommentBitfields { |
139 | friend class BlockCommandComment; |
140 | |
141 | unsigned : NumCommentBits; |
142 | |
143 | unsigned CommandID : CommandInfo::NumCommandIDBits; |
144 | |
145 | /// Describes the syntax that was used in a documentation command. |
146 | /// Contains values from CommandMarkerKind enum. |
147 | unsigned CommandMarker : 1; |
148 | }; |
149 | enum { NumBlockCommandCommentBits = NumCommentBits + |
150 | CommandInfo::NumCommandIDBits + 1 }; |
151 | |
152 | class ParamCommandCommentBitfields { |
153 | friend class ParamCommandComment; |
154 | |
155 | unsigned : NumBlockCommandCommentBits; |
156 | |
157 | /// Parameter passing direction, see ParamCommandComment::PassDirection. |
158 | unsigned Direction : 2; |
159 | |
160 | /// True if direction was specified explicitly in the comment. |
161 | unsigned IsDirectionExplicit : 1; |
162 | }; |
163 | enum { NumParamCommandCommentBits = NumBlockCommandCommentBits + 3 }; |
164 | |
165 | union { |
166 | CommentBitfields CommentBits; |
167 | InlineContentCommentBitfields InlineContentCommentBits; |
168 | TextCommentBitfields TextCommentBits; |
169 | InlineCommandCommentBitfields InlineCommandCommentBits; |
170 | HTMLTagCommentBitfields HTMLTagCommentBits; |
171 | HTMLStartTagCommentBitfields HTMLStartTagCommentBits; |
172 | ParagraphCommentBitfields ParagraphCommentBits; |
173 | BlockCommandCommentBitfields BlockCommandCommentBits; |
174 | ParamCommandCommentBitfields ParamCommandCommentBits; |
175 | }; |
176 | |
177 | void setSourceRange(SourceRange SR) { |
178 | Range = SR; |
179 | } |
180 | |
181 | void setLocation(SourceLocation L) { |
182 | Loc = L; |
183 | } |
184 | |
185 | public: |
186 | enum CommentKind { |
187 | NoCommentKind = 0, |
188 | #define COMMENT(CLASS, PARENT) CLASS##Kind, |
189 | #define COMMENT_RANGE(BASE, FIRST, LAST) \ |
190 | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind, |
191 | #define LAST_COMMENT_RANGE(BASE, FIRST, LAST) \ |
192 | First##BASE##Constant=FIRST##Kind, Last##BASE##Constant=LAST##Kind |
193 | #define ABSTRACT_COMMENT(COMMENT) |
194 | #include "clang/AST/CommentNodes.inc" |
195 | }; |
196 | |
197 | Comment(CommentKind K, |
198 | SourceLocation LocBegin, |
199 | SourceLocation LocEnd) : |
200 | Loc(LocBegin), Range(SourceRange(LocBegin, LocEnd)) { |
201 | CommentBits.Kind = K; |
202 | } |
203 | |
204 | CommentKind getCommentKind() const { |
205 | return static_cast<CommentKind>(CommentBits.Kind); |
206 | } |
207 | |
208 | const char *getCommentKindName() const; |
209 | |
210 | void dump() const; |
211 | void dumpColor() const; |
212 | void dump(const ASTContext &Context) const; |
213 | void dump(raw_ostream &OS, const CommandTraits *Traits, |
214 | const SourceManager *SM) const; |
215 | |
216 | SourceRange getSourceRange() const LLVM_READONLY__attribute__((__pure__)) { return Range; } |
217 | |
218 | SourceLocation getBeginLoc() const LLVM_READONLY__attribute__((__pure__)) { return Range.getBegin(); } |
219 | |
220 | SourceLocation getEndLoc() const LLVM_READONLY__attribute__((__pure__)) { return Range.getEnd(); } |
221 | |
222 | SourceLocation getLocation() const LLVM_READONLY__attribute__((__pure__)) { return Loc; } |
223 | |
224 | typedef Comment * const *child_iterator; |
225 | |
226 | child_iterator child_begin() const; |
227 | child_iterator child_end() const; |
228 | |
229 | // TODO: const child iterator |
230 | |
231 | unsigned child_count() const { |
232 | return child_end() - child_begin(); |
233 | } |
234 | }; |
235 | |
236 | /// Inline content (contained within a block). |
237 | /// Abstract class. |
238 | class InlineContentComment : public Comment { |
239 | protected: |
240 | InlineContentComment(CommentKind K, |
241 | SourceLocation LocBegin, |
242 | SourceLocation LocEnd) : |
243 | Comment(K, LocBegin, LocEnd) { |
244 | InlineContentCommentBits.HasTrailingNewline = 0; |
245 | } |
246 | |
247 | public: |
248 | static bool classof(const Comment *C) { |
249 | return C->getCommentKind() >= FirstInlineContentCommentConstant && |
250 | C->getCommentKind() <= LastInlineContentCommentConstant; |
251 | } |
252 | |
253 | void addTrailingNewline() { |
254 | InlineContentCommentBits.HasTrailingNewline = 1; |
255 | } |
256 | |
257 | bool hasTrailingNewline() const { |
258 | return InlineContentCommentBits.HasTrailingNewline; |
259 | } |
260 | }; |
261 | |
262 | /// Plain text. |
263 | class TextComment : public InlineContentComment { |
264 | StringRef Text; |
265 | |
266 | public: |
267 | TextComment(SourceLocation LocBegin, |
268 | SourceLocation LocEnd, |
269 | StringRef Text) : |
270 | InlineContentComment(TextCommentKind, LocBegin, LocEnd), |
271 | Text(Text) { |
272 | TextCommentBits.IsWhitespaceValid = false; |
273 | } |
274 | |
275 | static bool classof(const Comment *C) { |
276 | return C->getCommentKind() == TextCommentKind; |
277 | } |
278 | |
279 | child_iterator child_begin() const { return nullptr; } |
280 | |
281 | child_iterator child_end() const { return nullptr; } |
282 | |
283 | StringRef getText() const LLVM_READONLY__attribute__((__pure__)) { return Text; } |
284 | |
285 | bool isWhitespace() const { |
286 | if (TextCommentBits.IsWhitespaceValid) |
287 | return TextCommentBits.IsWhitespace; |
288 | |
289 | TextCommentBits.IsWhitespace = isWhitespaceNoCache(); |
290 | TextCommentBits.IsWhitespaceValid = true; |
291 | return TextCommentBits.IsWhitespace; |
292 | } |
293 | |
294 | private: |
295 | bool isWhitespaceNoCache() const; |
296 | }; |
297 | |
298 | /// A command with word-like arguments that is considered inline content. |
299 | class InlineCommandComment : public InlineContentComment { |
300 | public: |
301 | struct Argument { |
302 | SourceRange Range; |
303 | StringRef Text; |
304 | |
305 | Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } |
306 | }; |
307 | |
308 | /// The most appropriate rendering mode for this command, chosen on command |
309 | /// semantics in Doxygen. |
310 | enum RenderKind { |
311 | RenderNormal, |
312 | RenderBold, |
313 | RenderMonospaced, |
314 | RenderEmphasized, |
315 | RenderAnchor |
316 | }; |
317 | |
318 | protected: |
319 | /// Command arguments. |
320 | ArrayRef<Argument> Args; |
321 | |
322 | public: |
323 | InlineCommandComment(SourceLocation LocBegin, |
324 | SourceLocation LocEnd, |
325 | unsigned CommandID, |
326 | RenderKind RK, |
327 | ArrayRef<Argument> Args) : |
328 | InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd), |
329 | Args(Args) { |
330 | InlineCommandCommentBits.RenderKind = RK; |
331 | InlineCommandCommentBits.CommandID = CommandID; |
332 | } |
333 | |
334 | static bool classof(const Comment *C) { |
335 | return C->getCommentKind() == InlineCommandCommentKind; |
336 | } |
337 | |
338 | child_iterator child_begin() const { return nullptr; } |
339 | |
340 | child_iterator child_end() const { return nullptr; } |
341 | |
342 | unsigned getCommandID() const { |
343 | return InlineCommandCommentBits.CommandID; |
344 | } |
345 | |
346 | StringRef getCommandName(const CommandTraits &Traits) const { |
347 | return Traits.getCommandInfo(getCommandID())->Name; |
348 | } |
349 | |
350 | SourceRange getCommandNameRange() const { |
351 | return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc()); |
352 | } |
353 | |
354 | RenderKind getRenderKind() const { |
355 | return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind); |
356 | } |
357 | |
358 | unsigned getNumArgs() const { |
359 | return Args.size(); |
360 | } |
361 | |
362 | StringRef getArgText(unsigned Idx) const { |
363 | return Args[Idx].Text; |
364 | } |
365 | |
366 | SourceRange getArgRange(unsigned Idx) const { |
367 | return Args[Idx].Range; |
368 | } |
369 | }; |
370 | |
371 | /// Abstract class for opening and closing HTML tags. HTML tags are always |
372 | /// treated as inline content (regardless HTML semantics). |
373 | class HTMLTagComment : public InlineContentComment { |
374 | protected: |
375 | StringRef TagName; |
376 | SourceRange TagNameRange; |
377 | |
378 | HTMLTagComment(CommentKind K, |
379 | SourceLocation LocBegin, |
380 | SourceLocation LocEnd, |
381 | StringRef TagName, |
382 | SourceLocation TagNameBegin, |
383 | SourceLocation TagNameEnd) : |
384 | InlineContentComment(K, LocBegin, LocEnd), |
385 | TagName(TagName), |
386 | TagNameRange(TagNameBegin, TagNameEnd) { |
387 | setLocation(TagNameBegin); |
388 | HTMLTagCommentBits.IsMalformed = 0; |
389 | } |
390 | |
391 | public: |
392 | static bool classof(const Comment *C) { |
393 | return C->getCommentKind() >= FirstHTMLTagCommentConstant && |
394 | C->getCommentKind() <= LastHTMLTagCommentConstant; |
395 | } |
396 | |
397 | StringRef getTagName() const LLVM_READONLY__attribute__((__pure__)) { return TagName; } |
398 | |
399 | SourceRange getTagNameSourceRange() const LLVM_READONLY__attribute__((__pure__)) { |
400 | SourceLocation L = getLocation(); |
401 | return SourceRange(L.getLocWithOffset(1), |
402 | L.getLocWithOffset(1 + TagName.size())); |
403 | } |
404 | |
405 | bool isMalformed() const { |
406 | return HTMLTagCommentBits.IsMalformed; |
407 | } |
408 | |
409 | void setIsMalformed() { |
410 | HTMLTagCommentBits.IsMalformed = 1; |
411 | } |
412 | }; |
413 | |
414 | /// An opening HTML tag with attributes. |
415 | class HTMLStartTagComment : public HTMLTagComment { |
416 | public: |
417 | class Attribute { |
418 | public: |
419 | SourceLocation NameLocBegin; |
420 | StringRef Name; |
421 | |
422 | SourceLocation EqualsLoc; |
423 | |
424 | SourceRange ValueRange; |
425 | StringRef Value; |
426 | |
427 | Attribute() { } |
428 | |
429 | Attribute(SourceLocation NameLocBegin, StringRef Name) : |
430 | NameLocBegin(NameLocBegin), Name(Name), |
431 | EqualsLoc(SourceLocation()), |
432 | ValueRange(SourceRange()), Value(StringRef()) |
433 | { } |
434 | |
435 | Attribute(SourceLocation NameLocBegin, StringRef Name, |
436 | SourceLocation EqualsLoc, |
437 | SourceRange ValueRange, StringRef Value) : |
438 | NameLocBegin(NameLocBegin), Name(Name), |
439 | EqualsLoc(EqualsLoc), |
440 | ValueRange(ValueRange), Value(Value) |
441 | { } |
442 | |
443 | SourceLocation getNameLocEnd() const { |
444 | return NameLocBegin.getLocWithOffset(Name.size()); |
445 | } |
446 | |
447 | SourceRange getNameRange() const { |
448 | return SourceRange(NameLocBegin, getNameLocEnd()); |
449 | } |
450 | }; |
451 | |
452 | private: |
453 | ArrayRef<Attribute> Attributes; |
454 | |
455 | public: |
456 | HTMLStartTagComment(SourceLocation LocBegin, |
457 | StringRef TagName) : |
458 | HTMLTagComment(HTMLStartTagCommentKind, |
459 | LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()), |
460 | TagName, |
461 | LocBegin.getLocWithOffset(1), |
462 | LocBegin.getLocWithOffset(1 + TagName.size())) { |
463 | HTMLStartTagCommentBits.IsSelfClosing = false; |
464 | } |
465 | |
466 | static bool classof(const Comment *C) { |
467 | return C->getCommentKind() == HTMLStartTagCommentKind; |
468 | } |
469 | |
470 | child_iterator child_begin() const { return nullptr; } |
471 | |
472 | child_iterator child_end() const { return nullptr; } |
473 | |
474 | unsigned getNumAttrs() const { |
475 | return Attributes.size(); |
476 | } |
477 | |
478 | const Attribute &getAttr(unsigned Idx) const { |
479 | return Attributes[Idx]; |
480 | } |
481 | |
482 | void setAttrs(ArrayRef<Attribute> Attrs) { |
483 | Attributes = Attrs; |
484 | if (!Attrs.empty()) { |
485 | const Attribute &Attr = Attrs.back(); |
486 | SourceLocation L = Attr.ValueRange.getEnd(); |
487 | if (L.isValid()) |
488 | Range.setEnd(L); |
489 | else { |
490 | Range.setEnd(Attr.getNameLocEnd()); |
491 | } |
492 | } |
493 | } |
494 | |
495 | void setGreaterLoc(SourceLocation GreaterLoc) { |
496 | Range.setEnd(GreaterLoc); |
497 | } |
498 | |
499 | bool isSelfClosing() const { |
500 | return HTMLStartTagCommentBits.IsSelfClosing; |
501 | } |
502 | |
503 | void setSelfClosing() { |
504 | HTMLStartTagCommentBits.IsSelfClosing = true; |
505 | } |
506 | }; |
507 | |
508 | /// A closing HTML tag. |
509 | class HTMLEndTagComment : public HTMLTagComment { |
510 | public: |
511 | HTMLEndTagComment(SourceLocation LocBegin, |
512 | SourceLocation LocEnd, |
513 | StringRef TagName) : |
514 | HTMLTagComment(HTMLEndTagCommentKind, |
515 | LocBegin, LocEnd, |
516 | TagName, |
517 | LocBegin.getLocWithOffset(2), |
518 | LocBegin.getLocWithOffset(2 + TagName.size())) |
519 | { } |
520 | |
521 | static bool classof(const Comment *C) { |
522 | return C->getCommentKind() == HTMLEndTagCommentKind; |
523 | } |
524 | |
525 | child_iterator child_begin() const { return nullptr; } |
526 | |
527 | child_iterator child_end() const { return nullptr; } |
528 | }; |
529 | |
530 | /// Block content (contains inline content). |
531 | /// Abstract class. |
532 | class BlockContentComment : public Comment { |
533 | protected: |
534 | BlockContentComment(CommentKind K, |
535 | SourceLocation LocBegin, |
536 | SourceLocation LocEnd) : |
537 | Comment(K, LocBegin, LocEnd) |
538 | { } |
539 | |
540 | public: |
541 | static bool classof(const Comment *C) { |
542 | return C->getCommentKind() >= FirstBlockContentCommentConstant && |
543 | C->getCommentKind() <= LastBlockContentCommentConstant; |
544 | } |
545 | }; |
546 | |
547 | /// A single paragraph that contains inline content. |
548 | class ParagraphComment : public BlockContentComment { |
549 | ArrayRef<InlineContentComment *> Content; |
550 | |
551 | public: |
552 | ParagraphComment(ArrayRef<InlineContentComment *> Content) : |
553 | BlockContentComment(ParagraphCommentKind, |
554 | SourceLocation(), |
555 | SourceLocation()), |
556 | Content(Content) { |
557 | if (Content.empty()) { |
558 | ParagraphCommentBits.IsWhitespace = true; |
559 | ParagraphCommentBits.IsWhitespaceValid = true; |
560 | return; |
561 | } |
562 | |
563 | ParagraphCommentBits.IsWhitespaceValid = false; |
564 | |
565 | setSourceRange(SourceRange(Content.front()->getBeginLoc(), |
566 | Content.back()->getEndLoc())); |
567 | setLocation(Content.front()->getBeginLoc()); |
568 | } |
569 | |
570 | static bool classof(const Comment *C) { |
571 | return C->getCommentKind() == ParagraphCommentKind; |
572 | } |
573 | |
574 | child_iterator child_begin() const { |
575 | return reinterpret_cast<child_iterator>(Content.begin()); |
576 | } |
577 | |
578 | child_iterator child_end() const { |
579 | return reinterpret_cast<child_iterator>(Content.end()); |
580 | } |
581 | |
582 | bool isWhitespace() const { |
583 | if (ParagraphCommentBits.IsWhitespaceValid) |
584 | return ParagraphCommentBits.IsWhitespace; |
585 | |
586 | ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache(); |
587 | ParagraphCommentBits.IsWhitespaceValid = true; |
588 | return ParagraphCommentBits.IsWhitespace; |
589 | } |
590 | |
591 | private: |
592 | bool isWhitespaceNoCache() const; |
593 | }; |
594 | |
595 | /// A command that has zero or more word-like arguments (number of word-like |
596 | /// arguments depends on command name) and a paragraph as an argument |
597 | /// (e. g., \\brief). |
598 | class BlockCommandComment : public BlockContentComment { |
599 | public: |
600 | struct Argument { |
601 | SourceRange Range; |
602 | StringRef Text; |
603 | |
604 | Argument() { } |
605 | Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { } |
606 | }; |
607 | |
608 | protected: |
609 | /// Word-like arguments. |
610 | ArrayRef<Argument> Args; |
611 | |
612 | /// Paragraph argument. |
613 | ParagraphComment *Paragraph; |
614 | |
615 | BlockCommandComment(CommentKind K, |
616 | SourceLocation LocBegin, |
617 | SourceLocation LocEnd, |
618 | unsigned CommandID, |
619 | CommandMarkerKind CommandMarker) : |
620 | BlockContentComment(K, LocBegin, LocEnd), |
621 | Paragraph(nullptr) { |
622 | setLocation(getCommandNameBeginLoc()); |
623 | BlockCommandCommentBits.CommandID = CommandID; |
624 | BlockCommandCommentBits.CommandMarker = CommandMarker; |
625 | } |
626 | |
627 | public: |
628 | BlockCommandComment(SourceLocation LocBegin, |
629 | SourceLocation LocEnd, |
630 | unsigned CommandID, |
631 | CommandMarkerKind CommandMarker) : |
632 | BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd), |
633 | Paragraph(nullptr) { |
634 | setLocation(getCommandNameBeginLoc()); |
635 | BlockCommandCommentBits.CommandID = CommandID; |
636 | BlockCommandCommentBits.CommandMarker = CommandMarker; |
637 | } |
638 | |
639 | static bool classof(const Comment *C) { |
640 | return C->getCommentKind() >= FirstBlockCommandCommentConstant && |
641 | C->getCommentKind() <= LastBlockCommandCommentConstant; |
642 | } |
643 | |
644 | child_iterator child_begin() const { |
645 | return reinterpret_cast<child_iterator>(&Paragraph); |
646 | } |
647 | |
648 | child_iterator child_end() const { |
649 | return reinterpret_cast<child_iterator>(&Paragraph + 1); |
650 | } |
651 | |
652 | unsigned getCommandID() const { |
653 | return BlockCommandCommentBits.CommandID; |
654 | } |
655 | |
656 | StringRef getCommandName(const CommandTraits &Traits) const { |
657 | return Traits.getCommandInfo(getCommandID())->Name; |
658 | } |
659 | |
660 | SourceLocation getCommandNameBeginLoc() const { |
661 | return getBeginLoc().getLocWithOffset(1); |
662 | } |
663 | |
664 | SourceRange getCommandNameRange(const CommandTraits &Traits) const { |
665 | StringRef Name = getCommandName(Traits); |
666 | return SourceRange(getCommandNameBeginLoc(), |
667 | getBeginLoc().getLocWithOffset(1 + Name.size())); |
668 | } |
669 | |
670 | unsigned getNumArgs() const { |
671 | return Args.size(); |
672 | } |
673 | |
674 | StringRef getArgText(unsigned Idx) const { |
675 | return Args[Idx].Text; |
676 | } |
677 | |
678 | SourceRange getArgRange(unsigned Idx) const { |
679 | return Args[Idx].Range; |
680 | } |
681 | |
682 | void setArgs(ArrayRef<Argument> A) { |
683 | Args = A; |
684 | if (Args.size() > 0) { |
685 | SourceLocation NewLocEnd = Args.back().Range.getEnd(); |
686 | if (NewLocEnd.isValid()) |
687 | setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
688 | } |
689 | } |
690 | |
691 | ParagraphComment *getParagraph() const LLVM_READONLY__attribute__((__pure__)) { |
692 | return Paragraph; |
693 | } |
694 | |
695 | bool hasNonWhitespaceParagraph() const { |
696 | return Paragraph && !Paragraph->isWhitespace(); |
697 | } |
698 | |
699 | void setParagraph(ParagraphComment *PC) { |
700 | Paragraph = PC; |
701 | SourceLocation NewLocEnd = PC->getEndLoc(); |
702 | if (NewLocEnd.isValid()) |
703 | setSourceRange(SourceRange(getBeginLoc(), NewLocEnd)); |
704 | } |
705 | |
706 | CommandMarkerKind getCommandMarker() const LLVM_READONLY__attribute__((__pure__)) { |
707 | return static_cast<CommandMarkerKind>( |
708 | BlockCommandCommentBits.CommandMarker); |
709 | } |
710 | }; |
711 | |
712 | /// Doxygen \\param command. |
713 | class ParamCommandComment : public BlockCommandComment { |
714 | private: |
715 | /// Parameter index in the function declaration. |
716 | unsigned ParamIndex; |
717 | |
718 | public: |
719 | enum : unsigned { |
720 | InvalidParamIndex = ~0U, |
721 | VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U |
722 | }; |
723 | |
724 | ParamCommandComment(SourceLocation LocBegin, |
725 | SourceLocation LocEnd, |
726 | unsigned CommandID, |
727 | CommandMarkerKind CommandMarker) : |
728 | BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, |
729 | CommandID, CommandMarker), |
730 | ParamIndex(InvalidParamIndex) { |
731 | ParamCommandCommentBits.Direction = In; |
732 | ParamCommandCommentBits.IsDirectionExplicit = false; |
733 | } |
734 | |
735 | static bool classof(const Comment *C) { |
736 | return C->getCommentKind() == ParamCommandCommentKind; |
737 | } |
738 | |
739 | enum PassDirection { |
740 | In, |
741 | Out, |
742 | InOut |
743 | }; |
744 | |
745 | static const char *getDirectionAsString(PassDirection D); |
746 | |
747 | PassDirection getDirection() const LLVM_READONLY__attribute__((__pure__)) { |
748 | return static_cast<PassDirection>(ParamCommandCommentBits.Direction); |
749 | } |
750 | |
751 | bool isDirectionExplicit() const LLVM_READONLY__attribute__((__pure__)) { |
752 | return ParamCommandCommentBits.IsDirectionExplicit; |
753 | } |
754 | |
755 | void setDirection(PassDirection Direction, bool Explicit) { |
756 | ParamCommandCommentBits.Direction = Direction; |
757 | ParamCommandCommentBits.IsDirectionExplicit = Explicit; |
758 | } |
759 | |
760 | bool hasParamName() const { |
761 | return getNumArgs() > 0; |
762 | } |
763 | |
764 | StringRef getParamName(const FullComment *FC) const; |
765 | |
766 | StringRef getParamNameAsWritten() const { |
767 | return Args[0].Text; |
768 | } |
769 | |
770 | SourceRange getParamNameRange() const { |
771 | return Args[0].Range; |
772 | } |
773 | |
774 | bool isParamIndexValid() const LLVM_READONLY__attribute__((__pure__)) { |
775 | return ParamIndex != InvalidParamIndex; |
776 | } |
777 | |
778 | bool isVarArgParam() const LLVM_READONLY__attribute__((__pure__)) { |
779 | return ParamIndex == VarArgParamIndex; |
780 | } |
781 | |
782 | void setIsVarArgParam() { |
783 | ParamIndex = VarArgParamIndex; |
784 | assert(isParamIndexValid())((isParamIndexValid()) ? static_cast<void> (0) : __assert_fail ("isParamIndexValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 784, __PRETTY_FUNCTION__)); |
785 | } |
786 | |
787 | unsigned getParamIndex() const LLVM_READONLY__attribute__((__pure__)) { |
788 | assert(isParamIndexValid())((isParamIndexValid()) ? static_cast<void> (0) : __assert_fail ("isParamIndexValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 788, __PRETTY_FUNCTION__)); |
789 | assert(!isVarArgParam())((!isVarArgParam()) ? static_cast<void> (0) : __assert_fail ("!isVarArgParam()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 789, __PRETTY_FUNCTION__)); |
790 | return ParamIndex; |
791 | } |
792 | |
793 | void setParamIndex(unsigned Index) { |
794 | ParamIndex = Index; |
795 | assert(isParamIndexValid())((isParamIndexValid()) ? static_cast<void> (0) : __assert_fail ("isParamIndexValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 795, __PRETTY_FUNCTION__)); |
796 | assert(!isVarArgParam())((!isVarArgParam()) ? static_cast<void> (0) : __assert_fail ("!isVarArgParam()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 796, __PRETTY_FUNCTION__)); |
797 | } |
798 | }; |
799 | |
800 | /// Doxygen \\tparam command, describes a template parameter. |
801 | class TParamCommandComment : public BlockCommandComment { |
802 | private: |
803 | /// If this template parameter name was resolved (found in template parameter |
804 | /// list), then this stores a list of position indexes in all template |
805 | /// parameter lists. |
806 | /// |
807 | /// For example: |
808 | /// \verbatim |
809 | /// template<typename C, template<typename T> class TT> |
810 | /// void test(TT<int> aaa); |
811 | /// \endverbatim |
812 | /// For C: Position = { 0 } |
813 | /// For TT: Position = { 1 } |
814 | /// For T: Position = { 1, 0 } |
815 | ArrayRef<unsigned> Position; |
816 | |
817 | public: |
818 | TParamCommandComment(SourceLocation LocBegin, |
819 | SourceLocation LocEnd, |
820 | unsigned CommandID, |
821 | CommandMarkerKind CommandMarker) : |
822 | BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID, |
823 | CommandMarker) |
824 | { } |
825 | |
826 | static bool classof(const Comment *C) { |
827 | return C->getCommentKind() == TParamCommandCommentKind; |
828 | } |
829 | |
830 | bool hasParamName() const { |
831 | return getNumArgs() > 0; |
832 | } |
833 | |
834 | StringRef getParamName(const FullComment *FC) const; |
835 | |
836 | StringRef getParamNameAsWritten() const { |
837 | return Args[0].Text; |
838 | } |
839 | |
840 | SourceRange getParamNameRange() const { |
841 | return Args[0].Range; |
842 | } |
843 | |
844 | bool isPositionValid() const LLVM_READONLY__attribute__((__pure__)) { |
845 | return !Position.empty(); |
846 | } |
847 | |
848 | unsigned getDepth() const { |
849 | assert(isPositionValid())((isPositionValid()) ? static_cast<void> (0) : __assert_fail ("isPositionValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 849, __PRETTY_FUNCTION__)); |
850 | return Position.size(); |
851 | } |
852 | |
853 | unsigned getIndex(unsigned Depth) const { |
854 | assert(isPositionValid())((isPositionValid()) ? static_cast<void> (0) : __assert_fail ("isPositionValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 854, __PRETTY_FUNCTION__)); |
855 | return Position[Depth]; |
856 | } |
857 | |
858 | void setPosition(ArrayRef<unsigned> NewPosition) { |
859 | Position = NewPosition; |
860 | assert(isPositionValid())((isPositionValid()) ? static_cast<void> (0) : __assert_fail ("isPositionValid()", "/build/llvm-toolchain-snapshot-10~++20200107111111+051c4d5b7bc/clang/include/clang/AST/Comment.h" , 860, __PRETTY_FUNCTION__)); |
861 | } |
862 | }; |
863 | |
864 | /// A line of text contained in a verbatim block. |
865 | class VerbatimBlockLineComment : public Comment { |
866 | StringRef Text; |
867 | |
868 | public: |
869 | VerbatimBlockLineComment(SourceLocation LocBegin, |
870 | StringRef Text) : |
871 | Comment(VerbatimBlockLineCommentKind, |
872 | LocBegin, |
873 | LocBegin.getLocWithOffset(Text.size())), |
874 | Text(Text) |
875 | { } |
876 | |
877 | static bool classof(const Comment *C) { |
878 | return C->getCommentKind() == VerbatimBlockLineCommentKind; |
879 | } |
880 | |
881 | child_iterator child_begin() const { return nullptr; } |
882 | |
883 | child_iterator child_end() const { return nullptr; } |
884 | |
885 | StringRef getText() const LLVM_READONLY__attribute__((__pure__)) { |
886 | return Text; |
887 | } |
888 | }; |
889 | |
890 | /// A verbatim block command (e. g., preformatted code). Verbatim block has an |
891 | /// opening and a closing command and contains multiple lines of text |
892 | /// (VerbatimBlockLineComment nodes). |
893 | class VerbatimBlockComment : public BlockCommandComment { |
894 | protected: |
895 | StringRef CloseName; |
896 | SourceLocation CloseNameLocBegin; |
897 | ArrayRef<VerbatimBlockLineComment *> Lines; |
898 | |
899 | public: |
900 | VerbatimBlockComment(SourceLocation LocBegin, |
901 | SourceLocation LocEnd, |
902 | unsigned CommandID) : |
903 | BlockCommandComment(VerbatimBlockCommentKind, |
904 | LocBegin, LocEnd, CommandID, |
905 | CMK_At) // FIXME: improve source fidelity. |
906 | { } |
907 | |
908 | static bool classof(const Comment *C) { |
909 | return C->getCommentKind() == VerbatimBlockCommentKind; |
910 | } |
911 | |
912 | child_iterator child_begin() const { |
913 | return reinterpret_cast<child_iterator>(Lines.begin()); |
914 | } |
915 | |
916 | child_iterator child_end() const { |
917 | return reinterpret_cast<child_iterator>(Lines.end()); |
918 | } |
919 | |
920 | void setCloseName(StringRef Name, SourceLocation LocBegin) { |
921 | CloseName = Name; |
922 | CloseNameLocBegin = LocBegin; |
923 | } |
924 | |
925 | void setLines(ArrayRef<VerbatimBlockLineComment *> L) { |
926 | Lines = L; |
927 | } |
928 | |
929 | StringRef getCloseName() const { |
930 | return CloseName; |
931 | } |
932 | |
933 | unsigned getNumLines() const { |
934 | return Lines.size(); |
935 | } |
936 | |
937 | StringRef getText(unsigned LineIdx) const { |
938 | return Lines[LineIdx]->getText(); |
939 | } |
940 | }; |
941 | |
942 | /// A verbatim line command. Verbatim line has an opening command, a single |
943 | /// line of text (up to the newline after the opening command) and has no |
944 | /// closing command. |
945 | class VerbatimLineComment : public BlockCommandComment { |
946 | protected: |
947 | StringRef Text; |
948 | SourceLocation TextBegin; |
949 | |
950 | public: |
951 | VerbatimLineComment(SourceLocation LocBegin, |
952 | SourceLocation LocEnd, |
953 | unsigned CommandID, |
954 | SourceLocation TextBegin, |
955 | StringRef Text) : |
956 | BlockCommandComment(VerbatimLineCommentKind, |
957 | LocBegin, LocEnd, |
958 | CommandID, |
959 | CMK_At), // FIXME: improve source fidelity. |
960 | Text(Text), |
961 | TextBegin(TextBegin) |
962 | { } |
963 | |
964 | static bool classof(const Comment *C) { |
965 | return C->getCommentKind() == VerbatimLineCommentKind; |
966 | } |
967 | |
968 | child_iterator child_begin() const { return nullptr; } |
969 | |
970 | child_iterator child_end() const { return nullptr; } |
971 | |
972 | StringRef getText() const { |
973 | return Text; |
974 | } |
975 | |
976 | SourceRange getTextRange() const { |
977 | return SourceRange(TextBegin, getEndLoc()); |
978 | } |
979 | }; |
980 | |
981 | /// Information about the declaration, useful to clients of FullComment. |
982 | struct DeclInfo { |
983 | /// Declaration the comment is actually attached to (in the source). |
984 | /// Should not be NULL. |
985 | const Decl *CommentDecl; |
986 | |
987 | /// CurrentDecl is the declaration with which the FullComment is associated. |
988 | /// |
989 | /// It can be different from \c CommentDecl. It happens when we decide |
990 | /// that the comment originally attached to \c CommentDecl is fine for |
991 | /// \c CurrentDecl too (for example, for a redeclaration or an overrider of |
992 | /// \c CommentDecl). |
993 | /// |
994 | /// The information in the DeclInfo corresponds to CurrentDecl. |
995 | const Decl *CurrentDecl; |
996 | |
997 | /// Parameters that can be referenced by \\param if \c CommentDecl is something |
998 | /// that we consider a "function". |
999 | ArrayRef<const ParmVarDecl *> ParamVars; |
1000 | |
1001 | /// Function return type if \c CommentDecl is something that we consider |
1002 | /// a "function". |
1003 | QualType ReturnType; |
1004 | |
1005 | /// Template parameters that can be referenced by \\tparam if \c CommentDecl is |
1006 | /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is |
1007 | /// true). |
1008 | const TemplateParameterList *TemplateParameters; |
1009 | |
1010 | /// A simplified description of \c CommentDecl kind that should be good enough |
1011 | /// for documentation rendering purposes. |
1012 | enum DeclKind { |
1013 | /// Everything else not explicitly mentioned below. |
1014 | OtherKind, |
1015 | |
1016 | /// Something that we consider a "function": |
1017 | /// \li function, |
1018 | /// \li function template, |
1019 | /// \li function template specialization, |
1020 | /// \li member function, |
1021 | /// \li member function template, |
1022 | /// \li member function template specialization, |
1023 | /// \li ObjC method, |
1024 | /// \li a typedef for a function pointer, member function pointer, |
1025 | /// ObjC block. |
1026 | FunctionKind, |
1027 | |
1028 | /// Something that we consider a "class": |
1029 | /// \li class/struct, |
1030 | /// \li class template, |
1031 | /// \li class template (partial) specialization. |
1032 | ClassKind, |
1033 | |
1034 | /// Something that we consider a "variable": |
1035 | /// \li namespace scope variables; |
1036 | /// \li static and non-static class data members; |
1037 | /// \li enumerators. |
1038 | VariableKind, |
1039 | |
1040 | /// A C++ namespace. |
1041 | NamespaceKind, |
1042 | |
1043 | /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration), |
1044 | /// see \c TypedefNameDecl. |
1045 | TypedefKind, |
1046 | |
1047 | /// An enumeration or scoped enumeration. |
1048 | EnumKind |
1049 | }; |
1050 | |
1051 | /// What kind of template specialization \c CommentDecl is. |
1052 | enum TemplateDeclKind { |
1053 | NotTemplate, |
1054 | Template, |
1055 | TemplateSpecialization, |
1056 | TemplatePartialSpecialization |
1057 | }; |
1058 | |
1059 | /// If false, only \c CommentDecl is valid. |
1060 | unsigned IsFilled : 1; |
1061 | |
1062 | /// Simplified kind of \c CommentDecl, see \c DeclKind enum. |
1063 | unsigned Kind : 3; |
1064 | |
1065 | /// Is \c CommentDecl a template declaration. |
1066 | unsigned TemplateKind : 2; |
1067 | |
1068 | /// Is \c CommentDecl an ObjCMethodDecl. |
1069 | unsigned IsObjCMethod : 1; |
1070 | |
1071 | /// Is \c CommentDecl a non-static member function of C++ class or |
1072 | /// instance method of ObjC class. |
1073 | /// Can be true only if \c IsFunctionDecl is true. |
1074 | unsigned IsInstanceMethod : 1; |
1075 | |
1076 | /// Is \c CommentDecl a static member function of C++ class or |
1077 | /// class method of ObjC class. |
1078 | /// Can be true only if \c IsFunctionDecl is true. |
1079 | unsigned IsClassMethod : 1; |
1080 | |
1081 | void fill(); |
1082 | |
1083 | DeclKind getKind() const LLVM_READONLY__attribute__((__pure__)) { |
1084 | return static_cast<DeclKind>(Kind); |
1085 | } |
1086 | |
1087 | TemplateDeclKind getTemplateKind() const LLVM_READONLY__attribute__((__pure__)) { |
1088 | return static_cast<TemplateDeclKind>(TemplateKind); |
1089 | } |
1090 | }; |
1091 | |
1092 | /// A full comment attached to a declaration, contains block content. |
1093 | class FullComment : public Comment { |
1094 | ArrayRef<BlockContentComment *> Blocks; |
1095 | DeclInfo *ThisDeclInfo; |
1096 | |
1097 | public: |
1098 | FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) : |
1099 | Comment(FullCommentKind, SourceLocation(), SourceLocation()), |
1100 | Blocks(Blocks), ThisDeclInfo(D) { |
1101 | if (Blocks.empty()) |
1102 | return; |
1103 | |
1104 | setSourceRange( |
1105 | SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc())); |
1106 | setLocation(Blocks.front()->getBeginLoc()); |
1107 | } |
1108 | |
1109 | static bool classof(const Comment *C) { |
1110 | return C->getCommentKind() == FullCommentKind; |
1111 | } |
1112 | |
1113 | child_iterator child_begin() const { |
1114 | return reinterpret_cast<child_iterator>(Blocks.begin()); |
1115 | } |
1116 | |
1117 | child_iterator child_end() const { |
1118 | return reinterpret_cast<child_iterator>(Blocks.end()); |
1119 | } |
1120 | |
1121 | const Decl *getDecl() const LLVM_READONLY__attribute__((__pure__)) { |
1122 | return ThisDeclInfo->CommentDecl; |
1123 | } |
1124 | |
1125 | const DeclInfo *getDeclInfo() const LLVM_READONLY__attribute__((__pure__)) { |
1126 | if (!ThisDeclInfo->IsFilled) |
1127 | ThisDeclInfo->fill(); |
1128 | return ThisDeclInfo; |
1129 | } |
1130 | |
1131 | ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; } |
1132 | |
1133 | }; |
1134 | } // end namespace comments |
1135 | } // end namespace clang |
1136 | |
1137 | #endif |
1138 |