aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/CommentParser.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/AST/CommentParser.cpp247
1 files changed, 201 insertions, 46 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/CommentParser.cpp b/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
index 29983b0a16c3..d5e5bb27ceba 100644
--- a/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
+++ b/contrib/llvm-project/clang/lib/AST/CommentParser.cpp
@@ -89,6 +89,31 @@ class TextTokenRetokenizer {
}
}
+ /// Extract a template type
+ bool lexTemplate(SmallString<32> &WordText) {
+ unsigned BracketCount = 0;
+ while (!isEnd()) {
+ const char C = peek();
+ WordText.push_back(C);
+ consumeChar();
+ switch (C) {
+ case '<': {
+ BracketCount++;
+ break;
+ }
+ case '>': {
+ BracketCount--;
+ if (!BracketCount)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
/// Add a token.
/// Returns true on success, false if there are no interesting tokens to
/// fetch from lexer.
@@ -149,6 +174,111 @@ public:
addToken();
}
+ /// Extract a type argument
+ bool lexType(Token &Tok) {
+ if (isEnd())
+ return false;
+
+ // Save current position in case we need to rollback because the type is
+ // empty.
+ Position SavedPos = Pos;
+
+ // Consume any leading whitespace.
+ consumeWhitespace();
+ SmallString<32> WordText;
+ const char *WordBegin = Pos.BufferPtr;
+ SourceLocation Loc = getSourceLocation();
+
+ while (!isEnd()) {
+ const char C = peek();
+ // For non-whitespace characters we check if it's a template or otherwise
+ // continue reading the text into a word.
+ if (!isWhitespace(C)) {
+ if (C == '<') {
+ if (!lexTemplate(WordText))
+ return false;
+ } else {
+ WordText.push_back(C);
+ consumeChar();
+ }
+ } else {
+ consumeChar();
+ break;
+ }
+ }
+
+ const unsigned Length = WordText.size();
+ if (Length == 0) {
+ Pos = SavedPos;
+ return false;
+ }
+
+ char *TextPtr = Allocator.Allocate<char>(Length + 1);
+
+ memcpy(TextPtr, WordText.c_str(), Length + 1);
+ StringRef Text = StringRef(TextPtr, Length);
+
+ formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
+ return true;
+ }
+
+ // Check if this line starts with @par or \par
+ bool startsWithParCommand() {
+ unsigned Offset = 1;
+
+ // Skip all whitespace characters at the beginning.
+ // This needs to backtrack because Pos has already advanced past the
+ // actual \par or @par command by the time this function is called.
+ while (isWhitespace(*(Pos.BufferPtr - Offset)))
+ Offset++;
+
+ // Once we've reached the whitespace, backtrack and check if the previous
+ // four characters are \par or @par.
+ llvm::StringRef LineStart(Pos.BufferPtr - Offset - 3, 4);
+ return LineStart.starts_with("\\par") || LineStart.starts_with("@par");
+ }
+
+ /// Extract a par command argument-header.
+ bool lexParHeading(Token &Tok) {
+ if (isEnd())
+ return false;
+
+ Position SavedPos = Pos;
+
+ consumeWhitespace();
+ SmallString<32> WordText;
+ const char *WordBegin = Pos.BufferPtr;
+ SourceLocation Loc = getSourceLocation();
+
+ if (!startsWithParCommand())
+ return false;
+
+ // Read until the end of this token, which is effectively the end of the
+ // line. This gets us the content of the par header, if there is one.
+ while (!isEnd()) {
+ WordText.push_back(peek());
+ if (Pos.BufferPtr + 1 == Pos.BufferEnd) {
+ consumeChar();
+ break;
+ }
+ consumeChar();
+ }
+
+ unsigned Length = WordText.size();
+ if (Length == 0) {
+ Pos = SavedPos;
+ return false;
+ }
+
+ char *TextPtr = Allocator.Allocate<char>(Length + 1);
+
+ memcpy(TextPtr, WordText.c_str(), Length + 1);
+ StringRef Text = StringRef(TextPtr, Length);
+
+ formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
+ return true;
+ }
+
/// Extract a word -- sequence of non-whitespace characters.
bool lexWord(Token &Tok) {
if (isEnd())
@@ -245,7 +375,7 @@ public:
Pos.CurToken++;
}
- P.putBack(llvm::makeArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
+ P.putBack(llvm::ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
Pos.CurToken = Toks.size();
if (HavePartialTok)
@@ -289,22 +419,54 @@ void Parser::parseTParamCommandArgs(TParamCommandComment *TPC,
Arg.getText());
}
-void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
- TextTokenRetokenizer &Retokenizer,
- unsigned NumArgs) {
- typedef BlockCommandComment::Argument Argument;
- Argument *Args =
- new (Allocator.Allocate<Argument>(NumArgs)) Argument[NumArgs];
+ArrayRef<Comment::Argument>
+Parser::parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs) {
+ auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
+ Comment::Argument[NumArgs];
unsigned ParsedArgs = 0;
Token Arg;
while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {
- Args[ParsedArgs] = Argument(SourceRange(Arg.getLocation(),
- Arg.getEndLocation()),
- Arg.getText());
+ Args[ParsedArgs] = Comment::Argument{
+ SourceRange(Arg.getLocation(), Arg.getEndLocation()), Arg.getText()};
ParsedArgs++;
}
- S.actOnBlockCommandArgs(BC, llvm::makeArrayRef(Args, ParsedArgs));
+ return llvm::ArrayRef(Args, ParsedArgs);
+}
+
+ArrayRef<Comment::Argument>
+Parser::parseThrowCommandArgs(TextTokenRetokenizer &Retokenizer,
+ unsigned NumArgs) {
+ auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
+ Comment::Argument[NumArgs];
+ unsigned ParsedArgs = 0;
+ Token Arg;
+
+ while (ParsedArgs < NumArgs && Retokenizer.lexType(Arg)) {
+ Args[ParsedArgs] = Comment::Argument{
+ SourceRange(Arg.getLocation(), Arg.getEndLocation()), Arg.getText()};
+ ParsedArgs++;
+ }
+
+ return llvm::ArrayRef(Args, ParsedArgs);
+}
+
+ArrayRef<Comment::Argument>
+Parser::parseParCommandArgs(TextTokenRetokenizer &Retokenizer,
+ unsigned NumArgs) {
+ assert(NumArgs > 0);
+ auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
+ Comment::Argument[NumArgs];
+ unsigned ParsedArgs = 0;
+ Token Arg;
+
+ while (ParsedArgs < NumArgs && Retokenizer.lexParHeading(Arg)) {
+ Args[ParsedArgs] = Comment::Argument{
+ SourceRange(Arg.getLocation(), Arg.getEndLocation()), Arg.getText()};
+ ParsedArgs++;
+ }
+
+ return llvm::ArrayRef(Args, ParsedArgs);
}
BlockCommandComment *Parser::parseBlockCommand() {
@@ -337,7 +499,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
- ParagraphComment *Paragraph = S.actOnParagraphComment(None);
+ ParagraphComment *Paragraph = S.actOnParagraphComment(std::nullopt);
if (PC) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -359,8 +521,14 @@ BlockCommandComment *Parser::parseBlockCommand() {
parseParamCommandArgs(PC, Retokenizer);
else if (TPC)
parseTParamCommandArgs(TPC, Retokenizer);
+ else if (Info->IsThrowsCommand)
+ S.actOnBlockCommandArgs(
+ BC, parseThrowCommandArgs(Retokenizer, Info->NumArgs));
+ else if (Info->IsParCommand)
+ S.actOnBlockCommandArgs(BC,
+ parseParCommandArgs(Retokenizer, Info->NumArgs));
else
- parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs);
+ S.actOnBlockCommandArgs(BC, parseCommandArgs(Retokenizer, Info->NumArgs));
Retokenizer.putBackLeftoverTokens();
}
@@ -379,7 +547,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
ParagraphComment *Paragraph;
if (EmptyParagraph)
- Paragraph = S.actOnParagraphComment(None);
+ Paragraph = S.actOnParagraphComment(std::nullopt);
else {
BlockContentComment *Block = parseParagraphOrBlockCommand();
// Since we have checked for a block command, we should have parsed a
@@ -401,32 +569,24 @@ BlockCommandComment *Parser::parseBlockCommand() {
InlineCommandComment *Parser::parseInlineCommand() {
assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
+ const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
const Token CommandTok = Tok;
consumeToken();
TextTokenRetokenizer Retokenizer(Allocator, *this);
+ ArrayRef<Comment::Argument> Args =
+ parseCommandArgs(Retokenizer, Info->NumArgs);
- Token ArgTok;
- bool ArgTokValid = Retokenizer.lexWord(ArgTok);
-
- InlineCommandComment *IC;
- if (ArgTokValid) {
- IC = S.actOnInlineCommand(CommandTok.getLocation(),
- CommandTok.getEndLocation(),
- CommandTok.getCommandID(),
- ArgTok.getLocation(),
- ArgTok.getEndLocation(),
- ArgTok.getText());
- } else {
- IC = S.actOnInlineCommand(CommandTok.getLocation(),
- CommandTok.getEndLocation(),
- CommandTok.getCommandID());
+ InlineCommandComment *IC = S.actOnInlineCommand(
+ CommandTok.getLocation(), CommandTok.getEndLocation(),
+ CommandTok.getCommandID(), Args);
+ if (Args.size() < Info->NumArgs) {
Diag(CommandTok.getEndLocation().getLocWithOffset(1),
- diag::warn_doc_inline_contents_no_argument)
- << CommandTok.is(tok::at_command)
- << Traits.getCommandInfo(CommandTok.getCommandID())->Name
+ diag::warn_doc_inline_command_not_enough_arguments)
+ << CommandTok.is(tok::at_command) << Info->Name << Args.size()
+ << Info->NumArgs
<< SourceRange(CommandTok.getLocation(), CommandTok.getEndLocation());
}
@@ -478,16 +638,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
}
case tok::html_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ false);
consumeToken();
return HST;
case tok::html_slash_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ true);
consumeToken();
@@ -505,16 +663,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
Tok.is(tok::html_slash_greater))
continue;
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
return HST;
default:
// Not a token from an HTML start tag. Thus HTML tag prematurely ended.
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
bool StartLineInvalid;
@@ -653,7 +809,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
break;
}
- return S.actOnParagraphComment(S.copyArray(llvm::makeArrayRef(Content)));
+ return S.actOnParagraphComment(S.copyArray(llvm::ArrayRef(Content)));
}
VerbatimBlockComment *Parser::parseVerbatimBlock() {
@@ -690,14 +846,13 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
if (Tok.is(tok::verbatim_block_end)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
- S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
- Info->Name,
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), Info->Name,
+ S.copyArray(llvm::ArrayRef(Lines)));
consumeToken();
} else {
// Unterminated \\verbatim block
S.actOnVerbatimBlockFinish(VB, SourceLocation(), "",
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.copyArray(llvm::ArrayRef(Lines)));
}
return VB;
@@ -773,7 +928,7 @@ FullComment *Parser::parseFullComment() {
while (Tok.is(tok::newline))
consumeToken();
}
- return S.actOnFullComment(S.copyArray(llvm::makeArrayRef(Blocks)));
+ return S.actOnFullComment(S.copyArray(llvm::ArrayRef(Blocks)));
}
} // end namespace comments