Skip to content

Commit d3a4033

Browse files
committed
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
1 parent 99d3582 commit d3a4033

File tree

10 files changed

+56
-103
lines changed

10 files changed

+56
-103
lines changed

clang/include/clang/AST/Comment.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ class Comment {
194194
#include "clang/AST/CommentNodes.inc"
195195
};
196196

197+
struct Argument {
198+
SourceRange Range;
199+
StringRef Text;
200+
};
201+
197202
Comment(CommentKind K,
198203
SourceLocation LocBegin,
199204
SourceLocation LocEnd) :
@@ -296,13 +301,6 @@ class TextComment : public InlineContentComment {
296301
/// A command with word-like arguments that is considered inline content.
297302
class InlineCommandComment : public InlineContentComment {
298303
public:
299-
struct Argument {
300-
SourceRange Range;
301-
StringRef Text;
302-
303-
Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
304-
};
305-
306304
/// The most appropriate rendering mode for this command, chosen on command
307305
/// semantics in Doxygen.
308306
enum RenderKind {
@@ -588,15 +586,6 @@ class ParagraphComment : public BlockContentComment {
588586
/// arguments depends on command name) and a paragraph as an argument
589587
/// (e. g., \\brief).
590588
class BlockCommandComment : public BlockContentComment {
591-
public:
592-
struct Argument {
593-
SourceRange Range;
594-
StringRef Text;
595-
596-
Argument() { }
597-
Argument(SourceRange Range, StringRef Text) : Range(Range), Text(Text) { }
598-
};
599-
600589
protected:
601590
/// Word-like arguments.
602591
ArrayRef<Argument> Args;

clang/include/clang/AST/CommentCommands.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Command<string name> {
3131
}
3232

3333
class InlineCommand<string name> : Command<name> {
34+
let NumArgs = 1;
3435
let IsInlineCommand = 1;
3536
}
3637

@@ -86,6 +87,7 @@ def C : InlineCommand<"c">;
8687
def P : InlineCommand<"p">;
8788
def A : InlineCommand<"a">;
8889
def E : InlineCommand<"e">;
90+
def N : InlineCommand<"n"> { let NumArgs = 0; }
8991
def Em : InlineCommand<"em">;
9092
def Emoji : InlineCommand<"emoji">;
9193

clang/include/clang/AST/CommentParser.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,8 @@ class Parser {
9797
void parseTParamCommandArgs(TParamCommandComment *TPC,
9898
TextTokenRetokenizer &Retokenizer);
9999

100-
void parseBlockCommandArgs(BlockCommandComment *BC,
101-
TextTokenRetokenizer &Retokenizer,
102-
unsigned NumArgs);
100+
ArrayRef<Comment::Argument>
101+
parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);
103102

104103
BlockCommandComment *parseBlockCommand();
105104
InlineCommandComment *parseInlineCommand();

clang/include/clang/AST/CommentSema.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,16 +128,10 @@ class Sema {
128128
void actOnTParamCommandFinish(TParamCommandComment *Command,
129129
ParagraphComment *Paragraph);
130130

131-
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
132-
SourceLocation CommandLocEnd,
133-
unsigned CommandID);
134-
135131
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
136132
SourceLocation CommandLocEnd,
137133
unsigned CommandID,
138-
SourceLocation ArgLocBegin,
139-
SourceLocation ArgLocEnd,
140-
StringRef Arg);
134+
ArrayRef<Comment::Argument> Args);
141135

142136
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
143137
SourceLocation LocEnd,

clang/include/clang/Basic/DiagnosticCommentKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ def note_add_deprecation_attr : Note<
155155

156156
// inline contents commands
157157

158-
def warn_doc_inline_contents_no_argument : Warning<
159-
"'%select{\\|@}0%1' command does not have a valid word argument">,
158+
def warn_doc_inline_command_not_enough_arguments : Warning<
159+
"'%select{\\|@}0%1' command has %plural{0:no|:%2}2 word argument%s2, expected %3">,
160160
InGroup<Documentation>, DefaultIgnore;
161161

162162
// verbatim block commands

clang/lib/AST/CommentParser.cpp

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -289,22 +289,19 @@ void Parser::parseTParamCommandArgs(TParamCommandComment *TPC,
289289
Arg.getText());
290290
}
291291

292-
void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
293-
TextTokenRetokenizer &Retokenizer,
294-
unsigned NumArgs) {
295-
typedef BlockCommandComment::Argument Argument;
296-
Argument *Args =
297-
new (Allocator.Allocate<Argument>(NumArgs)) Argument[NumArgs];
292+
ArrayRef<Comment::Argument>
293+
Parser::parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs) {
294+
auto *Args = new (Allocator.Allocate<Comment::Argument>(NumArgs))
295+
Comment::Argument[NumArgs];
298296
unsigned ParsedArgs = 0;
299297
Token Arg;
300298
while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {
301-
Args[ParsedArgs] = Argument(SourceRange(Arg.getLocation(),
302-
Arg.getEndLocation()),
303-
Arg.getText());
299+
Args[ParsedArgs] = Comment::Argument{
300+
SourceRange(Arg.getLocation(), Arg.getEndLocation()), Arg.getText()};
304301
ParsedArgs++;
305302
}
306303

307-
S.actOnBlockCommandArgs(BC, llvm::makeArrayRef(Args, ParsedArgs));
304+
return llvm::makeArrayRef(Args, ParsedArgs);
308305
}
309306

310307
BlockCommandComment *Parser::parseBlockCommand() {
@@ -360,7 +357,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
360357
else if (TPC)
361358
parseTParamCommandArgs(TPC, Retokenizer);
362359
else
363-
parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs);
360+
S.actOnBlockCommandArgs(BC, parseCommandArgs(Retokenizer, Info->NumArgs));
364361

365362
Retokenizer.putBackLeftoverTokens();
366363
}
@@ -401,32 +398,24 @@ BlockCommandComment *Parser::parseBlockCommand() {
401398

402399
InlineCommandComment *Parser::parseInlineCommand() {
403400
assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
401+
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
404402

405403
const Token CommandTok = Tok;
406404
consumeToken();
407405

408406
TextTokenRetokenizer Retokenizer(Allocator, *this);
407+
ArrayRef<Comment::Argument> Args =
408+
parseCommandArgs(Retokenizer, Info->NumArgs);
409409

410-
Token ArgTok;
411-
bool ArgTokValid = Retokenizer.lexWord(ArgTok);
412-
413-
InlineCommandComment *IC;
414-
if (ArgTokValid) {
415-
IC = S.actOnInlineCommand(CommandTok.getLocation(),
416-
CommandTok.getEndLocation(),
417-
CommandTok.getCommandID(),
418-
ArgTok.getLocation(),
419-
ArgTok.getEndLocation(),
420-
ArgTok.getText());
421-
} else {
422-
IC = S.actOnInlineCommand(CommandTok.getLocation(),
423-
CommandTok.getEndLocation(),
424-
CommandTok.getCommandID());
410+
InlineCommandComment *IC = S.actOnInlineCommand(
411+
CommandTok.getLocation(), CommandTok.getEndLocation(),
412+
CommandTok.getCommandID(), Args);
425413

414+
if (Args.size() < Info->NumArgs) {
426415
Diag(CommandTok.getEndLocation().getLocWithOffset(1),
427-
diag::warn_doc_inline_contents_no_argument)
428-
<< CommandTok.is(tok::at_command)
429-
<< Traits.getCommandInfo(CommandTok.getCommandID())->Name
416+
diag::warn_doc_inline_command_not_enough_arguments)
417+
<< CommandTok.is(tok::at_command) << Info->Name << Args.size()
418+
<< Info->NumArgs
430419
<< SourceRange(CommandTok.getLocation(), CommandTok.getEndLocation());
431420
}
432421

clang/lib/AST/CommentSema.cpp

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,8 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
265265
// User didn't provide a direction argument.
266266
Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
267267
}
268-
typedef BlockCommandComment::Argument Argument;
269-
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
270-
ArgLocEnd),
271-
Arg);
268+
auto *A = new (Allocator)
269+
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
272270
Command->setArgs(llvm::makeArrayRef(A, 1));
273271
}
274272

@@ -303,10 +301,8 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
303301
// Parser will not feed us more arguments than needed.
304302
assert(Command->getNumArgs() == 0);
305303

306-
typedef BlockCommandComment::Argument Argument;
307-
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
308-
ArgLocEnd),
309-
Arg);
304+
auto *A = new (Allocator)
305+
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
310306
Command->setArgs(llvm::makeArrayRef(A, 1));
311307

312308
if (!isTemplateOrSpecialization()) {
@@ -361,37 +357,15 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
361357
checkBlockCommandEmptyParagraph(Command);
362358
}
363359

364-
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
365-
SourceLocation CommandLocEnd,
366-
unsigned CommandID) {
367-
ArrayRef<InlineCommandComment::Argument> Args;
360+
InlineCommandComment *
361+
Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
362+
SourceLocation CommandLocEnd, unsigned CommandID,
363+
ArrayRef<Comment::Argument> Args) {
368364
StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
369-
return new (Allocator) InlineCommandComment(
370-
CommandLocBegin,
371-
CommandLocEnd,
372-
CommandID,
373-
getInlineCommandRenderKind(CommandName),
374-
Args);
375-
}
376365

377-
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
378-
SourceLocation CommandLocEnd,
379-
unsigned CommandID,
380-
SourceLocation ArgLocBegin,
381-
SourceLocation ArgLocEnd,
382-
StringRef Arg) {
383-
typedef InlineCommandComment::Argument Argument;
384-
Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
385-
ArgLocEnd),
386-
Arg);
387-
StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
388-
389-
return new (Allocator) InlineCommandComment(
390-
CommandLocBegin,
391-
CommandLocEnd,
392-
CommandID,
393-
getInlineCommandRenderKind(CommandName),
394-
llvm::makeArrayRef(A, 1));
366+
return new (Allocator)
367+
InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
368+
getInlineCommandRenderKind(CommandName), Args);
395369
}
396370

397371
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,

clang/test/AST/ast-dump-comment.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ int Test_InlineCommandComment;
6262
// CHECK: VarDecl{{.*}}Test_InlineCommandComment
6363
// CHECK: InlineCommandComment{{.*}} Name="c" RenderMonospaced Arg[0]="Aaa"
6464

65+
/// \n Aaa
66+
int Test_InlineCommandComment_NoArgs;
67+
// CHECK: VarDecl{{.*}}Test_InlineCommandComment_NoArgs
68+
// CHECK: InlineCommandComment{{.*}} Name="n" RenderNormal
69+
// CHECK-NEXT: TextComment{{.*}} Text=" Aaa"
70+
6571
/// \anchor Aaa
6672
int Test_InlineCommandCommentAnchor;
6773
// CHECK: VarDecl{{.*}}Test_InlineCommandComment

clang/test/Headers/x86-intrinsics-headers-clean.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Make sure the intrinsic headers compile cleanly with no warnings or errors.
22

33
// RUN: %clang_cc1 -ffreestanding -triple i386-unknown-unknown \
4-
// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation \
4+
// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation -Wdocumentation-pedantic -Wdocumentation-unknown-command \
55
// RUN: -fsyntax-only -fretain-comments-from-system-headers -flax-vector-conversions=none -x c++ -verify %s
66

77
// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown \
8-
// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation \
8+
// RUN: -Wextra -Werror -Wsystem-headers -Wsign-conversion -Wcast-qual -Wdocumentation -Wdocumentation-pedantic -Wdocumentation-unknown-command \
99
// RUN: -fsyntax-only -fretain-comments-from-system-headers -flax-vector-conversions=none -x c++ -verify %s
1010

1111
// expected-no-diagnostics

clang/test/Sema/warn-documentation.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,49 +1116,49 @@ template <typename B>
11161116
void test_attach38<int>::test_attach39(int, B);
11171117

11181118
// The inline comments expect a string after the command.
1119-
// expected-warning@+1 {{'\a' command does not have a valid word argument}}
1119+
// expected-warning@+1 {{'\a' command has no word arguments, expected 1}}
11201120
/// \a
11211121
int test_inline_no_argument_a_bad(int);
11221122

11231123
/// \a A
11241124
int test_inline_no_argument_a_good(int);
11251125

1126-
// expected-warning@+1 {{'\anchor' command does not have a valid word argument}}
1126+
// expected-warning@+1 {{'\anchor' command has no word arguments, expected 1}}
11271127
/// \anchor
11281128
int test_inline_no_argument_anchor_bad(int);
11291129

11301130
/// \anchor A
11311131
int test_inline_no_argument_anchor_good(int);
11321132

1133-
// expected-warning@+1 {{'@b' command does not have a valid word argument}}
1133+
// expected-warning@+1 {{'@b' command has no word arguments, expected 1}}
11341134
/// @b
11351135
int test_inline_no_argument_b_bad(int);
11361136

11371137
/// @b A
11381138
int test_inline_no_argument_b_good(int);
11391139

1140-
// expected-warning@+1 {{'\c' command does not have a valid word argument}}
1140+
// expected-warning@+1 {{'\c' command has no word arguments, expected 1}}
11411141
/// \c
11421142
int test_inline_no_argument_c_bad(int);
11431143

11441144
/// \c A
11451145
int test_inline_no_argument_c_good(int);
11461146

1147-
// expected-warning@+1 {{'\e' command does not have a valid word argument}}
1147+
// expected-warning@+1 {{'\e' command has no word arguments, expected 1}}
11481148
/// \e
11491149
int test_inline_no_argument_e_bad(int);
11501150

11511151
/// \e A
11521152
int test_inline_no_argument_e_good(int);
11531153

1154-
// expected-warning@+1 {{'\em' command does not have a valid word argument}}
1154+
// expected-warning@+1 {{'\em' command has no word arguments, expected 1}}
11551155
/// \em
11561156
int test_inline_no_argument_em_bad(int);
11571157

11581158
/// \em A
11591159
int test_inline_no_argument_em_good(int);
11601160

1161-
// expected-warning@+1 {{'\p' command does not have a valid word argument}}
1161+
// expected-warning@+1 {{'\p' command has no word arguments, expected 1}}
11621162
/// \p
11631163
int test_inline_no_argument_p_bad(int);
11641164

0 commit comments

Comments
 (0)