Bug Summary

File:src/gnu/usr.bin/clang/libclangAST/../../../llvm/clang/lib/AST/Comment.cpp
Warning:line 385, column 30
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Comment.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/libclangAST/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/libclangAST/obj/../include/clang/AST -I /usr/src/gnu/usr.bin/clang/libclangAST/../../../llvm/clang/include -I /usr/src/gnu/usr.bin/clang/libclangAST/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/libclangAST/../include -I /usr/src/gnu/usr.bin/clang/libclangAST/obj -I /usr/src/gnu/usr.bin/clang/libclangAST/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/libclangAST/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/libclangAST/../../../llvm/clang/lib/AST/Comment.cpp

/usr/src/gnu/usr.bin/clang/libclangAST/../../../llvm/clang/lib/AST/Comment.cpp

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
18namespace clang {
19namespace 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.
32static_assert(std::is_trivially_destructible<DeclInfo>::value,
33 "DeclInfo should be trivially destructible!");
34
35const 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!")__builtin_unreachable();
47}
48
49namespace {
50struct good {};
51struct bad {};
52
53template <typename T>
54good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
55 return good();
56}
57
58LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__))
59static 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
67LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__))
68static 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
82Comment::child_iterator Comment::child_begin() const {
83 switch (getCommentKind()) {
84 case NoCommentKind: llvm_unreachable("comment without a kind")__builtin_unreachable();
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!")__builtin_unreachable();
94}
95
96Comment::child_iterator Comment::child_end() const {
97 switch (getCommentKind()) {
98 case NoCommentKind: llvm_unreachable("comment without a kind")__builtin_unreachable();
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!")__builtin_unreachable();
108}
109
110bool 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
119bool 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
130static 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
158static 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
192const 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")__builtin_unreachable();
202}
203
204void DeclInfo::fill() {
205 assert(!IsFilled)((void)0);
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;
5
Null pointer value stored to field 'TemplateParameters'
215
216 if (!CommentDecl) {
6
Assuming field 'CommentDecl' is null
7
Taking true branch
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
371StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
372 assert(isParamIndexValid())((void)0);
373 if (isVarArgParam())
374 return "...";
375 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
376}
377
378StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
379 assert(isPositionValid())((void)0);
380 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
1
Calling 'FullComment::getDeclInfo'
9
Returning from 'FullComment::getDeclInfo'
10
'TPL' initialized to a null pointer value
381 for (unsigned i = 0, e = getDepth(); i != e; ++i) {
11
Assuming 'i' is not equal to 'e'
12
Loop condition is true. Entering loop body
382 assert(TPL && "Unknown TemplateParameterList")((void)0);
383 if (i == e - 1)
13
Assuming the condition is false
14
Taking false branch
384 return TPL->getParam(getIndex(i))->getName();
385 const NamedDecl *Param = TPL->getParam(getIndex(i));
15
Called C++ object pointer is null
386 if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
387 TPL = TTP->getTemplateParameters();
388 }
389 return "";
390}
391
392} // end namespace comments
393} // end namespace clang
394

/usr/src/gnu/usr.bin/clang/libclangAST/../../../llvm/clang/include/clang/AST/Comment.h

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
23namespace clang {
24class Decl;
25class ParmVarDecl;
26class TemplateParameterList;
27
28namespace comments {
29class 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.
36enum 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.
52class Comment {
53protected:
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
185public:
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(raw_ostream &OS, const ASTContext &Context) const;
213
214 SourceRange getSourceRange() const LLVM_READONLY__attribute__((__pure__)) { return Range; }
215
216 SourceLocation getBeginLoc() const LLVM_READONLY__attribute__((__pure__)) { return Range.getBegin(); }
217
218 SourceLocation getEndLoc() const LLVM_READONLY__attribute__((__pure__)) { return Range.getEnd(); }
219
220 SourceLocation getLocation() const LLVM_READONLY__attribute__((__pure__)) { return Loc; }
221
222 typedef Comment * const *child_iterator;
223
224 child_iterator child_begin() const;
225 child_iterator child_end() const;
226
227 // TODO: const child iterator
228
229 unsigned child_count() const {
230 return child_end() - child_begin();
231 }
232};
233
234/// Inline content (contained within a block).
235/// Abstract class.
236class InlineContentComment : public Comment {
237protected:
238 InlineContentComment(CommentKind K,
239 SourceLocation LocBegin,
240 SourceLocation LocEnd) :
241 Comment(K, LocBegin, LocEnd) {
242 InlineContentCommentBits.HasTrailingNewline = 0;
243 }
244
245public:
246 static bool classof(const Comment *C) {
247 return C->getCommentKind() >= FirstInlineContentCommentConstant &&
248 C->getCommentKind() <= LastInlineContentCommentConstant;
249 }
250
251 void addTrailingNewline() {
252 InlineContentCommentBits.HasTrailingNewline = 1;
253 }
254
255 bool hasTrailingNewline() const {
256 return InlineContentCommentBits.HasTrailingNewline;
257 }
258};
259
260/// Plain text.
261class TextComment : public InlineContentComment {
262 StringRef Text;
263
264public:
265 TextComment(SourceLocation LocBegin,
266 SourceLocation LocEnd,
267 StringRef Text) :
268 InlineContentComment(TextCommentKind, LocBegin, LocEnd),
269 Text(Text) {
270 TextCommentBits.IsWhitespaceValid = false;
271 }
272
273 static bool classof(const Comment *C) {
274 return C->getCommentKind() == TextCommentKind;
275 }
276
277 child_iterator child_begin() const { return nullptr; }
278
279 child_iterator child_end() const { return nullptr; }
280
281 StringRef getText() const LLVM_READONLY__attribute__((__pure__)) { return Text; }
282
283 bool isWhitespace() const {
284 if (TextCommentBits.IsWhitespaceValid)
285 return TextCommentBits.IsWhitespace;
286
287 TextCommentBits.IsWhitespace = isWhitespaceNoCache();
288 TextCommentBits.IsWhitespaceValid = true;
289 return TextCommentBits.IsWhitespace;
290 }
291
292private:
293 bool isWhitespaceNoCache() const;
294};
295
296/// A command with word-like arguments that is considered inline content.
297class InlineCommandComment : public InlineContentComment {
298public:
299 struct Argument {
300 SourceRange Range;
301 StringRef Text;
302
303 Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
304 };
305
306 /// The most appropriate rendering mode for this command, chosen on command
307 /// semantics in Doxygen.
308 enum RenderKind {
309 RenderNormal,
310 RenderBold,
311 RenderMonospaced,
312 RenderEmphasized,
313 RenderAnchor
314 };
315
316protected:
317 /// Command arguments.
318 ArrayRef<Argument> Args;
319
320public:
321 InlineCommandComment(SourceLocation LocBegin,
322 SourceLocation LocEnd,
323 unsigned CommandID,
324 RenderKind RK,
325 ArrayRef<Argument> Args) :
326 InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
327 Args(Args) {
328 InlineCommandCommentBits.RenderKind = RK;
329 InlineCommandCommentBits.CommandID = CommandID;
330 }
331
332 static bool classof(const Comment *C) {
333 return C->getCommentKind() == InlineCommandCommentKind;
334 }
335
336 child_iterator child_begin() const { return nullptr; }
337
338 child_iterator child_end() const { return nullptr; }
339
340 unsigned getCommandID() const {
341 return InlineCommandCommentBits.CommandID;
342 }
343
344 StringRef getCommandName(const CommandTraits &Traits) const {
345 return Traits.getCommandInfo(getCommandID())->Name;
346 }
347
348 SourceRange getCommandNameRange() const {
349 return SourceRange(getBeginLoc().getLocWithOffset(-1), getEndLoc());
350 }
351
352 RenderKind getRenderKind() const {
353 return static_cast<RenderKind>(InlineCommandCommentBits.RenderKind);
354 }
355
356 unsigned getNumArgs() const {
357 return Args.size();
358 }
359
360 StringRef getArgText(unsigned Idx) const {
361 return Args[Idx].Text;
362 }
363
364 SourceRange getArgRange(unsigned Idx) const {
365 return Args[Idx].Range;
366 }
367};
368
369/// Abstract class for opening and closing HTML tags. HTML tags are always
370/// treated as inline content (regardless HTML semantics).
371class HTMLTagComment : public InlineContentComment {
372protected:
373 StringRef TagName;
374 SourceRange TagNameRange;
375
376 HTMLTagComment(CommentKind K,
377 SourceLocation LocBegin,
378 SourceLocation LocEnd,
379 StringRef TagName,
380 SourceLocation TagNameBegin,
381 SourceLocation TagNameEnd) :
382 InlineContentComment(K, LocBegin, LocEnd),
383 TagName(TagName),
384 TagNameRange(TagNameBegin, TagNameEnd) {
385 setLocation(TagNameBegin);
386 HTMLTagCommentBits.IsMalformed = 0;
387 }
388
389public:
390 static bool classof(const Comment *C) {
391 return C->getCommentKind() >= FirstHTMLTagCommentConstant &&
392 C->getCommentKind() <= LastHTMLTagCommentConstant;
393 }
394
395 StringRef getTagName() const LLVM_READONLY__attribute__((__pure__)) { return TagName; }
396
397 SourceRange getTagNameSourceRange() const LLVM_READONLY__attribute__((__pure__)) {
398 SourceLocation L = getLocation();
399 return SourceRange(L.getLocWithOffset(1),
400 L.getLocWithOffset(1 + TagName.size()));
401 }
402
403 bool isMalformed() const {
404 return HTMLTagCommentBits.IsMalformed;
405 }
406
407 void setIsMalformed() {
408 HTMLTagCommentBits.IsMalformed = 1;
409 }
410};
411
412/// An opening HTML tag with attributes.
413class HTMLStartTagComment : public HTMLTagComment {
414public:
415 class Attribute {
416 public:
417 SourceLocation NameLocBegin;
418 StringRef Name;
419
420 SourceLocation EqualsLoc;
421
422 SourceRange ValueRange;
423 StringRef Value;
424
425 Attribute() { }
426
427 Attribute(SourceLocation NameLocBegin, StringRef Name) :
428 NameLocBegin(NameLocBegin), Name(Name),
429 EqualsLoc(SourceLocation()),
430 ValueRange(SourceRange()), Value(StringRef())
431 { }
432
433 Attribute(SourceLocation NameLocBegin, StringRef Name,
434 SourceLocation EqualsLoc,
435 SourceRange ValueRange, StringRef Value) :
436 NameLocBegin(NameLocBegin), Name(Name),
437 EqualsLoc(EqualsLoc),
438 ValueRange(ValueRange), Value(Value)
439 { }
440
441 SourceLocation getNameLocEnd() const {
442 return NameLocBegin.getLocWithOffset(Name.size());
443 }
444
445 SourceRange getNameRange() const {
446 return SourceRange(NameLocBegin, getNameLocEnd());
447 }
448 };
449
450private:
451 ArrayRef<Attribute> Attributes;
452
453public:
454 HTMLStartTagComment(SourceLocation LocBegin,
455 StringRef TagName) :
456 HTMLTagComment(HTMLStartTagCommentKind,
457 LocBegin, LocBegin.getLocWithOffset(1 + TagName.size()),
458 TagName,
459 LocBegin.getLocWithOffset(1),
460 LocBegin.getLocWithOffset(1 + TagName.size())) {
461 HTMLStartTagCommentBits.IsSelfClosing = false;
462 }
463
464 static bool classof(const Comment *C) {
465 return C->getCommentKind() == HTMLStartTagCommentKind;
466 }
467
468 child_iterator child_begin() const { return nullptr; }
469
470 child_iterator child_end() const { return nullptr; }
471
472 unsigned getNumAttrs() const {
473 return Attributes.size();
474 }
475
476 const Attribute &getAttr(unsigned Idx) const {
477 return Attributes[Idx];
478 }
479
480 void setAttrs(ArrayRef<Attribute> Attrs) {
481 Attributes = Attrs;
482 if (!Attrs.empty()) {
483 const Attribute &Attr = Attrs.back();
484 SourceLocation L = Attr.ValueRange.getEnd();
485 if (L.isValid())
486 Range.setEnd(L);
487 else {
488 Range.setEnd(Attr.getNameLocEnd());
489 }
490 }
491 }
492
493 void setGreaterLoc(SourceLocation GreaterLoc) {
494 Range.setEnd(GreaterLoc);
495 }
496
497 bool isSelfClosing() const {
498 return HTMLStartTagCommentBits.IsSelfClosing;
499 }
500
501 void setSelfClosing() {
502 HTMLStartTagCommentBits.IsSelfClosing = true;
503 }
504};
505
506/// A closing HTML tag.
507class HTMLEndTagComment : public HTMLTagComment {
508public:
509 HTMLEndTagComment(SourceLocation LocBegin,
510 SourceLocation LocEnd,
511 StringRef TagName) :
512 HTMLTagComment(HTMLEndTagCommentKind,
513 LocBegin, LocEnd,
514 TagName,
515 LocBegin.getLocWithOffset(2),
516 LocBegin.getLocWithOffset(2 + TagName.size()))
517 { }
518
519 static bool classof(const Comment *C) {
520 return C->getCommentKind() == HTMLEndTagCommentKind;
521 }
522
523 child_iterator child_begin() const { return nullptr; }
524
525 child_iterator child_end() const { return nullptr; }
526};
527
528/// Block content (contains inline content).
529/// Abstract class.
530class BlockContentComment : public Comment {
531protected:
532 BlockContentComment(CommentKind K,
533 SourceLocation LocBegin,
534 SourceLocation LocEnd) :
535 Comment(K, LocBegin, LocEnd)
536 { }
537
538public:
539 static bool classof(const Comment *C) {
540 return C->getCommentKind() >= FirstBlockContentCommentConstant &&
541 C->getCommentKind() <= LastBlockContentCommentConstant;
542 }
543};
544
545/// A single paragraph that contains inline content.
546class ParagraphComment : public BlockContentComment {
547 ArrayRef<InlineContentComment *> Content;
548
549public:
550 ParagraphComment(ArrayRef<InlineContentComment *> Content) :
551 BlockContentComment(ParagraphCommentKind,
552 SourceLocation(),
553 SourceLocation()),
554 Content(Content) {
555 if (Content.empty()) {
556 ParagraphCommentBits.IsWhitespace = true;
557 ParagraphCommentBits.IsWhitespaceValid = true;
558 return;
559 }
560
561 ParagraphCommentBits.IsWhitespaceValid = false;
562
563 setSourceRange(SourceRange(Content.front()->getBeginLoc(),
564 Content.back()->getEndLoc()));
565 setLocation(Content.front()->getBeginLoc());
566 }
567
568 static bool classof(const Comment *C) {
569 return C->getCommentKind() == ParagraphCommentKind;
570 }
571
572 child_iterator child_begin() const {
573 return reinterpret_cast<child_iterator>(Content.begin());
574 }
575
576 child_iterator child_end() const {
577 return reinterpret_cast<child_iterator>(Content.end());
578 }
579
580 bool isWhitespace() const {
581 if (ParagraphCommentBits.IsWhitespaceValid)
582 return ParagraphCommentBits.IsWhitespace;
583
584 ParagraphCommentBits.IsWhitespace = isWhitespaceNoCache();
585 ParagraphCommentBits.IsWhitespaceValid = true;
586 return ParagraphCommentBits.IsWhitespace;
587 }
588
589private:
590 bool isWhitespaceNoCache() const;
591};
592
593/// A command that has zero or more word-like arguments (number of word-like
594/// arguments depends on command name) and a paragraph as an argument
595/// (e. g., \\brief).
596class BlockCommandComment : public BlockContentComment {
597public:
598 struct Argument {
599 SourceRange Range;
600 StringRef Text;
601
602 Argument() { }
603 Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
604 };
605
606protected:
607 /// Word-like arguments.
608 ArrayRef<Argument> Args;
609
610 /// Paragraph argument.
611 ParagraphComment *Paragraph;
612
613 BlockCommandComment(CommentKind K,
614 SourceLocation LocBegin,
615 SourceLocation LocEnd,
616 unsigned CommandID,
617 CommandMarkerKind CommandMarker) :
618 BlockContentComment(K, LocBegin, LocEnd),
619 Paragraph(nullptr) {
620 setLocation(getCommandNameBeginLoc());
621 BlockCommandCommentBits.CommandID = CommandID;
622 BlockCommandCommentBits.CommandMarker = CommandMarker;
623 }
624
625public:
626 BlockCommandComment(SourceLocation LocBegin,
627 SourceLocation LocEnd,
628 unsigned CommandID,
629 CommandMarkerKind CommandMarker) :
630 BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
631 Paragraph(nullptr) {
632 setLocation(getCommandNameBeginLoc());
633 BlockCommandCommentBits.CommandID = CommandID;
634 BlockCommandCommentBits.CommandMarker = CommandMarker;
635 }
636
637 static bool classof(const Comment *C) {
638 return C->getCommentKind() >= FirstBlockCommandCommentConstant &&
639 C->getCommentKind() <= LastBlockCommandCommentConstant;
640 }
641
642 child_iterator child_begin() const {
643 return reinterpret_cast<child_iterator>(&Paragraph);
644 }
645
646 child_iterator child_end() const {
647 return reinterpret_cast<child_iterator>(&Paragraph + 1);
648 }
649
650 unsigned getCommandID() const {
651 return BlockCommandCommentBits.CommandID;
652 }
653
654 StringRef getCommandName(const CommandTraits &Traits) const {
655 return Traits.getCommandInfo(getCommandID())->Name;
656 }
657
658 SourceLocation getCommandNameBeginLoc() const {
659 return getBeginLoc().getLocWithOffset(1);
660 }
661
662 SourceRange getCommandNameRange(const CommandTraits &Traits) const {
663 StringRef Name = getCommandName(Traits);
664 return SourceRange(getCommandNameBeginLoc(),
665 getBeginLoc().getLocWithOffset(1 + Name.size()));
666 }
667
668 unsigned getNumArgs() const {
669 return Args.size();
670 }
671
672 StringRef getArgText(unsigned Idx) const {
673 return Args[Idx].Text;
674 }
675
676 SourceRange getArgRange(unsigned Idx) const {
677 return Args[Idx].Range;
678 }
679
680 void setArgs(ArrayRef<Argument> A) {
681 Args = A;
682 if (Args.size() > 0) {
683 SourceLocation NewLocEnd = Args.back().Range.getEnd();
684 if (NewLocEnd.isValid())
685 setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
686 }
687 }
688
689 ParagraphComment *getParagraph() const LLVM_READONLY__attribute__((__pure__)) {
690 return Paragraph;
691 }
692
693 bool hasNonWhitespaceParagraph() const {
694 return Paragraph && !Paragraph->isWhitespace();
695 }
696
697 void setParagraph(ParagraphComment *PC) {
698 Paragraph = PC;
699 SourceLocation NewLocEnd = PC->getEndLoc();
700 if (NewLocEnd.isValid())
701 setSourceRange(SourceRange(getBeginLoc(), NewLocEnd));
702 }
703
704 CommandMarkerKind getCommandMarker() const LLVM_READONLY__attribute__((__pure__)) {
705 return static_cast<CommandMarkerKind>(
706 BlockCommandCommentBits.CommandMarker);
707 }
708};
709
710/// Doxygen \\param command.
711class ParamCommandComment : public BlockCommandComment {
712private:
713 /// Parameter index in the function declaration.
714 unsigned ParamIndex;
715
716public:
717 enum : unsigned {
718 InvalidParamIndex = ~0U,
719 VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U
720 };
721
722 ParamCommandComment(SourceLocation LocBegin,
723 SourceLocation LocEnd,
724 unsigned CommandID,
725 CommandMarkerKind CommandMarker) :
726 BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
727 CommandID, CommandMarker),
728 ParamIndex(InvalidParamIndex) {
729 ParamCommandCommentBits.Direction = In;
730 ParamCommandCommentBits.IsDirectionExplicit = false;
731 }
732
733 static bool classof(const Comment *C) {
734 return C->getCommentKind() == ParamCommandCommentKind;
735 }
736
737 enum PassDirection {
738 In,
739 Out,
740 InOut
741 };
742
743 static const char *getDirectionAsString(PassDirection D);
744
745 PassDirection getDirection() const LLVM_READONLY__attribute__((__pure__)) {
746 return static_cast<PassDirection>(ParamCommandCommentBits.Direction);
747 }
748
749 bool isDirectionExplicit() const LLVM_READONLY__attribute__((__pure__)) {
750 return ParamCommandCommentBits.IsDirectionExplicit;
751 }
752
753 void setDirection(PassDirection Direction, bool Explicit) {
754 ParamCommandCommentBits.Direction = Direction;
755 ParamCommandCommentBits.IsDirectionExplicit = Explicit;
756 }
757
758 bool hasParamName() const {
759 return getNumArgs() > 0;
760 }
761
762 StringRef getParamName(const FullComment *FC) const;
763
764 StringRef getParamNameAsWritten() const {
765 return Args[0].Text;
766 }
767
768 SourceRange getParamNameRange() const {
769 return Args[0].Range;
770 }
771
772 bool isParamIndexValid() const LLVM_READONLY__attribute__((__pure__)) {
773 return ParamIndex != InvalidParamIndex;
774 }
775
776 bool isVarArgParam() const LLVM_READONLY__attribute__((__pure__)) {
777 return ParamIndex == VarArgParamIndex;
778 }
779
780 void setIsVarArgParam() {
781 ParamIndex = VarArgParamIndex;
782 assert(isParamIndexValid())((void)0);
783 }
784
785 unsigned getParamIndex() const LLVM_READONLY__attribute__((__pure__)) {
786 assert(isParamIndexValid())((void)0);
787 assert(!isVarArgParam())((void)0);
788 return ParamIndex;
789 }
790
791 void setParamIndex(unsigned Index) {
792 ParamIndex = Index;
793 assert(isParamIndexValid())((void)0);
794 assert(!isVarArgParam())((void)0);
795 }
796};
797
798/// Doxygen \\tparam command, describes a template parameter.
799class TParamCommandComment : public BlockCommandComment {
800private:
801 /// If this template parameter name was resolved (found in template parameter
802 /// list), then this stores a list of position indexes in all template
803 /// parameter lists.
804 ///
805 /// For example:
806 /// \verbatim
807 /// template<typename C, template<typename T> class TT>
808 /// void test(TT<int> aaa);
809 /// \endverbatim
810 /// For C: Position = { 0 }
811 /// For TT: Position = { 1 }
812 /// For T: Position = { 1, 0 }
813 ArrayRef<unsigned> Position;
814
815public:
816 TParamCommandComment(SourceLocation LocBegin,
817 SourceLocation LocEnd,
818 unsigned CommandID,
819 CommandMarkerKind CommandMarker) :
820 BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
821 CommandMarker)
822 { }
823
824 static bool classof(const Comment *C) {
825 return C->getCommentKind() == TParamCommandCommentKind;
826 }
827
828 bool hasParamName() const {
829 return getNumArgs() > 0;
830 }
831
832 StringRef getParamName(const FullComment *FC) const;
833
834 StringRef getParamNameAsWritten() const {
835 return Args[0].Text;
836 }
837
838 SourceRange getParamNameRange() const {
839 return Args[0].Range;
840 }
841
842 bool isPositionValid() const LLVM_READONLY__attribute__((__pure__)) {
843 return !Position.empty();
844 }
845
846 unsigned getDepth() const {
847 assert(isPositionValid())((void)0);
848 return Position.size();
849 }
850
851 unsigned getIndex(unsigned Depth) const {
852 assert(isPositionValid())((void)0);
853 return Position[Depth];
854 }
855
856 void setPosition(ArrayRef<unsigned> NewPosition) {
857 Position = NewPosition;
858 assert(isPositionValid())((void)0);
859 }
860};
861
862/// A line of text contained in a verbatim block.
863class VerbatimBlockLineComment : public Comment {
864 StringRef Text;
865
866public:
867 VerbatimBlockLineComment(SourceLocation LocBegin,
868 StringRef Text) :
869 Comment(VerbatimBlockLineCommentKind,
870 LocBegin,
871 LocBegin.getLocWithOffset(Text.size())),
872 Text(Text)
873 { }
874
875 static bool classof(const Comment *C) {
876 return C->getCommentKind() == VerbatimBlockLineCommentKind;
877 }
878
879 child_iterator child_begin() const { return nullptr; }
880
881 child_iterator child_end() const { return nullptr; }
882
883 StringRef getText() const LLVM_READONLY__attribute__((__pure__)) {
884 return Text;
885 }
886};
887
888/// A verbatim block command (e. g., preformatted code). Verbatim block has an
889/// opening and a closing command and contains multiple lines of text
890/// (VerbatimBlockLineComment nodes).
891class VerbatimBlockComment : public BlockCommandComment {
892protected:
893 StringRef CloseName;
894 SourceLocation CloseNameLocBegin;
895 ArrayRef<VerbatimBlockLineComment *> Lines;
896
897public:
898 VerbatimBlockComment(SourceLocation LocBegin,
899 SourceLocation LocEnd,
900 unsigned CommandID) :
901 BlockCommandComment(VerbatimBlockCommentKind,
902 LocBegin, LocEnd, CommandID,
903 CMK_At) // FIXME: improve source fidelity.
904 { }
905
906 static bool classof(const Comment *C) {
907 return C->getCommentKind() == VerbatimBlockCommentKind;
908 }
909
910 child_iterator child_begin() const {
911 return reinterpret_cast<child_iterator>(Lines.begin());
912 }
913
914 child_iterator child_end() const {
915 return reinterpret_cast<child_iterator>(Lines.end());
916 }
917
918 void setCloseName(StringRef Name, SourceLocation LocBegin) {
919 CloseName = Name;
920 CloseNameLocBegin = LocBegin;
921 }
922
923 void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
924 Lines = L;
925 }
926
927 StringRef getCloseName() const {
928 return CloseName;
929 }
930
931 unsigned getNumLines() const {
932 return Lines.size();
933 }
934
935 StringRef getText(unsigned LineIdx) const {
936 return Lines[LineIdx]->getText();
937 }
938};
939
940/// A verbatim line command. Verbatim line has an opening command, a single
941/// line of text (up to the newline after the opening command) and has no
942/// closing command.
943class VerbatimLineComment : public BlockCommandComment {
944protected:
945 StringRef Text;
946 SourceLocation TextBegin;
947
948public:
949 VerbatimLineComment(SourceLocation LocBegin,
950 SourceLocation LocEnd,
951 unsigned CommandID,
952 SourceLocation TextBegin,
953 StringRef Text) :
954 BlockCommandComment(VerbatimLineCommentKind,
955 LocBegin, LocEnd,
956 CommandID,
957 CMK_At), // FIXME: improve source fidelity.
958 Text(Text),
959 TextBegin(TextBegin)
960 { }
961
962 static bool classof(const Comment *C) {
963 return C->getCommentKind() == VerbatimLineCommentKind;
964 }
965
966 child_iterator child_begin() const { return nullptr; }
967
968 child_iterator child_end() const { return nullptr; }
969
970 StringRef getText() const {
971 return Text;
972 }
973
974 SourceRange getTextRange() const {
975 return SourceRange(TextBegin, getEndLoc());
976 }
977};
978
979/// Information about the declaration, useful to clients of FullComment.
980struct DeclInfo {
981 /// Declaration the comment is actually attached to (in the source).
982 /// Should not be NULL.
983 const Decl *CommentDecl;
984
985 /// CurrentDecl is the declaration with which the FullComment is associated.
986 ///
987 /// It can be different from \c CommentDecl. It happens when we decide
988 /// that the comment originally attached to \c CommentDecl is fine for
989 /// \c CurrentDecl too (for example, for a redeclaration or an overrider of
990 /// \c CommentDecl).
991 ///
992 /// The information in the DeclInfo corresponds to CurrentDecl.
993 const Decl *CurrentDecl;
994
995 /// Parameters that can be referenced by \\param if \c CommentDecl is something
996 /// that we consider a "function".
997 ArrayRef<const ParmVarDecl *> ParamVars;
998
999 /// Function return type if \c CommentDecl is something that we consider
1000 /// a "function".
1001 QualType ReturnType;
1002
1003 /// Template parameters that can be referenced by \\tparam if \c CommentDecl is
1004 /// a template (\c IsTemplateDecl or \c IsTemplatePartialSpecialization is
1005 /// true).
1006 const TemplateParameterList *TemplateParameters;
1007
1008 /// A simplified description of \c CommentDecl kind that should be good enough
1009 /// for documentation rendering purposes.
1010 enum DeclKind {
1011 /// Everything else not explicitly mentioned below.
1012 OtherKind,
1013
1014 /// Something that we consider a "function":
1015 /// \li function,
1016 /// \li function template,
1017 /// \li function template specialization,
1018 /// \li member function,
1019 /// \li member function template,
1020 /// \li member function template specialization,
1021 /// \li ObjC method,
1022 /// \li a typedef for a function pointer, member function pointer,
1023 /// ObjC block.
1024 FunctionKind,
1025
1026 /// Something that we consider a "class":
1027 /// \li class/struct,
1028 /// \li class template,
1029 /// \li class template (partial) specialization.
1030 ClassKind,
1031
1032 /// Something that we consider a "variable":
1033 /// \li namespace scope variables;
1034 /// \li static and non-static class data members;
1035 /// \li enumerators.
1036 VariableKind,
1037
1038 /// A C++ namespace.
1039 NamespaceKind,
1040
1041 /// A C++ typedef-name (a 'typedef' decl specifier or alias-declaration),
1042 /// see \c TypedefNameDecl.
1043 TypedefKind,
1044
1045 /// An enumeration or scoped enumeration.
1046 EnumKind
1047 };
1048
1049 /// What kind of template specialization \c CommentDecl is.
1050 enum TemplateDeclKind {
1051 NotTemplate,
1052 Template,
1053 TemplateSpecialization,
1054 TemplatePartialSpecialization
1055 };
1056
1057 /// If false, only \c CommentDecl is valid.
1058 unsigned IsFilled : 1;
1059
1060 /// Simplified kind of \c CommentDecl, see \c DeclKind enum.
1061 unsigned Kind : 3;
1062
1063 /// Is \c CommentDecl a template declaration.
1064 unsigned TemplateKind : 2;
1065
1066 /// Is \c CommentDecl an ObjCMethodDecl.
1067 unsigned IsObjCMethod : 1;
1068
1069 /// Is \c CommentDecl a non-static member function of C++ class or
1070 /// instance method of ObjC class.
1071 /// Can be true only if \c IsFunctionDecl is true.
1072 unsigned IsInstanceMethod : 1;
1073
1074 /// Is \c CommentDecl a static member function of C++ class or
1075 /// class method of ObjC class.
1076 /// Can be true only if \c IsFunctionDecl is true.
1077 unsigned IsClassMethod : 1;
1078
1079 void fill();
1080
1081 DeclKind getKind() const LLVM_READONLY__attribute__((__pure__)) {
1082 return static_cast<DeclKind>(Kind);
1083 }
1084
1085 TemplateDeclKind getTemplateKind() const LLVM_READONLY__attribute__((__pure__)) {
1086 return static_cast<TemplateDeclKind>(TemplateKind);
1087 }
1088};
1089
1090/// A full comment attached to a declaration, contains block content.
1091class FullComment : public Comment {
1092 ArrayRef<BlockContentComment *> Blocks;
1093 DeclInfo *ThisDeclInfo;
1094
1095public:
1096 FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
1097 Comment(FullCommentKind, SourceLocation(), SourceLocation()),
1098 Blocks(Blocks), ThisDeclInfo(D) {
1099 if (Blocks.empty())
1100 return;
1101
1102 setSourceRange(
1103 SourceRange(Blocks.front()->getBeginLoc(), Blocks.back()->getEndLoc()));
1104 setLocation(Blocks.front()->getBeginLoc());
1105 }
1106
1107 static bool classof(const Comment *C) {
1108 return C->getCommentKind() == FullCommentKind;
1109 }
1110
1111 child_iterator child_begin() const {
1112 return reinterpret_cast<child_iterator>(Blocks.begin());
1113 }
1114
1115 child_iterator child_end() const {
1116 return reinterpret_cast<child_iterator>(Blocks.end());
1117 }
1118
1119 const Decl *getDecl() const LLVM_READONLY__attribute__((__pure__)) {
1120 return ThisDeclInfo->CommentDecl;
1121 }
1122
1123 const DeclInfo *getDeclInfo() const LLVM_READONLY__attribute__((__pure__)) {
1124 if (!ThisDeclInfo->IsFilled)
2
Assuming field 'IsFilled' is 0
3
Taking true branch
1125 ThisDeclInfo->fill();
4
Calling 'DeclInfo::fill'
8
Returning from 'DeclInfo::fill'
1126 return ThisDeclInfo;
1127 }
1128
1129 ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
1130
1131};
1132} // end namespace comments
1133} // end namespace clang
1134
1135#endif
1136