forked from OSchip/llvm-project
Comment parsing: add support for \tparam command on all levels.
The only caveat is renumbering CXCommentKind enum for aesthetic reasons -- this breaks libclang binary compatibility, but should not be a problem since API is so new. This also fixes PR13372 as a side-effect. llvm-svn: 161087
This commit is contained in:
parent
708709c015
commit
34df220410
|
@ -3276,6 +3276,14 @@ enum CXCommentKind {
|
|||
*/
|
||||
CXComment_ParamCommand = 7,
|
||||
|
||||
/**
|
||||
* \brief A \\tparam command that describes a template parameter (name and
|
||||
* description).
|
||||
*
|
||||
* \brief For example: \\tparam T description.
|
||||
*/
|
||||
CXComment_TParamCommand = 8,
|
||||
|
||||
/**
|
||||
* \brief A verbatim block command (e. g., preformatted code). Verbatim
|
||||
* block has an opening and a closing command and contains multiple lines of
|
||||
|
@ -3286,25 +3294,25 @@ enum CXCommentKind {
|
|||
* aaa
|
||||
* \\endverbatim
|
||||
*/
|
||||
CXComment_VerbatimBlockCommand = 8,
|
||||
CXComment_VerbatimBlockCommand = 9,
|
||||
|
||||
/**
|
||||
* \brief A line of text that is contained within a
|
||||
* CXComment_VerbatimBlockCommand node.
|
||||
*/
|
||||
CXComment_VerbatimBlockLine = 9,
|
||||
CXComment_VerbatimBlockLine = 10,
|
||||
|
||||
/**
|
||||
* \brief A verbatim line command. Verbatim line has an opening command,
|
||||
* a single line of text (up to the newline after the opening command) and
|
||||
* has no closing command.
|
||||
*/
|
||||
CXComment_VerbatimLine = 10,
|
||||
CXComment_VerbatimLine = 11,
|
||||
|
||||
/**
|
||||
* \brief A full comment attached to a declaration, contains block content.
|
||||
*/
|
||||
CXComment_FullComment = 11
|
||||
CXComment_FullComment = 12
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -3563,6 +3571,63 @@ CINDEX_LINKAGE
|
|||
enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
|
||||
CXComment Comment);
|
||||
|
||||
/**
|
||||
* \param Comment a \c CXComment_TParamCommand AST node.
|
||||
*
|
||||
* \returns template parameter name.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
CXString clang_TParamCommandComment_getParamName(CXComment Comment);
|
||||
|
||||
/**
|
||||
* \param Comment a \c CXComment_TParamCommand AST node.
|
||||
*
|
||||
* \returns non-zero if the parameter that this AST node represents was found
|
||||
* in the template parameter list and
|
||||
* \c clang_TParamCommandComment_getDepth and
|
||||
* \c clang_TParamCommandComment_getIndex functions will return a meaningful
|
||||
* value.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment Comment);
|
||||
|
||||
/**
|
||||
* \param Comment a \c CXComment_TParamCommand AST node.
|
||||
*
|
||||
* \returns zero-based nesting depth of this parameter in the template parameter list.
|
||||
*
|
||||
* For example,
|
||||
* \verbatim
|
||||
* template<typename C, template<typename T> class TT>
|
||||
* void test(TT<int> aaa);
|
||||
* \endverbatim
|
||||
* for C and TT nesting depth is 0,
|
||||
* for T nesting depth is 1.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
unsigned clang_TParamCommandComment_getDepth(CXComment Comment);
|
||||
|
||||
/**
|
||||
* \param Comment a \c CXComment_TParamCommand AST node.
|
||||
*
|
||||
* \returns zero-based parameter index in the template parameter list at a
|
||||
* given nesting depth.
|
||||
*
|
||||
* For example,
|
||||
* \verbatim
|
||||
* template<typename C, template<typename T> class TT>
|
||||
* void test(TT<int> aaa);
|
||||
* \endverbatim
|
||||
* for C and TT nesting depth is 0, so we can ask for index at depth 0:
|
||||
* at depth 0 C's index is 0, TT's index is 1.
|
||||
*
|
||||
* For T nesting depth is 1, so we can ask for index at depth 0 and 1:
|
||||
* at depth 0 T's index is 1 (same as TT's),
|
||||
* at depth 1 T's index is 0.
|
||||
*/
|
||||
CINDEX_LINKAGE
|
||||
unsigned clang_TParamCommandComment_getIndex(CXComment Comment, unsigned Depth);
|
||||
|
||||
/**
|
||||
* \param Comment a \c CXComment_VerbatimBlockLine AST node.
|
||||
*
|
||||
|
@ -3606,6 +3671,15 @@ CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment);
|
|||
* \li "param-name-index-invalid" and "param-descr-index-invalid" are used if
|
||||
* parameter index is invalid.
|
||||
*
|
||||
* Template parameter documentation is rendered as a \<dl\> list with
|
||||
* parameters sorted in template parameter list order. CSS classes used:
|
||||
* \li "tparam-name-index-NUMBER" for parameter name (\<dt\>);
|
||||
* \li "tparam-descr-index-NUMBER" for parameter description (\<dd\>);
|
||||
* \li "taram-name-index-other" and "tparam-descr-index-other" are used for
|
||||
* names inside template template parameters;
|
||||
* \li "tparam-name-index-invalid" and "tparam-descr-index-invalid" are used if
|
||||
* parameter position is invalid.
|
||||
*
|
||||
* \param Comment a \c CXComment_FullComment AST node.
|
||||
*
|
||||
* \returns string containing an HTML fragment.
|
||||
|
|
|
@ -723,6 +723,68 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Doxygen \\tparam command, describes a template parameter.
|
||||
class TParamCommandComment : public BlockCommandComment {
|
||||
private:
|
||||
/// If this template parameter name was resolved (found in template parameter
|
||||
/// list), then this stores a list of position indexes in all template
|
||||
/// parameter lists.
|
||||
///
|
||||
/// For example:
|
||||
/// \verbatim
|
||||
/// template<typename C, template<typename T> class TT>
|
||||
/// void test(TT<int> aaa);
|
||||
/// \endverbatim
|
||||
/// For C: Position = { 0 }
|
||||
/// For TT: Position = { 1 }
|
||||
/// For T: Position = { 1, 0 }
|
||||
llvm::ArrayRef<unsigned> Position;
|
||||
|
||||
public:
|
||||
TParamCommandComment(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) :
|
||||
BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, Name)
|
||||
{ }
|
||||
|
||||
static bool classof(const Comment *C) {
|
||||
return C->getCommentKind() == TParamCommandCommentKind;
|
||||
}
|
||||
|
||||
static bool classof(const TParamCommandComment *) { return true; }
|
||||
|
||||
bool hasParamName() const {
|
||||
return getNumArgs() > 0;
|
||||
}
|
||||
|
||||
StringRef getParamName() const {
|
||||
return Args[0].Text;
|
||||
}
|
||||
|
||||
SourceRange getParamNameRange() const {
|
||||
return Args[0].Range;
|
||||
}
|
||||
|
||||
bool isPositionValid() const LLVM_READONLY {
|
||||
return !Position.empty();
|
||||
}
|
||||
|
||||
unsigned getDepth() const {
|
||||
assert(isPositionValid());
|
||||
return Position.size();
|
||||
}
|
||||
|
||||
unsigned getIndex(unsigned Depth) const {
|
||||
assert(isPositionValid());
|
||||
return Position[Depth];
|
||||
}
|
||||
|
||||
void setPosition(ArrayRef<unsigned> NewPosition) {
|
||||
Position = NewPosition;
|
||||
assert(isPositionValid());
|
||||
}
|
||||
};
|
||||
|
||||
/// A line of text contained in a verbatim block.
|
||||
class VerbatimBlockLineComment : public Comment {
|
||||
StringRef Text;
|
||||
|
|
|
@ -42,17 +42,6 @@ class Parser {
|
|||
/// Source manager for the comment being parsed.
|
||||
const SourceManager &SourceMgr;
|
||||
|
||||
template<typename T>
|
||||
ArrayRef<T> copyArray(ArrayRef<T> Source) {
|
||||
size_t Size = Source.size();
|
||||
if (Size != 0) {
|
||||
T *Mem = Allocator.Allocate<T>(Size);
|
||||
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
|
||||
return llvm::makeArrayRef(Mem, Size);
|
||||
} else
|
||||
return llvm::makeArrayRef(static_cast<T *>(NULL), 0);
|
||||
}
|
||||
|
||||
DiagnosticsEngine &Diags;
|
||||
|
||||
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
|
||||
|
@ -105,6 +94,11 @@ public:
|
|||
ParamCommandComment *PC,
|
||||
TextTokenRetokenizer &Retokenizer);
|
||||
|
||||
/// Parse arguments for \\tparam command.
|
||||
TParamCommandComment *parseTParamCommandArgs(
|
||||
TParamCommandComment *TPC,
|
||||
TextTokenRetokenizer &Retokenizer);
|
||||
|
||||
BlockCommandComment *parseBlockCommandArgs(
|
||||
BlockCommandComment *BC,
|
||||
TextTokenRetokenizer &Retokenizer,
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
#include "clang/AST/Comment.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class FunctionDecl;
|
||||
class ParmVarDecl;
|
||||
class TemplateParameterList;
|
||||
class SourceMgr;
|
||||
|
||||
namespace comments {
|
||||
|
@ -56,6 +58,18 @@ class Sema {
|
|||
/// true.
|
||||
llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
|
||||
|
||||
/// Template parameters that can be referenced by \\tparam if \c ThisDecl is
|
||||
/// a template.
|
||||
///
|
||||
/// Contains a valid value if \c IsThisDeclInspected is true.
|
||||
const TemplateParameterList *TemplateParameters;
|
||||
|
||||
/// Comment AST nodes that correspond to parameter names in
|
||||
/// \c TemplateParameters.
|
||||
///
|
||||
/// Contains a valid value if \c IsThisDeclInspected is true.
|
||||
llvm::StringMap<TParamCommandComment *> TemplateParameterDocs;
|
||||
|
||||
/// True if we extracted all important information from \c ThisDecl into
|
||||
/// \c Sema members.
|
||||
unsigned IsThisDeclInspected : 1;
|
||||
|
@ -64,6 +78,10 @@ class Sema {
|
|||
/// Contains a valid value if \c IsThisDeclInspected is true.
|
||||
unsigned IsFunctionDecl : 1;
|
||||
|
||||
/// Is \c ThisDecl a template declaration.
|
||||
/// Contains a valid value if \c IsThisDeclInspected is true.
|
||||
unsigned IsTemplateDecl : 1;
|
||||
|
||||
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
|
||||
return Diags.Report(Loc, DiagID);
|
||||
}
|
||||
|
@ -78,6 +96,18 @@ public:
|
|||
|
||||
void setDecl(const Decl *D);
|
||||
|
||||
/// Returns a copy of array, owned by Sema's allocator.
|
||||
template<typename T>
|
||||
ArrayRef<T> copyArray(ArrayRef<T> Source) {
|
||||
size_t Size = Source.size();
|
||||
if (Size != 0) {
|
||||
T *Mem = Allocator.Allocate<T>(Size);
|
||||
std::uninitialized_copy(Source.begin(), Source.end(), Mem);
|
||||
return llvm::makeArrayRef(Mem, Size);
|
||||
} else
|
||||
return llvm::makeArrayRef(static_cast<T *>(NULL), 0);
|
||||
}
|
||||
|
||||
ParagraphComment *actOnParagraphComment(
|
||||
ArrayRef<InlineContentComment *> Content);
|
||||
|
||||
|
@ -111,6 +141,19 @@ public:
|
|||
ParamCommandComment *actOnParamCommandFinish(ParamCommandComment *Command,
|
||||
ParagraphComment *Paragraph);
|
||||
|
||||
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name);
|
||||
|
||||
TParamCommandComment *actOnTParamCommandParamNameArg(
|
||||
TParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg);
|
||||
|
||||
TParamCommandComment *actOnTParamCommandFinish(TParamCommandComment *Command,
|
||||
ParagraphComment *Paragraph);
|
||||
|
||||
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName);
|
||||
|
@ -165,6 +208,8 @@ public:
|
|||
void checkBlockCommandEmptyParagraph(BlockCommandComment *Command);
|
||||
|
||||
bool isFunctionDecl();
|
||||
bool isTemplateDecl();
|
||||
|
||||
ArrayRef<const ParmVarDecl *> getParamVars();
|
||||
|
||||
/// Extract all important semantic information from \c ThisDecl into
|
||||
|
@ -180,8 +225,17 @@ public:
|
|||
unsigned correctTypoInParmVarReference(StringRef Typo,
|
||||
ArrayRef<const ParmVarDecl *> ParamVars);
|
||||
|
||||
bool resolveTParamReference(StringRef Name,
|
||||
const TemplateParameterList *TemplateParameters,
|
||||
SmallVectorImpl<unsigned> *Position);
|
||||
|
||||
StringRef correctTypoInTParamReference(
|
||||
StringRef Typo,
|
||||
const TemplateParameterList *TemplateParameters);
|
||||
|
||||
bool isBlockCommand(StringRef Name);
|
||||
bool isParamCommand(StringRef Name);
|
||||
bool isTParamCommand(StringRef Name);
|
||||
unsigned getBlockCommandNumArgs(StringRef Name);
|
||||
|
||||
bool isInlineCommand(StringRef Name) const;
|
||||
|
|
|
@ -17,6 +17,7 @@ def BlockContentComment : Comment<1>;
|
|||
def ParagraphComment : DComment<BlockContentComment>;
|
||||
def BlockCommandComment : DComment<BlockContentComment>;
|
||||
def ParamCommandComment : DComment<BlockCommandComment>;
|
||||
def TParamCommandComment : DComment<BlockCommandComment>;
|
||||
def VerbatimBlockComment : DComment<BlockCommandComment>;
|
||||
def VerbatimLineComment : DComment<BlockCommandComment>;
|
||||
|
||||
|
|
|
@ -77,5 +77,26 @@ def warn_doc_param_not_found : Warning<
|
|||
def note_doc_param_name_suggestion : Note<
|
||||
"did you mean '%0'?">;
|
||||
|
||||
// \tparam command
|
||||
|
||||
def warn_doc_tparam_not_attached_to_a_template_decl : Warning<
|
||||
"'\\tparam' command used in a comment that is not attached to "
|
||||
"a template declaration">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def warn_doc_tparam_duplicate : Warning<
|
||||
"template parameter '%0' is already documented">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def note_doc_tparam_previous : Note<
|
||||
"previous documentation">;
|
||||
|
||||
def warn_doc_tparam_not_found : Warning<
|
||||
"template parameter '%0' not found in the template declaration">,
|
||||
InGroup<Documentation>, DefaultIgnore;
|
||||
|
||||
def note_doc_tparam_name_suggestion : Note<
|
||||
"did you mean '%0'?">;
|
||||
|
||||
} // end of documentation issue category
|
||||
} // end of AST component
|
||||
|
|
|
@ -72,6 +72,13 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
|
|||
if (isa<ParmVarDecl>(D))
|
||||
return NULL;
|
||||
|
||||
// TODO: we could look up template parameter documentation in the template
|
||||
// documentation.
|
||||
if (isa<TemplateTypeParmDecl>(D) ||
|
||||
isa<NonTypeTemplateParmDecl>(D) ||
|
||||
isa<TemplateTemplateParmDecl>(D))
|
||||
return NULL;
|
||||
|
||||
ArrayRef<RawComment *> RawComments = Comments.getComments();
|
||||
|
||||
// If there are no comments anywhere, we won't find anything.
|
||||
|
@ -86,7 +93,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
|
|||
// so we use the location of the identifier as the "declaration location".
|
||||
SourceLocation DeclLoc;
|
||||
if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
|
||||
isa<ObjCPropertyDecl>(D))
|
||||
isa<ObjCPropertyDecl>(D) ||
|
||||
isa<FunctionTemplateDecl>(D) ||
|
||||
isa<ClassTemplateDecl>(D) || isa<ClassTemplateSpecializationDecl>(D))
|
||||
DeclLoc = D->getLocStart();
|
||||
else
|
||||
DeclLoc = D->getLocation();
|
||||
|
|
|
@ -48,6 +48,7 @@ bool isBlockCommand(StringRef Name) {
|
|||
.Case("pre", true)
|
||||
.Case("post", true)
|
||||
.Cases("param", "arg", true)
|
||||
.Case("tparam", true)
|
||||
.Default(false);
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
void visitParagraphComment(const ParagraphComment *C);
|
||||
void visitBlockCommandComment(const BlockCommandComment *C);
|
||||
void visitParamCommandComment(const ParamCommandComment *C);
|
||||
void visitTParamCommandComment(const TParamCommandComment *C);
|
||||
void visitVerbatimBlockComment(const VerbatimBlockComment *C);
|
||||
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
|
||||
void visitVerbatimLineComment(const VerbatimLineComment *C);
|
||||
|
@ -176,6 +177,24 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
|
|||
OS << " ParamIndex=" << C->getParamIndex();
|
||||
}
|
||||
|
||||
void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
|
||||
dumpComment(C);
|
||||
|
||||
if (C->hasParamName()) {
|
||||
OS << " Param=\"" << C->getParamName() << "\"";
|
||||
}
|
||||
|
||||
if (C->isPositionValid()) {
|
||||
OS << " Position=<";
|
||||
for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
|
||||
OS << C->getIndex(i);
|
||||
if (i != e - 1)
|
||||
OS << ", ";
|
||||
}
|
||||
OS << ">";
|
||||
}
|
||||
}
|
||||
|
||||
void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
|
||||
dumpComment(C);
|
||||
|
||||
|
|
|
@ -276,6 +276,19 @@ ParamCommandComment *Parser::parseParamCommandArgs(
|
|||
return PC;
|
||||
}
|
||||
|
||||
TParamCommandComment *Parser::parseTParamCommandArgs(
|
||||
TParamCommandComment *TPC,
|
||||
TextTokenRetokenizer &Retokenizer) {
|
||||
Token Arg;
|
||||
if (Retokenizer.lexWord(Arg))
|
||||
TPC = S.actOnTParamCommandParamNameArg(TPC,
|
||||
Arg.getLocation(),
|
||||
Arg.getEndLocation(),
|
||||
Arg.getText());
|
||||
|
||||
return TPC;
|
||||
}
|
||||
|
||||
BlockCommandComment *Parser::parseBlockCommandArgs(
|
||||
BlockCommandComment *BC,
|
||||
TextTokenRetokenizer &Retokenizer,
|
||||
|
@ -299,14 +312,21 @@ BlockCommandComment *Parser::parseBlockCommand() {
|
|||
assert(Tok.is(tok::command));
|
||||
|
||||
ParamCommandComment *PC;
|
||||
TParamCommandComment *TPC;
|
||||
BlockCommandComment *BC;
|
||||
bool IsParam = false;
|
||||
bool IsTParam = false;
|
||||
unsigned NumArgs = 0;
|
||||
if (S.isParamCommand(Tok.getCommandName())) {
|
||||
IsParam = true;
|
||||
PC = S.actOnParamCommandStart(Tok.getLocation(),
|
||||
Tok.getEndLocation(),
|
||||
Tok.getCommandName());
|
||||
} if (S.isTParamCommand(Tok.getCommandName())) {
|
||||
IsTParam = true;
|
||||
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
|
||||
Tok.getEndLocation(),
|
||||
Tok.getCommandName());
|
||||
} else {
|
||||
NumArgs = S.getBlockCommandNumArgs(Tok.getCommandName());
|
||||
BC = S.actOnBlockCommandStart(Tok.getLocation(),
|
||||
|
@ -323,13 +343,15 @@ BlockCommandComment *Parser::parseBlockCommand() {
|
|||
return S.actOnBlockCommandFinish(IsParam ? PC : BC, Paragraph);
|
||||
}
|
||||
|
||||
if (IsParam || NumArgs > 0) {
|
||||
if (IsParam || IsTParam || NumArgs > 0) {
|
||||
// In order to parse command arguments we need to retokenize a few
|
||||
// following text tokens.
|
||||
TextTokenRetokenizer Retokenizer(Allocator, *this);
|
||||
|
||||
if (IsParam)
|
||||
PC = parseParamCommandArgs(PC, Retokenizer);
|
||||
else if (IsTParam)
|
||||
TPC = parseTParamCommandArgs(TPC, Retokenizer);
|
||||
else
|
||||
BC = parseBlockCommandArgs(BC, Retokenizer, NumArgs);
|
||||
|
||||
|
@ -341,6 +363,8 @@ BlockCommandComment *Parser::parseBlockCommand() {
|
|||
// paragraph.
|
||||
if (IsParam)
|
||||
return S.actOnParamCommandFinish(PC, cast<ParagraphComment>(Block));
|
||||
else if (IsTParam)
|
||||
return S.actOnTParamCommandFinish(TPC, cast<ParagraphComment>(Block));
|
||||
else
|
||||
return S.actOnBlockCommandFinish(BC, cast<ParagraphComment>(Block));
|
||||
}
|
||||
|
@ -419,7 +443,7 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
|
|||
|
||||
case tok::html_greater:
|
||||
HST = S.actOnHTMLStartTagFinish(HST,
|
||||
copyArray(llvm::makeArrayRef(Attrs)),
|
||||
S.copyArray(llvm::makeArrayRef(Attrs)),
|
||||
Tok.getLocation(),
|
||||
/* IsSelfClosing = */ false);
|
||||
consumeToken();
|
||||
|
@ -427,7 +451,7 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
|
|||
|
||||
case tok::html_slash_greater:
|
||||
HST = S.actOnHTMLStartTagFinish(HST,
|
||||
copyArray(llvm::makeArrayRef(Attrs)),
|
||||
S.copyArray(llvm::makeArrayRef(Attrs)),
|
||||
Tok.getLocation(),
|
||||
/* IsSelfClosing = */ true);
|
||||
consumeToken();
|
||||
|
@ -446,14 +470,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
|
|||
continue;
|
||||
|
||||
return S.actOnHTMLStartTagFinish(HST,
|
||||
copyArray(llvm::makeArrayRef(Attrs)),
|
||||
S.copyArray(llvm::makeArrayRef(Attrs)),
|
||||
SourceLocation(),
|
||||
/* IsSelfClosing = */ false);
|
||||
|
||||
default:
|
||||
// Not a token from an HTML start tag. Thus HTML tag prematurely ended.
|
||||
HST = S.actOnHTMLStartTagFinish(HST,
|
||||
copyArray(llvm::makeArrayRef(Attrs)),
|
||||
S.copyArray(llvm::makeArrayRef(Attrs)),
|
||||
SourceLocation(),
|
||||
/* IsSelfClosing = */ false);
|
||||
bool StartLineInvalid;
|
||||
|
@ -563,7 +587,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
|
|||
break;
|
||||
}
|
||||
|
||||
return S.actOnParagraphComment(copyArray(llvm::makeArrayRef(Content)));
|
||||
return S.actOnParagraphComment(S.copyArray(llvm::makeArrayRef(Content)));
|
||||
}
|
||||
|
||||
VerbatimBlockComment *Parser::parseVerbatimBlock() {
|
||||
|
@ -601,12 +625,12 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
|
|||
if (Tok.is(tok::verbatim_block_end)) {
|
||||
VB = S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
|
||||
Tok.getVerbatimBlockName(),
|
||||
copyArray(llvm::makeArrayRef(Lines)));
|
||||
S.copyArray(llvm::makeArrayRef(Lines)));
|
||||
consumeToken();
|
||||
} else {
|
||||
// Unterminated \\verbatim block
|
||||
VB = S.actOnVerbatimBlockFinish(VB, SourceLocation(), "",
|
||||
copyArray(llvm::makeArrayRef(Lines)));
|
||||
S.copyArray(llvm::makeArrayRef(Lines)));
|
||||
}
|
||||
|
||||
return VB;
|
||||
|
@ -680,7 +704,7 @@ FullComment *Parser::parseFullComment() {
|
|||
while (Tok.is(tok::newline))
|
||||
consumeToken();
|
||||
}
|
||||
return S.actOnFullComment(copyArray(llvm::makeArrayRef(Blocks)));
|
||||
return S.actOnFullComment(S.copyArray(llvm::makeArrayRef(Blocks)));
|
||||
}
|
||||
|
||||
} // end namespace comments
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "clang/AST/CommentDiagnostic.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
|
@ -200,6 +201,90 @@ ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command,
|
|||
return Command;
|
||||
}
|
||||
|
||||
TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
|
||||
SourceLocation LocEnd,
|
||||
StringRef Name) {
|
||||
TParamCommandComment *Command =
|
||||
new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name);
|
||||
|
||||
if (!isTemplateDecl())
|
||||
Diag(Command->getLocation(),
|
||||
diag::warn_doc_tparam_not_attached_to_a_template_decl)
|
||||
<< Command->getCommandNameRange();
|
||||
|
||||
return Command;
|
||||
}
|
||||
|
||||
TParamCommandComment *Sema::actOnTParamCommandParamNameArg(
|
||||
TParamCommandComment *Command,
|
||||
SourceLocation ArgLocBegin,
|
||||
SourceLocation ArgLocEnd,
|
||||
StringRef Arg) {
|
||||
// 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);
|
||||
Command->setArgs(llvm::makeArrayRef(A, 1));
|
||||
|
||||
if (!isTemplateDecl()) {
|
||||
// We already warned that this \\tparam is not attached to a template decl.
|
||||
return Command;
|
||||
}
|
||||
|
||||
SmallVector<unsigned, 2> Position;
|
||||
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
|
||||
Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
|
||||
llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
|
||||
TemplateParameterDocs.find(Arg);
|
||||
if (PrevCommandIt != TemplateParameterDocs.end()) {
|
||||
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
|
||||
Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
|
||||
<< Arg << ArgRange;
|
||||
TParamCommandComment *PrevCommand = PrevCommandIt->second;
|
||||
Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
|
||||
<< PrevCommand->getParamNameRange();
|
||||
}
|
||||
TemplateParameterDocs[Arg] = Command;
|
||||
return Command;
|
||||
}
|
||||
|
||||
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
|
||||
Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
|
||||
<< Arg << ArgRange;
|
||||
|
||||
if (!TemplateParameters || TemplateParameters->size() == 0)
|
||||
return Command;
|
||||
|
||||
StringRef CorrectedName;
|
||||
if (TemplateParameters->size() == 1) {
|
||||
const NamedDecl *Param = TemplateParameters->getParam(0);
|
||||
const IdentifierInfo *II = Param->getIdentifier();
|
||||
if (II)
|
||||
CorrectedName = II->getName();
|
||||
} else {
|
||||
CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
|
||||
}
|
||||
|
||||
if (!CorrectedName.empty()) {
|
||||
Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
|
||||
<< CorrectedName
|
||||
<< FixItHint::CreateReplacement(ArgRange, CorrectedName);
|
||||
}
|
||||
|
||||
return Command;
|
||||
}
|
||||
|
||||
TParamCommandComment *Sema::actOnTParamCommandFinish(
|
||||
TParamCommandComment *Command,
|
||||
ParagraphComment *Paragraph) {
|
||||
Command->setParagraph(Paragraph);
|
||||
checkBlockCommandEmptyParagraph(Command);
|
||||
return Command;
|
||||
}
|
||||
|
||||
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
|
||||
SourceLocation CommandLocEnd,
|
||||
StringRef CommandName) {
|
||||
|
@ -387,6 +472,12 @@ bool Sema::isFunctionDecl() {
|
|||
return IsFunctionDecl;
|
||||
}
|
||||
|
||||
bool Sema::isTemplateDecl() {
|
||||
if (!IsThisDeclInspected)
|
||||
inspectThisDecl();
|
||||
return IsTemplateDecl;
|
||||
}
|
||||
|
||||
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
|
||||
if (!IsThisDeclInspected)
|
||||
inspectThisDecl();
|
||||
|
@ -397,18 +488,56 @@ void Sema::inspectThisDecl() {
|
|||
assert(!IsThisDeclInspected);
|
||||
if (!ThisDecl) {
|
||||
IsFunctionDecl = false;
|
||||
IsTemplateDecl = false;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>();
|
||||
TemplateParameters = NULL;
|
||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = true;
|
||||
IsTemplateDecl = false;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
|
||||
FD->getNumParams());
|
||||
TemplateParameters = NULL;
|
||||
unsigned NumLists = FD->getNumTemplateParameterLists();
|
||||
if (NumLists != 0) {
|
||||
IsTemplateDecl = true;
|
||||
TemplateParameters = FD->getTemplateParameterList(NumLists - 1);
|
||||
}
|
||||
} else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = true;
|
||||
IsTemplateDecl = false;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(),
|
||||
MD->param_size());
|
||||
TemplateParameters = NULL;
|
||||
} else if (const FunctionTemplateDecl *FTD =
|
||||
dyn_cast<FunctionTemplateDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = true;
|
||||
IsTemplateDecl = true;
|
||||
const FunctionDecl *FD = FTD->getTemplatedDecl();
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(),
|
||||
FD->getNumParams());
|
||||
TemplateParameters = FTD->getTemplateParameters();
|
||||
} else if (const ClassTemplateDecl *CTD =
|
||||
dyn_cast<ClassTemplateDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = false;
|
||||
IsTemplateDecl = true;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>();
|
||||
TemplateParameters = CTD->getTemplateParameters();
|
||||
} else if (const ClassTemplatePartialSpecializationDecl *CTPSD =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = false;
|
||||
IsTemplateDecl = true;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>();
|
||||
TemplateParameters = CTPSD->getTemplateParameters();
|
||||
} else if (isa<ClassTemplateSpecializationDecl>(ThisDecl)) {
|
||||
IsFunctionDecl = false;
|
||||
IsTemplateDecl = true;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>();
|
||||
TemplateParameters = NULL;
|
||||
} else {
|
||||
IsFunctionDecl = false;
|
||||
IsTemplateDecl = false;
|
||||
ParamVars = ArrayRef<const ParmVarDecl *>();
|
||||
TemplateParameters = NULL;
|
||||
}
|
||||
ParamVarDocs.resize(ParamVars.size(), NULL);
|
||||
IsThisDeclInspected = true;
|
||||
|
@ -424,34 +553,136 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
|
|||
return ParamCommandComment::InvalidParamIndex;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class SimpleTypoCorrector {
|
||||
StringRef Typo;
|
||||
const unsigned MaxEditDistance;
|
||||
|
||||
const NamedDecl *BestDecl;
|
||||
unsigned BestEditDistance;
|
||||
unsigned BestIndex;
|
||||
unsigned NextIndex;
|
||||
|
||||
public:
|
||||
SimpleTypoCorrector(StringRef Typo) :
|
||||
Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
|
||||
BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
|
||||
BestIndex(0), NextIndex(0)
|
||||
{ }
|
||||
|
||||
void addDecl(const NamedDecl *ND);
|
||||
|
||||
const NamedDecl *getBestDecl() const {
|
||||
if (BestEditDistance > MaxEditDistance)
|
||||
return NULL;
|
||||
|
||||
return BestDecl;
|
||||
}
|
||||
|
||||
unsigned getBestDeclIndex() const {
|
||||
assert(getBestDecl());
|
||||
return BestIndex;
|
||||
}
|
||||
};
|
||||
|
||||
void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
|
||||
unsigned CurrIndex = NextIndex++;
|
||||
|
||||
const IdentifierInfo *II = ND->getIdentifier();
|
||||
if (!II)
|
||||
return;
|
||||
|
||||
StringRef Name = II->getName();
|
||||
unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
|
||||
if (MinPossibleEditDistance > 0 &&
|
||||
Typo.size() / MinPossibleEditDistance < 3)
|
||||
return;
|
||||
|
||||
unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
|
||||
if (EditDistance < BestEditDistance) {
|
||||
BestEditDistance = EditDistance;
|
||||
BestDecl = ND;
|
||||
BestIndex = CurrIndex;
|
||||
}
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
unsigned Sema::correctTypoInParmVarReference(
|
||||
StringRef Typo,
|
||||
ArrayRef<const ParmVarDecl *> ParamVars) {
|
||||
const unsigned MaxEditDistance = (Typo.size() + 2) / 3;
|
||||
unsigned BestPVDIndex = 0;
|
||||
unsigned BestEditDistance = MaxEditDistance + 1;
|
||||
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
|
||||
const IdentifierInfo *II = ParamVars[i]->getIdentifier();
|
||||
if (II) {
|
||||
StringRef Name = II->getName();
|
||||
unsigned MinPossibleEditDistance =
|
||||
abs((int)Name.size() - (int)Typo.size());
|
||||
if (MinPossibleEditDistance > 0 &&
|
||||
Typo.size() / MinPossibleEditDistance < 3)
|
||||
continue;
|
||||
SimpleTypoCorrector Corrector(Typo);
|
||||
for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
|
||||
Corrector.addDecl(ParamVars[i]);
|
||||
if (Corrector.getBestDecl())
|
||||
return Corrector.getBestDeclIndex();
|
||||
else
|
||||
return ParamCommandComment::InvalidParamIndex;;
|
||||
}
|
||||
|
||||
unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
|
||||
if (EditDistance < BestEditDistance) {
|
||||
BestEditDistance = EditDistance;
|
||||
BestPVDIndex = i;
|
||||
}
|
||||
namespace {
|
||||
bool ResolveTParamReferenceHelper(
|
||||
StringRef Name,
|
||||
const TemplateParameterList *TemplateParameters,
|
||||
SmallVectorImpl<unsigned> *Position) {
|
||||
for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
|
||||
const NamedDecl *Param = TemplateParameters->getParam(i);
|
||||
const IdentifierInfo *II = Param->getIdentifier();
|
||||
if (II && II->getName() == Name) {
|
||||
Position->push_back(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const TemplateTemplateParmDecl *TTP =
|
||||
dyn_cast<TemplateTemplateParmDecl>(Param)) {
|
||||
Position->push_back(i);
|
||||
if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
|
||||
Position))
|
||||
return true;
|
||||
Position->pop_back();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
if (BestEditDistance <= MaxEditDistance)
|
||||
return BestPVDIndex;
|
||||
else
|
||||
return ParamCommandComment::InvalidParamIndex;
|
||||
bool Sema::resolveTParamReference(
|
||||
StringRef Name,
|
||||
const TemplateParameterList *TemplateParameters,
|
||||
SmallVectorImpl<unsigned> *Position) {
|
||||
Position->clear();
|
||||
if (!TemplateParameters)
|
||||
return false;
|
||||
|
||||
return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void CorrectTypoInTParamReferenceHelper(
|
||||
const TemplateParameterList *TemplateParameters,
|
||||
SimpleTypoCorrector &Corrector) {
|
||||
for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
|
||||
const NamedDecl *Param = TemplateParameters->getParam(i);
|
||||
Corrector.addDecl(Param);
|
||||
|
||||
if (const TemplateTemplateParmDecl *TTP =
|
||||
dyn_cast<TemplateTemplateParmDecl>(Param))
|
||||
CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
|
||||
Corrector);
|
||||
}
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
StringRef Sema::correctTypoInTParamReference(
|
||||
StringRef Typo,
|
||||
const TemplateParameterList *TemplateParameters) {
|
||||
SimpleTypoCorrector Corrector(Typo);
|
||||
CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
|
||||
if (const NamedDecl *ND = Corrector.getBestDecl()) {
|
||||
const IdentifierInfo *II = ND->getIdentifier();
|
||||
assert(II && "SimpleTypoCorrector should not return this decl");
|
||||
return II->getName();
|
||||
}
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
// TODO: tablegen
|
||||
|
@ -465,7 +696,7 @@ bool Sema::isBlockCommand(StringRef Name) {
|
|||
.Case("authors", true)
|
||||
.Case("pre", true)
|
||||
.Case("post", true)
|
||||
.Default(false) || isParamCommand(Name);
|
||||
.Default(false) || isParamCommand(Name) || isTParamCommand(Name);
|
||||
}
|
||||
|
||||
bool Sema::isParamCommand(StringRef Name) {
|
||||
|
@ -475,6 +706,10 @@ bool Sema::isParamCommand(StringRef Name) {
|
|||
.Default(false);
|
||||
}
|
||||
|
||||
bool Sema::isTParamCommand(StringRef Name) {
|
||||
return Name == "tparam";
|
||||
}
|
||||
|
||||
unsigned Sema::getBlockCommandNumArgs(StringRef Name) {
|
||||
return llvm::StringSwitch<unsigned>(Name)
|
||||
.Cases("brief", "short", 0)
|
||||
|
|
|
@ -7618,6 +7618,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
|
|||
<< FD->getName() << "dllimport";
|
||||
}
|
||||
}
|
||||
ActOnDocumentableDecl(FD);
|
||||
return FD;
|
||||
}
|
||||
|
||||
|
|
|
@ -1139,6 +1139,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
if (PrevClassTemplate)
|
||||
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
|
||||
|
||||
ActOnDocumentableDecl(NewTemplate);
|
||||
|
||||
return NewTemplate;
|
||||
}
|
||||
|
||||
|
@ -5568,7 +5570,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
Decl *Sema::ActOnTemplateDeclarator(Scope *S,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D) {
|
||||
return HandleDeclarator(S, D, move(TemplateParameterLists));
|
||||
Decl *NewDecl = HandleDeclarator(S, D, move(TemplateParameterLists));
|
||||
ActOnDocumentableDecl(NewDecl);
|
||||
return NewDecl;
|
||||
}
|
||||
|
||||
Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
||||
|
|
|
@ -290,6 +290,30 @@ void comment_to_html_conversion_15(int x1, int x2);
|
|||
/// \param x1 Aaa.
|
||||
void comment_to_html_conversion_16(int x1, int x2);
|
||||
|
||||
/// \tparam
|
||||
/// \param aaa Blah blah
|
||||
template<typename T>
|
||||
void comment_to_html_conversion_17(T aaa);
|
||||
|
||||
/// \tparam T2 Bbb
|
||||
/// \tparam T1 Aaa
|
||||
template<typename T1, typename T2>
|
||||
void comment_to_html_conversion_18(T1 aaa, T2 bbb);
|
||||
|
||||
/// \tparam T2 Bbb
|
||||
/// \tparam U Zzz
|
||||
/// \tparam V Ccc
|
||||
/// \tparam T1 Aaa
|
||||
template<typename T1, typename T2, int V>
|
||||
void comment_to_html_conversion_19(T1 aaa, T2 bbb);
|
||||
|
||||
/// \tparam TTT Ddd
|
||||
/// \tparam C Ccc
|
||||
/// \tparam T Aaa
|
||||
/// \tparam TT Bbb
|
||||
template<template<template<typename T> class TT, class C> class TTT>
|
||||
void comment_to_html_conversion_20();
|
||||
|
||||
/// \brief Aaa.
|
||||
///
|
||||
/// Bbb.
|
||||
|
@ -297,35 +321,35 @@ void comment_to_html_conversion_16(int x1, int x2);
|
|||
/// \param x2 Ddd.
|
||||
/// \param x1 Ccc.
|
||||
/// \returns Eee.
|
||||
void comment_to_html_conversion_17(int x1, int x2);
|
||||
void comment_to_html_conversion_21(int x1, int x2);
|
||||
|
||||
/// <br><a href="http://example.com/">Aaa</a>
|
||||
void comment_to_html_conversion_18();
|
||||
void comment_to_html_conversion_22();
|
||||
|
||||
/// \verbatim
|
||||
/// <a href="http://example.com/">Aaa</a>
|
||||
/// <a href='http://example.com/'>Aaa</a>
|
||||
/// \endverbatim
|
||||
void comment_to_html_conversion_19();
|
||||
|
||||
/// \b Aaa
|
||||
void comment_to_html_conversion_20();
|
||||
|
||||
/// \c Aaa \p Bbb
|
||||
void comment_to_html_conversion_21();
|
||||
|
||||
/// \a Aaa \e Bbb \em Ccc
|
||||
void comment_to_html_conversion_22();
|
||||
|
||||
/// \\ \@ \& \$ \# \< \> \% \" \. \::
|
||||
void comment_to_html_conversion_23();
|
||||
|
||||
/// & < > "
|
||||
/// \b Aaa
|
||||
void comment_to_html_conversion_24();
|
||||
|
||||
/// <em>0<i</em>
|
||||
/// \c Aaa \p Bbb
|
||||
void comment_to_html_conversion_25();
|
||||
|
||||
/// \a Aaa \e Bbb \em Ccc
|
||||
void comment_to_html_conversion_26();
|
||||
|
||||
/// \\ \@ \& \$ \# \< \> \% \" \. \::
|
||||
void comment_to_html_conversion_27();
|
||||
|
||||
/// & < > "
|
||||
void comment_to_html_conversion_28();
|
||||
|
||||
/// <em>0<i</em>
|
||||
void comment_to_html_conversion_29();
|
||||
|
||||
#endif
|
||||
|
||||
// RUN: rm -rf %t
|
||||
|
@ -555,7 +579,70 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
|
||||
// CHECK: annotate-comments.cpp:300:6: FunctionDecl=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p>]
|
||||
// CHECK: annotate-comments.cpp:296:6: FunctionTemplate=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[] ParamPosition=Invalid
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))]
|
||||
// CHECK: annotate-comments.cpp:301:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<dl><dt class="taram-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="taram-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
|
||||
// CHECK: annotate-comments.cpp:308:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<dl><dt class="taram-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="taram-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="taram-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[U] ParamPosition=Invalid
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Zzz] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[V] ParamPosition={2}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
|
||||
// CHECK: annotate-comments.cpp:315:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<dl><dt class="taram-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="taram-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="taram-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="taram-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TTT] ParamPosition={0}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Ddd] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[C] ParamPosition={0, 1}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0, 0, 0}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Aaa] HasTrailingNewline)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
|
||||
// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TT] ParamPosition={0, 0}
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Bbb]))))]
|
||||
// CHECK: annotate-comments.cpp:324:6: FunctionDecl=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
|
@ -578,7 +665,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))]
|
||||
// CHECK: annotate-comments.cpp:303:6: FunctionDecl=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>]
|
||||
// CHECK: annotate-comments.cpp:327:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
@ -587,7 +674,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_HTMLStartTag Name=[a] Attrs: href=http://example.com/)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[Aaa])
|
||||
// CHECK-NEXT: (CXComment_HTMLEndTag Name=[a])))]
|
||||
// CHECK: annotate-comments.cpp:309:6: FunctionDecl=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<pre> <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a></pre>]
|
||||
// CHECK: annotate-comments.cpp:333:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<pre> <a href="http://example.com/">Aaa</a>\n <a href='http://example.com/'>Aaa</a></pre>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
|
||||
|
@ -595,13 +682,13 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_VerbatimBlockCommand CommandName=[verbatim]
|
||||
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href="http://example.com/">Aaa</a>])
|
||||
// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href='http://example.com/'>Aaa</a>])))]
|
||||
// CHECK: annotate-comments.cpp:312:6: FunctionDecl=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>]
|
||||
// CHECK: annotate-comments.cpp:336:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
|
||||
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[b] RenderBold Arg[0]=Aaa)))]
|
||||
// CHECK: annotate-comments.cpp:315:6: FunctionDecl=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>]
|
||||
// CHECK: annotate-comments.cpp:339:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
@ -609,7 +696,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[c] RenderMonospaced Arg[0]=Aaa)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
|
||||
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[p] RenderMonospaced Arg[0]=Bbb)))]
|
||||
// CHECK: annotate-comments.cpp:318:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>]
|
||||
// CHECK: annotate-comments.cpp:342:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
@ -619,7 +706,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[e] RenderEmphasized Arg[0]=Bbb)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
|
||||
// CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=Ccc)))]
|
||||
// CHECK: annotate-comments.cpp:321:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ & $ # < > % " . ::</p>]
|
||||
// CHECK: annotate-comments.cpp:345:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ & $ # < > % " . ::</p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
@ -645,7 +732,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_Text Text=[.])
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
|
||||
// CHECK-NEXT: (CXComment_Text Text=[::])))]
|
||||
// CHECK: annotate-comments.cpp:324:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> & < > "</p>]
|
||||
// CHECK: annotate-comments.cpp:348:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> & < > "</p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
@ -657,7 +744,7 @@ void comment_to_html_conversion_25();
|
|||
// CHECK-NEXT: (CXComment_Text Text=[>])
|
||||
// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
|
||||
// CHECK-NEXT: (CXComment_Text Text=["])))]
|
||||
// CHECK: annotate-comments.cpp:327:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0<i</em></p>]
|
||||
// CHECK: annotate-comments.cpp:351:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0<i</em></p>]
|
||||
// CHECK-NEXT: CommentAST=[
|
||||
// CHECK-NEXT: (CXComment_FullComment
|
||||
// CHECK-NEXT: (CXComment_Paragraph
|
||||
|
|
|
@ -170,18 +170,86 @@ class C {
|
|||
int test_param15(int bbb, int ccc);
|
||||
};
|
||||
|
||||
// expected-warning@+1 {{parameter 'aab' not found in the function declaration}}
|
||||
/// \param aab Blah blah.
|
||||
template<typename T>
|
||||
void test_param16(int bbb, int ccc);
|
||||
|
||||
// expected-warning@+3 {{parameter 'a' is already documented}}
|
||||
// expected-note@+1 {{previous documentation}}
|
||||
/// \param a Aaa.
|
||||
/// \param a Aaa.
|
||||
int test_param16(int a);
|
||||
int test_param17(int a);
|
||||
|
||||
// expected-warning@+4 {{parameter 'x2' is already documented}}
|
||||
// expected-note@+2 {{previous documentation}}
|
||||
/// \param x1 Aaa.
|
||||
/// \param x2 Bbb.
|
||||
/// \param x2 Ccc.
|
||||
int test_param17(int x1, int x2, int x3);
|
||||
int test_param18(int x1, int x2, int x3);
|
||||
|
||||
|
||||
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
|
||||
/// \tparam T Aaa
|
||||
int test_tparam1;
|
||||
|
||||
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
|
||||
/// \tparam T Aaa
|
||||
void test_tparam2(int aaa);
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\tparam' command}}
|
||||
/// \tparam
|
||||
/// \param aaa Blah blah
|
||||
template<typename T>
|
||||
void test_tparam3(T aaa);
|
||||
|
||||
// expected-warning@+1 {{template parameter 'T' not found in the template declaration}} expected-note@+1 {{did you mean 'TT'?}}
|
||||
/// \tparam T Aaa
|
||||
template<typename TT>
|
||||
void test_tparam4(TT aaa);
|
||||
|
||||
// expected-warning@+1 {{template parameter 'T' not found in the template declaration}} expected-note@+1 {{did you mean 'TT'?}}
|
||||
/// \tparam T Aaa
|
||||
template<typename TT>
|
||||
class test_tparam5 {
|
||||
// expected-warning@+1 {{template parameter 'T' not found in the template declaration}} expected-note@+1 {{did you mean 'TTT'?}}
|
||||
/// \tparam T Aaa
|
||||
template<typename TTT>
|
||||
void test_tparam6(TTT aaa);
|
||||
};
|
||||
|
||||
/// \tparam T1 Aaa
|
||||
/// \tparam T2 Bbb
|
||||
template<typename T1, typename T2>
|
||||
void test_tparam7(T1 aaa, T2 bbb);
|
||||
|
||||
// expected-warning@+1 {{template parameter 'SomTy' not found in the template declaration}} expected-note@+1 {{did you mean 'SomeTy'?}}
|
||||
/// \tparam SomTy Aaa
|
||||
/// \tparam OtherTy Bbb
|
||||
template<typename SomeTy, typename OtherTy>
|
||||
void test_tparam8(SomeTy aaa, OtherTy bbb);
|
||||
|
||||
// expected-warning@+2 {{template parameter 'T1' is already documented}} expected-note@+1 {{previous documentation}}
|
||||
/// \tparam T1 Aaa
|
||||
/// \tparam T1 Bbb
|
||||
template<typename T1, typename T2>
|
||||
void test_tparam9(T1 aaa, T2 bbb);
|
||||
|
||||
/// \tparam T Aaa
|
||||
/// \tparam TT Bbb
|
||||
template<template<typename T> class TT>
|
||||
void test_tparam10(TT<int> aaa);
|
||||
|
||||
/// \tparam T Aaa
|
||||
/// \tparam TT Bbb
|
||||
/// \tparam TTT Ccc
|
||||
template<template<template<typename T> class TT, class C> class TTT>
|
||||
void test_tparam11();
|
||||
|
||||
/// \tparam I Aaa
|
||||
template<int I>
|
||||
void test_tparam12();
|
||||
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
int test1; ///< \brief\brief Aaa
|
||||
|
@ -292,6 +360,125 @@ namespace test_attach24 {
|
|||
}
|
||||
}
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T>
|
||||
void test_attach26(T aaa);
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T, typename U>
|
||||
void test_attach27(T aaa, U bbb);
|
||||
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{template parameter 'T' not found in the template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<>
|
||||
void test_attach27(int aaa, int bbb);
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T>
|
||||
class test_attach28 {
|
||||
T aaa;
|
||||
};
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T, typename U>
|
||||
class test_attach29 { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T>
|
||||
class test_attach29<T, int> { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
template<>
|
||||
class test_attach29<int, int> { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T, typename U, typename V>
|
||||
class test_attach30 { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T, typename U>
|
||||
class test_attach30<T, U, int> { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T>
|
||||
class test_attach30<T, int, int> { };
|
||||
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{template parameter 'T' not found in the template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<>
|
||||
class test_attach30<int, int, int> { };
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
class test_attach31 {
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T, typename U>
|
||||
void test_attach32(T aaa, U bbb);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class test_attach33 {
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{template parameter 'T' not found in the template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename TT, typename UU>
|
||||
void test_attach34(TT aaa, UU bbb);
|
||||
};
|
||||
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{template parameter 'T' not found in the template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<> template<>
|
||||
void test_attach33<int>::test_attach34(int aaa, int bbb) {}
|
||||
|
||||
template<typename T>
|
||||
class test_attach35 {
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{'\tparam' command used in a comment that is not attached to a template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
void test_attach36(int aaa, int bbb);
|
||||
};
|
||||
|
||||
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<typename T>
|
||||
void test_attach35<T>::test_attach36(int aaa, int bbb) {}
|
||||
|
||||
// expected-warning@+2 {{empty paragraph passed to '\brief' command}}
|
||||
// expected-warning@+2 {{template parameter 'T' not found in the template declaration}}
|
||||
/// \brief\brief Aaa
|
||||
/// \tparam T Aaa
|
||||
template<>
|
||||
void test_attach35<int>::test_attach36(int aaa, int bbb) {}
|
||||
|
||||
|
||||
// PR13411, reduced. We used to crash on this.
|
||||
/**
|
||||
* @code Aaa.
|
||||
|
|
|
@ -378,6 +378,23 @@ static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
|
|||
else
|
||||
printf(" ParamIndex=Invalid");
|
||||
break;
|
||||
case CXComment_TParamCommand:
|
||||
printf("CXComment_TParamCommand");
|
||||
PrintCXStringWithPrefixAndDispose(
|
||||
"ParamName",
|
||||
clang_TParamCommandComment_getParamName(Comment));
|
||||
if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
|
||||
printf(" ParamPosition={");
|
||||
for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
|
||||
i != e; ++i) {
|
||||
printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
|
||||
if (i != e - 1)
|
||||
printf(", ");
|
||||
}
|
||||
printf("}");
|
||||
} else
|
||||
printf(" ParamPosition=Invalid");
|
||||
break;
|
||||
case CXComment_VerbatimBlockCommand:
|
||||
printf("CXComment_VerbatimBlockCommand");
|
||||
PrintCXStringWithPrefixAndDispose(
|
||||
|
|
|
@ -59,6 +59,9 @@ enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
|
|||
case Comment::ParamCommandCommentKind:
|
||||
return CXComment_ParamCommand;
|
||||
|
||||
case Comment::TParamCommandCommentKind:
|
||||
return CXComment_TParamCommand;
|
||||
|
||||
case Comment::VerbatimBlockCommentKind:
|
||||
return CXComment_VerbatimBlockCommand;
|
||||
|
||||
|
@ -291,6 +294,38 @@ enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
|
|||
llvm_unreachable("unknown ParamCommandComment::PassDirection");
|
||||
}
|
||||
|
||||
CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
|
||||
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
||||
if (!TPCC || !TPCC->hasParamName())
|
||||
return createCXString((const char *) 0);
|
||||
|
||||
return createCXString(TPCC->getParamName(), /*DupString=*/ false);
|
||||
}
|
||||
|
||||
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
|
||||
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
||||
if (!TPCC)
|
||||
return false;
|
||||
|
||||
return TPCC->isPositionValid();
|
||||
}
|
||||
|
||||
unsigned clang_TParamCommandComment_getDepth(CXComment CXC) {
|
||||
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
||||
if (!TPCC || !TPCC->isPositionValid())
|
||||
return 0;
|
||||
|
||||
return TPCC->getDepth();
|
||||
}
|
||||
|
||||
unsigned clang_TParamCommandComment_getIndex(CXComment CXC, unsigned Depth) {
|
||||
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
|
||||
if (!TPCC || !TPCC->isPositionValid() || Depth >= TPCC->getDepth())
|
||||
return 0;
|
||||
|
||||
return TPCC->getIndex(Depth);
|
||||
}
|
||||
|
||||
CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
|
||||
const VerbatimBlockLineComment *VBL =
|
||||
getASTNodeAs<VerbatimBlockLineComment>(CXC);
|
||||
|
@ -333,6 +368,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// This comparison will sort template parameters in the following order:
|
||||
/// \li real template parameters (depth = 1) in index order;
|
||||
/// \li all other names (depth > 1);
|
||||
/// \li unresolved names.
|
||||
class TParamCommandCommentComparePosition {
|
||||
public:
|
||||
bool operator()(const TParamCommandComment *LHS,
|
||||
const TParamCommandComment *RHS) const {
|
||||
// Sort unresolved names last.
|
||||
if (!LHS->isPositionValid())
|
||||
return false;
|
||||
if (!RHS->isPositionValid())
|
||||
return true;
|
||||
|
||||
if (LHS->getDepth() > 1)
|
||||
return false;
|
||||
if (RHS->getDepth() > 1)
|
||||
return true;
|
||||
|
||||
// Sort template parameters in index order.
|
||||
if (LHS->getDepth() == 1 && RHS->getDepth() == 1)
|
||||
return LHS->getIndex(0) < RHS->getIndex(0);
|
||||
|
||||
// Leave all other names in source order.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CommentASTToHTMLConverter :
|
||||
public ConstCommentVisitor<CommentASTToHTMLConverter> {
|
||||
public:
|
||||
|
@ -349,6 +412,7 @@ public:
|
|||
void visitParagraphComment(const ParagraphComment *C);
|
||||
void visitBlockCommandComment(const BlockCommandComment *C);
|
||||
void visitParamCommandComment(const ParamCommandComment *C);
|
||||
void visitTParamCommandComment(const TParamCommandComment *C);
|
||||
void visitVerbatimBlockComment(const VerbatimBlockComment *C);
|
||||
void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
|
||||
void visitVerbatimLineComment(const VerbatimLineComment *C);
|
||||
|
@ -486,6 +550,34 @@ void CommentASTToHTMLConverter::visitParamCommandComment(
|
|||
Result << "</dd>";
|
||||
}
|
||||
|
||||
void CommentASTToHTMLConverter::visitTParamCommandComment(
|
||||
const TParamCommandComment *C) {
|
||||
if (C->isPositionValid()) {
|
||||
if (C->getDepth() == 1)
|
||||
Result << "<dt class=\"taram-name-index-"
|
||||
<< C->getIndex(0)
|
||||
<< "\">";
|
||||
else
|
||||
Result << "<dt class=\"taram-name-index-other\">";
|
||||
} else
|
||||
Result << "<dt class=\"tparam-name-index-invalid\">";
|
||||
|
||||
Result << C->getParamName() << "</dt>";
|
||||
|
||||
if (C->isPositionValid()) {
|
||||
if (C->getDepth() == 1)
|
||||
Result << "<dd class=\"tparam-descr-index-"
|
||||
<< C->getIndex(0)
|
||||
<< "\">";
|
||||
else
|
||||
Result << "<dd class=\"tparam-descr-index-other\">";
|
||||
} else
|
||||
Result << "<dd class=\"tparam-descr-index-invalid\">";
|
||||
|
||||
visitNonStandaloneParagraphComment(C->getParagraph());
|
||||
Result << "</dd>";
|
||||
}
|
||||
|
||||
void CommentASTToHTMLConverter::visitVerbatimBlockComment(
|
||||
const VerbatimBlockComment *C) {
|
||||
unsigned NumLines = C->getNumLines();
|
||||
|
@ -518,6 +610,7 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
|
|||
const ParagraphComment *FirstParagraph = NULL;
|
||||
const BlockCommandComment *Returns = NULL;
|
||||
SmallVector<const ParamCommandComment *, 8> Params;
|
||||
SmallVector<const TParamCommandComment *, 4> TParams;
|
||||
SmallVector<const BlockContentComment *, 8> MiscBlocks;
|
||||
|
||||
// Extract various blocks into separate variables and vectors above.
|
||||
|
@ -568,6 +661,15 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
|
|||
break;
|
||||
}
|
||||
|
||||
case Comment::TParamCommandCommentKind: {
|
||||
const TParamCommandComment *TPCC = cast<TParamCommandComment>(Child);
|
||||
if (!TPCC->hasParamName())
|
||||
break;
|
||||
|
||||
TParams.push_back(TPCC);
|
||||
break;
|
||||
}
|
||||
|
||||
case Comment::VerbatimBlockCommentKind:
|
||||
case Comment::VerbatimLineCommentKind:
|
||||
MiscBlocks.push_back(cast<BlockCommandComment>(Child));
|
||||
|
@ -590,6 +692,9 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
|
|||
std::stable_sort(Params.begin(), Params.end(),
|
||||
ParamCommandCommentCompareIndex());
|
||||
|
||||
std::stable_sort(TParams.begin(), TParams.end(),
|
||||
TParamCommandCommentComparePosition());
|
||||
|
||||
bool FirstParagraphIsBrief = false;
|
||||
if (Brief)
|
||||
visit(Brief);
|
||||
|
@ -607,6 +712,13 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
|
|||
visit(C);
|
||||
}
|
||||
|
||||
if (TParams.size() != 0) {
|
||||
Result << "<dl>";
|
||||
for (unsigned i = 0, e = TParams.size(); i != e; ++i)
|
||||
visit(TParams[i]);
|
||||
Result << "</dl>";
|
||||
}
|
||||
|
||||
if (Params.size() != 0) {
|
||||
Result << "<dl>";
|
||||
for (unsigned i = 0, e = Params.size(); i != e; ++i)
|
||||
|
|
|
@ -42,6 +42,10 @@ clang_ParamCommandComment_isParamIndexValid
|
|||
clang_ParamCommandComment_getParamIndex
|
||||
clang_ParamCommandComment_isDirectionExplicit
|
||||
clang_ParamCommandComment_getDirection
|
||||
clang_TParamCommandComment_getParamName
|
||||
clang_TParamCommandComment_isParamPositionValid
|
||||
clang_TParamCommandComment_getDepth
|
||||
clang_TParamCommandComment_getIndex
|
||||
clang_VerbatimBlockLineComment_getText
|
||||
clang_VerbatimLineComment_getText
|
||||
clang_HTMLTagComment_getAsString
|
||||
|
|
|
@ -221,6 +221,39 @@ template <typename T>
|
|||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
::testing::AssertionResult HasTParamCommandAt(
|
||||
const Comment *C,
|
||||
size_t Idx,
|
||||
TParamCommandComment *&TPCC,
|
||||
StringRef CommandName,
|
||||
StringRef ParamName,
|
||||
ParagraphComment *&Paragraph) {
|
||||
::testing::AssertionResult AR = GetChildAt(C, Idx, TPCC);
|
||||
if (!AR)
|
||||
return AR;
|
||||
|
||||
StringRef ActualCommandName = TPCC->getCommandName();
|
||||
if (ActualCommandName != CommandName)
|
||||
return ::testing::AssertionFailure()
|
||||
<< "TParamCommandComment has name \"" << ActualCommandName.str() << "\", "
|
||||
"expected \"" << CommandName.str() << "\"";
|
||||
|
||||
if (!TPCC->hasParamName())
|
||||
return ::testing::AssertionFailure()
|
||||
<< "TParamCommandComment has no parameter name";
|
||||
|
||||
StringRef ActualParamName = TPCC->getParamName();
|
||||
if (ActualParamName != ParamName)
|
||||
return ::testing::AssertionFailure()
|
||||
<< "TParamCommandComment has parameter name \"" << ActualParamName.str()
|
||||
<< "\", "
|
||||
"expected \"" << ParamName.str() << "\"";
|
||||
|
||||
Paragraph = TPCC->getParagraph();
|
||||
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
::testing::AssertionResult HasInlineCommandAt(const Comment *C,
|
||||
size_t Idx,
|
||||
InlineCommandComment *&ICC,
|
||||
|
@ -838,6 +871,33 @@ TEST_F(CommentParserTest, ParamCommand6) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(CommentParserTest, TParamCommand1) {
|
||||
const char *Sources[] = {
|
||||
"// \\tparam aaa Bbb\n",
|
||||
"// \\tparam\n"
|
||||
"// aaa Bbb\n",
|
||||
"// \\tparam \n"
|
||||
"// aaa Bbb\n",
|
||||
"// \\tparam aaa\n"
|
||||
"// Bbb\n"
|
||||
};
|
||||
|
||||
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
|
||||
FullComment *FC = parseString(Sources[i]);
|
||||
ASSERT_TRUE(HasChildCount(FC, 2));
|
||||
|
||||
ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " "));
|
||||
{
|
||||
TParamCommandComment *TPCC;
|
||||
ParagraphComment *PC;
|
||||
ASSERT_TRUE(HasTParamCommandAt(FC, 1, TPCC, "tparam",
|
||||
"aaa", PC));
|
||||
ASSERT_TRUE(HasChildCount(TPCC, 1));
|
||||
ASSERT_TRUE(HasParagraphCommentAt(TPCC, 0, " Bbb"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CommentParserTest, InlineCommand1) {
|
||||
const char *Source = "// \\c";
|
||||
|
||||
|
|
Loading…
Reference in New Issue