Skip to content

Commit 5d0ede1

Browse files
committed
[clang-doc] Serialize record files with mangled name
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.
1 parent 093afed commit 5d0ede1

19 files changed

+86
-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: 14 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();
@@ -501,15 +502,26 @@ Error JSONGenerator::generateDocs(
501502

502503
SmallString<128> Path;
503504
sys::path::native(RootDir, Path);
504-
sys::path::append(Path, Info->getRelativeFilePath(""));
505505
if (!CreatedDirs.contains(Path)) {
506506
if (std::error_code Err = sys::fs::create_directories(Path);
507507
Err != std::error_code())
508508
return createFileError(Twine(Path), Err);
509509
CreatedDirs.insert(Path);
510510
}
511511

512-
sys::path::append(Path, Info->getFileBaseName() + ".json");
512+
SmallString<16> FileName;
513+
if (Info->IT == InfoType::IT_record) {
514+
auto *RecordSymbolInfo = static_cast<SymbolInfo *>(Info);
515+
if (RecordSymbolInfo->MangledName.size() < 255)
516+
FileName = RecordSymbolInfo->MangledName;
517+
else
518+
FileName = toStringRef(toHex(RecordSymbolInfo->USR));
519+
} else if (Info->IT == InfoType::IT_namespace && Info->Name != "")
520+
// Serialize the global namespace as index.json
521+
FileName = Info->Name;
522+
else
523+
FileName = Info->getFileBaseName();
524+
sys::path::append(Path, FileName + ".json");
513525
FileToInfos[Path].push_back(Info);
514526
}
515527

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
@@ -378,6 +378,7 @@ struct SymbolInfo : public Info {
378378
std::optional<Location> DefLoc; // Location where this decl is defined.
379379
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
380380
bool IsStatic = false;
381+
SmallString<16> MangledName;
381382
};
382383

383384
struct FriendInfo : SymbolInfo {

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

Lines changed: 11 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,16 @@ 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 = D->getASTContext().createMangleContext();
773+
std::string MangledName;
774+
llvm::raw_string_ostream MangledStream(MangledName);
775+
if (auto *CXXD = dyn_cast<CXXRecordDecl>(D))
776+
Mangler->mangleCXXVTable(CXXD, MangledStream);
777+
else
778+
MangledStream << D->getNameAsString();
779+
I.MangledName = MangledName;
780+
delete Mangler;
770781
}
771782

772783
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)