mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-04 12:15:46 +00:00
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
This commit is contained in:
parent
99d35826a0
commit
d3a4033d6e
@ -194,6 +194,11 @@ public:
|
||||
#include "clang/AST/CommentNodes.inc"
|
||||
};
|
||||
|
||||
struct Argument {
|
||||
SourceRange Range;
|
||||
StringRef Text;
|
||||
};
|
||||
|
||||
Comment(CommentKind K,
|
||||
SourceLocation LocBegin,
|
||||
SourceLocation LocEnd) :
|
||||
@ -296,13 +301,6 @@ private:
|
||||
/// 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 @@ private:
|
||||
/// 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;
|
||||
|
@ -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">;
|
||||
|
||||
|
@ -97,9 +97,8 @@ public:
|
||||
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();
|
||||
|
@ -128,16 +128,10 @@ public:
|
||||
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,
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
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);
|
||||
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),
|
||||
llvm::makeArrayRef(A, 1));
|
||||
return new (Allocator)
|
||||
InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
|
||||
getInlineCommandRenderKind(CommandName), Args);
|
||||
}
|
||||
|
||||
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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@+1 {{'\a' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'\anchor' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'@b' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'\c' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'\e' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'\em' command does not have a valid word argument}}
|
||||
// expected-warning@+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@+1 {{'\p' command does not have a valid word argument}}
|
||||
// expected-warning@+1 {{'\p' command has no word arguments, expected 1}}
|
||||
/// \p
|
||||
int test_inline_no_argument_p_bad(int);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user