
These should be all the commands from [1] except those that are marked obsolete, and "link" / "endlink", as that conflicts with the existing HeaderDoc pair "link / "/link". For some commands we don't have the ideal category, but it should work good enough for most cases. There seems to be no existing test for most commands (except the ones interpreted by -Wdocumentation), and to some extent such a test wouldn't look very interesting. But I added a test for the correct parsing of formulas, as they're a bit special. And I had to adapt comment-lots-of-unknown-commands.c because typo correction was kicking in and recognizing some of the commands. This should fix a couple of reported bugs: PR17437, PR19581, PR24062 (partially, no diagnostic for matching cond/endcond), PR32909, PR37813, PR44243 (partially, email@domain.com must be addressed separately). [1] https://www.doxygen.nl/manual/commands.html Reviewed By: gribozavr2 Differential Revision: https://reviews.llvm.org/D111190
131 lines
4.3 KiB
C++
131 lines
4.3 KiB
C++
//===--- ClangCommentCommandInfoEmitter.cpp - Generate command lists -----====//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This tablegen backend emits command lists and efficient matchers for command
|
|
// names that are used in documentation comments.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TableGenBackends.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/StringMatcher.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
void clang::EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
|
|
emitSourceFileHeader("A list of commands useable in documentation "
|
|
"comments", OS);
|
|
|
|
OS << "namespace {\n"
|
|
"const CommandInfo Commands[] = {\n";
|
|
std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
|
|
for (size_t i = 0, e = Tags.size(); i != e; ++i) {
|
|
Record &Tag = *Tags[i];
|
|
OS << " { "
|
|
<< "\"" << Tag.getValueAsString("Name") << "\", "
|
|
<< "\"" << Tag.getValueAsString("EndCommandName") << "\", "
|
|
<< i << ", "
|
|
<< Tag.getValueAsInt("NumArgs") << ", "
|
|
<< Tag.getValueAsBit("IsInlineCommand") << ", "
|
|
<< Tag.getValueAsBit("IsBlockCommand") << ", "
|
|
<< Tag.getValueAsBit("IsBriefCommand") << ", "
|
|
<< Tag.getValueAsBit("IsReturnsCommand") << ", "
|
|
<< Tag.getValueAsBit("IsParamCommand") << ", "
|
|
<< Tag.getValueAsBit("IsTParamCommand") << ", "
|
|
<< Tag.getValueAsBit("IsThrowsCommand") << ", "
|
|
<< Tag.getValueAsBit("IsDeprecatedCommand") << ", "
|
|
<< Tag.getValueAsBit("IsHeaderfileCommand") << ", "
|
|
<< Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
|
|
<< Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
|
|
<< Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
|
|
<< Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
|
|
<< Tag.getValueAsBit("IsDeclarationCommand") << ", "
|
|
<< Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
|
|
<< Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", "
|
|
<< Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", "
|
|
<< /* IsUnknownCommand = */ "0"
|
|
<< " }";
|
|
if (i + 1 != e)
|
|
OS << ",";
|
|
OS << "\n";
|
|
}
|
|
OS << "};\n"
|
|
"} // unnamed namespace\n\n";
|
|
|
|
std::vector<StringMatcher::StringPair> Matches;
|
|
for (size_t i = 0, e = Tags.size(); i != e; ++i) {
|
|
Record &Tag = *Tags[i];
|
|
std::string Name = std::string(Tag.getValueAsString("Name"));
|
|
std::string Return;
|
|
raw_string_ostream(Return) << "return &Commands[" << i << "];";
|
|
Matches.emplace_back(std::move(Name), std::move(Return));
|
|
}
|
|
|
|
OS << "const CommandInfo *CommandTraits::getBuiltinCommandInfo(\n"
|
|
<< " StringRef Name) {\n";
|
|
StringMatcher("Name", Matches, OS).Emit();
|
|
OS << " return nullptr;\n"
|
|
<< "}\n\n";
|
|
}
|
|
|
|
static std::string MangleName(StringRef Str) {
|
|
std::string Mangled;
|
|
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
|
|
switch (Str[i]) {
|
|
default:
|
|
Mangled += Str[i];
|
|
break;
|
|
case '(':
|
|
Mangled += "lparen";
|
|
break;
|
|
case ')':
|
|
Mangled += "rparen";
|
|
break;
|
|
case '[':
|
|
Mangled += "lsquare";
|
|
break;
|
|
case ']':
|
|
Mangled += "rsquare";
|
|
break;
|
|
case '{':
|
|
Mangled += "lbrace";
|
|
break;
|
|
case '}':
|
|
Mangled += "rbrace";
|
|
break;
|
|
case '$':
|
|
Mangled += "dollar";
|
|
break;
|
|
case '/':
|
|
Mangled += "slash";
|
|
break;
|
|
}
|
|
}
|
|
return Mangled;
|
|
}
|
|
|
|
void clang::EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
|
|
emitSourceFileHeader("A list of commands useable in documentation "
|
|
"comments", OS);
|
|
|
|
OS << "#ifndef COMMENT_COMMAND\n"
|
|
<< "# define COMMENT_COMMAND(NAME)\n"
|
|
<< "#endif\n";
|
|
|
|
std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
|
|
for (size_t i = 0, e = Tags.size(); i != e; ++i) {
|
|
Record &Tag = *Tags[i];
|
|
std::string MangledName = MangleName(Tag.getValueAsString("Name"));
|
|
|
|
OS << "COMMENT_COMMAND(" << MangledName << ")\n";
|
|
}
|
|
}
|