clang: lib/AST/RawCommentList.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
18#include "llvm/Support/Allocator.h"
19
20using namespace clang;
21
22namespace {
23
24std::pair<RawComment::CommentKind, bool> getCommentKind(StringRef Comment,
25 bool ParseAllComments) {
26 const size_t MinCommentLength = ParseAllComments ? 2 : 3;
27 if ((Comment.size() < MinCommentLength) || Comment[0] != '/')
29
31 if (Comment[1] == '/') {
32 if (Comment.size() < 3)
34
35 if (Comment[2] == '/')
37 else if (Comment[2] == '!')
39 else
41 } else {
42 assert(Comment.size() >= 4);
43
44
45
46 if (Comment[1] != '*' ||
47 Comment[Comment.size() - 2] != '*' ||
48 Comment[Comment.size() - 1] != '/')
50
51 if (Comment[2] == '*')
53 else if (Comment[2] == '!')
55 else
57 }
58 const bool TrailingComment = (Comment.size() > 3) && (Comment[3] == '<');
59 return std::make_pair(K, TrailingComment);
60}
61
62bool mergedCommentIsTrailingComment(StringRef Comment) {
63 return (Comment.size() > 3) && (Comment[3] == '<');
64}
65
66
67
73 unsigned C1 = SM.getPresumedColumnNumber(L1, &Invalid);
75 unsigned C2 = SM.getPresumedColumnNumber(L2, &Invalid);
76 return && (C1 == C2);
77 }
78 return false;
79}
80}
81
82
83
84
85
86
87
88
90
91 for (unsigned I = P; I != 0; --I) {
92 char C = Buffer[I - 1];
94 return true;
96 return false;
97 }
98
99 return true;
100}
101
102
107
110 Range(SR), RawTextValid(false), BriefTextValid(false),
111 IsAttached(false), IsTrailingComment(false),
112 IsAlmostTrailingComment(false) {
113
116 return;
117 }
118
119
120 std::pair<CommentKind, bool> K =
122
123
126 unsigned BeginOffset;
127 std::tie(BeginFileID, BeginOffset) =
128 SourceMgr.getDecomposedLoc(Range.getBegin());
129 if (BeginOffset != 0) {
131 const char *Buffer =
132 SourceMgr.getBufferData(BeginFileID, &Invalid).data();
133 IsTrailingComment |=
135 }
136 }
137
138 if (!Merged) {
139 Kind = K.first;
140 IsTrailingComment |= K.second;
141
142 IsAlmostTrailingComment =
143 RawText.starts_with("//<") || RawText.starts_with("/*<");
144 } else {
146 IsTrailingComment =
147 IsTrailingComment || mergedCommentIsTrailingComment(RawText);
148 }
149}
150
151StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const {
154 unsigned BeginOffset;
155 unsigned EndOffset;
156
157 std::tie(BeginFileID, BeginOffset) =
158 SourceMgr.getDecomposedLoc(Range.getBegin());
159 std::tie(EndFileID, EndOffset) = SourceMgr.getDecomposedLoc(Range.getEnd());
160
161 const unsigned Length = EndOffset - BeginOffset;
162 if (Length < 2)
163 return StringRef();
164
165
166 assert(BeginFileID == EndFileID);
167
169 const char *BufferStart = SourceMgr.getBufferData(BeginFileID,
172 return StringRef();
173
174 return StringRef(BufferStart + BeginOffset, Length);
175}
176
177const char *RawComment::extractBriefText(const ASTContext &Context) const {
178
179 (void)getRawText(Context.getSourceManager());
180
181
182
183
184 llvm::BumpPtrAllocator Allocator;
185
187 Context.getCommentCommandTraits(),
189 RawText.begin(), RawText.end());
191
192 const std::string Result = P.Parse();
193 const unsigned BriefTextLength = Result.size();
194 char *BriefTextPtr = new (Context) char[BriefTextLength + 1];
195 memcpy(BriefTextPtr, Result.c_str(), BriefTextLength + 1);
196 BriefText = BriefTextPtr;
197 BriefTextValid = true;
198
199 return BriefTextPtr;
200}
201
204 const Decl *D) const {
205
206 (void)getRawText(Context.getSourceManager());
207
208 comments::Lexer L(Context.getAllocator(), Context.getDiagnostics(),
209 Context.getCommentCommandTraits(),
211 RawText.begin(), RawText.end());
212 comments::Sema S(Context.getAllocator(), Context.getSourceManager(),
213 Context.getDiagnostics(),
214 Context.getCommentCommandTraits(),
215 PP);
217 comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(),
218 Context.getDiagnostics(),
219 Context.getCommentCommandTraits());
220
222}
223
226 unsigned MaxNewlinesAllowed) {
229
230
231 if (Loc1Info.first != Loc2Info.first)
232 return false;
233
235 const char *Buffer = SM.getBufferData(Loc1Info.first, &Invalid).data();
237 return false;
238
239 unsigned NumNewlines = 0;
240 assert(Loc1Info.second <= Loc2Info.second && "Loc1 after Loc2!");
241
242 for (unsigned I = Loc1Info.second; I != Loc2Info.second; ++I) {
243 switch (Buffer[I]) {
244 default:
245 return false;
246 case ' ':
247 case '\t':
248 case '\f':
249 case '\v':
250 break;
251 case '\r':
252 case '\n':
253 ++NumNewlines;
254
255
256
257 if (NumNewlines > MaxNewlinesAllowed)
258 return false;
259
260
261 if (I + 1 != Loc2Info.second &&
262 (Buffer[I + 1] == '\n' || Buffer[I + 1] == '\r') &&
263 Buffer[I] != Buffer[I + 1])
264 ++I;
265 break;
266 }
267 }
268
269 return true;
270}
271
274 llvm::BumpPtrAllocator &Allocator) {
276 return;
277
278
280 return;
281
283
284 const FileID CommentFile = Loc.first;
285 const unsigned CommentOffset = Loc.second;
286
287
288
289 auto &OC = OrderedComments[CommentFile];
290 if (OC.empty()) {
291 OC[CommentOffset] = new (Allocator) RawComment(RC);
292 return;
293 }
294
295 const RawComment &C1 = *OC.rbegin()->second;
297
298
299
300
301
302
303
304
305
306
307
308
309
310
314 commentsStartOnSameColumn(SourceMgr, C1, C2))) &&
316 1)) {
318 *OrderedComments[CommentFile].rbegin()->second =
319 RawComment(SourceMgr, MergedRange, CommentOpts, true);
320 } else {
321 OrderedComments[CommentFile][CommentOffset] =
323 }
324}
325
326const std::map<unsigned, RawComment *> *
328 auto CommentsInFile = OrderedComments.find(File);
329 if (CommentsInFile == OrderedComments.end())
330 return nullptr;
331
332 return &CommentsInFile->second;
333}
334
336
338 unsigned Offset) const {
339 auto Cached = CommentBeginLine.find(C);
340 if (Cached != CommentBeginLine.end())
341 return Cached->second;
342 const unsigned Line = SourceMgr.getLineNumber(File, Offset);
343 CommentBeginLine[C] = Line;
345}
346
348 auto Cached = CommentEndOffset.find(C);
349 if (Cached != CommentEndOffset.end())
350 return Cached->second;
351 const unsigned Offset =
352 SourceMgr.getDecomposedLoc(C->getSourceRange().getEnd()).second;
353 CommentEndOffset[C] = Offset;
354 return Offset;
355}
356
359 llvm::StringRef CommentText = getRawText(SourceMgr);
360 if (CommentText.empty())
361 return "";
362
367
368 auto LastChar = Result.find_last_not_of('\n');
370
372}
373
374std::vectorRawComment::CommentLine
377 llvm::StringRef CommentText = getRawText(SourceMgr);
378 if (CommentText.empty())
379 return {};
380
381 llvm::BumpPtrAllocator Allocator;
382
383
387 CommentText.begin(), CommentText.end(),
388 false);
389
390 std::vectorRawComment::CommentLine Result;
391
392
393
394
395 unsigned IndentColumn = 0;
396
397
398
399
400
401
402
403
404
405 unsigned PreviousLine = 0;
406
407
408
409
410 auto LexLine = [&](bool IsFirstLine) -> bool {
412
413
416 return false;
418 PresumedLoc Loc = SourceMgr.getPresumedLoc(Tok.getLocation());
419 if (Loc.getLine() != PreviousLine) {
420 Result.emplace_back("", Loc, Loc);
421 PreviousLine = Loc.getLine();
422 }
423 return true;
424 }
426 llvm::StringRef TokText = L.getSpelling(Tok, SourceMgr);
427 bool LocInvalid = false;
428 unsigned TokColumn =
429 SourceMgr.getSpellingColumnNumber(Tok.getLocation(), &LocInvalid);
430 assert(!LocInvalid && "getFormattedText for invalid location");
431
432
433 size_t WhitespaceLen = TokText.find_first_not_of(" \t");
434 if (WhitespaceLen == StringRef::npos)
435 WhitespaceLen = TokText.size();
436
437
438 if (IsFirstLine)
439 IndentColumn = TokColumn + WhitespaceLen;
440
441
442
443
444 unsigned SkipLen =
445 IsFirstLine
446 ? WhitespaceLen
447 : std::min<size_t>(
448 WhitespaceLen,
449 std::max(static_cast<int>(IndentColumn) - TokColumn, 0));
450 llvm::StringRef Trimmed = TokText.drop_front(SkipLen);
451 Line += Trimmed;
452
454 SourceMgr.getPresumedLoc(Tok.getLocation().getLocWithOffset(SkipLen));
455
456
459
460 PresumedLoc End = SourceMgr.getPresumedLoc(Tok.getLocation());
461 if (End.getLine() != PreviousLine) {
462 Result.emplace_back(Line, Begin, End);
463 PreviousLine = End.getLine();
464 }
465 return true;
466 }
468 }
469 PresumedLoc End = SourceMgr.getPresumedLoc(Tok.getLocation());
470 Result.emplace_back(Line, Begin, End);
471
472 return false;
473 };
474
475
476 if (!LexLine(true))
478
479 while (LexLine(false))
480 ;
482}
Defines the clang::ASTContext interface.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Decl - This represents one declaration (or definition), e.g.
Concrete class used by the front-end to report problems and issues.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getLine() const
Return the presumed line number of this location.
Encodes a location in the source.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
std::pair< FileID, unsigned > FileIDAndOffset
LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)
Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.
@ Result
The result type of a method or function.