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 Invalid && (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.