[clang] d3a4033 - Comment parsing: Allow inline commands to have 0 or more than 1 argument
Aaron Puchert via cfe-commits
cfe-commits at lists.llvm.org
Fri May 13 04:49:30 PDT 2022
Author: Aaron Puchert
Date: 2022-05-13T13:48:46+02:00
New Revision: d3a4033d6ee1d017e216ff7caeeeb5ca2e18a783
URL: https://github.com/llvm/llvm-project/commit/d3a4033d6ee1d017e216ff7caeeeb5ca2e18a783
DIFF: https://github.com/llvm/llvm-project/commit/d3a4033d6ee1d017e216ff7caeeeb5ca2e18a783.diff
LOG: Comment parsing: Allow inline commands to have 0 or more than 1 argument
That's required to support `\n`, but can also be used for other commands.
We already had the infrastructure in place to parse a varying number of
arguments, we simply needed to generalize it so that it would work not
only for block commands.
This should fix #55319.
Reviewed By: gribozavr2
Differential Revision: https://reviews.llvm.org/D125429
Added:
Modified:
clang/include/clang/AST/Comment.h
clang/include/clang/AST/CommentCommands.td
clang/include/clang/AST/CommentParser.h
clang/include/clang/AST/CommentSema.h
clang/include/clang/Basic/DiagnosticCommentKinds.td
clang/lib/AST/CommentParser.cpp
clang/lib/AST/CommentSema.cpp
clang/test/AST/ast-dump-comment.cpp
clang/test/Headers/x86-intrinsics-headers-clean.cpp
clang/test/Sema/warn-documentation.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h
index 5ecc35791b7b0..0b68c11316649 100644
--- a/clang/include/clang/AST/Comment.h
+++ b/clang/include/clang/AST/Comment.h
@@ -194,6 +194,11 @@ class Comment {
#include "clang/AST/CommentNodes.inc"
};
+ struct Argument {
+ SourceRange Range;
+ StringRef Text;
+ };
+
Comment(CommentKind K,
SourceLocation LocBegin,
SourceLocation LocEnd) :
@@ -296,13 +301,6 @@ class TextComment : public InlineContentComment {
/// A command with word-like arguments that is considered inline content.
class InlineCommandComment : public InlineContentComment {
public:
- struct Argument {
- SourceRange Range;
- StringRef Text;
-
- Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
- };
-
/// The most appropriate rendering mode for this command, chosen on command
/// semantics in Doxygen.
enum RenderKind {
@@ -588,15 +586,6 @@ class ParagraphComment : public BlockContentComment {
/// arguments depends on command name) and a paragraph as an argument
/// (e. g., \\brief).
class BlockCommandComment : public BlockContentComment {
-public:
- struct Argument {
- SourceRange Range;
- StringRef Text;
-
- Argument() { }
- Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
- };
-
protected:
/// Word-like arguments.
ArrayRef<Argument> Args;
diff --git a/clang/include/clang/AST/CommentCommands.td b/clang/include/clang/AST/CommentCommands.td
index d357ec1cf8b99..a3b9eb313fcf5 100644
--- a/clang/include/clang/AST/CommentCommands.td
+++ b/clang/include/clang/AST/CommentCommands.td
@@ -31,6 +31,7 @@ class Command<string name> {
}
class InlineCommand<string name> : Command<name> {
+ let NumArgs = 1;
let IsInlineCommand = 1;
}
@@ -86,6 +87,7 @@ def C : InlineCommand<"c">;
def P : InlineCommand<"p">;
def A : InlineCommand<"a">;
def E : InlineCommand<"e">;
+def N : InlineCommand<"n"> { let NumArgs = 0; }
def Em : InlineCommand<"em">;
def Emoji : InlineCommand<"emoji">;
diff --git a/clang/include/clang/AST/CommentParser.h b/clang/include/clang/AST/CommentParser.h
index 1a0cfb06e52b7..e11e818b1af0a 100644
--- a/clang/include/clang/AST/CommentParser.h
+++ b/clang/include/clang/AST/CommentParser.h
@@ -97,9 +97,8 @@ class Parser {
void parseTParamCommandArgs(TParamCommandComment *TPC,
TextTokenRetokenizer &Retokenizer);
- void parseBlockCommandArgs(BlockCommandComment *BC,
- TextTokenRetokenizer &Retokenizer,
- unsigned NumArgs);
+ ArrayRef<Comment::Argument>
+ parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);
BlockCommandComment *parseBlockCommand();
InlineCommandComment *parseInlineCommand();
diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h
index 015ce8f8652ac..5e30ff8adb915 100644
--- a/clang/include/clang/AST/CommentSema.h
+++ b/clang/include/clang/AST/CommentSema.h
@@ -128,16 +128,10 @@ class Sema {
void actOnTParamCommandFinish(TParamCommandComment *Command,
ParagraphComment *Paragraph);
- InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
- SourceLocation CommandLocEnd,
- unsigned CommandID);
-
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
unsigned CommandID,
- SourceLocation ArgLocBegin,
- SourceLocation ArgLocEnd,
- StringRef Arg);
+ ArrayRef<Comment::Argument> Args);
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
SourceLocation LocEnd,
diff --git a/clang/include/clang/Basic/DiagnosticCommentKinds.td b/clang/include/clang/Basic/DiagnosticCommentKinds.td
index ae63bb623ed3a..1122ace3027d8 100644
--- a/clang/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommentKinds.td
@@ -155,8 +155,8 @@ def note_add_deprecation_attr : Note<
// inline contents commands
-def warn_doc_inline_contents_no_argument : Warning<
- "'%select{\\|@}0%1' command does not have a valid word argument">,
+def warn_doc_inline_command_not_enough_arguments : Warning<
+ "'%select{\\|@}0%1' command has %plural{0:no|:%2}2 word argument%s2, expected %3">,
InGroup<Documentation>, DefaultIgnore;
// verbatim block commands
diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp
index 29983b0a16c3c..7bac1fb99b887 100644
--- a/clang/lib/AST/CommentParser.cpp
+++ b/clang/lib/AST/CommentParser.cpp
@@ -289,22 +289,19 @@ 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::makeArrayRef(Args, ParsedArgs);
}
BlockCommandComment *Parser::parseBlockCommand() {
@@ -360,7 +357,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
else if (TPC)
parseTParamCommandArgs(TPC, Retokenizer);
else
- parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs);
+ S.actOnBlockCommandArgs(BC, parseCommandArgs(Retokenizer, Info->NumArgs));
Retokenizer.putBackLeftoverTokens();
}
@@ -401,32 +398,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());
}
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 087f103e49318..9b0f034458884 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -265,10 +265,8 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
// User didn't provide a direction argument.
Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
}
- typedef BlockCommandComment::Argument Argument;
- Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
- ArgLocEnd),
- Arg);
+ auto *A = new (Allocator)
+ Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
Command->setArgs(llvm::makeArrayRef(A, 1));
}
@@ -303,10 +301,8 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
// Parser will not feed us more arguments than needed.
assert(Command->getNumArgs() == 0);
- typedef BlockCommandComment::Argument Argument;
- Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
- ArgLocEnd),
- Arg);
+ auto *A = new (Allocator)
+ Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
Command->setArgs(llvm::makeArrayRef(A, 1));
if (!isTemplateOrSpecialization()) {
@@ -361,37 +357,15 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
}
-InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
- SourceLocation CommandLocEnd,
- unsigned CommandID) {
- ArrayRef<InlineCommandComment::Argument> Args;
+InlineCommandComment *
+Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
+ SourceLocation CommandLocEnd, unsigned CommandID,
+ ArrayRef<Comment::Argument> Args) {
StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
- return new (Allocator) InlineCommandComment(
- CommandLocBegin,
- CommandLocEnd,
- CommandID,
- getInlineCommandRenderKind(CommandName),
- Args);
-}
-InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
- SourceLocation CommandLocEnd,
- unsigned CommandID,
- SourceLocation ArgLocBegin,
- SourceLocation ArgLocEnd,
- StringRef Arg) {
- typedef InlineCommandComment::Argument Argument;
- Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
- ArgLocEnd),
- Arg);
- StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
-
- return new (Allocator) InlineCommandComment(
- CommandLocBegin,
- CommandLocEnd,
- CommandID,
- getInlineCommandRenderKind(CommandName),
- llvm::makeArrayRef(A, 1));
+ return new (Allocator)
+ InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
+ getInlineCommandRenderKind(CommandName), Args);
}
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
diff --git a/clang/test/AST/ast-dump-comment.cpp b/clang/test/AST/ast-dump-comment.cpp
index 1936c732cb989..8b058911d614d 100644
--- a/clang/test/AST/ast-dump-comment.cpp
+++ b/clang/test/AST/ast-dump-comment.cpp
@@ -62,6 +62,12 @@ int Test_InlineCommandComment;
// CHECK: VarDecl{{.*}}Test_InlineCommandComment
// CHECK: InlineCommandComment{{.*}} Name="c" RenderMonospaced Arg[0]="Aaa"
+/// \n Aaa
+int Test_InlineCommandComment_NoArgs;
+// CHECK: VarDecl{{.*}}Test_InlineCommandComment_NoArgs
+// CHECK: InlineCommandComment{{.*}} Name="n" RenderNormal
+// CHECK-NEXT: TextComment{{.*}} Text=" Aaa"
+
/// \anchor Aaa
int Test_InlineCommandCommentAnchor;
// CHECK: VarDecl{{.*}}Test_InlineCommandComment
diff --git a/clang/test/Headers/x86-intrinsics-headers-clean.cpp b/clang/test/Headers/x86-intrinsics-headers-clean.cpp
index 9af49657a1d5f..a19207f34ead8 100644
--- a/clang/test/Headers/x86-intrinsics-headers-clean.cpp
+++ b/clang/test/Headers/x86-intrinsics-headers-clean.cpp
@@ -1,11 +1,11 @@
// Make sure the intrinsic headers compile cleanly with no warnings or errors.
// RUN: %clang_cc1 -ffreestanding -triple i386-unknown-unknown \
-// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation \
+// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation -Wdocumentation-pedantic -Wdocumentation-unknown-command \
// RUN: -fsyntax-only -fretain-comments-from-system-headers -flax-vector-conversions=none -x c++ -verify %s
// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown \
-// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation \
+// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation -Wdocumentation-pedantic -Wdocumentation-unknown-command \
// RUN: -fsyntax-only -fretain-comments-from-system-headers -flax-vector-conversions=none -x c++ -verify %s
// expected-no-diagnostics
diff --git a/clang/test/Sema/warn-documentation.cpp b/clang/test/Sema/warn-documentation.cpp
index 570b5baf54029..431c0e078dd98 100644
--- a/clang/test/Sema/warn-documentation.cpp
+++ b/clang/test/Sema/warn-documentation.cpp
@@ -1116,49 +1116,49 @@ template <typename B>
void test_attach38<int>::test_attach39(int, B);
// The inline comments expect a string after the command.
-// expected-warning at +1 {{'\a' command does not have a valid word argument}}
+// expected-warning at +1 {{'\a' command has no word arguments, expected 1}}
/// \a
int test_inline_no_argument_a_bad(int);
/// \a A
int test_inline_no_argument_a_good(int);
-// expected-warning at +1 {{'\anchor' command does not have a valid word argument}}
+// expected-warning at +1 {{'\anchor' command has no word arguments, expected 1}}
/// \anchor
int test_inline_no_argument_anchor_bad(int);
/// \anchor A
int test_inline_no_argument_anchor_good(int);
-// expected-warning at +1 {{'@b' command does not have a valid word argument}}
+// expected-warning at +1 {{'@b' command has no word arguments, expected 1}}
/// @b
int test_inline_no_argument_b_bad(int);
/// @b A
int test_inline_no_argument_b_good(int);
-// expected-warning at +1 {{'\c' command does not have a valid word argument}}
+// expected-warning at +1 {{'\c' command has no word arguments, expected 1}}
/// \c
int test_inline_no_argument_c_bad(int);
/// \c A
int test_inline_no_argument_c_good(int);
-// expected-warning at +1 {{'\e' command does not have a valid word argument}}
+// expected-warning at +1 {{'\e' command has no word arguments, expected 1}}
/// \e
int test_inline_no_argument_e_bad(int);
/// \e A
int test_inline_no_argument_e_good(int);
-// expected-warning at +1 {{'\em' command does not have a valid word argument}}
+// expected-warning at +1 {{'\em' command has no word arguments, expected 1}}
/// \em
int test_inline_no_argument_em_bad(int);
/// \em A
int test_inline_no_argument_em_good(int);
-// expected-warning at +1 {{'\p' command does not have a valid word argument}}
+// expected-warning at +1 {{'\p' command has no word arguments, expected 1}}
/// \p
int test_inline_no_argument_p_bad(int);
More information about the cfe-commits
mailing list