clang: lib/AST/CommentParser.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

16#include "llvm/Support/ErrorHandling.h"

17

19

21 for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {

23 return false;

24 }

25 return true;

26}

27

28namespace comments {

29

30

32 llvm::BumpPtrAllocator &Allocator;

34

35

36 bool NoMoreInterestingTokens;

37

38

40

41

42 struct Position {

43 const char *BufferStart;

44 const char *BufferEnd;

45 const char *BufferPtr;

47 unsigned CurToken;

48 };

49

50

51 Position Pos;

52

53 bool isEnd() const {

54 return Pos.CurToken >= Toks.size();

55 }

56

57

58 void setupBuffer() {

59 assert(!isEnd());

60 const Token &Tok = Toks[Pos.CurToken];

61

62 Pos.BufferStart = Tok.getText().begin();

63 Pos.BufferEnd = Tok.getText().end();

64 Pos.BufferPtr = Pos.BufferStart;

65 Pos.BufferStartLoc = Tok.getLocation();

66 }

67

69 const unsigned CharNo = Pos.BufferPtr - Pos.BufferStart;

71 }

72

73 char peek() const {

74 assert(!isEnd());

75 assert(Pos.BufferPtr != Pos.BufferEnd);

76 return *Pos.BufferPtr;

77 }

78

79 void consumeChar() {

80 assert(!isEnd());

81 assert(Pos.BufferPtr != Pos.BufferEnd);

82 Pos.BufferPtr++;

83 if (Pos.BufferPtr == Pos.BufferEnd) {

84 Pos.CurToken++;

85 if (isEnd() && !addToken())

86 return;

87

88 assert(!isEnd());

89 setupBuffer();

90 }

91 }

92

93

95 unsigned BracketCount = 0;

96 while (!isEnd()) {

97 const char C = peek();

98 WordText.push_back(C);

99 consumeChar();

100 switch (C) {

101 case '<': {

102 BracketCount++;

103 break;

104 }

105 case '>': {

106 BracketCount--;

107 if (!BracketCount)

108 return true;

109 break;

110 }

111 default:

112 break;

113 }

114 }

115 return false;

116 }

117

118

119

120

121 bool addToken() {

122 if (NoMoreInterestingTokens)

123 return false;

124

126

127 Token Newline = P.Tok;

128 P.consumeToken();

130 P.putBack(Newline);

131 NoMoreInterestingTokens = true;

132 return false;

133 }

134 }

136 NoMoreInterestingTokens = true;

137 return false;

138 }

139

140 Toks.push_back(P.Tok);

141 P.consumeToken();

142 if (Toks.size() == 1)

143 setupBuffer();

144 return true;

145 }

146

147 void consumeWhitespace() {

148 while (!isEnd()) {

150 consumeChar();

151 else

152 break;

153 }

154 }

155

158 const char *TokBegin,

159 unsigned TokLength,

160 StringRef Text) {

161 Result.setLocation(Loc);

163 Result.setLength(TokLength);

164#ifndef NDEBUG

165 Result.TextPtr = "";

167#endif

169 }

170

171public:

173 Allocator(Allocator), P(P), NoMoreInterestingTokens(false) {

174 Pos.CurToken = 0;

175 addToken();

176 }

177

178

180 if (isEnd())

181 return false;

182

183

184

185 Position SavedPos = Pos;

186

187

188 consumeWhitespace();

190 const char *WordBegin = Pos.BufferPtr;

192

193 while (!isEnd()) {

194 const char C = peek();

195

196

198 if (C == '<') {

199 if (!lexTemplate(WordText))

200 return false;

201 } else {

202 WordText.push_back(C);

203 consumeChar();

204 }

205 } else {

206 consumeChar();

207 break;

208 }

209 }

210

211 const unsigned Length = WordText.size();

212 if (Length == 0) {

213 Pos = SavedPos;

214 return false;

215 }

216

217 char *TextPtr = Allocator.Allocate<char>(Length + 1);

218

219 memcpy(TextPtr, WordText.c_str(), Length + 1);

220 StringRef Text = StringRef(TextPtr, Length);

221

222 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);

223 return true;

224 }

225

226

228 unsigned Offset = 1;

229

230

231

232

233 while (isWhitespace(*(Pos.BufferPtr - Offset)))

234 Offset++;

235

236

237

238 llvm::StringRef LineStart(Pos.BufferPtr - Offset - 3, 4);

239 return LineStart.starts_with("\\par") || LineStart.starts_with("@par");

240 }

241

242

244 if (isEnd())

245 return false;

246

247 Position SavedPos = Pos;

248

249 consumeWhitespace();

251 const char *WordBegin = Pos.BufferPtr;

253

255 return false;

256

257

258

259 while (!isEnd()) {

260 WordText.push_back(peek());

261 if (Pos.BufferPtr + 1 == Pos.BufferEnd) {

262 consumeChar();

263 break;

264 }

265 consumeChar();

266 }

267

268 unsigned Length = WordText.size();

269 if (Length == 0) {

270 Pos = SavedPos;

271 return false;

272 }

273

274 char *TextPtr = Allocator.Allocate<char>(Length + 1);

275

276 memcpy(TextPtr, WordText.c_str(), Length + 1);

277 StringRef Text = StringRef(TextPtr, Length);

278

279 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);

280 return true;

281 }

282

283

285 if (isEnd())

286 return false;

287

288 Position SavedPos = Pos;

289

290 consumeWhitespace();

292 const char *WordBegin = Pos.BufferPtr;

294 while (!isEnd()) {

295 const char C = peek();

297 WordText.push_back(C);

298 consumeChar();

299 } else

300 break;

301 }

302 const unsigned Length = WordText.size();

303 if (Length == 0) {

304 Pos = SavedPos;

305 return false;

306 }

307

308 char *TextPtr = Allocator.Allocate<char>(Length + 1);

309

310 memcpy(TextPtr, WordText.c_str(), Length + 1);

311 StringRef Text = StringRef(TextPtr, Length);

312

313 formTokenWithChars(Tok, Loc, WordBegin, Length, Text);

314 return true;

315 }

316

318 if (isEnd())

319 return false;

320

321 Position SavedPos = Pos;

322

323 consumeWhitespace();

325 const char *WordBegin = Pos.BufferPtr;

327 bool Error = false;

328 if (!isEnd()) {

329 const char C = peek();

330 if (C == OpenDelim) {

331 WordText.push_back(C);

332 consumeChar();

333 } else

335 }

336 char C = '\0';

337 while (Error && !isEnd()) {

338 C = peek();

339 WordText.push_back(C);

340 consumeChar();

341 if (C == CloseDelim)

342 break;

343 }

344 if (Error && C != CloseDelim)

346

348 Pos = SavedPos;

349 return false;

350 }

351

352 const unsigned Length = WordText.size();

353 char *TextPtr = Allocator.Allocate<char>(Length + 1);

354

355 memcpy(TextPtr, WordText.c_str(), Length + 1);

356 StringRef Text = StringRef(TextPtr, Length);

357

358 formTokenWithChars(Tok, Loc, WordBegin,

359 Pos.BufferPtr - WordBegin, Text);

360 return true;

361 }

362

363

365 if (isEnd())

366 return;

367

368 bool HavePartialTok = false;

369 Token PartialTok;

370 if (Pos.BufferPtr != Pos.BufferStart) {

371 formTokenWithChars(PartialTok, getSourceLocation(),

372 Pos.BufferPtr, Pos.BufferEnd - Pos.BufferPtr,

373 StringRef(Pos.BufferPtr,

374 Pos.BufferEnd - Pos.BufferPtr));

375 HavePartialTok = true;

376 Pos.CurToken++;

377 }

378

379 P.putBack(ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));

380 Pos.CurToken = Toks.size();

381

382 if (HavePartialTok)

383 P.putBack(PartialTok);

384 }

385};

386

387Parser::Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,

390 L(L), S(S), Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags),

391 Traits(Traits) {

392 consumeToken();

393}

394

398

399

401 S.actOnParamCommandDirectionArg(PC,

405

406 if (Retokenizer.lexWord(Arg))

407 S.actOnParamCommandParamNameArg(PC,

411}

412

416 if (Retokenizer.lexWord(Arg))

417 S.actOnTParamCommandParamNameArg(TPC,

421}

422

425 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))

427 unsigned ParsedArgs = 0;

429 while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {

432 ParsedArgs++;

433 }

434

435 return ArrayRef(Args, ParsedArgs);

436}

437

440 unsigned NumArgs) {

441 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))

443 unsigned ParsedArgs = 0;

445

446 while (ParsedArgs < NumArgs && Retokenizer.lexType(Arg)) {

449 ParsedArgs++;

450 }

451

452 return ArrayRef(Args, ParsedArgs);

453}

454

457 unsigned NumArgs) {

458 assert(NumArgs > 0);

459 auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))

461 unsigned ParsedArgs = 0;

463

464 while (ParsedArgs < NumArgs && Retokenizer.lexParHeading(Arg)) {

467 ParsedArgs++;

468 }

469

470 return ArrayRef(Args, ParsedArgs);

471}

472

475

479 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());

483 PC = S.actOnParamCommandStart(Tok.getLocation(),

484 Tok.getEndLocation(),

485 Tok.getCommandID(),

486 CommandMarker);

488 TPC = S.actOnTParamCommandStart(Tok.getLocation(),

489 Tok.getEndLocation(),

490 Tok.getCommandID(),

491 CommandMarker);

492 } else {

493 BC = S.actOnBlockCommandStart(Tok.getLocation(),

494 Tok.getEndLocation(),

495 Tok.getCommandID(),

496 CommandMarker);

497 }

498 consumeToken();

499

500 if (isTokBlockCommand()) {

501

502

504 if (PC) {

505 S.actOnParamCommandFinish(PC, Paragraph);

506 return PC;

507 } else if (TPC) {

508 S.actOnTParamCommandFinish(TPC, Paragraph);

509 return TPC;

510 } else {

511 S.actOnBlockCommandFinish(BC, Paragraph);

512 return BC;

513 }

514 }

515

516 if (PC || TPC || Info->NumArgs > 0) {

517

518

520

521 if (PC)

523 else if (TPC)

526 S.actOnBlockCommandArgs(

529 S.actOnBlockCommandArgs(BC,

531 else

533

535 }

536

537

538

539 bool EmptyParagraph = false;

540 if (isTokBlockCommand())

541 EmptyParagraph = true;

543 Token PrevTok = Tok;

544 consumeToken();

545 EmptyParagraph = isTokBlockCommand();

546 putBack(PrevTok);

547 }

548

550 if (EmptyParagraph)

551 Paragraph = S.actOnParagraphComment({});

552 else {

554

555

557 }

558

559 if (PC) {

560 S.actOnParamCommandFinish(PC, Paragraph);

561 return PC;

562 } else if (TPC) {

563 S.actOnTParamCommandFinish(TPC, Paragraph);

564 return TPC;

565 } else {

566 S.actOnBlockCommandFinish(BC, Paragraph);

567 return BC;

568 }

569}

570

575 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());

576

577 const Token CommandTok = Tok;

578 consumeToken();

579

583

587

588 if (Args.size() < Info->NumArgs) {

590 diag::warn_doc_inline_command_not_enough_arguments)

594 }

595

597

598 return IC;

599}

600

604 S.actOnHTMLStartTagStart(Tok.getLocation(),

605 Tok.getHTMLTagStartName());

606 consumeToken();

607

609 while (true) {

610 switch (Tok.getKind()) {

612 Token Ident = Tok;

613 consumeToken();

617 continue;

618 }

619 Token Equals = Tok;

620 consumeToken();

622 Diag(Tok.getLocation(),

623 diag::warn_doc_html_start_tag_expected_quoted_string)

629 consumeToken();

630 continue;

631 }

635 Equals.getLocation(),

637 Tok.getEndLocation()),

638 Tok.getHTMLQuotedString()));

639 consumeToken();

640 continue;

641 }

642

644 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),

646 false);

647 consumeToken();

648 return HST;

649

651 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),

653 true);

654 consumeToken();

655 return HST;

656

659 Diag(Tok.getLocation(),

660 diag::warn_doc_html_start_tag_expected_ident_or_greater);

663 consumeToken();

667 continue;

668

669 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),

671 false);

672 return HST;

673

674 default:

675

676 S.actOnHTMLStartTagFinish(HST, S.copyArray(ArrayRef(Attrs)),

678 false);

679 bool StartLineInvalid;

680 const unsigned StartLine = SourceMgr.getPresumedLineNumber(

682 &StartLineInvalid);

683 bool EndLineInvalid;

684 const unsigned EndLine = SourceMgr.getPresumedLineNumber(

685 Tok.getLocation(),

686 &EndLineInvalid);

687 if (StartLineInvalid || EndLineInvalid || StartLine == EndLine)

688 Diag(Tok.getLocation(),

689 diag::warn_doc_html_start_tag_expected_ident_or_greater)

691 else {

692 Diag(Tok.getLocation(),

693 diag::warn_doc_html_start_tag_expected_ident_or_greater);

694 Diag(HST->getLocation(), diag::note_doc_html_tag_started_here)

696 }

697 return HST;

698 }

699 }

700}

701

704 Token TokEndTag = Tok;

705 consumeToken();

708 Loc = Tok.getLocation();

709 consumeToken();

710 }

711

712 return S.actOnHTMLEndTag(TokEndTag.getLocation(),

713 Loc,

715}

716

719

720 while (true) {

721 switch (Tok.getKind()) {

725 break;

726

728 Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),

729 Tok.getEndLocation(),

730 Tok.getUnknownCommandName()));

731 consumeToken();

732 continue;

733

736 const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());

738 if (Content.size() == 0)

740 break;

741 }

743 Diag(Tok.getLocation(),

744 diag::warn_verbatim_block_end_without_start)

746 << Info->Name

747 << SourceRange(Tok.getLocation(), Tok.getEndLocation());

748 consumeToken();

749 continue;

750 }

752 Content.push_back(S.actOnUnknownCommand(Tok.getLocation(),

753 Tok.getEndLocation(),

755 consumeToken();

756 continue;

757 }

760 continue;

761 }

762

764 consumeToken();

766 consumeToken();

767 break;

768 }

769

770

772 Token WhitespaceTok = Tok;

773 consumeToken();

775 consumeToken();

776 break;

777 }

778

779 putBack(WhitespaceTok);

780 }

781 if (Content.size() > 0)

782 Content.back()->addTrailingNewline();

783 continue;

784 }

785

786

789 continue;

790

793 continue;

794

796 Content.push_back(S.actOnText(Tok.getLocation(),

797 Tok.getEndLocation(),

798 Tok.getText()));

799 consumeToken();

800 continue;

801

810 llvm_unreachable("should not see this token");

811 }

812 break;

813 }

814

815 return S.actOnParagraphComment(S.copyArray(ArrayRef(Content)));

816}

817

820

822 S.actOnVerbatimBlockStart(Tok.getLocation(),

823 Tok.getVerbatimBlockID());

824 consumeToken();

825

826

827

829 consumeToken();

830

836 Line = S.actOnVerbatimBlockLine(Tok.getLocation(),

837 Tok.getVerbatimBlockText());

838 consumeToken();

840 consumeToken();

841 }

842 } else {

843

844 Line = S.actOnVerbatimBlockLine(Tok.getLocation(), "");

845 consumeToken();

846 }

847 Lines.push_back(Line);

848 }

849

851 const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());

852 S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), Info->Name,

853 S.copyArray(ArrayRef(Lines)));

854 consumeToken();

855 } else {

856

858 S.copyArray(ArrayRef(Lines)));

859 }

860

861 return VB;

862}

863

866

867 Token NameTok = Tok;

868 consumeToken();

869

871 StringRef Text;

872

873

875 TextBegin = Tok.getLocation();

876 Text = Tok.getVerbatimLineText();

877 } else {

880 }

881

884 TextBegin,

886 consumeToken();

887 return VL;

888}

889

891 switch (Tok.getKind()) {

899

902

905

916 llvm_unreachable("should not see this token");

917 }

918 llvm_unreachable("bogus token kind");

919}

920

922

924 consumeToken();

925

927 while (Tok.isNot(tok::eof)) {

929

930

932 consumeToken();

933 }

934 return S.actOnFullComment(S.copyArray(ArrayRef(Blocks)));

935}

936

937}

938}

Defines the SourceManager interface.

__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)

Concrete class used by the front-end to report problems and issues.

Encodes a location in the source.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

A trivial tuple used to represent a source range.

Block content (contains inline content).

The JSON file list parser is used to communicate input to InstallAPI.

@ Result

The result type of a method or function.

LLVM_READONLY bool isWhitespace(unsigned char c)

Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...

U cast(CodeGen::Address addr)