Skip to content

Commit 529e912

Browse files
authored
[clang][doc]: Merge entries with duplicate content. (#134089)
Before the patch: ![docb4](https://github.com/user-attachments/assets/6db1000f-d555-48b8-8a19-85c41b043fd8) after the patch: ![doc-after](https://github.com/user-attachments/assets/1cff64b6-db2e-48d8-b0a9-a403fd61f8af) Fixes #133706
1 parent 369c773 commit 529e912

File tree

1 file changed

+74
-8
lines changed

1 file changed

+74
-8
lines changed

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5144,6 +5144,14 @@ class SpellingList {
51445144

51455145
Spellings[(size_t)Kind].push_back(Name);
51465146
}
5147+
5148+
void merge(const SpellingList &Other) {
5149+
for (size_t Kind = 0; Kind < NumSpellingKinds; ++Kind) {
5150+
Spellings[Kind].insert(Spellings[Kind].end(),
5151+
Other.Spellings[Kind].begin(),
5152+
Other.Spellings[Kind].end());
5153+
}
5154+
}
51475155
};
51485156

51495157
class DocumentationData {
@@ -5301,31 +5309,89 @@ void EmitClangAttrDocs(const RecordKeeper &Records, raw_ostream &OS) {
53015309
return L->getValueAsString("Name") < R->getValueAsString("Name");
53025310
}
53035311
};
5304-
std::map<const Record *, std::vector<DocumentationData>, CategoryLess>
5305-
SplitDocs;
5312+
5313+
std::map<const Record *, std::map<uint32_t, DocumentationData>, CategoryLess>
5314+
MergedDocs;
5315+
5316+
std::vector<DocumentationData> UndocumentedDocs;
5317+
const Record *UndocumentedCategory = nullptr;
5318+
5319+
// Collect documentation data, grouping by category and heading.
53065320
for (const auto *A : Records.getAllDerivedDefinitions("Attr")) {
53075321
const Record &Attr = *A;
53085322
std::vector<const Record *> Docs =
53095323
Attr.getValueAsListOfDefs("Documentation");
5324+
53105325
for (const auto *D : Docs) {
53115326
const Record &Doc = *D;
53125327
const Record *Category = Doc.getValueAsDef("Category");
53135328
// If the category is "InternalOnly", then there cannot be any other
53145329
// documentation categories (otherwise, the attribute would be
53155330
// emitted into the docs).
5316-
const StringRef Cat = Category->getValueAsString("Name");
5317-
bool InternalOnly = Cat == "InternalOnly";
5318-
if (InternalOnly && Docs.size() > 1)
5331+
StringRef Cat = Category->getValueAsString("Name");
5332+
if (Cat == "InternalOnly" && Docs.size() > 1)
53195333
PrintFatalError(Doc.getLoc(),
53205334
"Attribute is \"InternalOnly\", but has multiple "
53215335
"documentation categories");
53225336

5323-
if (!InternalOnly)
5324-
SplitDocs[Category].push_back(DocumentationData(
5325-
Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr, Cat)));
5337+
if (Cat == "InternalOnly")
5338+
continue;
5339+
5340+
// Track the Undocumented category Record for later grouping
5341+
if (Cat == "Undocumented" && !UndocumentedCategory)
5342+
UndocumentedCategory = Category;
5343+
5344+
// Generate Heading and Spellings.
5345+
auto HeadingAndSpellings =
5346+
GetAttributeHeadingAndSpellings(Doc, Attr, Cat);
5347+
5348+
// Handle Undocumented category separately - no content merging
5349+
if (Cat == "Undocumented" && UndocumentedCategory) {
5350+
UndocumentedDocs.push_back(
5351+
DocumentationData(Doc, Attr, HeadingAndSpellings));
5352+
continue;
5353+
}
5354+
5355+
auto &CategoryDocs = MergedDocs[Category];
5356+
5357+
std::string key = Doc.getValueAsString("Content").str();
5358+
uint32_t keyHash = llvm::hash_value(key);
5359+
5360+
// If the content already exists, merge the documentation.
5361+
auto It = CategoryDocs.find(keyHash);
5362+
if (It != CategoryDocs.end()) {
5363+
// Merge heading
5364+
if (It->second.Heading != HeadingAndSpellings.first)
5365+
It->second.Heading += ", " + HeadingAndSpellings.first;
5366+
// Merge spellings
5367+
It->second.SupportedSpellings.merge(HeadingAndSpellings.second);
5368+
// Merge content
5369+
It->second.Documentation = &Doc; // Update reference
5370+
} else {
5371+
// Create new entry for unique content
5372+
CategoryDocs.emplace(keyHash,
5373+
DocumentationData(Doc, Attr, HeadingAndSpellings));
5374+
}
53265375
}
53275376
}
53285377

5378+
std::map<const Record *, std::vector<DocumentationData>, CategoryLess>
5379+
SplitDocs;
5380+
5381+
for (auto &CategoryPair : MergedDocs) {
5382+
5383+
std::vector<DocumentationData> MD;
5384+
for (auto &DocPair : CategoryPair.second)
5385+
MD.push_back(std::move(DocPair.second));
5386+
5387+
SplitDocs.emplace(CategoryPair.first, MD);
5388+
}
5389+
5390+
// Append Undocumented category entries
5391+
if (!UndocumentedDocs.empty() && UndocumentedCategory) {
5392+
SplitDocs.emplace(UndocumentedCategory, UndocumentedDocs);
5393+
}
5394+
53295395
// Having split the attributes out based on what documentation goes where,
53305396
// we can begin to generate sections of documentation.
53315397
for (auto &I : SplitDocs) {

0 commit comments

Comments
 (0)