diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/CommentParser.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/AST/CommentParser.cpp | 247 |
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 |