Skip to content

Commit 94bb9e1

Browse files
authored
[clang-doc] Serialize record files with mangled name (#148021)
This patch changes JSON file serialization. Now, files are serialized to a single directory instead of nesting them based on namespaces. The global namespace retains the "index.json" name. This solves the problem of class template specializations being serialized to the same file as its base template. This is also planned as part of future integration with the Mustache generator which will consume the JSON files.
1 parent 136558b commit 94bb9e1

19 files changed

+92
-14
lines changed

clang-tools-extra/clang-doc/BitcodeReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ static llvm::Error parseRecord(const Record &R, unsigned ID,
180180
return decodeRecord(R, I->TagType, Blob);
181181
case RECORD_IS_TYPE_DEF:
182182
return decodeRecord(R, I->IsTypeDef, Blob);
183+
case RECORD_MANGLED_NAME:
184+
return decodeRecord(R, I->MangledName, Blob);
183185
default:
184186
return llvm::createStringError(llvm::inconvertibleErrorCode(),
185187
"invalid field for RecordInfo");

clang-tools-extra/clang-doc/BitcodeWriter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
189189
{RECORD_LOCATION, {"Location", &genLocationAbbrev}},
190190
{RECORD_TAG_TYPE, {"TagType", &genIntAbbrev}},
191191
{RECORD_IS_TYPE_DEF, {"IsTypeDef", &genBoolAbbrev}},
192+
{RECORD_MANGLED_NAME, {"MangledName", &genStringAbbrev}},
192193
{BASE_RECORD_USR, {"USR", &genSymbolIdAbbrev}},
193194
{BASE_RECORD_NAME, {"Name", &genStringAbbrev}},
194195
{BASE_RECORD_PATH, {"Path", &genStringAbbrev}},
@@ -271,7 +272,8 @@ static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
271272
// Record Block
272273
{BI_RECORD_BLOCK_ID,
273274
{RECORD_USR, RECORD_NAME, RECORD_PATH, RECORD_DEFLOCATION,
274-
RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF}},
275+
RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_IS_TYPE_DEF,
276+
RECORD_MANGLED_NAME}},
275277
// BaseRecord Block
276278
{BI_BASE_RECORD_BLOCK_ID,
277279
{BASE_RECORD_USR, BASE_RECORD_NAME, BASE_RECORD_PATH,
@@ -616,6 +618,7 @@ void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
616618
emitRecord(I.USR, RECORD_USR);
617619
emitRecord(I.Name, RECORD_NAME);
618620
emitRecord(I.Path, RECORD_PATH);
621+
emitRecord(I.MangledName, RECORD_MANGLED_NAME);
619622
for (const auto &N : I.Namespace)
620623
emitBlock(N, FieldId::F_namespace);
621624
for (const auto &CI : I.Description)

clang-tools-extra/clang-doc/BitcodeWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ enum RecordId {
126126
RECORD_LOCATION,
127127
RECORD_TAG_TYPE,
128128
RECORD_IS_TYPE_DEF,
129+
RECORD_MANGLED_NAME,
129130
BASE_RECORD_USR,
130131
BASE_RECORD_NAME,
131132
BASE_RECORD_PATH,

clang-tools-extra/clang-doc/JSONGenerator.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ static void serializeInfo(const RecordInfo &I, json::Object &Obj,
386386
Obj["FullName"] = I.FullName;
387387
Obj["TagType"] = getTagType(I.TagType);
388388
Obj["IsTypedef"] = I.IsTypeDef;
389+
Obj["MangledName"] = I.MangledName;
389390

390391
if (!I.Children.Functions.empty()) {
391392
json::Value PubFunctionsArray = Array();
@@ -491,6 +492,23 @@ static void serializeInfo(const NamespaceInfo &I, json::Object &Obj,
491492
serializeCommonChildren(I.Children, Obj, RepositoryUrl);
492493
}
493494

495+
static SmallString<16> determineFileName(Info *I, SmallString<128> &Path) {
496+
SmallString<16> FileName;
497+
if (I->IT == InfoType::IT_record) {
498+
auto *RecordSymbolInfo = static_cast<SymbolInfo *>(I);
499+
if (RecordSymbolInfo->MangledName.size() < 255)
500+
FileName = RecordSymbolInfo->MangledName;
501+
else
502+
FileName = toStringRef(toHex(RecordSymbolInfo->USR));
503+
} else if (I->IT == InfoType::IT_namespace && I->Name != "")
504+
// Serialize the global namespace as index.json
505+
FileName = I->Name;
506+
else
507+
FileName = I->getFileBaseName();
508+
sys::path::append(Path, FileName + ".json");
509+
return FileName;
510+
}
511+
494512
Error JSONGenerator::generateDocs(
495513
StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,
496514
const ClangDocContext &CDCtx) {
@@ -501,15 +519,14 @@ Error JSONGenerator::generateDocs(
501519

502520
SmallString<128> Path;
503521
sys::path::native(RootDir, Path);
504-
sys::path::append(Path, Info->getRelativeFilePath(""));
505522
if (!CreatedDirs.contains(Path)) {
506523
if (std::error_code Err = sys::fs::create_directories(Path);
507524
Err != std::error_code())
508525
return createFileError(Twine(Path), Err);
509526
CreatedDirs.insert(Path);
510527
}
511528

512-
sys::path::append(Path, Info->getFileBaseName() + ".json");
529+
SmallString<16> FileName = determineFileName(Info, Path);
513530
FileToInfos[Path].push_back(Info);
514531
}
515532

clang-tools-extra/clang-doc/Representation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ void SymbolInfo::merge(SymbolInfo &&Other) {
290290
auto *Last = llvm::unique(Loc);
291291
Loc.erase(Last, Loc.end());
292292
mergeBase(std::move(Other));
293+
if (MangledName.empty())
294+
MangledName = std::move(Other.MangledName);
293295
}
294296

295297
NamespaceInfo::NamespaceInfo(SymbolID USR, StringRef Name, StringRef Path)

clang-tools-extra/clang-doc/Representation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ struct SymbolInfo : public Info {
377377

378378
std::optional<Location> DefLoc; // Location where this decl is defined.
379379
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
380+
SmallString<16> MangledName;
380381
bool IsStatic = false;
381382
};
382383

clang-tools-extra/clang-doc/Serialize.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "clang/AST/Attr.h"
1313
#include "clang/AST/Comment.h"
1414
#include "clang/AST/DeclFriend.h"
15+
#include "clang/AST/Mangle.h"
1516
#include "clang/Index/USRGeneration.h"
1617
#include "clang/Lex/Lexer.h"
1718
#include "llvm/ADT/StringExtras.h"
@@ -767,6 +768,17 @@ static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
767768
I.DefLoc = Loc;
768769
else
769770
I.Loc.emplace_back(Loc);
771+
772+
auto *Mangler = ItaniumMangleContext::create(
773+
D->getASTContext(), D->getASTContext().getDiagnostics());
774+
std::string MangledName;
775+
llvm::raw_string_ostream MangledStream(MangledName);
776+
if (auto *CXXD = dyn_cast<CXXRecordDecl>(D))
777+
Mangler->mangleCXXVTable(CXXD, MangledStream);
778+
else
779+
MangledStream << D->getNameAsString();
780+
I.MangledName = MangledName;
781+
delete Mangler;
770782
}
771783

772784
static void

clang-tools-extra/test/clang-doc/json/class-requires.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: rm -rf %t && mkdir -p %t
22
// RUN: clang-doc --extra-arg -std=c++20 --output=%t --format=json --executor=standalone %s
3-
// RUN: FileCheck %s < %t/GlobalNamespace/MyClass.json
3+
// RUN: FileCheck %s < %t/_ZTV7MyClass.json
44

55
template<typename T>
66
concept Addable = requires(T a, T b) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
3+
// RUN: FileCheck %s < %t/_ZTV7MyClass.json --check-prefix=BASE
4+
// RUN: FileCheck %s < %t/_ZTV7MyClassIiE.json --check-prefix=SPECIALIZATION
5+
6+
template<typename T> struct MyClass {};
7+
8+
template<> struct MyClass<int> {};
9+
10+
// BASE: "MangledName": "_ZTV7MyClass",
11+
// BASE-NEXT: "Name": "MyClass",
12+
// BASE-NEXT: "Namespace": [
13+
// BASE-NEXT: "GlobalNamespace"
14+
// BASE-NEXT: ],
15+
// BASE-NEXT: "Path": "GlobalNamespace",
16+
// BASE-NEXT: "TagType": "struct",
17+
// BASE-NEXT: "Template": {
18+
// BASE-NEXT: "Parameters": [
19+
// BASE-NEXT: "typename T"
20+
// BASE-NEXT: ]
21+
// BASE-NEXT: },
22+
23+
// SPECIALIZATION: "MangledName": "_ZTV7MyClassIiE",
24+
// SPECIALIZATION-NEXT: "Name": "MyClass",
25+
// SPECIALIZATION-NEXT: "Namespace": [
26+
// SPECIALIZATION-NEXT: "GlobalNamespace"
27+
// SPECIALIZATION-NEXT: ],
28+
// SPECIALIZATION-NEXT: "Path": "GlobalNamespace",
29+
// SPECIALIZATION-NEXT: "TagType": "struct",
30+
// SPECIALIZATION-NEXT: "Template": {
31+
// SPECIALIZATION-NEXT: "Specialization": {
32+
// SPECIALIZATION-NEXT: "Parameters": [
33+
// SPECIALIZATION-NEXT: "int"
34+
// SPECIALIZATION-NEXT: ],
35+
// SPECIALIZATION-NEXT: "SpecializationOf": "{{[0-9A-F]*}}"
36+
// SPECIALIZATION-NEXT: }
37+
// SPECIALIZATION-NEXT: },

clang-tools-extra/test/clang-doc/json/class-template.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: rm -rf %t && mkdir -p %t
22
// RUN: clang-doc --output=%t --format=json --executor=standalone %s
3-
// RUN: FileCheck %s < %t/GlobalNamespace/MyClass.json
3+
// RUN: FileCheck %s < %t/_ZTV7MyClass.json
44

55
template<typename T> struct MyClass {
66
T MemberTemplate;

0 commit comments

Comments
 (0)