https://github.com/tcottin updated https://github.com/llvm/llvm-project/pull/202121
>From d5e315d578a0b80bbc3aca76c93dc5bf0277314e Mon Sep 17 00:00:00 2001 From: Tim Cottin <[email protected]> Date: Sun, 7 Jun 2026 10:16:21 +0000 Subject: [PATCH] fix unknown doxygen command parsing --- .../clangd/CodeCompletionStrings.cpp | 7 +- .../clangd/SymbolDocumentation.cpp | 18 ++-- .../clangd/SymbolDocumentation.h | 11 -- clang-tools-extra/clangd/support/Markup.cpp | 12 +++ .../unittests/CodeCompletionStringsTests.cpp | 54 ++++++++++ .../clangd/unittests/HoverTests.cpp | 66 ++++++++++++ .../unittests/SymbolDocumentationTests.cpp | 100 ++++++++++++++++++ clang/include/clang/AST/Comment.h | 9 -- clang/include/clang/AST/CommentLexer.h | 13 ++- clang/include/clang/AST/CommentSema.h | 6 +- clang/lib/AST/CommentLexer.cpp | 6 +- clang/lib/AST/CommentParser.cpp | 19 ++-- clang/lib/AST/CommentSema.cpp | 20 ++-- clang/unittests/AST/CommentLexer.cpp | 40 ++++++- 14 files changed, 321 insertions(+), 60 deletions(-) diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/clang-tools-extra/clangd/CodeCompletionStrings.cpp index 9c4241b54057a..dc86be60a876f 100644 --- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp +++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp @@ -127,11 +127,12 @@ std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) { // not write them into PCH, because they are racy and slow to load. assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc())); - comments::FullComment *FC = RC->parse(Ctx, /*PP=*/nullptr, ND); - if (!FC) + std::string DeclDoc = + RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics()); + if (!looksLikeDocComment(DeclDoc)) return ""; - SymbolDocCommentVisitor V(FC, Ctx.getLangOpts().CommentOpts); + SymbolDocCommentVisitor V(DeclDoc, Ctx.getLangOpts().CommentOpts); std::string RawDoc; llvm::raw_string_ostream OS(RawDoc); diff --git a/clang-tools-extra/clangd/SymbolDocumentation.cpp b/clang-tools-extra/clangd/SymbolDocumentation.cpp index a50d7a565b1bc..c54f752f04196 100644 --- a/clang-tools-extra/clangd/SymbolDocumentation.cpp +++ b/clang-tools-extra/clangd/SymbolDocumentation.cpp @@ -34,9 +34,10 @@ void commandToMarkup(markup::Paragraph &Out, StringRef Command, comments::CommandMarkerKind CommandMarker, StringRef Args) { Out.appendBoldText(commandMarkerAsString(CommandMarker) + Command.str()); - Out.appendSpace(); - if (!Args.empty()) + if (!Args.empty()) { + Out.appendSpace(); Out.appendCode(Args.str()); + } } template <typename T> std::string getArgText(const T *Command) { @@ -108,6 +109,7 @@ class ParagraphToMarkupDocument commandToMarkup(Out, C->getCommandName(Traits), C->getCommandMarker(), ""); + LastChunkEndsWithNewline = false; } } @@ -159,7 +161,11 @@ class ParagraphToString } } - void visitTextComment(const comments::TextComment *C) { Out << C->getText(); } + void visitTextComment(const comments::TextComment *C) { + Out << C->getText(); + if (C->hasTrailingNewline()) + Out << "\n"; + } void visitInlineCommandComment(const comments::InlineCommandComment *C) { Out << commandMarkerAsString(C->getCommandMarker()); @@ -167,7 +173,6 @@ class ParagraphToString std::string ArgText = getArgText(C); if (!ArgText.empty()) Out << " " << ArgText; - Out << " "; } void visitHTMLStartTagComment(const comments::HTMLStartTagComment *STC) { @@ -251,10 +256,7 @@ class BlockCommentToMarkupDocument commandToMarkup(P, B->getCommandName(Traits), B->getCommandMarker(), ArgText); if (B->getParagraph() && !B->getParagraph()->isWhitespace()) { - // For commands with arguments, the paragraph starts after the first - // space. Therefore we need to append a space manually in this case. - if (!ArgText.empty()) - P.appendSpace(); + P.appendSpace(); ParagraphToMarkupDocument(P, Traits).visit(B->getParagraph()); } } diff --git a/clang-tools-extra/clangd/SymbolDocumentation.h b/clang-tools-extra/clangd/SymbolDocumentation.h index 88c7ade633516..95787ae6c92b9 100644 --- a/clang-tools-extra/clangd/SymbolDocumentation.h +++ b/clang-tools-extra/clangd/SymbolDocumentation.h @@ -31,17 +31,6 @@ namespace clangd { class SymbolDocCommentVisitor : public comments::ConstCommentVisitor<SymbolDocCommentVisitor> { public: - SymbolDocCommentVisitor(comments::FullComment *FC, - const CommentOptions &CommentOpts) - : Traits(Allocator, CommentOpts), Allocator() { - if (!FC) - return; - - for (auto *Block : FC->getBlocks()) { - visit(Block); - } - } - SymbolDocCommentVisitor(llvm::StringRef Documentation, const CommentOptions &CommentOpts) : Traits(Allocator, CommentOpts), Allocator() { diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp index 9ba993a04709c..8ecaa823eb280 100644 --- a/clang-tools-extra/clangd/support/Markup.cpp +++ b/clang-tools-extra/clangd/support/Markup.cpp @@ -537,16 +537,28 @@ void Paragraph::renderEscapedMarkdown(llvm::raw_ostream &OS) const { void Paragraph::renderMarkdown(llvm::raw_ostream &OS) const { bool NeedsSpace = false; bool HasChunks = false; + bool TextEndsWithNewline = false; std::string ParagraphText; ParagraphText.reserve(EstimatedStringSize); llvm::raw_string_ostream ParagraphTextOS(ParagraphText); for (auto &C : Chunks) { + + if (TextEndsWithNewline) { + ParagraphTextOS << "\n"; + TextEndsWithNewline = false; + } + if (C.SpaceBefore || NeedsSpace) ParagraphTextOS << " "; + switch (C.Kind) { case ChunkKind::PlainText: ParagraphTextOS << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/false); + // renderText removes trailing newlines, but in case there are additional + // chunks to process, we need to keep track of the trailing newline and + // add it in the next iteration. + TextEndsWithNewline = llvm::StringRef(C.Contents).ends_with("\n"); break; case ChunkKind::InlineCode: ParagraphTextOS << renderInlineBlock(C.Contents); diff --git a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp index de5f533d31645..6b8b003a4fe18 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CodeCompletionStrings.h" +#include "Config.h" #include "TestTU.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "gmock/gmock.h" @@ -69,6 +70,59 @@ TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) { getDeclComment(AST.getASTContext(), findDecl(AST, "X"))); } +TEST_F(CompletionStringTest, GetDeclCommentForParam) { + auto TU = + TestTU::withCode("/** @param a this is param a */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("this is param a", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForMultipleParams) { + auto TU = TestTU::withCode("/** @param a this is param a\n * @param b this " + "is param b\n */\nvoid func(int a, int b);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 2UL); + EXPECT_EQ("this is param a", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); + EXPECT_EQ("this is param b", + getDeclComment(AST.getASTContext(), *FD.parameters()[1])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForUndocumentedParam) { + auto TU = + TestTU::withCode("/** @param c this is param c */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("", getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForParamWithUnknownDoxygenCommand) { + auto TU = TestTU::withCode("/** @param a this is param a and an\n * @unknown " + "command\n */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast<FunctionDecl>(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("this is param a and an\n@unknown command", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + TEST_F(CompletionStringTest, MultipleAnnotations) { Builder.AddAnnotation("Ano1"); Builder.AddAnnotation("Ano2"); diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 7b168b0bdca60..476494cdd3e6d 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -4431,6 +4431,56 @@ brief doc ### Details longer doc)"}, + {[](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Function; + HI.Documentation = "@brief brief doc\n" + "@unknown command is treated as an inline command"; + HI.Definition = "int foo(int a)"; + HI.ReturnType = "int"; + HI.Name = "foo"; + HI.Parameters.emplace(); + HI.Parameters->emplace_back(); + HI.Parameters->back().Type = "int"; + HI.Parameters->back().Name = "a"; + }, + R"(### function `foo` + +--- +→ `int` + +Parameters: + +- `int a` + +@brief brief doc +@unknown command is treated as an inline command + +--- +```cpp +int foo(int a) +```)", + R"(### function + +--- +```cpp +int foo(int a) +``` + +--- +### Brief + +brief doc +**@unknown** command is treated as an inline command + +--- +### Parameters + +- `int a` + +--- +### Returns + +`int`)"}, }; for (const auto &C : Cases) { @@ -5203,6 +5253,22 @@ TEST(Hover, FunctionParameters) { "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is " "\\<b>doc\\</b> \\<html-tag attribute/> \\<another-html-tag " "attribute=\"value\">for\\</another-html-tag> `b`\n\n---\nType: `int`"}, + {R"cpp(/// Function doc + /// @param a the next command is an + /// @unknown command. + void foo(int [[^a]]); + )cpp", + [](HoverInfo &HI) { + HI.Name = "a"; + HI.Kind = index::SymbolKind::Parameter; + HI.NamespaceScope = ""; + HI.LocalScope = "foo::"; + HI.Type = "int"; + HI.Definition = "int a"; + HI.Documentation = "the next command is an\n @unknown command."; + }, + "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthe next " + "command is an\n**@unknown** command.\n\n---\nType: `int`"}, }; // Create a tiny index, so tests above can verify documentation is fetched. diff --git a/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp index 676f7dfc74483..d140ab00a175f 100644 --- a/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp @@ -10,6 +10,7 @@ #include "support/Markup.h" #include "clang/Basic/CommentOptions.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" namespace clang { @@ -732,5 +733,104 @@ line } } +TEST(SymbolDocumentation, ParameterDocToString) { + CommentOptions CommentOpts; + + struct Case { + llvm::StringRef Documentation; + llvm::StringRef ExpectedOutputString; + llvm::StringRef ParameterName; + } Cases[] = { + {"This documentation does not contain parameter docs", "", "a"}, + {"@param a this is a parameter", "", "not_exists"}, + {"@param a this is a parameter", " this is a parameter", "a"}, + {R"(@param a parameter doc with an \p inline command)", + R"( parameter doc with an \p inline command)", "a"}, + {R"(@param a parameter doc with an \unknown command)", + R"( parameter doc with an \unknown command)", "a"}, + {"@param a parameter doc with an @unknown command", + " parameter doc with an @unknown command", "a"}, + {R"(@param a parameter doc with +multiple lines)", + R"( parameter doc with +multiple lines)", + "a"}, + {R"(@param a parameter doc with an +@unknown command starting a new line)", + R"( parameter doc with an +@unknown command starting a new line)", + "a"}, + {R"(@param a parameter doc with a +@note command which is a new block command and therefore ends the parameter doc paragraph)", + R"( parameter doc with a +)", + "a"}, + {R"(Unrelated docs +@param a parameter doc + +New paragraph with unrelated docs)", + " parameter doc", "a"}, + }; + for (const auto &C : Cases) { + std::string Result; + llvm::raw_string_ostream OS(Result); + SymbolDocCommentVisitor SymbolDoc(C.Documentation, CommentOpts); + + SymbolDoc.parameterDocToString(C.ParameterName, OS); + + EXPECT_EQ(Result, C.ExpectedOutputString); + } +} + +TEST(SymbolDocumentation, TemplateParameterDocToString) { + CommentOptions CommentOpts; + + struct Case { + llvm::StringRef Documentation; + llvm::StringRef ExpectedOutputString; + llvm::StringRef TemplateParameterName; + } Cases[] = { + {"This documentation does not contain parameter docs", "", "a"}, + {"@tparam a this is a template type parameter", "", "not_exists"}, + {"@tparam a this is a template type parameter", + " this is a template type parameter", "a"}, + {R"(@tparam a template type parameter doc with an \p inline command)", + R"( template type parameter doc with an \p inline command)", "a"}, + {R"(@tparam a template type parameter doc with an \unknown command)", + R"( template type parameter doc with an \unknown command)", "a"}, + {"@tparam a template type parameter doc with an @unknown command", + " template type parameter doc with an @unknown command", "a"}, + {R"(@tparam a template type parameter doc with +multiple lines)", + R"( template type parameter doc with +multiple lines)", + "a"}, + {R"(@tparam a template type parameter doc with an +@unknown command starting a new line)", + R"( template type parameter doc with an +@unknown command starting a new line)", + "a"}, + {R"(@tparam a template type parameter doc with a +@note command which is a new block command and therefore ends the template type parameter doc paragraph)", + R"( template type parameter doc with a +)", + "a"}, + {R"(Unrelated docs +@tparam a template type parameter doc + +New paragraph with unrelated docs)", + " template type parameter doc", "a"}, + }; + for (const auto &C : Cases) { + std::string Result; + llvm::raw_string_ostream OS(Result); + SymbolDocCommentVisitor SymbolDoc(C.Documentation, CommentOpts); + + SymbolDoc.templateTypeParmDocToString(C.TemplateParameterName, OS); + + EXPECT_EQ(Result, C.ExpectedOutputString); + } +} + } // namespace clangd } // namespace clang diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h index 9ea86089373d5..84e5444675ae1 100644 --- a/clang/include/clang/AST/Comment.h +++ b/clang/include/clang/AST/Comment.h @@ -344,15 +344,6 @@ class InlineCommandComment : public InlineContentComment { ArrayRef<Argument> Args; public: - InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, - unsigned CommandID, InlineCommandRenderKind RK, - ArrayRef<Argument> Args) - : InlineContentComment(CommentKind::InlineCommandComment, LocBegin, - LocEnd), - Args(Args) { - InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK); - InlineCommandCommentBits.CommandID = CommandID; - } InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, InlineCommandRenderKind RK, CommandMarkerKind CommandMarker, ArrayRef<Argument> Args) diff --git a/clang/include/clang/AST/CommentLexer.h b/clang/include/clang/AST/CommentLexer.h index 9aa1681cb2c5c..194a31cb7b934 100644 --- a/clang/include/clang/AST/CommentLexer.h +++ b/clang/include/clang/AST/CommentLexer.h @@ -33,9 +33,12 @@ enum TokenKind { eof, newline, text, - unknown_command, // Command that does not have an ID. - backslash_command, // Command with an ID, that used backslash marker. - at_command, // Command with an ID, that used 'at' marker. + unknown_backslash_command, // Command that does not have an ID, that used + // backslash marker. + unknown_at_command, // Command that does not have an ID, that used 'at' + // marker. + backslash_command, // Command with an ID, that used backslash marker. + at_command, // Command with an ID, that used 'at' marker. verbatim_block_begin, verbatim_block_line, verbatim_block_end, @@ -107,12 +110,12 @@ class Token { } StringRef getUnknownCommandName() const LLVM_READONLY { - assert(is(tok::unknown_command)); + assert(is(tok::unknown_backslash_command) || is(tok::unknown_at_command)); return StringRef(TextPtr, IntVal); } void setUnknownCommandName(StringRef Name) { - assert(is(tok::unknown_command)); + assert(is(tok::unknown_backslash_command) || is(tok::unknown_at_command)); TextPtr = Name.data(); IntVal = Name.size(); } diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h index 8dc6e50763dc5..3a7eda6538cbe 100644 --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -136,11 +136,13 @@ class Sema { InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef CommandName); + StringRef CommandName, + CommandMarkerKind CommandMarker); InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - unsigned CommandID); + unsigned CommandID, + CommandMarkerKind CommandMarker); TextComment *actOnText(SourceLocation LocBegin, SourceLocation LocEnd, diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index a0903d0903dd8..a8ac08c90c630 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentLexer.h" +#include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/DiagnosticComment.h" @@ -420,7 +421,10 @@ void Lexer::lexCommentText(Token &T) { << FullRange << CommandName << CorrectedName << FixItHint::CreateReplacement(CommandRange, CorrectedName); } else { - formTokenWithChars(T, TokenPtr, tok::unknown_command); + formTokenWithChars(T, TokenPtr, + CommandKind == tok::backslash_command + ? tok::unknown_backslash_command + : tok::unknown_at_command); T.setUnknownCommandName(CommandName); Diag(T.getLocation(), diag::warn_unknown_comment_command_name) << SourceRange(T.getLocation(), T.getEndLocation()); diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp index 68f18cfb5173e..87f8c870919d1 100644 --- a/clang/lib/AST/CommentParser.cpp +++ b/clang/lib/AST/CommentParser.cpp @@ -726,10 +726,12 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { case tok::eof: break; // Block content or EOF ahead, finish this parapgaph. - case tok::unknown_command: - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Tok.getUnknownCommandName())); + case tok::unknown_backslash_command: + case tok::unknown_at_command: + Content.push_back(S.actOnUnknownCommand( + Tok.getLocation(), Tok.getEndLocation(), Tok.getUnknownCommandName(), + Tok.getKind() == tok::unknown_backslash_command ? CMK_Backslash + : CMK_At)); consumeToken(); continue; @@ -751,9 +753,9 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { continue; } if (Info->IsUnknownCommand) { - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Info->getID())); + Content.push_back(S.actOnUnknownCommand( + Tok.getLocation(), Tok.getEndLocation(), Info->getID(), + Tok.getKind() == tok::backslash_command ? CMK_Backslash : CMK_At)); consumeToken(); continue; } @@ -892,7 +894,8 @@ VerbatimLineComment *Parser::parseVerbatimLine() { BlockContentComment *Parser::parseBlockContent() { switch (Tok.getKind()) { case tok::text: - case tok::unknown_command: + case tok::unknown_backslash_command: + case tok::unknown_at_command: case tok::backslash_command: case tok::at_command: case tok::html_start_tag: diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index e74c7cb5ce605..bc7884f1ffd52 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -376,19 +376,21 @@ Sema::actOnInlineCommand(SourceLocation CommandLocBegin, getInlineCommandRenderKind(CommandName), CommandMarker, Args); } -InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, - SourceLocation LocEnd, - StringRef CommandName) { +InlineContentComment * +Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, + StringRef CommandName, + CommandMarkerKind CommandMarker) { unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); - return actOnUnknownCommand(LocBegin, LocEnd, CommandID); + return actOnUnknownCommand(LocBegin, LocEnd, CommandID, CommandMarker); } -InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID) { +InlineContentComment * +Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, + unsigned CommandID, CommandMarkerKind CommandMarker) { ArrayRef<InlineCommandComment::Argument> Args; - return new (Allocator) InlineCommandComment( - LocBegin, LocEnd, CommandID, InlineCommandRenderKind::Normal, Args); + return new (Allocator) InlineCommandComment(LocBegin, LocEnd, CommandID, + InlineCommandRenderKind::Normal, + CommandMarker, Args); } TextComment *Sema::actOnText(SourceLocation LocBegin, diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp index 99f469173964e..1d016cee2877b 100644 --- a/clang/unittests/AST/CommentLexer.cpp +++ b/clang/unittests/AST/CommentLexer.cpp @@ -447,22 +447,22 @@ TEST_F(CommentLexerTest, DoxygenCommand9) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::unknown_command, Toks[1].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[1].getKind()); ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName()); - ASSERT_EQ(tok::unknown_command, Toks[2].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[2].getKind()); ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[3].getKind()); ASSERT_EQ(StringRef(" "), Toks[3].getText()); - ASSERT_EQ(tok::unknown_command, Toks[4].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[4].getKind()); ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[5].getKind()); ASSERT_EQ(StringRef("\t"), Toks[5].getText()); - ASSERT_EQ(tok::unknown_command, Toks[6].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[6].getKind()); ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName()); ASSERT_EQ(tok::newline, Toks[7].getKind()); @@ -485,6 +485,38 @@ TEST_F(CommentLexerTest, DoxygenCommand10) { ASSERT_EQ(tok::newline, Toks[2].getKind()); } +TEST_F(CommentLexerTest, DoxygenCommand11) { + const char *Source = "/// @aaa@bbb @ccc\t@ddd\n"; + std::vector<Token> Toks; + + lexString(Source, Toks); + + ASSERT_EQ(8U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName()); + + ASSERT_EQ(tok::unknown_at_command, Toks[2].getKind()); + ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName()); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef(" "), Toks[3].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[4].getKind()); + ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName()); + + ASSERT_EQ(tok::text, Toks[5].getKind()); + ASSERT_EQ(StringRef("\t"), Toks[5].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[6].getKind()); + ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName()); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); +} + TEST_F(CommentLexerTest, RegisterCustomBlockCommand) { const char *Source = "/// \\NewBlockCommand Aaa.\n" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
