Index: clang-tools-extra/clang-doc/Representation.h =================================================================== --- clang-tools-extra/clang-doc/Representation.h +++ clang-tools-extra/clang-doc/Representation.h @@ -108,6 +108,7 @@ AttrValues; // List of attribute values for each key (for HTML). llvm::SmallVector, 4> Args; // List of arguments to commands (for InlineCommand). + // Parameter names (for ParamCommand). std::vector> Children; // List of child comments for this CommentInfo. }; Index: clang-tools-extra/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/clang-doc/Serialize.cpp +++ clang-tools-extra/clang-doc/Serialize.cpp @@ -137,8 +137,14 @@ CurrentCI.Direction = ParamCommandComment::getDirectionAsString(C->getDirection()); CurrentCI.Explicit = C->isDirectionExplicit(); - if (C->hasParamName()) - CurrentCI.ParamName = C->getParamNameAsWritten(); + for (unsigned I = 0, E = C->getNumParams(); I != E; ++I) { + StringRef ParamName = C->getParamName(I); + if (I != 0) + CurrentCI.ParamName += ", "; + CurrentCI.ParamName += ParamName; + + CurrentCI.Args.push_back(ParamName); + } } void ClangDocCommentVisitor::visitTParamCommandComment( Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -64,6 +64,11 @@ - -Wbitwise-conditional-parentheses will warn on operator precedence issues when mixing bitwise-and (&) and bitwise-or (|) operator with the conditional operator (?:). +- -Wdocumentation properly handles Doxygen comments with multiple identifiers in + one \param command. The validation whether the name of the identifier is valid + has been improved. +- -Wdocumentation now warns about not documented function arguments if at least + once \param command is supplied in the function's documentation. Non-comprehensive list of changes in this release ------------------------------------------------- @@ -351,7 +356,16 @@ libclang -------- -- ... +- Function ``clang_ParamCommandComment_getNumParams`` has been added to + determine the number of parameters to a single Doxygen \param command.p +- Function ``clang_ParamCommandComment_isVarArgParam`` has been added to + determine the whether the parameter refers to the variadic argument. +- Function ``clang_ParamCommandComment_getParamName`` has been modified. It + takes an additional index argument. +- Function ``clang_ParamCommandComment_isParamIndexValid`` has been modified. It + takes an additional index argument. +- Function ``clang_ParamCommandComment_getParamIndex`` has been modified. It + takes an additional index argument. Static Analyzer --------------- Index: clang/include/clang-c/Documentation.h =================================================================== --- clang/include/clang-c/Documentation.h +++ clang/include/clang-c/Documentation.h @@ -377,28 +377,57 @@ /** * \param Comment a \c CXComment_ParamCommand AST node. * - * \returns parameter name. + * \returns the number of identifiers. */ CINDEX_LINKAGE -CXString clang_ParamCommandComment_getParamName(CXComment Comment); +unsigned clang_ParamCommandComment_getNumParams(CXComment Comment); /** * \param Comment a \c CXComment_ParamCommand AST node. * - * \returns non-zero if the parameter that this AST node represents was found + * \param Idx the (zero-based) index of the identifier of the param command. + * + * \returns identifier name. + */ +CINDEX_LINKAGE +CXString clang_ParamCommandComment_getParamName(CXComment Comment, + unsigned Idx); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \param Idx the (zero-based) index of the identifier of the param command. + * + * \returns non-zero if the identifier that this AST node represents was found * in the function prototype and \c clang_ParamCommandComment_getParamIndex * function will return a meaningful value. */ CINDEX_LINKAGE -unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment); +unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment, + unsigned Idx); /** * \param Comment a \c CXComment_ParamCommand AST node. * + * \param Idx the (zero-based) index of the identifier of the param command. + * + * \returns non-zero if the identifier that this AST node represents was found + * in the function prototype and points to the variadic argument. + */ +CINDEX_LINKAGE +unsigned clang_ParamCommandComment_isVarArgParam(CXComment Comment, + unsigned Idx); + +/** + * \param Comment a \c CXComment_ParamCommand AST node. + * + * \param Idx the (zero-based) index of the identifier of the param command. + * * \returns zero-based parameter index in function prototype. */ CINDEX_LINKAGE -unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment); +unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment, + unsigned Idx); /** * \param Comment a \c CXComment_ParamCommand AST node. Index: clang/include/clang/AST/Comment.h =================================================================== --- clang/include/clang/AST/Comment.h +++ clang/include/clang/AST/Comment.h @@ -712,8 +712,8 @@ /// Doxygen \\param command. class ParamCommandComment : public BlockCommandComment { private: - /// Parameter index in the function declaration. - unsigned ParamIndex; + /// The index of the identifier in the function declaration. + MutableArrayRef ParamIndex; public: enum : unsigned { @@ -721,13 +721,11 @@ VarArgParamIndex = ~0U/*InvalidParamIndex*/ - 1U }; - ParamCommandComment(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID, - CommandMarkerKind CommandMarker) : - BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, - CommandID, CommandMarker), - ParamIndex(InvalidParamIndex) { + ParamCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, + unsigned CommandID, CommandMarkerKind CommandMarker) + : BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd, + CommandID, CommandMarker), + ParamIndex() { ParamCommandCommentBits.Direction = In; ParamCommandCommentBits.IsDirectionExplicit = false; } @@ -757,43 +755,58 @@ ParamCommandCommentBits.IsDirectionExplicit = Explicit; } - bool hasParamName() const { - return getNumArgs() > 0; + unsigned getNumParams() const LLVM_READONLY { + assert(Args.size() == ParamIndex.size()); + return ParamIndex.size(); } - StringRef getParamName(const FullComment *FC) const; + void setParamIndex(MutableArrayRef Idx) { + assert(ParamIndex.empty() && "Can't initialize more than once."); + ParamIndex = Idx; + } - StringRef getParamNameAsWritten() const { - return Args[0].Text; + void setParamIndex(unsigned Idx, unsigned ArgumentIndex) { + assert(Idx < ParamIndex.size()); + ParamIndex[Idx] = ArgumentIndex; } - SourceRange getParamNameRange() const { - return Args[0].Range; + unsigned getParamIndex(unsigned Idx) const LLVM_READONLY { + assert(Idx < ParamIndex.size()); + return ParamIndex[Idx]; } - bool isParamIndexValid() const LLVM_READONLY { - return ParamIndex != InvalidParamIndex; + /// Returns the name of the identifier as used in the \\param command. + /// + /// @param Idx The index of the identifier in the \\param command. + StringRef getParamName(unsigned Idx) const LLVM_READONLY { + return getArgText(Idx); } - bool isVarArgParam() const LLVM_READONLY { - return ParamIndex == VarArgParamIndex; + /// Returns the name of the function argument as written in \p FC. + /// + /// If the identifier is not mapped to an argument it returns the identifer + /// used in the \\param command. + /// + /// @param Idx The index of the identifier in the \\param command. + StringRef getParamName(const FullComment *FC, unsigned Idx) const; + + SourceRange getParamRange(unsigned Idx) const LLVM_READONLY { + return getArgRange(Idx); } - void setIsVarArgParam() { - ParamIndex = VarArgParamIndex; - assert(isParamIndexValid()); + const Argument *getParam(unsigned Idx) const LLVM_READONLY { + assert(Idx < Args.size()); + return &Args[Idx]; } - unsigned getParamIndex() const LLVM_READONLY { - assert(isParamIndexValid()); - assert(!isVarArgParam()); - return ParamIndex; + bool isParamIndexValid(unsigned Idx) const LLVM_READONLY { + assert(Idx < ParamIndex.size()); + return !isVarArgParam(Idx) && ParamIndex[Idx] != InvalidParamIndex; } - void setParamIndex(unsigned Index) { - ParamIndex = Index; - assert(isParamIndexValid()); - assert(!isVarArgParam()); + bool isVarArgParam(unsigned Idx) const LLVM_READONLY { + assert(Idx < ParamIndex.size()); + return ParamIndex[Idx] == VarArgParamIndex; } }; Index: clang/include/clang/AST/CommentSema.h =================================================================== --- clang/include/clang/AST/CommentSema.h +++ clang/include/clang/AST/CommentSema.h @@ -107,10 +107,9 @@ SourceLocation ArgLocEnd, StringRef Arg); - void actOnParamCommandParamNameArg(ParamCommandComment *Command, - SourceLocation ArgLocBegin, - SourceLocation ArgLocEnd, - StringRef Arg); + void + actOnParamCommandParamNameArg(ParamCommandComment *Command, + ArrayRef Args); void actOnParamCommandFinish(ParamCommandComment *Command, ParagraphComment *Paragraph); Index: clang/include/clang/Basic/DiagnosticCommentKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticCommentKinds.td +++ clang/include/clang/Basic/DiagnosticCommentKinds.td @@ -109,6 +109,18 @@ def note_doc_param_name_suggestion : Note< "did you mean '%0'?">; +def warn_doc_param_undocumented : Warning< + "parameter '%0' is not documented">, + InGroup, DefaultIgnore; + +def warn_doc_param_identifier_invalid : Warning< + "'%select{\\|@}0param' command does not have a valid identifier">, + InGroup, DefaultIgnore; + +def warn_doc_param_identifier_no_terminator : Warning< + "'%select{\\|@}0param' command's identifier is not properly terminated">, + InGroup, DefaultIgnore; + // tparam command def warn_doc_tparam_not_attached_to_a_template_decl : Warning< Index: clang/lib/AST/Comment.cpp =================================================================== --- clang/lib/AST/Comment.cpp +++ clang/lib/AST/Comment.cpp @@ -368,11 +368,19 @@ IsFilled = true; } -StringRef ParamCommandComment::getParamName(const FullComment *FC) const { - assert(isParamIndexValid()); - if (isVarArgParam()) +StringRef ParamCommandComment::getParamName(const FullComment *FC, + unsigned Idx) const { + unsigned ParamIdx = getParamIndex(Idx); + switch (ParamIdx) { + case InvalidParamIndex: + return getParamName(Idx); + + case VarArgParamIndex: return "..."; - return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName(); + + default: + return FC->getDeclInfo()->ParamVars[ParamIdx]->getName(); + } } StringRef TParamCommandComment::getParamName(const FullComment *FC) const { Index: clang/lib/AST/CommentParser.cpp =================================================================== --- clang/lib/AST/CommentParser.cpp +++ clang/lib/AST/CommentParser.cpp @@ -183,6 +183,53 @@ return true; } + bool lexIdentifier(Token &Tok) { + if (isEnd()) + return false; + + Position SavedPos = Pos; + consumeWhitespace(); + if (isEnd()) { + Pos = SavedPos; + return false; + } + + SmallString<32> IdentifierText; + const char *IdentifierBegin = Pos.BufferPtr; + SourceLocation Loc = getSourceLocation(); + char C = peek(); + if (isIdentifierHead(C)) { + IdentifierText.push_back(C); + consumeChar(); + while (!isEnd()) { + C = peek(); + if (isIdentifierBody(C)) { + IdentifierText.push_back(C); + consumeChar(); + } else + break; + } + } else if (C == '.') { + do { + IdentifierText.push_back('.'); + consumeChar(); + } while (!isEnd() && peek() == '.'); + } else { + Pos = SavedPos; + return false; + } + + const unsigned Length = IdentifierText.size(); + char *TextPtr = Allocator.Allocate(Length + 1); + + memcpy(TextPtr, IdentifierText.c_str(), Length + 1); + StringRef Text = StringRef(TextPtr, Length); + + formTokenWithChars(Tok, Loc, IdentifierBegin, + Pos.BufferPtr - IdentifierBegin, Text); + return true; + } + bool lexDelimitedSeq(Token &Tok, char OpenDelim, char CloseDelim) { if (isEnd()) return false; @@ -229,6 +276,43 @@ return true; } + bool lexChar(Token &Tok, char Char) { + assert(!isWhitespace(Char)); + if (isEnd()) + return false; + + Position SavedPos = Pos; + + consumeWhitespace(); + SmallString<2> CharText; + const char *CharBegin = Pos.BufferPtr; + SourceLocation Loc = getSourceLocation(); + if (!isEnd() && peek() == Char) { + CharText.push_back(Char); + consumeChar(); + } else { + Pos = SavedPos; + return false; + } + + const unsigned Length = CharText.size(); + char *TextPtr = Allocator.Allocate(Length + 1); + + memcpy(TextPtr, CharText.c_str(), Length + 1); + StringRef Text = StringRef(TextPtr, Length); + + formTokenWithChars(Tok, Loc, CharBegin, Pos.BufferPtr - CharBegin, Text); + return true; + } + + bool hasIdentifierTerminator() { + if (isEnd()) + return true; + + char C = peek(); + return C == ',' || isWhitespace(C); + } + /// Put back tokens that we didn't consume. void putBackLeftoverTokens() { if (isEnd()) @@ -272,11 +356,43 @@ Arg.getEndLocation(), Arg.getText()); - if (Retokenizer.lexWord(Arg)) - S.actOnParamCommandParamNameArg(PC, - Arg.getLocation(), - Arg.getEndLocation(), - Arg.getText()); + using Argument = BlockCommandComment::Argument; + SmallVector ArgumentTokens; + do { + if (Retokenizer.lexIdentifier(Arg)) { + ArgumentTokens.push_back(Arg); + if (!Retokenizer.hasIdentifierTerminator()) + Diag(Arg.getEndLocation(), + diag::warn_doc_param_identifier_no_terminator) + << PC->getCommandMarker() + << SourceRange(Arg.getLocation(), Arg.getEndLocation()); + + } else if (!ArgumentTokens.empty()) { + Diag(Arg.getEndLocation(), diag::warn_doc_param_identifier_invalid) + << PC->getCommandMarker() << PC->getSourceRange(); + + return; + } + } while (Retokenizer.lexChar(Arg, ',')); + + if (ArgumentTokens.empty()) { + Diag(PC->getEndLoc(), diag::warn_doc_param_identifier_invalid) + << PC->getCommandMarker() << PC->getSourceRange(); + return; + } + + unsigned NumArgs = ArgumentTokens.size(); + Argument *Args = + new (Allocator.Allocate(NumArgs)) Argument[NumArgs]; + + std::transform(ArgumentTokens.begin(), ArgumentTokens.end(), &Args[0], + [](const Token &Arg) { + return Argument{ + SourceRange(Arg.getLocation(), Arg.getEndLocation()), + Arg.getText()}; + }); + + S.actOnParamCommandParamNameArg(PC, llvm::makeArrayRef(Args, NumArgs)); } void Parser::parseTParamCommandArgs(TParamCommandComment *TPC, Index: clang/lib/AST/CommentSema.cpp =================================================================== --- clang/lib/AST/CommentSema.cpp +++ clang/lib/AST/CommentSema.cpp @@ -253,22 +253,26 @@ /*Explicit=*/true); } -void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, - SourceLocation ArgLocBegin, - SourceLocation ArgLocEnd, - StringRef Arg) { +void Sema::actOnParamCommandParamNameArg( + ParamCommandComment *Command, + ArrayRef Args) { // Parser will not feed us more arguments than needed. assert(Command->getNumArgs() == 0); + assert(Command->getNumParams() == 0); if (!Command->isDirectionExplicit()) { // 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); - Command->setArgs(llvm::makeArrayRef(A, 1)); + + Command->setArgs(Args); + + unsigned Size = Args.size(); + auto ParamIndex = llvm::makeMutableArrayRef( + new (Allocator.Allocate(Size)) unsigned[Size], Size); + std::fill(ParamIndex.begin(), ParamIndex.end(), + ParamCommandComment::InvalidParamIndex); + Command->setParamIndex(ParamIndex); } void Sema::actOnParamCommandFinish(ParamCommandComment *Command, @@ -733,44 +737,66 @@ return; } - SmallVector UnresolvedParamCommands; + SmallVector UnresolvedParamCommands; - // Comment AST nodes that correspond to \c ParamVars for which we have + // Comment AST nodes that correspond to \\c ParamVars for which we have // found a \\param command or NULL if no documentation was found so far. - SmallVector ParamVarDocs; + // SmallVector ParamVarDocs; + SmallVector ParamVarDocs; + const SourceRange *VarArgDocs = nullptr; ArrayRef ParamVars = getParamVars(); ParamVarDocs.resize(ParamVars.size(), nullptr); - // First pass over all \\param commands: resolve all parameter names. - for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); - I != E; ++I) { - ParamCommandComment *PCC = dyn_cast(*I); - if (!PCC || !PCC->hasParamName()) - continue; - StringRef ParamName = PCC->getParamNameAsWritten(); + // Warn about undocumented params, if at least one \\param has been found. + // This to avoid warning when none are documented. + // TODO Add a flag to always warn? + bool WarnUndocumentedParameters = false; + + auto ProcessParameter = [&](ParamCommandComment *PCC, unsigned Idx) { + WarnUndocumentedParameters = true; + StringRef ParamName = PCC->getParamName(Idx); // Check that referenced parameter name is in the function decl. - const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, - ParamVars); - if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { - PCC->setIsVarArgParam(); - continue; - } + const unsigned ResolvedParamIndex = + resolveParmVarReference(ParamName, ParamVars); + if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { - UnresolvedParamCommands.push_back(PCC); - continue; + UnresolvedParamCommands.push_back(PCC->getParam(Idx)); + return; } - PCC->setParamIndex(ResolvedParamIndex); - if (ParamVarDocs[ResolvedParamIndex]) { - SourceRange ArgRange = PCC->getParamNameRange(); - Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) - << ParamName << ArgRange; - ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; - Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) - << PrevCommand->getParamNameRange(); + PCC->setParamIndex(Idx, ResolvedParamIndex); + + if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { + if (VarArgDocs) { + SourceRange ParamRange = PCC->getParamRange(Idx); + Diag(ParamRange.getBegin(), diag::warn_doc_param_duplicate) + << ParamName << ParamRange; + Diag(VarArgDocs->getBegin(), diag::note_doc_param_previous) + << *VarArgDocs; + } else + VarArgDocs = &(PCC->getParam(Idx)->Range); + + return; } - ParamVarDocs[ResolvedParamIndex] = PCC; + + if (const SourceRange *PrevRange = ParamVarDocs[ResolvedParamIndex]) { + SourceRange ParamRange = PCC->getParamRange(Idx); + Diag(ParamRange.getBegin(), diag::warn_doc_param_duplicate) + << ParamName << ParamRange; + Diag(PrevRange->getBegin(), diag::note_doc_param_previous) << *PrevRange; + } else + ParamVarDocs[ResolvedParamIndex] = &(PCC->getParam(Idx)->Range); + }; + + // First pass over all \\param commands: resolve all parameter names. + for (auto *C : FC->getBlocks()) { + ParamCommandComment *PCC = dyn_cast(C); + if (!PCC) + continue; + + for (unsigned I = 0, E = PCC->getNumParams(); I != E; ++I) + ProcessParameter(PCC, I); } // Find parameter declarations that have no corresponding \\param. @@ -779,38 +805,69 @@ if (!ParamVarDocs[i]) OrphanedParamDecls.push_back(ParamVars[i]); } + bool UndocumentedVariadic = isFunctionOrMethodVariadic() && !VarArgDocs; // Second pass over unresolved \\param commands: do typo correction. // Suggest corrections from a set of parameter declarations that have no // corresponding \\param. - for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { - const ParamCommandComment *PCC = UnresolvedParamCommands[i]; - - SourceRange ArgRange = PCC->getParamNameRange(); - StringRef ParamName = PCC->getParamNameAsWritten(); + for (const auto *Arg : UnresolvedParamCommands) { + SourceRange ArgRange = Arg->Range; + StringRef ParamName = Arg->Text; Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) - << ParamName << ArgRange; + << ParamName << ArgRange; // All parameters documented -- can't suggest a correction. - if (OrphanedParamDecls.size() == 0) + if (OrphanedParamDecls.size() == 0 && !UndocumentedVariadic) continue; - unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; - if (OrphanedParamDecls.size() == 1) { - // If one parameter is not documented then that parameter is the only - // possible suggestion. - CorrectedParamIndex = 0; - } else { - // Do typo correction. - CorrectedParamIndex = correctTypoInParmVarReference(ParamName, - OrphanedParamDecls); - } - if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { - const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; - if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) + unsigned CorrectedParamIndex = + OrphanedParamDecls.size() == 1 && !UndocumentedVariadic + // If one parameter is not documented then that parameter is the + // only possible suggestion. + ? 0 + // Do typo correction. + : correctTypoInParmVarReference(ParamName, OrphanedParamDecls); + + switch (CorrectedParamIndex) { + case ParamCommandComment::InvalidParamIndex: + /* DO NOTHING */ + break; + + case ParamCommandComment::VarArgParamIndex: + Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) + << "..." << FixItHint::CreateReplacement(ArgRange, "..."); + + UndocumentedVariadic = false; + break; + + default: + if (const IdentifierInfo *CorrectedII = + OrphanedParamDecls[CorrectedParamIndex]->getIdentifier()) Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) - << CorrectedII->getName() - << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); + << CorrectedII->getName() + << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); + + // Avoid suggesting the same parameter twice + OrphanedParamDecls.erase(OrphanedParamDecls.begin() + + CorrectedParamIndex); + } + } + if (WarnUndocumentedParameters) { + for (const auto *OrphanedParamDecl : OrphanedParamDecls) + if (auto Identifier = OrphanedParamDecl->getIdentifier()) { + SourceLocation Loc = OrphanedParamDecl->getLocation(); + Diag(Loc, diag::warn_doc_param_undocumented) + << Identifier->getName() + << SourceRange(Loc, OrphanedParamDecl->getEndLoc()); + } + if (UndocumentedVariadic) { + const FunctionDecl *FD = + dyn_cast(ThisDeclInfo->CurrentDecl); + assert(FD); + + SourceLocation Loc = FD->getEllipsisLoc(); + Diag(Loc, diag::warn_doc_param_undocumented) + << "..." << SourceRange(Loc, Loc.getLocWithOffset(2)); } } } @@ -1057,16 +1114,20 @@ } } // end anonymous namespace -unsigned Sema::correctTypoInParmVarReference( - StringRef Typo, +unsigned +Sema::correctTypoInParmVarReference(StringRef Typo, ArrayRef ParamVars) { + if (isFunctionOrMethodVariadic() && + Typo.find_first_not_of('.') == StringRef::npos) + return ParamCommandComment::VarArgParamIndex; + 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; + + return ParamCommandComment::InvalidParamIndex; } namespace { Index: clang/lib/AST/JSONNodeDumper.cpp =================================================================== --- clang/lib/AST/JSONNodeDumper.cpp +++ clang/lib/AST/JSONNodeDumper.cpp @@ -1578,12 +1578,31 @@ } attributeOnlyIfTrue("explicit", C->isDirectionExplicit()); - if (C->hasParamName()) - JOS.attribute("param", C->isParamIndexValid() ? C->getParamName(FC) - : C->getParamNameAsWritten()); - - if (C->isParamIndexValid() && !C->isVarArgParam()) - JOS.attribute("paramIdx", C->getParamIndex()); + unsigned E = C->getNumParams(); + if (E) { + llvm::json::Array Params; + llvm::json::Array Indexes; + for (unsigned I = 0; I != E; ++I) { + Params.push_back(C->getParamName(FC, I)); + + unsigned Idx = C->getParamIndex(I); + switch (Idx) { + case comments::ParamCommandComment::InvalidParamIndex: + Indexes.push_back("invalid"); + break; + + case comments::ParamCommandComment::VarArgParamIndex: + Indexes.push_back("..."); + break; + + default: + Indexes.push_back(Idx); + break; + } + } + JOS.attribute("params", std::move(Params)); + JOS.attribute("positions", std::move(Indexes)); + } } void JSONNodeDumper::visitTParamCommandComment( Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -534,15 +534,38 @@ else OS << " implicitly"; - if (C->hasParamName()) { - if (C->isParamIndexValid()) - OS << " Param=\"" << C->getParamName(FC) << "\""; - else - OS << " Param=\"" << C->getParamNameAsWritten() << "\""; - } + unsigned E = C->getNumParams(); + if (E) { + OS << " Param=["; + for (unsigned I = 0; I != E; ++I) { + if (I != 0) + OS << ", "; + OS << C->getParamName(FC, I); + } + OS << "]"; + + OS << " ParamIndex=["; + for (unsigned I = 0; I != E; ++I) { + if (I != 0) + OS << ", "; - if (C->isParamIndexValid() && !C->isVarArgParam()) - OS << " ParamIndex=" << C->getParamIndex(); + unsigned Idx = C->getParamIndex(I); + switch (Idx) { + case comments::ParamCommandComment::InvalidParamIndex: + OS << "invalid"; + break; + + case comments::ParamCommandComment::VarArgParamIndex: + OS << "..."; + break; + + default: + OS << Idx; + break; + } + } + OS << "]"; + } } void TextNodeDumper::visitTParamCommandComment( Index: clang/lib/Index/CommentToXML.cpp =================================================================== --- clang/lib/Index/CommentToXML.cpp +++ clang/lib/Index/CommentToXML.cpp @@ -29,22 +29,22 @@ public: bool operator()(const ParamCommandComment *LHS, const ParamCommandComment *RHS) const { - unsigned LHSIndex = UINT_MAX; - unsigned RHSIndex = UINT_MAX; - - if (LHS->isParamIndexValid()) { - if (LHS->isVarArgParam()) - LHSIndex = UINT_MAX - 1; - else - LHSIndex = LHS->getParamIndex(); + unsigned LHS_I = 0; + unsigned LHS_E = LHS->getNumParams(); + unsigned RHS_I = 0; + unsigned RHS_E = LHS->getNumParams(); + + for (; LHS_I != LHS_E && RHS_I != RHS_E; ++LHS_I, ++RHS_I) { + unsigned LHSIndex = LHS->getParamIndex(LHS_I); + unsigned RHSIndex = RHS->getParamIndex(RHS_I); + + if (LHSIndex < RHSIndex) + return true; + if (LHSIndex > RHSIndex) + return false; } - if (RHS->isParamIndexValid()) { - if (RHS->isVarArgParam()) - RHSIndex = UINT_MAX - 1; - else - RHSIndex = RHS->getParamIndex(); - } - return LHSIndex < RHSIndex; + + return LHS_I == LHS_E && RHS_I != RHS_E; } }; @@ -140,7 +140,7 @@ case Comment::ParamCommandCommentKind: { const ParamCommandComment *PCC = cast(Child); - if (!PCC->hasParamName()) + if (PCC->getNumParams() == 0) break; if (!PCC->isDirectionExplicit() && !PCC->hasNonWhitespaceParagraph()) @@ -349,32 +349,39 @@ void CommentASTToHTMLConverter::visitParamCommandComment( const ParamCommandComment *C) { - if (C->isParamIndexValid()) { - if (C->isVarArgParam()) { - Result << "
"; - appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); - } else { - Result << "
getParamIndex() - << "\">"; - appendToResultWithHTMLEscaping(C->getParamName(FC)); + + unsigned E = C->getNumParams(); + if (E == 0) + return; + + SmallString<16> ID; + SmallString<128> Identifier; + for (unsigned I = 0; I != E; ++I) { + unsigned Idx = C->getParamIndex(I); + switch (Idx) { + case ParamCommandComment::InvalidParamIndex: + ID += "-invalid"; + break; + + case ParamCommandComment::VarArgParamIndex: + ID += "-vararg"; + break; + + default: + ID += '-'; + ID += std::to_string(Idx); + break; } - } else { - Result << "
"; - appendToResultWithHTMLEscaping(C->getParamNameAsWritten()); + if (!Identifier.empty()) + Identifier += ","; + Identifier += C->getParamName(FC, I); } - Result << "
"; - if (C->isParamIndexValid()) { - if (C->isVarArgParam()) - Result << "
"; - else - Result << "
getParamIndex() - << "\">"; - } else - Result << "
"; + Result << "
"; + appendToResultWithHTMLEscaping(Identifier); + Result << "
"; + Result << "
"; visitNonStandaloneParagraphComment(C->getParagraph()); Result << "
"; } @@ -734,17 +741,36 @@ void CommentASTToXMLConverter::visitParamCommandComment( const ParamCommandComment *C) { - Result << ""; - appendToResultWithXMLEscaping(C->isParamIndexValid() - ? C->getParamName(FC) - : C->getParamNameAsWritten()); - Result << ""; - if (C->isParamIndexValid()) { - if (C->isVarArgParam()) - Result << ""; - else - Result << "" << C->getParamIndex() << ""; + Result << ""; + unsigned E = C->getNumParams(); + if (E) { + Result << ""; + for (unsigned I = 0; I != E; ++I) { + Result << ""; + + Result << ""; + appendToResultWithXMLEscaping(C->getParamName(FC, I)); + Result << ""; + + unsigned Idx = C->getParamIndex(I); + switch (Idx) { + case comments::ParamCommandComment::InvalidParamIndex: + /* DO NOTHING */ + break; + + case comments::ParamCommandComment::VarArgParamIndex: + Result << ""; + break; + + default: + Result << "" << Idx << ""; + break; + } + + Result << ""; + } + Result << ""; } Result << "isDirectionExplicit() << "\">"; Index: clang/test/AST/ast-dump-comment-json.cpp =================================================================== --- clang/test/AST/ast-dump-comment-json.cpp +++ clang/test/AST/ast-dump-comment-json.cpp @@ -33,7 +33,18 @@ /// \param ... More arguments template -void Test_TemplatedFunctionVariadic(int arg, ...); +void Test_TemplatedFunctionVariadic(...); + +/// \param aaa xxx +/// \param bbb Invalid argument +/// \param ... More arguments +template +void Test_TemplatedFunctionParamAndVariadic(int aaa, ...); + +/// \param aaa,bbb,... xxx +template +void Test_TemplatedFunctionParamAndVariadic2(int aaa, ...); + // NOTE: CHECK lines have been autogenerated by gen_ast_dump_json_test.py // using --filters=FullComment @@ -413,8 +424,12 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "direction": "in", -// CHECK-NEXT: "param": "Aaa", -// CHECK-NEXT: "paramIdx": 0, +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "Aaa" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 0 +// CHECK-NEXT: ], // CHECK-NEXT: "inner": [ // CHECK-NEXT: { // CHECK-NEXT: "id": "0x{{.*}}", @@ -511,8 +526,12 @@ // CHECK-NEXT: }, // CHECK-NEXT: "direction": "in,out", // CHECK-NEXT: "explicit": true, -// CHECK-NEXT: "param": "Bbb", -// CHECK-NEXT: "paramIdx": 1, +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "Bbb" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 1 +// CHECK-NEXT: ], // CHECK-NEXT: "inner": [ // CHECK-NEXT: { // CHECK-NEXT: "id": "0x{{.*}}", @@ -1326,7 +1345,12 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "direction": "in", -// CHECK-NEXT: "param": "...", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], // CHECK-NEXT: "inner": [ // CHECK-NEXT: { // CHECK-NEXT: "id": "0x{{.*}}", @@ -1464,7 +1488,12 @@ // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "direction": "in", -// CHECK-NEXT: "param": "...", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], // CHECK-NEXT: "inner": [ // CHECK-NEXT: { // CHECK-NEXT: "id": "0x{{.*}}", @@ -1515,3 +1544,998 @@ // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } + + +// CHECK: "kind": "FullComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 633, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 632, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "aaa" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 0 +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 645, +// CHECK-NEXT: "col": 18, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " xxx" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 652, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 651, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "bbb" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "invalid" +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 677, +// CHECK-NEXT: "col": 31, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " Invalid argument" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 684, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 683, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " More arguments" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + + +// CHECK: "kind": "FullComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 631, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 633, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 632, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "aaa" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 0 +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "line": 38, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 642, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 645, +// CHECK-NEXT: "col": 18, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " xxx" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 650, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 652, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 651, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "bbb" +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "invalid" +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "line": 39, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 661, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 677, +// CHECK-NEXT: "col": 31, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " Invalid argument" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "line": 40, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 682, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 684, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 683, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 693, +// CHECK-NEXT: "col": 15, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 707, +// CHECK-NEXT: "col": 29, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " More arguments" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + + +// CHECK: "kind": "FullComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "line": 44, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 795, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 794, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "aaa", +// CHECK-NEXT: "bbb", +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 0, +// CHECK-NEXT: "invalid", +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " xxx" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } + + +// CHECK: "kind": "FullComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 793, +// CHECK-NEXT: "col": 4, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " " +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParamCommandComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 795, +// CHECK-NEXT: "col": 6, +// CHECK-NEXT: "tokLen": 5 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 794, +// CHECK-NEXT: "col": 5, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "direction": "in", +// CHECK-NEXT: "params": [ +// CHECK-NEXT: "aaa", +// CHECK-NEXT: "bbb", +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "positions": [ +// CHECK-NEXT: 0, +// CHECK-NEXT: "invalid", +// CHECK-NEXT: "..." +// CHECK-NEXT: ], +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "ParagraphComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "inner": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "TextComment", +// CHECK-NEXT: "loc": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 812, +// CHECK-NEXT: "col": 23, +// CHECK-NEXT: "tokLen": 0 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 815, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "text": " xxx" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: } Index: clang/test/AST/ast-dump-comment.cpp =================================================================== --- clang/test/AST/ast-dump-comment.cpp +++ clang/test/AST/ast-dump-comment.cpp @@ -28,10 +28,10 @@ /// \param [in,out] Bbb yyy void Test_ParamCommandComment(int Aaa, int Bbb); // CHECK: FunctionDecl{{.*}}Test_ParamCommandComment -// CHECK: ParamCommandComment{{.*}} [in] implicitly Param="Aaa" ParamIndex=0 +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[Aaa] ParamIndex=[0] // CHECK-NEXT: ParagraphComment // CHECK-NEXT: TextComment{{.*}} Text=" xxx" -// CHECK: ParamCommandComment{{.*}} [in,out] explicitly Param="Bbb" ParamIndex=1 +// CHECK: ParamCommandComment{{.*}} [in,out] explicitly Param=[Bbb] ParamIndex=[1] // CHECK-NEXT: ParagraphComment // CHECK-NEXT: TextComment{{.*}} Text=" yyy" @@ -75,8 +75,32 @@ /// \param ... More arguments template -void Test_TemplatedFunctionVariadic(int arg, ...); +void Test_TemplatedFunctionVariadic(...); // CHECK: FunctionTemplateDecl{{.*}}Test_TemplatedFunctionVariadic -// CHECK: ParamCommandComment{{.*}} [in] implicitly Param="..." +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[...] ParamIndex=[...] // CHECK-NEXT: ParagraphComment // CHECK-NEXT: TextComment{{.*}} Text=" More arguments" + +/// \param aaa xxx +/// \param bbb Invalid argument +/// \param ... More arguments +template +void Test_TemplatedFunctionParamAndVariadic(int aaa, ...); +// CHECK: FunctionTemplateDecl{{.*}}Test_TemplatedFunctionParamAndVariadic +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[aaa] ParamIndex=[0] +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" xxx" +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[bbb] ParamIndex=[invalid] +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" Invalid argument" +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[...] ParamIndex=[...] +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" More arguments" + +/// \param aaa,bbb,... xxx +template +void Test_TemplatedFunctionParamAndVariadic2(int aaa, ...); +// CHECK: FunctionTemplateDecl{{.*}}Test_TemplatedFunctionParamAndVariadic +// CHECK: ParamCommandComment{{.*}} [in] implicitly Param=[aaa, bbb, ...] ParamIndex=[0, invalid, ...] +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" xxx" Index: clang/test/Index/comment-to-html-xml-conversion.cpp =================================================================== --- clang/test/Index/comment-to-html-xml-conversion.cpp +++ clang/test/Index/comment-to-html-xml-conversion.cpp @@ -234,30 +234,30 @@ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[] ParamIndex=Invalid +// CHECK-NEXT: (CXComment_ParamCommand in implicitly // CHECK-NEXT: (CXComment_Paragraph IsWhitespace)))] /// \param x1 Aaa. void test_cmd_param_2(int x1); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_2:{{.*}} FullCommentAsHTML=[
x1
Aaa.
] FullCommentAsXML=[test_cmd_param_2c:@F@test_cmd_param_2#I#void test_cmd_param_2(int x1)x10in Aaa.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_2:{{.*}} FullCommentAsHTML=[
x1
Aaa.
] FullCommentAsXML=[test_cmd_param_2c:@F@test_cmd_param_2#I#void test_cmd_param_2(int x1)x10in Aaa.] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x1] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] /// \param zzz Aaa. void test_cmd_param_3(int x1); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_3:{{.*}} FullCommentAsHTML=[
zzz
Aaa.
] FullCommentAsXML=[test_cmd_param_3c:@F@test_cmd_param_3#I#void test_cmd_param_3(int x1)zzzin Aaa.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_3:{{.*}} FullCommentAsHTML=[
zzz
Aaa.
] FullCommentAsXML=[test_cmd_param_3c:@F@test_cmd_param_3#I#void test_cmd_param_3(int x1)zzzin Aaa.] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[zzz] ParamIndex[0]=Invalid // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] @@ -265,16 +265,16 @@ /// \param x1 Aaa. void test_cmd_param_4(int x1, int x2); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_4:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
] FullCommentAsXML=[test_cmd_param_4c:@F@test_cmd_param_4#I#I#void test_cmd_param_4(int x1, int x2)x10in Aaa.x21in Bbb. ] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_4:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
] FullCommentAsXML=[test_cmd_param_4c:@F@test_cmd_param_4#I#I#void test_cmd_param_4(int x1, int x2)x10in Aaa.x21in Bbb. ] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x2] ParamIndex[0]=1 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x1] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] @@ -283,20 +283,20 @@ /// \param x1 Aaa. void test_cmd_param_5(int x1, int x2); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_5:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
zzz
Aaa.
] FullCommentAsXML=[test_cmd_param_5c:@F@test_cmd_param_5#I#I#void test_cmd_param_5(int x1, int x2)x10in Aaa.x21in Bbb. zzzin Aaa. ] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_5:{{.*}} FullCommentAsHTML=[
x1
Aaa.
x2
Bbb.
zzz
Aaa.
] FullCommentAsXML=[test_cmd_param_5c:@F@test_cmd_param_5#I#I#void test_cmd_param_5(int x1, int x2)x10in Aaa.x21in Bbb. zzzin Aaa. ] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x2] ParamIndex[0]=1 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[zzz] ParamIndex[0]=Invalid // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x1] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))] @@ -304,16 +304,16 @@ /// \param ... Bbb. void test_cmd_param_6(int x1, ...); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_6:{{.*}} FullCommentAsHTML=[
x1
Aaa.
...
Bbb.
] FullCommentAsXML=[test_cmd_param_6c:@F@test_cmd_param_6#I.#void test_cmd_param_6(int x1, ...)x10in Aaa. ...in Bbb.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_cmd_param_6:{{.*}} FullCommentAsHTML=[
x1
Aaa.
...
Bbb.
] FullCommentAsXML=[test_cmd_param_6c:@F@test_cmd_param_6#I.#void test_cmd_param_6(int x1, ...)x10in Aaa. ...in Bbb.] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x1] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[...] ParamIndex=4294967295 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[...] ParamIndex[0]=Variadic // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))] @@ -326,7 +326,7 @@ template void test_cmd_tparam_1(T aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_1:{{.*}} FullCommentAsHTML=[
aaa
Blah blah
] FullCommentAsXML=[test_cmd_tparam_1c:@FT@>1#Ttest_cmd_tparam_1#t0.0#v#template <typename T> void test_cmd_tparam_1(T aaa)aaa0in Blah blah] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_1:{{.*}} FullCommentAsHTML=[
aaa
Blah blah
] FullCommentAsXML=[test_cmd_tparam_1c:@FT@>1#Ttest_cmd_tparam_1#t0.0#v#template <typename T> void test_cmd_tparam_1(T aaa)aaa0in Blah blah] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -334,7 +334,7 @@ // 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_ParamCommand in implicitly ParamName[0]=[aaa] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))] @@ -343,7 +343,7 @@ template void test_cmd_tparam_2(T aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_2:{{.*}} FullCommentAsHTML=[
aaa
Blah blah
] FullCommentAsXML=[test_cmd_tparam_2c:@FT@>1#Ttest_cmd_tparam_2#t0.0#v#template <typename T> void test_cmd_tparam_2(T aaa)aaa0in Blah blah] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=test_cmd_tparam_2:{{.*}} FullCommentAsHTML=[
aaa
Blah blah
] FullCommentAsXML=[test_cmd_tparam_2c:@FT@>1#Ttest_cmd_tparam_2#t0.0#v#template <typename T> void test_cmd_tparam_2(T aaa)aaa0in Blah blah] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -351,7 +351,7 @@ // CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0} // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[aaa] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))] @@ -442,7 +442,7 @@ /// \returns Eee. void test_full_comment_1(int x1, int x2); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_full_comment_1:{{.*}} FullCommentAsHTML=[

Aaa.

Bbb.

x1
Ccc.
x2
Ddd.

Returns Eee.

] FullCommentAsXML=[test_full_comment_1c:@F@test_full_comment_1#I#I#void test_full_comment_1(int x1, int x2) Aaa.x10in Ccc. x21in Ddd. Eee. Bbb.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=test_full_comment_1:{{.*}} FullCommentAsHTML=[

Aaa.

Bbb.

x1
Ccc.
x2
Ddd.

Returns Eee.

] FullCommentAsXML=[test_full_comment_1c:@F@test_full_comment_1#I#I#void test_full_comment_1(int x1, int x2) Aaa.x10in Ccc. x21in Ddd. Eee. Bbb.] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph IsWhitespace @@ -454,11 +454,11 @@ // CHECK-NEXT: (CXComment_Text Text=[ Bbb.])) // CHECK-NEXT: (CXComment_Paragraph IsWhitespace // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x2] ParamIndex[0]=1 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Ddd.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0 +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[x1] ParamIndex[0]=0 // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Ccc.] HasTrailingNewline) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))) @@ -597,10 +597,10 @@ // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace) // CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=Ccc)))] -/// \a 1<2 \e 3<4 \em 5<6 \param 7<8 aaa \tparam 9<10 bbb +/// \a 1<2 \e 3<4 \em 5<6 \param a<8 aaa \tparam 9<10 bbb void comment_to_html_conversion_31(); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[

1<2 3<4 5<6

9<10
bbb
7<8
aaa
] FullCommentAsXML=[comment_to_html_conversion_31c:@F@comment_to_html_conversion_31#void comment_to_html_conversion_31() 1<2 3<4 5<6 9<10 bbb7<8in aaa ] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[

1<2 3<4 5<6

9<10
bbb
a
<8 aaa
] FullCommentAsXML=[comment_to_html_conversion_31c:@F@comment_to_html_conversion_31#void comment_to_html_conversion_31() 1<2 3<4 5<6 9<10 bbbain<8 aaa ] // CHECK-NEXT: CommentAST=[ // CHECK-NEXT: (CXComment_FullComment // CHECK-NEXT: (CXComment_Paragraph @@ -611,9 +611,10 @@ // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace) // CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=5<6) // CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)) -// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[7<8] ParamIndex=Invalid +// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName[0]=[a] ParamIndex[0]=Invalid // CHECK-NEXT: (CXComment_Paragraph -// CHECK-NEXT: (CXComment_Text Text=[ aaa ]))) +// CHECK-NEXT: (CXComment_Text Text=[<]) +// CHECK-NEXT: (CXComment_Text Text=[8 aaa ]))) // CHECK-NEXT: (CXComment_TParamCommand ParamName=[9<10] ParamPosition=Invalid // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ bbb]))))] @@ -752,7 +753,7 @@ /// \param aaa Blah blah. comment_to_xml_conversion_01(int aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_01c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#comment_to_xml_conversion_01(int aaa)aaa0in Blah blah.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_01c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#comment_to_xml_conversion_01(int aaa)aaa0in Blah blah.] /// Aaa. ~comment_to_xml_conversion_01(); @@ -762,12 +763,12 @@ /// \param aaa Blah blah. int comment_to_xml_conversion_02(int aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_02c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#int comment_to_xml_conversion_02(int aaa)aaa0in Blah blah.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_02c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#int comment_to_xml_conversion_02(int aaa)aaa0in Blah blah.] /// \param aaa Blah blah. static int comment_to_xml_conversion_03(int aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_03c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#Sstatic int comment_to_xml_conversion_03(int aaa)aaa0in Blah blah.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[comment_to_xml_conversion_03c:@S@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#Sstatic int comment_to_xml_conversion_03(int aaa)aaa0in Blah blah.] /// Aaa. int comment_to_xml_conversion_04; @@ -782,7 +783,7 @@ /// \param aaa Blah blah. void operator()(int aaa); -// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[operator()c:@S@comment_to_xml_conversion_01@F@operator()#I#void operator()(int aaa)aaa0in Blah blah.] +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[operator()c:@S@comment_to_xml_conversion_01@F@operator()#I#void operator()(int aaa)aaa0in Blah blah.] /// Aaa. operator bool(); @@ -1066,5 +1067,39 @@ // CHECK-NEXT: (CXComment_Paragraph // CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))] +/// \param aaa xxx +/// \param bbb Invalid argument +/// \param ... More arguments +template +void comment_to_xml_conversion_templated_function(int aaa, ...); +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionTemplate=comment_to_xml_conversion_templated_function:[[@LINE-1]]:{{.*}} FullCommentAsHTML=[
aaa
xxx
...
More arguments
bbb
Invalid argument
] FullCommentAsXML=[comment_to_xml_conversion_templated_functionc:@FT@>1#Tcomment_to_xml_conversion_templated_function#I.#v#template <typename T>\nvoid comment_to_xml_conversion_templated_function(int aaa, ...)aaa0in xxx ...in More argumentsbbbin Invalid argument ] +// CHECK: CommentAST=[ +// CHECK: (CXComment_FullComment +// CHECK: (CXComment_Paragraph IsWhitespace +// CHECK: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK: (CXComment_ParamCommand in implicitly ParamName[0]=[aaa] ParamIndex[0]=0 +// CHECK: (CXComment_Paragraph +// CHECK: (CXComment_Text Text=[ xxx] HasTrailingNewline) +// CHECK: (CXComment_Text Text=[ ] IsWhitespace))) +// CHECK: (CXComment_ParamCommand in implicitly ParamName[0]=[bbb] ParamIndex[0]=Invalid +// CHECK: (CXComment_Paragraph +// CHECK: (CXComment_Text Text=[ Invalid argument] HasTrailingNewline) +// CHECK: (CXComment_Text Text=[ ] IsWhitespace))) +// CHECK: (CXComment_ParamCommand in implicitly ParamName[0]=[...] ParamIndex[0]=Variadic +// CHECK: (CXComment_Paragraph +// CHECK: (CXComment_Text Text=[ More arguments]))))] + +/// \param aaa,bbb,... xxx +template +void comment_to_xml_conversion_templated_function2(int aaa, ...); +// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionTemplate=comment_to_xml_conversion_templated_function2:[[@LINE-1]]:{{.*}} RawCommentRange=[1092:1 - 1092:27] FullCommentAsHTML=[
aaa,bbb,...
xxx
] FullCommentAsXML=[comment_to_xml_conversion_templated_function2c:@FT@>1#Tcomment_to_xml_conversion_templated_function2#I.#v#template <typename T>\nvoid comment_to_xml_conversion_templated_function2(int aaa, ...)aaa0bbb...in xxx] +// CHECK: CommentAST=[ +// CHECK: (CXComment_FullComment +// CHECK: (CXComment_Paragraph IsWhitespace +// CHECK: (CXComment_Text Text=[ ] IsWhitespace)) +// CHECK: (CXComment_ParamCommand in implicitly ParamName[0]=[aaa] ParamName[1]=[bbb] ParamName[2]=[...] ParamIndex[0]=0 ParamIndex[1]=Invalid ParamIndex[2]=Variadic +// CHECK: (CXComment_Paragraph +// CHECK: (CXComment_Text Text=[ xxx]))))] + #endif Index: clang/test/Index/overriding-ftemplate-comments.cpp =================================================================== --- clang/test/Index/overriding-ftemplate-comments.cpp +++ clang/test/Index/overriding-ftemplate-comments.cpp @@ -13,12 +13,12 @@ template void comment_to_html_conversion_17(T AAA); -// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#v#template <typename T> void comment_to_html_conversion_17(T AAA)AAA0in Blah blah] +// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#v#template <typename T> void comment_to_html_conversion_17(T AAA)AAA0in Blah blah] template void comment_to_html_conversion_17(T PPP); -// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#v#template <typename T> void comment_to_html_conversion_17(T PPP)PPP0in Blah blah] +// CHECK: FullCommentAsXML=[comment_to_html_conversion_17c:@FT@>1#Tcomment_to_html_conversion_17#t0.0#v#template <typename T> void comment_to_html_conversion_17(T PPP)PPP0in Blah blah] //===----------------------------------------------------------------------===// Index: clang/test/Index/overriding-method-comments.mm =================================================================== --- clang/test/Index/overriding-method-comments.mm +++ clang/test/Index/overriding-method-comments.mm @@ -19,7 +19,7 @@ - (void)METH:(id)AAA; @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)AAA;AAA0in ZZZ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)AAA;AAA0in ZZZ] @interface Sub : Root @end @@ -28,13 +28,13 @@ - (void)METH:(id)BBB; @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)BBB;BBB0in ZZZ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)BBB;BBB0in ZZZ] @implementation Sub(CAT) - (void)METH:(id)III {} @end -// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)III;III0in ZZZ] +// CHECK: FullCommentAsXML=[METH:c:objc(cs)Root(im)METH:- (void)METH:(id)III;III0in ZZZ] @interface Redec : Root @end @@ -48,67 +48,67 @@ - (void)EXT_METH:(id)AAA : (double)BBB : (int)CCC; @end -// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;AAA0in input value BBB1in 2nd input value is doubleCCC2out output value is int ] +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;AAA0in input value BBB1in 2nd input value is doubleCCC2out output value is int ] @implementation Redec - (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {} @end -// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;PPP0in input value QQQ1in 2nd input value is doubleRRR2out output value is int ] +// CHECK: FullCommentAsXML=[EXT_METH:::c:objc(cs)Redec(im)EXT_METH:::- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;PPP0in input value QQQ1in 2nd input value is doubleRRR2out output value is int ] struct Base { /// \brief Does something. /// \param AAA argument to foo_pure. virtual void foo_pure(int AAA) = 0; -// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int AAA) = 0 Does something. AAA0in argument to foo_pure.] +// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int AAA) = 0 Does something. AAA0in argument to foo_pure.] /// \brief Does something. /// \param BBB argument to defined virtual. virtual void foo_inline(int BBB) {} -// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int BBB) Does something. BBB0in argument to defined virtual.] +// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int BBB) Does something. BBB0in argument to defined virtual.] /// \brief Does something. /// \param CCC argument to undefined virtual. virtual void foo_outofline(int CCC); -// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#virtual void foo_outofline(int CCC) Does something. CCC0in argument to undefined virtual.] +// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#virtual void foo_outofline(int CCC) Does something. CCC0in argument to undefined virtual.] }; void Base::foo_outofline(int RRR) {} -// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#void Base::foo_outofline(int RRR) Does something. RRR0in argument to undefined virtual.] +// CHECK: FullCommentAsXML=[foo_outoflinec:@S@Base@F@foo_outofline#I#void Base::foo_outofline(int RRR) Does something. RRR0in argument to undefined virtual.] struct Derived : public Base { virtual void foo_pure(int PPP); -// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int PPP) Does something. PPP0in argument to foo_pure.] +// CHECK: FullCommentAsXML=[foo_purec:@S@Base@F@foo_pure#I#virtual void foo_pure(int PPP) Does something. PPP0in argument to foo_pure.] virtual void foo_inline(int QQQ) {} -// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int QQQ) Does something. QQQ0in argument to defined virtual.] +// CHECK: FullCommentAsXML=[foo_inlinec:@S@Base@F@foo_inline#I#virtual void foo_inline(int QQQ) Does something. QQQ0in argument to defined virtual.] }; /// \brief Does something. /// \param DDD a value. void foo(int DDD); -// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int DDD) Does something. DDD0in a value.] +// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int DDD) Does something. DDD0in a value.] void foo(int SSS) {} -// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int SSS) Does something. SSS0in a value.] +// CHECK: FullCommentAsXML=[fooc:@F@foo#I#void foo(int SSS) Does something. SSS0in a value.] /// \brief Does something. /// \param EEE argument to function decl. void foo1(int EEE); -// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int EEE) Does something. EEE0in argument to function decl.] +// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int EEE) Does something. EEE0in argument to function decl.] void foo1(int TTT); -// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int TTT) Does something. TTT0in argument to function decl.] +// CHECK: FullCommentAsXML=[foo1c:@F@foo1#I#void foo1(int TTT) Does something. TTT0in argument to function decl.] /// \brief Documentation /// \tparam BBB The type, silly. Index: clang/test/Sema/warn-documentation-fixits.cpp =================================================================== --- clang/test/Sema/warn-documentation-fixits.cpp +++ clang/test/Sema/warn-documentation-fixits.cpp @@ -6,20 +6,29 @@ /// \param ZZZZZZZZZZ Blah blah. int test1(int a); -// expected-warning@+1 {{parameter 'aab' not found in the function declaration}} expected-note@+1 {{did you mean 'aaa'?}} +// expected-warning@+2 {{parameter 'aab' not found in the function declaration}} expected-note@+2 {{did you mean 'aaa'?}} +// expected-warning@+2 {{parameter 'bbb' is not documented}} /// \param aab Blah blah. int test2(int aaa, int bbb); +// expected-warning@+1 {{parameter '..' not found in the function declaration}} expected-note@+1 {{did you mean '...'?}} +/// \param .. Typo of existing variadic parameter +void test3(...); + +// expected-warning@+1 {{parameter '..' not found in the function declaration}} expected-note@+1 {{did you mean '...'?}} +/// \param aaa,.. Typo of existing variadic parameter +void test4(int aaa, ...); + // expected-warning@+1 {{template parameter 'ZZZZZZZZZZ' not found in the template declaration}} expected-note@+1 {{did you mean 'T'?}} /// \tparam ZZZZZZZZZZ Aaa template -void test3(T aaa); +void test5(T aaa); // 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 -void test4(SomeTy aaa, OtherTy bbb); +void test6(SomeTy aaa, OtherTy bbb); // expected-warning@+1 {{declaration is marked with '\deprecated' command but does not have a deprecation attribute}} expected-note@+2 {{add a deprecation attribute to the declaration to silence this warning}} /// \deprecated @@ -124,20 +133,22 @@ int PR18051(); // CHECK: fix-it:"{{.*}}":{6:12-6:22}:"a" -// CHECK: fix-it:"{{.*}}":{10:12-10:15}:"aaa" -// CHECK: fix-it:"{{.*}}":{14:13-14:23}:"T" -// CHECK: fix-it:"{{.*}}":{19:13-19:18}:"SomeTy" -// CHECK: fix-it:"{{.*}}":{26:1-26:1}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{30:1-30:1}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{35:3-35:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{39:3-39:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{47:3-47:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{51:3-51:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{76:3-76:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{81:3-81:3}:"[[ATTRIBUTE]] " -// CHECK14: fix-it:"{{.*}}":{87:3-87:3}:"[[ATTRIBUTE]] " -// CHECK: fix-it:"{{.*}}":{97:1-97:1}:"MY_ATTR_DEPRECATED " -// CHECK14: fix-it:"{{.*}}":{104:1-104:1}:"ATTRIBUTE_DEPRECATED " -// CHECK: fix-it:"{{.*}}":{110:6-110:11}:"return" -// CHECK: fix-it:"{{.*}}":{114:6-114:11}:"foobar" -// CHECK: fix-it:"{{.*}}":{123:6-123:12}:"endcode" +// CHECK: fix-it:"{{.*}}":{11:12-11:15}:"aaa" +// CHECK: fix-it:"{{.*}}":{15:12-15:14}:"..." +// CHECK: fix-it:"{{.*}}":{19:16-19:18}:"..." +// CHECK: fix-it:"{{.*}}":{23:13-23:23}:"T" +// CHECK: fix-it:"{{.*}}":{28:13-28:18}:"SomeTy" +// CHECK: fix-it:"{{.*}}":{35:1-35:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{39:1-39:1}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{44:3-44:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{48:3-48:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{56:3-56:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{60:3-60:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{85:3-85:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{90:3-90:3}:"[[ATTRIBUTE]] " +// CHECK14: fix-it:"{{.*}}":{96:3-96:3}:"[[ATTRIBUTE]] " +// CHECK: fix-it:"{{.*}}":{106:1-106:1}:"MY_ATTR_DEPRECATED " +// CHECK14: fix-it:"{{.*}}":{113:1-113:1}:"ATTRIBUTE_DEPRECATED " +// CHECK: fix-it:"{{.*}}":{119:6-119:11}:"return" +// CHECK: fix-it:"{{.*}}":{123:6-123:11}:"foobar" +// CHECK: fix-it:"{{.*}}":{132:6-132:12}:"endcode" Index: clang/test/Sema/warn-documentation.cpp =================================================================== --- clang/test/Sema/warn-documentation.cpp +++ clang/test/Sema/warn-documentation.cpp @@ -189,6 +189,7 @@ /// @param a Blah blah. int test_param1_at; +// expected-warning@+2 {{'\param' command does not have a valid identifier}} // expected-warning@+1 {{empty paragraph passed to '\param' command}} /// \param /// \param a Blah blah. @@ -230,7 +231,8 @@ /// \param A Blah blah. int test_param12(int a); -// expected-warning@+1 {{parameter 'aab' not found in the function declaration}} expected-note@+1 {{did you mean 'aaa'?}} +// expected-warning@+2 {{parameter 'aab' not found in the function declaration}} expected-note@+2 {{did you mean 'aaa'?}} +// expected-warning@+2 {{parameter 'bbb' is not documented}} /// \param aab Blah blah. int test_param13(int aaa, int bbb); @@ -239,7 +241,9 @@ /// \param aab Blah blah. int test_param14(int aaa, int bbb); -// expected-warning@+1 {{parameter 'aab' not found in the function declaration}} +// expected-warning@+3 {{parameter 'aab' not found in the function declaration}} +// expected-warning@+3 {{parameter 'bbb' is not documented}} +// expected-warning@+2 {{parameter 'ccc' is not documented}} /// \param aab Blah blah. int test_param15(int bbb, int ccc); @@ -261,17 +265,119 @@ /// \param aab Ccc. int test_param18(int aaa, int bbb); +// expected-warning@+1 {{'\param' command does not have a valid identifier}} +/// \param 9aaa xxx +void test_param_invalid_identifier(int aaa); + +// expected-warning@+1 {{'\param' command does not have a valid identifier}} +/// \param aaa,9aaa xxx +void test_param_invalid_identifier2(int aaa); + +// expected-warning@+1 {{'\param' command's identifier is not properly terminated}} +/// \param aaa#aaa xxx +void test_param_identifier_not_terminated(int aaa); + +// expected-warning@+1 {{'\param' command's identifier is not properly terminated}} +/// \param aaa, bbb#aaa xxx +void test_param_identifier_not_terminated2(int aaa, int bbb); + +// expected-warning@+1 {{parameter '..' not found in the function declaration}} expected-note@+1 {{did you mean '...'?}} +/// \param .. xxx +void test_param_typo_existing_variadic(...); + +// expected-warning@+2 {{parameter '..' not found in the function declaration}} expected-note@+2 {{did you mean '...'?}} +/// \param aaa xxx +/// \param .. xxx +void test_param_typo_existing_variadic2(int aaa, ...); + +// expected-warning@+1 {{parameter '..' not found in the function declaration}} expected-note@+1 {{did you mean '...'?}} +/// \param aaa,.. xxx +void test_param_typo_existing_variadic3(int aaa, ...); + +// expected-warning@+2 {{parameter '..' not found in the function declaration}} expected-note@+2 {{did you mean '...'?}} +// expected-warning@+2 {{parameter '..' not found in the function declaration}} +/// \param .. xxx +/// \param .. xxx +void test_param_typo_existing_variadic_twice(...); + +// expected-warning@+1 {{parameter '..' not found in the function declaration}} +/// \param .. xxx +void test_param_typo_non_existing_variadic(); + +// expected-warning@+2 {{parameter '..' not found in the function declaration}}} +/// \param aaa xxx +/// \param .. xxx +void test_param_typo_non_existing_variadic2(int aaa); + +// expected-warning@+1 {{parameter '..' not found in the function declaration}} +/// \param aaa, .. xxx +void test_param_typo_non_existing_variadic3(int aaa); + +// expected-warning@+4 {{parameter '...' is already documented}} expected-note@+3 {{previous documentation}} +// expected-warning@+4 {{parameter '...' is already documented}} expected-note@+2 {{previous documentation}} +/// \param aaa xxx +/// \param ... xxx +/// \param ... xxx +/// \param ... xxx +void test_param_duplicated_comment_variadic(int aaa, ...); + +// expected-warning@+3 {{parameter '...' is already documented}} expected-note@+2 {{previous documentation}} +// expected-warning@+3 {{parameter '...' is already documented}} expected-note@+1 {{previous documentation}} +/// \param aaa,... xxx +/// \param ... xxx +/// \param ... xxx +void test_param_duplicated_comment_variadic2(int aaa, ...); + +// expected-warning@+2 {{parameter '...' is already documented}} expected-note@+2 {{previous documentation}} +// expected-warning@+2 {{parameter '...' is already documented}} expected-note@+1 {{previous documentation}} +/// \param aaa,...,... xxx +/// \param ... xxx +void test_param_duplicated_comment_variadic3(int aaa, ...); + +// expected-warning@+3 {{parameter '...' is already documented}} expected-note@+2 {{previous documentation}} +// expected-warning@+3 {{parameter '...' is already documented}} expected-note@+1 {{previous documentation}} +/// \param ... xxx +/// \param ... xxx +/// \param ... xxx +void test_param_duplicated_comment_variadic4(...); + +// expected-warning@+2 {{parameter '...' is already documented}} expected-note@+2 {{previous documentation}} +// expected-warning@+2 {{parameter '...' is already documented}} expected-note@+1 {{previous documentation}} +/// \param ...,... xxx +/// \param ... xxx +void test_param_duplicated_comment_variadic5(...); + +// expected-warning@+2 {{parameter '..' not found in the function declaration}}} +/// \param aaa,... xxx +/// \param .. xxx +void test_param_no_typo_correction_for_documented_variadic(int aaa, ...); + +// expected-warning@+2 {{'\param' command does not have a valid identifier}} +// expected-warning@+1 {{empty paragraph passed to '\param' command}} +/// \param aaa, +void test_param_trailing_comma(int aaa); + +// expected-warning@+1 {{'\param' command does not have a valid identifier}} +/// \param aaa,, +void test_param_double_comma(int aaa); + class C { - // expected-warning@+1 {{parameter 'aaa' not found in the function declaration}} + // expected-warning@+3 {{parameter 'aaa' not found in the function declaration}} + // expected-warning@+3 {{parameter 'bbb' is not documented}} + // expected-warning@+2 {{parameter 'ccc' is not documented}} /// \param aaa Blah blah. C(int bbb, int ccc); - // expected-warning@+1 {{parameter 'aaa' not found in the function declaration}} + // expected-warning@+3 {{parameter 'aaa' not found in the function declaration}} + // expected-warning@+3 {{parameter 'bbb' is not documented}} + // expected-warning@+2 {{parameter 'ccc' is not documented}} /// \param aaa Blah blah. int test_param19(int bbb, int ccc); }; -// expected-warning@+1 {{parameter 'aab' not found in the function declaration}} +// expected-warning@+3 {{parameter 'aab' not found in the function declaration}} +// expected-warning@+4 {{parameter 'bbb' is not documented}} +// expected-warning@+3 {{parameter 'ccc' is not documented}} /// \param aab Blah blah. template void test_param20(int bbb, int ccc); @@ -282,14 +388,14 @@ /// \param a Aaa. int test_param21(int a); -// expected-warning@+4 {{parameter 'x2' is already documented}} -// expected-note@+2 {{previous documentation}} +// expected-warning@+4 {{parameter 'x2' is already documented}} expected-note@+3 {{previous documentation}} +// expected-warning@+4 {{parameter 'x3' is not documented}} /// \param x1 Aaa. /// \param x2 Bbb. /// \param x2 Ccc. int test_param22(int x1, int x2, int x3); -// expected-warning@+1 {{empty paragraph passed to '\param' command}} +// expected-warning@+2 {{empty paragraph passed to '\param' command}} /// \param a /// \retval 0 Blah blah. int test_param23(int a); Index: clang/tools/c-index-test/c-index-test.c =================================================================== --- clang/tools/c-index-test/c-index-test.c +++ clang/tools/c-index-test/c-index-test.c @@ -574,13 +574,23 @@ printf(" explicitly"); else printf(" implicitly"); - PrintCXStringWithPrefixAndDispose( - "ParamName", - clang_ParamCommandComment_getParamName(Comment)); - if (clang_ParamCommandComment_isParamIndexValid(Comment)) - printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment)); - else - printf(" ParamIndex=Invalid"); + if ((e = clang_ParamCommandComment_getNumParams(Comment))) { + for (i = 0; i != e; ++i) { + printf(" ParamName[%u]=[", i); + PrintCXStringAndDispose( + clang_ParamCommandComment_getParamName(Comment, i)); + printf("]"); + } + for (i = 0; i != e; ++i) { + printf(" ParamIndex[%u]=", i); + if (clang_ParamCommandComment_isVarArgParam(Comment, i)) { + printf("Variadic"); + } else if (clang_ParamCommandComment_isParamIndexValid(Comment, i)) + printf("%u", clang_ParamCommandComment_getParamIndex(Comment, i)); + else + printf("Invalid"); + } + } break; case CXComment_TParamCommand: printf("CXComment_TParamCommand"); Index: clang/tools/libclang/CXComment.cpp =================================================================== --- clang/tools/libclang/CXComment.cpp +++ clang/tools/libclang/CXComment.cpp @@ -257,28 +257,45 @@ return createCXComment(BCC->getParagraph(), CXC.TranslationUnit); } -CXString clang_ParamCommandComment_getParamName(CXComment CXC) { +unsigned clang_ParamCommandComment_getNumParams(CXComment CXC) { const ParamCommandComment *PCC = getASTNodeAs(CXC); - if (!PCC || !PCC->hasParamName()) + if (!PCC) + return 0; + + return PCC->getNumParams(); +} + +CXString clang_ParamCommandComment_getParamName(CXComment CXC, unsigned Idx) { + const ParamCommandComment *PCC = getASTNodeAs(CXC); + if (!PCC || Idx >= PCC->getNumParams()) return cxstring::createNull(); - return cxstring::createRef(PCC->getParamNameAsWritten()); + return cxstring::createRef(PCC->getParamName(Idx)); } -unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) { +unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC, + unsigned Idx) { const ParamCommandComment *PCC = getASTNodeAs(CXC); - if (!PCC) + if (!PCC || Idx >= PCC->getNumParams()) + return false; + + return PCC->isParamIndexValid(Idx); +} + +unsigned clang_ParamCommandComment_isVarArgParam(CXComment CXC, unsigned Idx) { + const ParamCommandComment *PCC = getASTNodeAs(CXC); + if (!PCC || Idx >= PCC->getNumParams()) return false; - return PCC->isParamIndexValid(); + return PCC->isVarArgParam(Idx); } -unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC) { +unsigned clang_ParamCommandComment_getParamIndex(CXComment CXC, unsigned Idx) { const ParamCommandComment *PCC = getASTNodeAs(CXC); - if (!PCC || !PCC->isParamIndexValid() || PCC->isVarArgParam()) + if (!PCC || Idx >= PCC->getNumParams() || !PCC->isParamIndexValid(Idx)) return ParamCommandComment::InvalidParamIndex; - return PCC->getParamIndex(); + return PCC->getParamIndex(Idx); } unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment CXC) { Index: clang/tools/libclang/libclang.exports =================================================================== --- clang/tools/libclang/libclang.exports +++ clang/tools/libclang/libclang.exports @@ -80,8 +80,10 @@ clang_BlockCommandComment_getNumArgs clang_BlockCommandComment_getArgText clang_BlockCommandComment_getParagraph +clang_ParamCommandComment_getNumParams clang_ParamCommandComment_getParamName clang_ParamCommandComment_isParamIndexValid +clang_ParamCommandComment_isVarArgParam clang_ParamCommandComment_getParamIndex clang_ParamCommandComment_isDirectionExplicit clang_ParamCommandComment_getDirection Index: clang/unittests/AST/CommentParser.cpp =================================================================== --- clang/unittests/AST/CommentParser.cpp +++ clang/unittests/AST/CommentParser.cpp @@ -176,16 +176,12 @@ return ::testing::AssertionSuccess(); } -::testing::AssertionResult HasParamCommandAt( - const Comment *C, - const CommandTraits &Traits, - size_t Idx, - ParamCommandComment *&PCC, - StringRef CommandName, - ParamCommandComment::PassDirection Direction, - bool IsDirectionExplicit, - StringRef ParamName, - ParagraphComment *&Paragraph) { +::testing::AssertionResult +HasParamCommandAt(const Comment *C, const CommandTraits &Traits, size_t Idx, + ParamCommandComment *&PCC, StringRef CommandName, + ParamCommandComment::PassDirection Direction, + bool IsDirectionExplicit, ArrayRef ParamName, + ParagraphComment *&Paragraph) { ::testing::AssertionResult AR = GetChildAt(C, Idx, PCC); if (!AR) return AR; @@ -208,22 +204,36 @@ << " direction, " "expected " << (IsDirectionExplicit ? "explicit" : "implicit"); - if (!ParamName.empty() && !PCC->hasParamName()) + if (ParamName.size() != PCC->getNumParams()) return ::testing::AssertionFailure() - << "ParamCommandComment has no parameter name"; - - StringRef ActualParamName = PCC->hasParamName() ? PCC->getParamNameAsWritten() : ""; - if (ActualParamName != ParamName) - return ::testing::AssertionFailure() - << "ParamCommandComment has parameter name \"" << ActualParamName.str() - << "\", " - "expected \"" << ParamName.str() << "\""; + << "ParamCommandComment has " << PCC->getNumParams() + << " parameters, expected " << ParamName.size(); + + for (unsigned I = 0, E = ParamName.size(); I != E; ++I) + if (ParamName[I] != PCC->getParamName(I)) + return ::testing::AssertionFailure() + << "ParamCommandComment has parameter name \"" + << PCC->getParamName(I) + << "\", " + "expected \"" + << ParamName[I] << "\""; Paragraph = PCC->getParagraph(); return ::testing::AssertionSuccess(); } +::testing::AssertionResult +HasParamCommandAt(const Comment *C, const CommandTraits &Traits, size_t Idx, + ParamCommandComment *&PCC, StringRef CommandName, + ParamCommandComment::PassDirection Direction, + bool IsDirectionExplicit, StringRef ParamName, + ParagraphComment *&Paragraph) { + return HasParamCommandAt(C, Traits, Idx, PCC, CommandName, Direction, + IsDirectionExplicit, makeArrayRef(ParamName), + Paragraph); +} + ::testing::AssertionResult HasTParamCommandAt( const Comment *C, const CommandTraits &Traits, @@ -775,10 +785,9 @@ { ParamCommandComment *PCC; ParagraphComment *PC; - ASSERT_TRUE(HasParamCommandAt(FC, Traits, 1, PCC, "param", - ParamCommandComment::In, - /* IsDirectionExplicit = */ false, - "", PC)); + ASSERT_TRUE(HasParamCommandAt( + FC, Traits, 1, PCC, "param", ParamCommandComment::In, + /* IsDirectionExplicit = */ false, ArrayRef(), PC)); ASSERT_TRUE(HasChildCount(PCC, 1)); ASSERT_TRUE(HasChildCount(PC, 0)); } @@ -936,6 +945,27 @@ } } +TEST_F(CommentParserTest, ParamCommand8) { + const char *Source = "// \\param aaa, bbb, ... ccc"; + StringRef ParamNames[] = {"aaa", "bbb", "..."}; + + FullComment *FC = parseString(Source); + ASSERT_TRUE(HasChildCount(FC, 2)); + + ASSERT_TRUE(HasParagraphCommentAt(FC, 0, " ")); + { + ParamCommandComment *PCC; + ParagraphComment *PC; + ASSERT_TRUE(HasParamCommandAt( + FC, Traits, 1, PCC, "param", ParamCommandComment::In, + /* IsDirectionExplicit = */ false, makeArrayRef(ParamNames), PC)); + ASSERT_TRUE(HasChildCount(PCC, 1)); + + ASSERT_TRUE(HasChildCount(PC, 1)); + ASSERT_TRUE(HasTextAt(PC, 0, " ccc")); + } +} + TEST_F(CommentParserTest, TParamCommand1) { const char *Sources[] = { "// \\tparam aaa Bbb\n",