Bug Summary

File:tools/clang/lib/AST/Comment.cpp
Warning:line 369, column 14
Called C++ object pointer is null

Annotated Source Code

/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp

1//===--- Comment.cpp - Comment AST node implementation --------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/AST/Comment.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclObjC.h"
14#include "clang/AST/DeclTemplate.h"
15#include "clang/Basic/CharInfo.h"
16#include "llvm/Support/ErrorHandling.h"
17
18namespace clang {
19namespace comments {
20
21const char *Comment::getCommentKindName() const {
22 switch (getCommentKind()) {
23 case NoCommentKind: return "NoCommentKind";
24#define ABSTRACT_COMMENT(COMMENT)
25#define COMMENT(CLASS, PARENT) \
26 case CLASS##Kind: \
27 return #CLASS;
28#include "clang/AST/CommentNodes.inc"
29#undef COMMENT
30#undef ABSTRACT_COMMENT
31 }
32 llvm_unreachable("Unknown comment kind!")::llvm::llvm_unreachable_internal("Unknown comment kind!", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 32)
;
33}
34
35namespace {
36struct good {};
37struct bad {};
38
39template <typename T>
40good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
41 return good();
42}
43
44LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__))
45static inline bad implements_child_begin_end(
46 Comment::child_iterator (Comment::*)() const) {
47 return bad();
48}
49
50#define ASSERT_IMPLEMENTS_child_begin(function) \
51 (void) good(implements_child_begin_end(function))
52
53LLVM_ATTRIBUTE_UNUSED__attribute__((__unused__))
54static inline void CheckCommentASTNodes() {
55#define ABSTRACT_COMMENT(COMMENT)
56#define COMMENT(CLASS, PARENT) \
57 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_begin); \
58 ASSERT_IMPLEMENTS_child_begin(&CLASS::child_end);
59#include "clang/AST/CommentNodes.inc"
60#undef COMMENT
61#undef ABSTRACT_COMMENT
62}
63
64#undef ASSERT_IMPLEMENTS_child_begin
65
66} // end unnamed namespace
67
68Comment::child_iterator Comment::child_begin() const {
69 switch (getCommentKind()) {
70 case NoCommentKind: llvm_unreachable("comment without a kind")::llvm::llvm_unreachable_internal("comment without a kind", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 70)
;
71#define ABSTRACT_COMMENT(COMMENT)
72#define COMMENT(CLASS, PARENT) \
73 case CLASS##Kind: \
74 return static_cast<const CLASS *>(this)->child_begin();
75#include "clang/AST/CommentNodes.inc"
76#undef COMMENT
77#undef ABSTRACT_COMMENT
78 }
79 llvm_unreachable("Unknown comment kind!")::llvm::llvm_unreachable_internal("Unknown comment kind!", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 79)
;
80}
81
82Comment::child_iterator Comment::child_end() 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-6.0~svn318631/tools/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_end();
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-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 93)
;
94}
95
96bool TextComment::isWhitespaceNoCache() const {
97 for (StringRef::const_iterator I = Text.begin(), E = Text.end();
98 I != E; ++I) {
99 if (!clang::isWhitespace(*I))
100 return false;
101 }
102 return true;
103}
104
105bool ParagraphComment::isWhitespaceNoCache() const {
106 for (child_iterator I = child_begin(), E = child_end(); I != E; ++I) {
107 if (const TextComment *TC = dyn_cast<TextComment>(*I)) {
108 if (!TC->isWhitespace())
109 return false;
110 } else
111 return false;
112 }
113 return true;
114}
115
116static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
117 TypeLoc TL = SrcTL.IgnoreParens();
118
119 // Look through attribute types.
120 if (AttributedTypeLoc AttributeTL = TL.getAs<AttributedTypeLoc>())
121 return AttributeTL.getModifiedLoc();
122 // Look through qualified types.
123 if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>())
124 return QualifiedTL.getUnqualifiedLoc();
125 // Look through pointer types.
126 if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>())
127 return PointerTL.getPointeeLoc().getUnqualifiedLoc();
128 // Look through reference types.
129 if (ReferenceTypeLoc ReferenceTL = TL.getAs<ReferenceTypeLoc>())
130 return ReferenceTL.getPointeeLoc().getUnqualifiedLoc();
131 // Look through adjusted types.
132 if (AdjustedTypeLoc ATL = TL.getAs<AdjustedTypeLoc>())
133 return ATL.getOriginalLoc();
134 if (BlockPointerTypeLoc BlockPointerTL = TL.getAs<BlockPointerTypeLoc>())
135 return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
136 if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())
137 return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
138 if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())
139 return ETL.getNamedTypeLoc();
140
141 return TL;
142}
143
144static bool getFunctionTypeLoc(TypeLoc TL, FunctionTypeLoc &ResFTL) {
145 TypeLoc PrevTL;
146 while (PrevTL != TL) {
147 PrevTL = TL;
148 TL = lookThroughTypedefOrTypeAliasLocs(TL);
149 }
150
151 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
152 ResFTL = FTL;
153 return true;
154 }
155
156 if (TemplateSpecializationTypeLoc STL =
157 TL.getAs<TemplateSpecializationTypeLoc>()) {
158 // If we have a typedef to a template specialization with exactly one
159 // template argument of a function type, this looks like std::function,
160 // boost::function, or other function wrapper. Treat these typedefs as
161 // functions.
162 if (STL.getNumArgs() != 1)
163 return false;
164 TemplateArgumentLoc MaybeFunction = STL.getArgLoc(0);
165 if (MaybeFunction.getArgument().getKind() != TemplateArgument::Type)
166 return false;
167 TypeSourceInfo *MaybeFunctionTSI = MaybeFunction.getTypeSourceInfo();
168 TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc();
169 if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
170 ResFTL = FTL;
171 return true;
172 }
173 }
174
175 return false;
176}
177
178const char *ParamCommandComment::getDirectionAsString(PassDirection D) {
179 switch (D) {
180 case ParamCommandComment::In:
181 return "[in]";
182 case ParamCommandComment::Out:
183 return "[out]";
184 case ParamCommandComment::InOut:
185 return "[in,out]";
186 }
187 llvm_unreachable("unknown PassDirection")::llvm::llvm_unreachable_internal("unknown PassDirection", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 187)
;
188}
189
190void DeclInfo::fill() {
191 assert(!IsFilled)(static_cast <bool> (!IsFilled) ? void (0) : __assert_fail
("!IsFilled", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 191, __extension__ __PRETTY_FUNCTION__))
;
192
193 // Set defaults.
194 Kind = OtherKind;
195 TemplateKind = NotTemplate;
196 IsObjCMethod = false;
197 IsInstanceMethod = false;
198 IsClassMethod = false;
199 ParamVars = None;
200 TemplateParameters = nullptr;
5
Null pointer value stored to field 'TemplateParameters'
201
202 if (!CommentDecl) {
6
Assuming the condition is false
7
Taking false branch
203 // If there is no declaration, the defaults is our only guess.
204 IsFilled = true;
205 return;
206 }
207 CurrentDecl = CommentDecl;
208
209 Decl::Kind K = CommentDecl->getKind();
210 switch (K) {
8
Control jumps to the 'default' case at line 211
211 default:
212 // Defaults are should be good for declarations we don't handle explicitly.
213 break;
9
Execution continues on line 354
214 case Decl::Function:
215 case Decl::CXXMethod:
216 case Decl::CXXConstructor:
217 case Decl::CXXDestructor:
218 case Decl::CXXConversion: {
219 const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl);
220 Kind = FunctionKind;
221 ParamVars = FD->parameters();
222 ReturnType = FD->getReturnType();
223 unsigned NumLists = FD->getNumTemplateParameterLists();
224 if (NumLists != 0) {
225 TemplateKind = TemplateSpecialization;
226 TemplateParameters =
227 FD->getTemplateParameterList(NumLists - 1);
228 }
229
230 if (K == Decl::CXXMethod || K == Decl::CXXConstructor ||
231 K == Decl::CXXDestructor || K == Decl::CXXConversion) {
232 const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl);
233 IsInstanceMethod = MD->isInstance();
234 IsClassMethod = !IsInstanceMethod;
235 }
236 break;
237 }
238 case Decl::ObjCMethod: {
239 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl);
240 Kind = FunctionKind;
241 ParamVars = MD->parameters();
242 ReturnType = MD->getReturnType();
243 IsObjCMethod = true;
244 IsInstanceMethod = MD->isInstanceMethod();
245 IsClassMethod = !IsInstanceMethod;
246 break;
247 }
248 case Decl::FunctionTemplate: {
249 const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl);
250 Kind = FunctionKind;
251 TemplateKind = Template;
252 const FunctionDecl *FD = FTD->getTemplatedDecl();
253 ParamVars = FD->parameters();
254 ReturnType = FD->getReturnType();
255 TemplateParameters = FTD->getTemplateParameters();
256 break;
257 }
258 case Decl::ClassTemplate: {
259 const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl);
260 Kind = ClassKind;
261 TemplateKind = Template;
262 TemplateParameters = CTD->getTemplateParameters();
263 break;
264 }
265 case Decl::ClassTemplatePartialSpecialization: {
266 const ClassTemplatePartialSpecializationDecl *CTPSD =
267 cast<ClassTemplatePartialSpecializationDecl>(CommentDecl);
268 Kind = ClassKind;
269 TemplateKind = TemplatePartialSpecialization;
270 TemplateParameters = CTPSD->getTemplateParameters();
271 break;
272 }
273 case Decl::ClassTemplateSpecialization:
274 Kind = ClassKind;
275 TemplateKind = TemplateSpecialization;
276 break;
277 case Decl::Record:
278 case Decl::CXXRecord:
279 Kind = ClassKind;
280 break;
281 case Decl::Var:
282 case Decl::Field:
283 case Decl::EnumConstant:
284 case Decl::ObjCIvar:
285 case Decl::ObjCAtDefsField:
286 case Decl::ObjCProperty: {
287 const TypeSourceInfo *TSI;
288 if (const auto *VD = dyn_cast<DeclaratorDecl>(CommentDecl))
289 TSI = VD->getTypeSourceInfo();
290 else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(CommentDecl))
291 TSI = PD->getTypeSourceInfo();
292 else
293 TSI = nullptr;
294 if (TSI) {
295 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
296 FunctionTypeLoc FTL;
297 if (getFunctionTypeLoc(TL, FTL)) {
298 ParamVars = FTL.getParams();
299 ReturnType = FTL.getReturnLoc().getType();
300 }
301 }
302 Kind = VariableKind;
303 break;
304 }
305 case Decl::Namespace:
306 Kind = NamespaceKind;
307 break;
308 case Decl::TypeAlias:
309 case Decl::Typedef: {
310 Kind = TypedefKind;
311 // If this is a typedef / using to something we consider a function, extract
312 // arguments and return type.
313 const TypeSourceInfo *TSI =
314 K == Decl::Typedef
315 ? cast<TypedefDecl>(CommentDecl)->getTypeSourceInfo()
316 : cast<TypeAliasDecl>(CommentDecl)->getTypeSourceInfo();
317 if (!TSI)
318 break;
319 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
320 FunctionTypeLoc FTL;
321 if (getFunctionTypeLoc(TL, FTL)) {
322 Kind = FunctionKind;
323 ParamVars = FTL.getParams();
324 ReturnType = FTL.getReturnLoc().getType();
325 }
326 break;
327 }
328 case Decl::TypeAliasTemplate: {
329 const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl);
330 Kind = TypedefKind;
331 TemplateKind = Template;
332 TemplateParameters = TAT->getTemplateParameters();
333 TypeAliasDecl *TAD = TAT->getTemplatedDecl();
334 if (!TAD)
335 break;
336
337 const TypeSourceInfo *TSI = TAD->getTypeSourceInfo();
338 if (!TSI)
339 break;
340 TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc();
341 FunctionTypeLoc FTL;
342 if (getFunctionTypeLoc(TL, FTL)) {
343 Kind = FunctionKind;
344 ParamVars = FTL.getParams();
345 ReturnType = FTL.getReturnLoc().getType();
346 }
347 break;
348 }
349 case Decl::Enum:
350 Kind = EnumKind;
351 break;
352 }
353
354 IsFilled = true;
355}
356
357StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
358 assert(isParamIndexValid())(static_cast <bool> (isParamIndexValid()) ? void (0) : __assert_fail
("isParamIndexValid()", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 358, __extension__ __PRETTY_FUNCTION__))
;
359 if (isVarArgParam())
360 return "...";
361 return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
362}
363
364StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
365 assert(isPositionValid())(static_cast <bool> (isPositionValid()) ? void (0) : __assert_fail
("isPositionValid()", "/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/lib/AST/Comment.cpp"
, 365, __extension__ __PRETTY_FUNCTION__))
;
366 const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
1
Calling 'FullComment::getDeclInfo'
11
Returning from 'FullComment::getDeclInfo'
12
'TPL' initialized to a null pointer value
367 for (unsigned i = 0, e = getDepth(); i != e; ++i) {
13
Assuming 'i' is not equal to 'e'
14
Loop condition is true. Entering loop body
368 if (i == e-1)
15
Assuming the condition is true
16
Taking true branch
369 return TPL->getParam(getIndex(i))->getName();
17
Called C++ object pointer is null
370 const NamedDecl *Param = TPL->getParam(getIndex(i));
371 if (const TemplateTemplateParmDecl *TTP =
372 dyn_cast<TemplateTemplateParmDecl>(Param))
373 TPL = TTP->getTemplateParameters();
374 }
375 return "";
376}
377
378} // end namespace comments
379} // end namespace clang
380

/build/llvm-toolchain-snapshot-6.0~svn318631/tools/clang/include/clang/AST/Comment.h

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