https://github.com/evelez7 created 
https://github.com/llvm/llvm-project/pull/173956

This patch serializes concepts in HTML. This patch also includes changes
to bitcode reading/writing and JSON to serialize the concept's location,
which was missing.

>From 1f75f44712550d9d076dc3ef89b36c32d3211cd7 Mon Sep 17 00:00:00 2001
From: Erick Velez <[email protected]>
Date: Tue, 9 Dec 2025 00:00:25 -0800
Subject: [PATCH] [clang-doc] Add concepts to namespace template

This patch serializes concepts in HTML. This patch also includes changes
to bitcode reading/writing and JSON to serialize the concept's location,
which was missing.
---
 clang-tools-extra/clang-doc/BitcodeReader.cpp |  2 +
 clang-tools-extra/clang-doc/BitcodeWriter.cpp |  5 +-
 clang-tools-extra/clang-doc/BitcodeWriter.h   |  1 +
 clang-tools-extra/clang-doc/JSONGenerator.cpp |  6 +-
 .../assets/comment-template.mustache          |  8 ++
 .../assets/namespace-template.mustache        | 30 +++++++
 .../clang-doc/json/compound-constraints.cpp   | 88 +++++++++++++++++++
 .../test/clang-doc/json/concept.cpp           |  5 ++
 8 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp 
b/clang-tools-extra/clang-doc/BitcodeReader.cpp
index 817981aa0d4a3..731b6990cb697 100644
--- a/clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -429,6 +429,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
     return decodeRecord(R, I->IsType, Blob);
   case CONCEPT_CONSTRAINT_EXPRESSION:
     return decodeRecord(R, I->ConstraintExpression, Blob);
+  case CONCEPT_DEFLOCATION:
+    return decodeRecord(R, I->DefLoc, Blob);
   }
   llvm_unreachable("invalid field for ConceptInfo");
 }
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.cpp 
b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
index 650501d1d7606..b7f60d88d96ff 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -223,6 +223,7 @@ static const llvm::IndexedMap<RecordIdDsc, 
RecordIdToIndexFunctor>
           {CONCEPT_IS_TYPE, {"IsType", &genBoolAbbrev}},
           {CONCEPT_CONSTRAINT_EXPRESSION,
            {"ConstraintExpression", &genStringAbbrev}},
+          {CONCEPT_DEFLOCATION, {"DefLocation", &genLocationAbbrev}},
           {CONSTRAINT_EXPRESSION, {"Expression", &genStringAbbrev}},
           {VAR_USR, {"USR", &genSymbolIdAbbrev}},
           {VAR_NAME, {"Name", &genStringAbbrev}},
@@ -295,7 +296,7 @@ static const std::vector<std::pair<BlockId, 
std::vector<RecordId>>>
         // Concept Block
         {BI_CONCEPT_BLOCK_ID,
          {CONCEPT_USR, CONCEPT_NAME, CONCEPT_IS_TYPE,
-          CONCEPT_CONSTRAINT_EXPRESSION}},
+          CONCEPT_CONSTRAINT_EXPRESSION, CONCEPT_DEFLOCATION}},
         // Constraint Block
         {BI_CONSTRAINT_BLOCK_ID, {CONSTRAINT_EXPRESSION}},
         {BI_VAR_BLOCK_ID, {VAR_NAME, VAR_USR, VAR_DEFLOCATION, VAR_IS_STATIC}},
@@ -698,6 +699,8 @@ void ClangDocBitcodeWriter::emitBlock(const ConceptInfo &I) 
{
   emitRecord(I.IsType, CONCEPT_IS_TYPE);
   emitRecord(I.ConstraintExpression, CONCEPT_CONSTRAINT_EXPRESSION);
   emitBlock(I.Template);
+  if (I.DefLoc)
+    emitRecord(*I.DefLoc, CONCEPT_DEFLOCATION);
 }
 
 void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
diff --git a/clang-tools-extra/clang-doc/BitcodeWriter.h 
b/clang-tools-extra/clang-doc/BitcodeWriter.h
index 6d1b9e9a7ebf2..89c556fc310cb 100644
--- a/clang-tools-extra/clang-doc/BitcodeWriter.h
+++ b/clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -148,6 +148,7 @@ enum RecordId {
   CONCEPT_NAME,
   CONCEPT_IS_TYPE,
   CONCEPT_CONSTRAINT_EXPRESSION,
+  CONCEPT_DEFLOCATION,
   CONSTRAINT_EXPRESSION,
   VAR_USR,
   VAR_NAME,
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp 
b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 6dec347ed0bd0..2887c5e7bc187 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -213,6 +213,8 @@ static Object serializeComment(const CommentInfo &I, Object 
&Description) {
     Child.insert({"Children", TextCommentsArray});
     if (I.Kind == CommentKind::CK_ParamCommandComment)
       insertComment(Description, ChildVal, "ParamComments");
+    if (I.Kind == CommentKind::CK_TParamCommandComment)
+      insertComment(Description, ChildVal, "TParamComments");
     return Obj;
   }
 
@@ -642,8 +644,10 @@ static void serializeInfo(const NamespaceInfo &I, 
json::Object &Obj,
     Obj["HasFunctions"] = true;
   }
 
-  if (!I.Children.Concepts.empty())
+  if (!I.Children.Concepts.empty()) {
     serializeArray(I.Children.Concepts, Obj, "Concepts", SerializeInfo);
+    Obj["HasConcepts"] = true;
+  }
 
   if (!I.Children.Variables.empty())
     serializeArray(I.Children.Variables, Obj, "Variables", SerializeInfo);
diff --git a/clang-tools-extra/clang-doc/assets/comment-template.mustache 
b/clang-tools-extra/clang-doc/assets/comment-template.mustache
index 1f40333cfd4b2..8d89cffd2c3bf 100644
--- a/clang-tools-extra/clang-doc/assets/comment-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/comment-template.mustache
@@ -32,6 +32,14 @@
 </div> 
 {{/ParamComments}}
 {{/HasParamComments}}
+{{#HasTParamComments}}
+<h3>Template Parameters</h3>
+{{#TParamComments}}
+<div>
+    <b>{{ParamName}}</b> {{#Explicit}}{{Direction}}{{/Explicit}} 
{{#Children}}{{TextComment}}{{/Children}}
+</div> 
+{{/#TParamComments}}
+{{/HasTParamComments}}
 {{#HasReturnComments}}
 <h3>Returns</h3>
 {{#ReturnComments}}
diff --git a/clang-tools-extra/clang-doc/assets/namespace-template.mustache 
b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
index 6a43def0386d5..3588ecf30b3f9 100644
--- a/clang-tools-extra/clang-doc/assets/namespace-template.mustache
+++ b/clang-tools-extra/clang-doc/assets/namespace-template.mustache
@@ -71,6 +71,20 @@
                         </ul>
                     </li>
                     {{/HasNamespaces}}
+                    {{#HasConcepts}}
+                    <li class="sidebar-section">
+                        <a class="sidebar-item" href="#Concepts">Concepts</a>
+                    </li>
+                    <li>
+                        <ul>
+                            {{#Concepts}}
+                            <li class="sidebar-item-container">
+                                <a class="sidebar-item" 
href="#{{USR}}">{{Name}}</a>
+                            </li>
+                            {{/Concepts}}
+                        </ul>
+                    </li>
+                    {{/HasConcepts}}
                 </ul>
             </div>
             <div class="resizer" id="resizer"></div>
@@ -125,6 +139,22 @@
                     </ul>
                 </section>
                 {{/HasFunctions}}
+                {{#HasConcepts}}
+                <section id="Concepts" class="section-container">
+                    <h2>Concepts</h2>
+                    {{#Concepts}}
+                    <div id="{{ID}}" class="delimiter-container">
+                        <div>
+                            <pre><code class="language-cpp 
code-clang-doc">{{#Template}}template &lt;{{#Parameters}}{{Param}}{{^End}}, 
{{/End}}{{/Parameters}}&gt;{{/Template}} {{Name}} 
{{ConstraintExpression}}</code></pre> 
+                        </div>
+                        {{#Description}}
+                        {{>Comments}}
+                        {{/Description}}
+                        <p>Defined at line {{Location.LineNumber}} of file 
{{Location.Filename}}</p>
+                    </div>
+                    {{/Concepts}}
+                </section>
+                {{/HasConcepts}}
             </div>
         </div>
     </main>
diff --git a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp 
b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
index afaad8f5d6775..3031740464d63 100644
--- a/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
+++ b/clang-tools-extra/test/clang-doc/json/compound-constraints.cpp
@@ -1,19 +1,33 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json 
--executor=standalone %s
+// RUN: clang-doc --extra-arg -std=c++20 --output=%t --doxygen --format=html 
--executor=standalone %s
 // RUN: FileCheck %s < %t/json/GlobalNamespace/index.json
+// RUN: FileCheck %s < %t/html/GlobalNamespace/index.html 
-check-prefix=CHECK-HTML
 
+/// \brief Concept for an incrementable value
+///
+/// \tparam T A value that can be incremented.
 template<typename T> concept Incrementable = requires (T a) {
   a++;
 };
 
+/// \brief Concept for a decrementable value
+///
+/// \tparam T A value that can be decremented
 template<typename T> concept Decrementable = requires (T a) {
   a--;
 };
 
+/// \brief Concept for a pre-incrementable value
+///
+/// \tparam T A value that can be pre-incremented
 template<typename T> concept PreIncrementable = requires (T a) {
   ++a;
 };
 
+/// \brief Concept for a -pre-decrementable value
+///
+/// \tparam T A value that can be pre-decremented
 template<typename T> concept PreDecrementable = requires (T a) {
   --a;
 };
@@ -112,3 +126,77 @@ template<typename T> requires (Incrementable<T> && 
Decrementable<T>) || PreIncre
 // CHECK-NEXT:          "USR": "{{[0-9A-F]*}}"
 // CHECK-NEXT:        }
 // CHECK-NEXT:      ],
+
+// CHECK-HTML:          <a class="sidebar-item" href="#Concepts">Concepts</a>
+// CHECK-HTML-NEXT: </li>
+// CHECK-HTML-NEXT: <li>
+// CHECK-HTML-NEXT:     <ul>
+// CHECK-HTML-NEXT:         <li class="sidebar-item-container">
+// CHECK-HTML-NEXT:             <a class="sidebar-item" 
href="#{{([0-9A-F]{40})}}">Incrementable</a>
+// CHECK-HTML-NEXT:         </li>
+// CHECK-HTML-NEXT:         <li class="sidebar-item-container">
+// CHECK-HTML-NEXT:             <a class="sidebar-item" 
href="#{{([0-9A-F]{40})}}">Decrementable</a>
+// CHECK-HTML-NEXT:         </li>
+// CHECK-HTML-NEXT:         <li class="sidebar-item-container">
+// CHECK-HTML-NEXT:             <a class="sidebar-item" 
href="#{{([0-9A-F]{40})}}">PreIncrementable</a>
+// CHECK-HTML-NEXT:         </li>
+// CHECK-HTML-NEXT:         <li class="sidebar-item-container">
+// CHECK-HTML-NEXT:             <a class="sidebar-item" 
href="#{{([0-9A-F]{40})}}">PreDecrementable</a>
+// CHECK-HTML-NEXT:         </li>
+// CHECK-HTML-NEXT:     </ul>
+// CHECK-HTML-NEXT: </li>
+// CHECK-HTML:      <section id="Concepts" class="section-container">
+// CHECK-HTML-NEXT:     <h2>Concepts</h2>
+// CHECK-HTML-NEXT:     <div id="" class="delimiter-container">
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <pre><code class="language-cpp 
code-clang-doc">template &lt;typename T&gt; Incrementable requires (T a) { a++; 
}</code></pre> 
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <p> Concept for an incrementable value</p>
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <h3>Template Parameters</h3>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <b>T</b>   A value that can be incremented.
+// CHECK-HTML-NEXT:         </div> 
+// CHECK-HTML-NEXT:         <p>Defined at line [[@LINE-151]] of file 
{{.*}}compound-constraints.cpp</p>
+// CHECK-HTML-NEXT:     </div>
+// CHECK-HTML-NEXT:     <div id="" class="delimiter-container">
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <pre><code class="language-cpp 
code-clang-doc">template &lt;typename T&gt; Decrementable requires (T a) { a--; 
}</code></pre> 
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <p> Concept for a decrementable value</p>
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <h3>Template Parameters</h3>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <b>T</b>   A value that can be decremented
+// CHECK-HTML-NEXT:         </div> 
+// CHECK-HTML-NEXT:         <p>Defined at line [[@LINE-157]] of file 
{{.*}}compound-constraints.cpp</p>
+// CHECK-HTML-NEXT:     </div>
+// CHECK-HTML-NEXT:     <div id="" class="delimiter-container">
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <pre><code class="language-cpp 
code-clang-doc">template &lt;typename T&gt; PreIncrementable requires (T a) { 
++a; }</code></pre> 
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <p> Concept for a pre-incrementable value</p>
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <h3>Template Parameters</h3>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <b>T</b>   A value that can be pre-incremented
+// CHECK-HTML-NEXT:         </div> 
+// CHECK-HTML-NEXT:         <p>Defined at line [[@LINE-163]] of file 
{{.*}}compound-constraints.cpp</p>
+// CHECK-HTML-NEXT:     </div>
+// CHECK-HTML-NEXT:     <div id="" class="delimiter-container">
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <pre><code class="language-cpp 
code-clang-doc">template &lt;typename T&gt; PreDecrementable requires (T a) { 
--a; }</code></pre> 
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <p> Concept for a -pre-decrementable value</p>
+// CHECK-HTML-NEXT:         </div>
+// CHECK-HTML-NEXT:         <h3>Template Parameters</h3>
+// CHECK-HTML-NEXT:         <div>
+// CHECK-HTML-NEXT:             <b>T</b>   A value that can be pre-decremented
+// CHECK-HTML-NEXT:         </div> 
+// CHECK-HTML-NEXT:         <p>Defined at line [[@LINE-169]] of file 
{{.*}}compound-constraints.cpp</p>
+// CHECK-HTML-NEXT:     </div>
+// CHECK-HTML-NEXT: </section>
diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp 
b/clang-tools-extra/test/clang-doc/json/concept.cpp
index fc440d095fc4c..401234504b785 100644
--- a/clang-tools-extra/test/clang-doc/json/concept.cpp
+++ b/clang-tools-extra/test/clang-doc/json/concept.cpp
@@ -1,5 +1,6 @@
 // RUN: rm -rf %t && mkdir -p %t
 // RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json 
--executor=standalone %s
+// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=html 
--executor=standalone %s
 // RUN: FileCheck %s < %t/json/GlobalNamespace/index.json
 
 // Requires that T suports post and pre-incrementing.
@@ -22,6 +23,10 @@ concept Incrementable = requires(T x) {
 // CHECK:             "End": true,
 // CHECK-NEXT:        "InfoType": "concept",
 // CHECK-NEXT:        "IsType": true,
+// CHECK-NEXT:        "Location": {
+// CHECK-NEXT:          "Filename": 
"/home/erick/code/llvm-project/clang-tools-extra/test/clang-doc/json/concept.cpp",
+// CHECK-NEXT:          "LineNumber": 7
+// CHECK-NEXT:        },
 // CHECK-NEXT:        "Name": "Incrementable",
 // CHECK-NEXT:        "Template": {
 // CHECK-NEXT:          "Parameters": [

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to