[clang-doc] Switch to string internment (#190044)
This is the first step in migrating all the Info types to be POD. We introduced a shared string saver that can be used safely across threads, and updated the internal represntation of various data types to use these over owned strings, like SmallString or std::string. This also required changes to YAMLGenerator to keep the single quoted string formatting and to update the YAML traits. This change gives an almost 50% reduction in peak memory when building documentation for clang, at about a 10% performance loss. Future patches can mitigate the performance penalties, and further reduce memory use. | Metric | Baseline | Prev | This | Culm% | Seq% | | :--- | :--- | :--- | :--- | :--- | :--- | | Time | 920.5s | 920.5s | 1011.0s | +9.8% | +9.8% | | Memory | 86.0G | 86.0G | 44.9G | -47.8% | -47.8% | | Benchmark | Baseline | Prev | This | Culm% | Seq% | | :--- | :--- | :--- | :--- | :--- | :--- | | BM_BitcodeReader_Scale/10 | 67.9us | 67.9us | 70.0us | +3.0% | +3.0% | | BM_BitcodeReader_Scale/10000 | 70.5ms | 70.5ms | 21.3ms | -69.8% | -69.8% | | BM_BitcodeReader_Scale/4096 | 23.2ms | 23.2ms | 4.5ms | -80.7% | -80.7% | | BM_BitcodeReader_Scale/512 | 509.4us | 509.4us | 538.8us | +5.8% | +5.8% | | BM_BitcodeReader_Scale/64 | 114.8us | 114.8us | 118.0us | +2.8% | +2.8% | | BM_Index_Insertion/10 | 2.3us | 2.3us | 4.0us | +71.6% | +71.6% | | BM_Index_Insertion/10000 | 3.1ms | 3.1ms | 5.0ms | +60.6% | +60.6% | | BM_Index_Insertion/4096 | 1.3ms | 1.3ms | 2.0ms | +57.1% | +57.1% | | BM_Index_Insertion/512 | 153.6us | 153.6us | 245.0us | +59.6% | +59.6% | | BM_Index_Insertion/64 | 18.1us | 18.1us | 28.9us | +60.0% | +60.0% | | BM_JSONGenerator_Scale/10 | 36.8us | 36.8us | 36.4us | -1.3% | -1.3% | | BM_Mapper_Scale/10000 | 104.3ms | 104.3ms | 105.4ms | +1.0% | +1.0% | | BM_Mapper_Scale/512 | 7.6ms | 7.6ms | 7.7ms | +1.9% | +1.9% | | BM_MergeInfos_Scale/10000 | 12.2ms | 12.2ms | 1.4ms | -88.2% | -88.2% | | BM_MergeInfos_Scale/2 | 1.9us | 1.9us | 1.7us | -10.3% | -10.3% | | BM_MergeInfos_Scale/4096 | 2.8ms | 2.8ms | 495.6us | -82.2% | -82.2% | | BM_MergeInfos_Scale/512 | 68.9us | 68.9us | 34.6us | -49.7% | -49.7% | | BM_MergeInfos_Scale/64 | 10.3us | 10.3us | 6.0us | -41.6% | -41.6% | | BM_MergeInfos_Scale/8 | 2.8us | 2.8us | 2.1us | -24.4% | -24.4% | | BM_SerializeFunctionInfo | 25.5us | 25.5us | 26.8us | +4.9% | +4.9% | note: I used an LLM to help generate the test code adjustments and the YAML traits.
This commit is contained in:
parent
a76750e6de
commit
2600533a66
@ -28,6 +28,12 @@ static llvm::Error decodeRecord(const Record &R,
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
static llvm::Error decodeRecord(const Record &R, llvm::StringRef &Field,
|
||||
llvm::StringRef Blob) {
|
||||
Field = internString(Blob);
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
static llvm::Error decodeRecord(const Record &R, SymbolID &Field,
|
||||
llvm::StringRef Blob) {
|
||||
if (R[0] != BitCodeConstants::USRHashSize)
|
||||
@ -123,11 +129,10 @@ static llvm::Error decodeRecord(const Record &R, FieldId &Field,
|
||||
"invalid value for FieldId");
|
||||
}
|
||||
|
||||
static llvm::Error
|
||||
decodeRecord(const Record &R,
|
||||
llvm::SmallVectorImpl<llvm::SmallString<16>> &Field,
|
||||
llvm::StringRef Blob) {
|
||||
Field.push_back(Blob);
|
||||
static llvm::Error decodeRecord(const Record &R,
|
||||
llvm::SmallVectorImpl<llvm::StringRef> &Field,
|
||||
llvm::StringRef Blob) {
|
||||
Field.push_back(internString(Blob));
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
|
||||
@ -837,11 +837,11 @@ static OwningVec<Index> preprocessCDCtxIndex(Index CDCtxIndex) {
|
||||
Processed.reserve(CDCtxIndex.Children.size());
|
||||
for (const auto *Idx : CDCtxIndex.getSortedChildren()) {
|
||||
Index NewIdx = *Idx;
|
||||
auto NewPath = NewIdx.getRelativeFilePath("");
|
||||
SmallString<128> NewPath(NewIdx.getRelativeFilePath(""));
|
||||
sys::path::native(NewPath, sys::path::Style::posix);
|
||||
sys::path::append(NewPath, sys::path::Style::posix,
|
||||
NewIdx.getFileBaseName() + ".md");
|
||||
NewIdx.Path = NewPath;
|
||||
NewIdx.Path = internString(NewPath);
|
||||
Processed.push_back(NewIdx);
|
||||
}
|
||||
|
||||
@ -968,7 +968,7 @@ Error JSONGenerator::generateDocumentation(
|
||||
if (FileToInfos.contains(Path))
|
||||
continue;
|
||||
FileToInfos[Path].push_back(Info);
|
||||
Info->DocumentationFileName = FileName;
|
||||
Info->DocumentationFileName = internString(FileName);
|
||||
}
|
||||
|
||||
if (CDCtx.Format == OutputFormatTy::md_mustache) {
|
||||
|
||||
@ -27,6 +27,11 @@
|
||||
namespace clang {
|
||||
namespace doc {
|
||||
|
||||
ConcurrentStringPool &getGlobalStringPool() {
|
||||
static ConcurrentStringPool GlobalPool;
|
||||
return GlobalPool;
|
||||
}
|
||||
|
||||
CommentKind stringToCommentKind(llvm::StringRef KindStr) {
|
||||
static const llvm::StringMap<CommentKind> KindMap = {
|
||||
{"FullComment", CommentKind::CK_FullComment},
|
||||
@ -207,26 +212,26 @@ calculateRelativeFilePath(const InfoType &Type, const StringRef &Path,
|
||||
return llvm::sys::path::relative_path(FilePath);
|
||||
}
|
||||
|
||||
llvm::SmallString<64>
|
||||
Reference::getRelativeFilePath(const StringRef &CurrentPath) const {
|
||||
return calculateRelativeFilePath(RefType, Path, Name, CurrentPath);
|
||||
StringRef Reference::getRelativeFilePath(const StringRef &CurrentPath) const {
|
||||
return internString(
|
||||
calculateRelativeFilePath(RefType, Path, Name, CurrentPath));
|
||||
}
|
||||
|
||||
llvm::SmallString<16> Reference::getFileBaseName() const {
|
||||
StringRef Reference::getFileBaseName() const {
|
||||
if (RefType == InfoType::IT_namespace)
|
||||
return llvm::SmallString<16>("index");
|
||||
return "index";
|
||||
|
||||
return Name;
|
||||
}
|
||||
|
||||
llvm::SmallString<64>
|
||||
Info::getRelativeFilePath(const StringRef &CurrentPath) const {
|
||||
return calculateRelativeFilePath(IT, Path, extractName(), CurrentPath);
|
||||
StringRef Info::getRelativeFilePath(const StringRef &CurrentPath) const {
|
||||
return internString(
|
||||
calculateRelativeFilePath(IT, Path, extractName(), CurrentPath));
|
||||
}
|
||||
|
||||
llvm::SmallString<16> Info::getFileBaseName() const {
|
||||
StringRef Info::getFileBaseName() const {
|
||||
if (IT == InfoType::IT_namespace)
|
||||
return llvm::SmallString<16>("index");
|
||||
return "index";
|
||||
|
||||
return extractName();
|
||||
}
|
||||
@ -406,7 +411,7 @@ BaseRecordInfo::BaseRecordInfo(SymbolID USR, StringRef Name, StringRef Path,
|
||||
: RecordInfo(USR, Name, Path), Access(Access), IsVirtual(IsVirtual),
|
||||
IsParent(IsParent) {}
|
||||
|
||||
llvm::SmallString<16> Info::extractName() const {
|
||||
StringRef Info::extractName() const {
|
||||
if (!Name.empty())
|
||||
return Name;
|
||||
|
||||
@ -417,37 +422,30 @@ llvm::SmallString<16> Info::extractName() const {
|
||||
// namespace, which would conflict with the hard-coded global namespace name
|
||||
// below.)
|
||||
if (Name == "GlobalNamespace" && Namespace.empty())
|
||||
return llvm::SmallString<16>("@GlobalNamespace");
|
||||
return "@GlobalNamespace";
|
||||
// The case of anonymous namespaces is taken care of in serialization,
|
||||
// so here we can safely assume an unnamed namespace is the global
|
||||
// one.
|
||||
return llvm::SmallString<16>("GlobalNamespace");
|
||||
return "GlobalNamespace";
|
||||
case InfoType::IT_record:
|
||||
return llvm::SmallString<16>("@nonymous_record_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_record_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_enum:
|
||||
return llvm::SmallString<16>("@nonymous_enum_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_enum_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_typedef:
|
||||
return llvm::SmallString<16>("@nonymous_typedef_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_typedef_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_function:
|
||||
return llvm::SmallString<16>("@nonymous_function_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_function_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_concept:
|
||||
return llvm::SmallString<16>("@nonymous_concept_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_concept_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_variable:
|
||||
return llvm::SmallString<16>("@nonymous_variable_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_variable_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_friend:
|
||||
return llvm::SmallString<16>("@nonymous_friend_" +
|
||||
toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_friend_" + toHex(llvm::toStringRef(USR)));
|
||||
case InfoType::IT_default:
|
||||
return llvm::SmallString<16>("@nonymous_" + toHex(llvm::toStringRef(USR)));
|
||||
return internString("@nonymous_" + toHex(llvm::toStringRef(USR)));
|
||||
}
|
||||
llvm_unreachable("Invalid InfoType.");
|
||||
return llvm::SmallString<16>("");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Order is based on the Name attribute: case insensitive order
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
#include "clang/Tooling/Execution.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/StringSaver.h"
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@ -28,6 +31,42 @@
|
||||
namespace clang {
|
||||
namespace doc {
|
||||
|
||||
class ConcurrentStringPool {
|
||||
public:
|
||||
StringRef intern(StringRef Name) {
|
||||
if (Name.empty())
|
||||
return StringRef();
|
||||
|
||||
llvm::sys::SmartScopedLock<true> Lock(PoolMutex);
|
||||
return Saver.save(Name);
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::sys::SmartMutex<true> PoolMutex;
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
llvm::UniqueStringSaver Saver{Alloc};
|
||||
};
|
||||
|
||||
ConcurrentStringPool &getGlobalStringPool();
|
||||
|
||||
inline StringRef internString(const Twine &T) {
|
||||
if (T.isTriviallyEmpty())
|
||||
return StringRef();
|
||||
|
||||
if (T.isSingleStringRef()) {
|
||||
StringRef S = T.getSingleStringRef();
|
||||
if (S.empty())
|
||||
return StringRef();
|
||||
return getGlobalStringPool().intern(S);
|
||||
}
|
||||
|
||||
SmallString<128> Buffer;
|
||||
StringRef S = T.toStringRef(Buffer);
|
||||
if (S.empty())
|
||||
return StringRef();
|
||||
return getGlobalStringPool().intern(S);
|
||||
}
|
||||
|
||||
// An abstraction for owned pointers. Initially mapped to OwnedPtr,
|
||||
// to be eventually transitioned to bare pointers in an arena.
|
||||
template <typename T> using OwnedPtr = std::unique_ptr<T>;
|
||||
@ -123,16 +162,16 @@ struct CommentInfo {
|
||||
|
||||
OwningPtrVec<CommentInfo>
|
||||
Children; // List of child comments for this CommentInfo.
|
||||
SmallString<8> Direction; // Parameter direction (for (T)ParamCommand).
|
||||
SmallString<16> Name; // Name of the comment (for Verbatim and HTML).
|
||||
SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
|
||||
SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
|
||||
SmallString<64> Text; // Text of the comment.
|
||||
llvm::SmallVector<SmallString<16>, 4>
|
||||
StringRef Direction; // Parameter direction (for (T)ParamCommand).
|
||||
StringRef Name; // Name of the comment (for Verbatim and HTML).
|
||||
StringRef ParamName; // Parameter name (for (T)ParamCommand).
|
||||
StringRef CloseName; // Closing tag name (for VerbatimBlock).
|
||||
StringRef Text; // Text of the comment.
|
||||
llvm::SmallVector<StringRef, 4>
|
||||
AttrKeys; // List of attribute keys (for HTML).
|
||||
llvm::SmallVector<SmallString<16>, 4>
|
||||
llvm::SmallVector<StringRef, 4>
|
||||
AttrValues; // List of attribute values for each key (for HTML).
|
||||
llvm::SmallVector<SmallString<16>, 4>
|
||||
llvm::SmallVector<StringRef, 4>
|
||||
Args; // List of arguments to commands (for InlineCommand).
|
||||
CommentKind Kind = CommentKind::
|
||||
CK_Unknown; // Kind of comment (FullComment, ParagraphComment,
|
||||
@ -154,14 +193,17 @@ struct Reference {
|
||||
// "GlobalNamespace" as the name, but an empty QualName).
|
||||
Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
|
||||
InfoType IT = InfoType::IT_default)
|
||||
: USR(USR), RefType(IT), Name(Name), QualName(Name) {}
|
||||
: USR(USR), RefType(IT), Name(internString(Name)),
|
||||
QualName(internString(Name)) {}
|
||||
Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
|
||||
StringRef Path = StringRef())
|
||||
: USR(USR), RefType(IT), Name(Name), QualName(QualName), Path(Path) {}
|
||||
: USR(USR), RefType(IT), Name(internString(Name)),
|
||||
QualName(internString(QualName)), Path(internString(Path)) {}
|
||||
Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
|
||||
StringRef Path, SmallString<16> DocumentationFileName)
|
||||
: USR(USR), RefType(IT), Name(Name), QualName(QualName), Path(Path),
|
||||
DocumentationFileName(DocumentationFileName) {}
|
||||
StringRef Path, StringRef DocumentationFileName)
|
||||
: USR(USR), RefType(IT), Name(internString(Name)),
|
||||
QualName(internString(QualName)), Path(internString(Path)),
|
||||
DocumentationFileName(internString(DocumentationFileName)) {}
|
||||
|
||||
bool operator==(const Reference &Other) const {
|
||||
return std::tie(USR, Name, QualName, RefType) ==
|
||||
@ -173,10 +215,10 @@ struct Reference {
|
||||
bool operator<(const Reference &Other) const { return Name < Other.Name; }
|
||||
|
||||
/// Returns the path for this Reference relative to CurrentPath.
|
||||
llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
|
||||
StringRef getRelativeFilePath(const StringRef &CurrentPath) const;
|
||||
|
||||
/// Returns the basename that should be used for this Reference.
|
||||
llvm::SmallString<16> getFileBaseName() const;
|
||||
StringRef getFileBaseName() const;
|
||||
|
||||
SymbolID USR = SymbolID(); // Unique identifier for referenced decl
|
||||
|
||||
@ -187,27 +229,27 @@ struct Reference {
|
||||
// Name of type (possibly unresolved). Not including namespaces or template
|
||||
// parameters (so for a std::vector<int> this would be "vector"). See also
|
||||
// QualName.
|
||||
SmallString<16> Name;
|
||||
StringRef Name;
|
||||
|
||||
// Full qualified name of this type, including namespaces and template
|
||||
// parameter (for example this could be "std::vector<int>"). Contrast to
|
||||
// Name.
|
||||
SmallString<16> QualName;
|
||||
StringRef QualName;
|
||||
|
||||
// Path of directory where the clang-doc generated file will be saved
|
||||
// (possibly unresolved)
|
||||
llvm::SmallString<128> Path;
|
||||
SmallString<16> DocumentationFileName;
|
||||
StringRef Path;
|
||||
StringRef DocumentationFileName;
|
||||
};
|
||||
|
||||
// A Context is a reference that holds a relative path from a certain Info's
|
||||
// location.
|
||||
struct Context : public Reference {
|
||||
Context(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
|
||||
StringRef Path, SmallString<16> DocumentationFileName)
|
||||
StringRef Path, StringRef DocumentationFileName)
|
||||
: Reference(USR, Name, IT, QualName, Path, DocumentationFileName) {}
|
||||
explicit Context(const Info &I);
|
||||
SmallString<128> RelativePath;
|
||||
StringRef RelativePath;
|
||||
};
|
||||
|
||||
// Holds the children of a record or namespace.
|
||||
@ -255,12 +297,13 @@ struct TypeInfo {
|
||||
// name and default values in the future if needed.
|
||||
struct TemplateParamInfo {
|
||||
TemplateParamInfo() = default;
|
||||
explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {}
|
||||
explicit TemplateParamInfo(StringRef Contents)
|
||||
: Contents(internString(Contents)) {}
|
||||
|
||||
// The literal contents of the code for that specifies this template parameter
|
||||
// for this declaration. Typical values will be "class T" and
|
||||
// "typename T = int".
|
||||
SmallString<16> Contents;
|
||||
StringRef Contents;
|
||||
};
|
||||
|
||||
struct TemplateSpecializationInfo {
|
||||
@ -277,7 +320,7 @@ struct ConstraintInfo {
|
||||
: ConceptRef(USR, Name, InfoType::IT_concept) {}
|
||||
Reference ConceptRef;
|
||||
|
||||
SmallString<16> ConstraintExpr;
|
||||
StringRef ConstraintExpr;
|
||||
};
|
||||
|
||||
// Records the template information for a struct or function that is a template
|
||||
@ -296,18 +339,19 @@ struct FieldTypeInfo : public TypeInfo {
|
||||
FieldTypeInfo() = default;
|
||||
FieldTypeInfo(const TypeInfo &TI, StringRef Name = StringRef(),
|
||||
StringRef DefaultValue = StringRef())
|
||||
: TypeInfo(TI), Name(Name), DefaultValue(DefaultValue) {}
|
||||
: TypeInfo(TI), Name(internString(Name)),
|
||||
DefaultValue(internString(DefaultValue)) {}
|
||||
|
||||
bool operator==(const FieldTypeInfo &Other) const {
|
||||
return std::tie(Type, Name, DefaultValue) ==
|
||||
std::tie(Other.Type, Other.Name, Other.DefaultValue);
|
||||
}
|
||||
|
||||
SmallString<16> Name; // Name associated with this info.
|
||||
StringRef Name; // Name associated with this info.
|
||||
|
||||
// When used for function parameters, contains the string representing the
|
||||
// expression of the default value, if any.
|
||||
SmallString<16> DefaultValue;
|
||||
StringRef DefaultValue;
|
||||
};
|
||||
|
||||
// Info for member types.
|
||||
@ -336,7 +380,7 @@ struct MemberTypeInfo : public FieldTypeInfo {
|
||||
struct Location {
|
||||
Location(int StartLineNumber = 0, int EndLineNumber = 0,
|
||||
StringRef Filename = StringRef(), bool IsFileInRootDir = false)
|
||||
: Filename(Filename), StartLineNumber(StartLineNumber),
|
||||
: Filename(internString(Filename)), StartLineNumber(StartLineNumber),
|
||||
EndLineNumber(EndLineNumber), IsFileInRootDir(IsFileInRootDir) {}
|
||||
|
||||
bool operator==(const Location &Other) const {
|
||||
@ -355,7 +399,7 @@ struct Location {
|
||||
std::tie(Other.StartLineNumber, Other.EndLineNumber, Other.Filename);
|
||||
}
|
||||
|
||||
SmallString<32> Filename;
|
||||
StringRef Filename;
|
||||
int StartLineNumber = 0;
|
||||
int EndLineNumber = 0;
|
||||
bool IsFileInRootDir = false;
|
||||
@ -365,7 +409,7 @@ struct Location {
|
||||
struct Info {
|
||||
Info(InfoType IT = InfoType::IT_default, SymbolID USR = SymbolID(),
|
||||
StringRef Name = StringRef(), StringRef Path = StringRef())
|
||||
: Path(Path), Name(Name), USR(USR), IT(IT) {}
|
||||
: Path(internString(Path)), Name(internString(Name)), USR(USR), IT(IT) {}
|
||||
|
||||
Info(const Info &Other) = delete;
|
||||
Info(Info &&Other) = default;
|
||||
@ -376,24 +420,24 @@ struct Info {
|
||||
void mergeBase(Info &&I);
|
||||
bool mergeable(const Info &Other);
|
||||
|
||||
llvm::SmallString<16> extractName() const;
|
||||
StringRef extractName() const;
|
||||
|
||||
/// Returns the file path for this Info relative to CurrentPath.
|
||||
llvm::SmallString<64> getRelativeFilePath(const StringRef &CurrentPath) const;
|
||||
StringRef getRelativeFilePath(const StringRef &CurrentPath) const;
|
||||
|
||||
/// Returns the basename that should be used for this Info.
|
||||
llvm::SmallString<16> getFileBaseName() const;
|
||||
StringRef getFileBaseName() const;
|
||||
|
||||
// Path of directory where the clang-doc generated file will be saved.
|
||||
llvm::SmallString<128> Path;
|
||||
StringRef Path;
|
||||
|
||||
// Unqualified name of the decl.
|
||||
SmallString<16> Name;
|
||||
StringRef Name;
|
||||
|
||||
// The name used for the file that this info is documented in.
|
||||
// In the JSON generator, infos are documented in files with mangled names.
|
||||
// Thus, we keep track of the physical filename for linking purposes.
|
||||
SmallString<16> DocumentationFileName;
|
||||
StringRef DocumentationFileName;
|
||||
|
||||
// List of parent namespaces for this decl.
|
||||
llvm::SmallVector<Reference, 4> Namespace;
|
||||
@ -450,7 +494,7 @@ struct SymbolInfo : public Info {
|
||||
|
||||
std::optional<Location> DefLoc; // Location where this decl is defined.
|
||||
llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
|
||||
SmallString<16> MangledName;
|
||||
StringRef MangledName;
|
||||
bool IsStatic = false;
|
||||
};
|
||||
|
||||
@ -490,7 +534,7 @@ struct FunctionInfo : public SymbolInfo {
|
||||
Reference Parent;
|
||||
TypeInfo ReturnType;
|
||||
llvm::SmallVector<FieldTypeInfo, 4> Params;
|
||||
SmallString<256> Prototype;
|
||||
StringRef Prototype;
|
||||
|
||||
// When present, this function is a template or specialization.
|
||||
std::optional<TemplateInfo> Template;
|
||||
@ -554,7 +598,7 @@ struct TypedefInfo : public SymbolInfo {
|
||||
std::optional<TemplateInfo> Template;
|
||||
|
||||
// Underlying type declaration
|
||||
SmallString<16> TypeDeclaration;
|
||||
StringRef TypeDeclaration;
|
||||
|
||||
// Indicates if this is a new C++ "using"-style typedef:
|
||||
// using MyVector = std::vector<int>
|
||||
@ -581,23 +625,24 @@ struct EnumValueInfo {
|
||||
explicit EnumValueInfo(StringRef Name = StringRef(),
|
||||
StringRef Value = StringRef("0"),
|
||||
StringRef ValueExpr = StringRef())
|
||||
: Name(Name), Value(Value), ValueExpr(ValueExpr) {}
|
||||
: Name(internString(Name)), Value(internString(Value)),
|
||||
ValueExpr(internString(ValueExpr)) {}
|
||||
|
||||
bool operator==(const EnumValueInfo &Other) const {
|
||||
return std::tie(Name, Value, ValueExpr) ==
|
||||
std::tie(Other.Name, Other.Value, Other.ValueExpr);
|
||||
}
|
||||
|
||||
SmallString<16> Name;
|
||||
StringRef Name;
|
||||
|
||||
// The computed value of the enumeration constant. This could be the result of
|
||||
// evaluating the ValueExpr, or it could be automatically generated according
|
||||
// to C rules.
|
||||
SmallString<16> Value;
|
||||
StringRef Value;
|
||||
|
||||
// Stores the user-supplied initialization expression for this enumeration
|
||||
// constant. This will be empty for implicit enumeration values.
|
||||
SmallString<16> ValueExpr;
|
||||
StringRef ValueExpr;
|
||||
|
||||
/// Comment description of this field.
|
||||
OwningVec<CommentInfo> Description;
|
||||
@ -630,7 +675,7 @@ struct ConceptInfo : public SymbolInfo {
|
||||
|
||||
bool IsType;
|
||||
TemplateInfo Template;
|
||||
SmallString<16> ConstraintExpression;
|
||||
StringRef ConstraintExpression;
|
||||
};
|
||||
|
||||
struct Index : public Reference {
|
||||
@ -644,7 +689,7 @@ struct Index : public Reference {
|
||||
bool operator==(const SymbolID &Other) const { return USR == Other; }
|
||||
bool operator<(const Index &Other) const;
|
||||
|
||||
std::optional<SmallString<16>> JumpToSection;
|
||||
std::optional<StringRef> JumpToSection;
|
||||
llvm::StringMap<Index> Children;
|
||||
|
||||
OwningVec<const Index *> getSortedChildren() const;
|
||||
|
||||
@ -27,13 +27,13 @@ namespace doc {
|
||||
namespace serialize {
|
||||
|
||||
namespace {
|
||||
static SmallString<16> exprToString(const clang::Expr *E) {
|
||||
static StringRef exprToString(const clang::Expr *E) {
|
||||
clang::LangOptions Opts;
|
||||
clang::PrintingPolicy Policy(Opts);
|
||||
SmallString<16> Result;
|
||||
llvm::raw_svector_ostream OS(Result);
|
||||
E->printPretty(OS, nullptr, Policy);
|
||||
return Result;
|
||||
return internString(Result);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -86,8 +86,7 @@ void Serializer::getTemplateParameters(
|
||||
|
||||
// Extract the full function prototype from a FunctionDecl including
|
||||
// Full Decl
|
||||
llvm::SmallString<256>
|
||||
Serializer::getFunctionPrototype(const FunctionDecl *FuncDecl) {
|
||||
StringRef Serializer::getFunctionPrototype(const FunctionDecl *FuncDecl) {
|
||||
llvm::SmallString<256> Result;
|
||||
llvm::raw_svector_ostream Stream(Result);
|
||||
const ASTContext &Ctx = FuncDecl->getASTContext();
|
||||
@ -154,10 +153,10 @@ Serializer::getFunctionPrototype(const FunctionDecl *FuncDecl) {
|
||||
if (auto ExceptionSpecType = FuncDecl->getExceptionSpecType())
|
||||
Stream << " " << ExceptionSpecType;
|
||||
|
||||
return Result; // Convert SmallString to std::string for return
|
||||
return internString(Result);
|
||||
}
|
||||
|
||||
llvm::SmallString<16> Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
|
||||
StringRef Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
|
||||
llvm::SmallString<16> Result;
|
||||
llvm::raw_svector_ostream Stream(Result);
|
||||
const ASTContext &Ctx = Alias->getASTContext();
|
||||
@ -167,7 +166,7 @@ llvm::SmallString<16> Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
|
||||
QualType Q = Alias->getUnderlyingType();
|
||||
Q.print(Stream, Ctx.getPrintingPolicy());
|
||||
|
||||
return Result;
|
||||
return internString(Result);
|
||||
}
|
||||
|
||||
// A function to extract the appropriate relative path for a given info's
|
||||
@ -183,15 +182,15 @@ llvm::SmallString<16> Serializer::getTypeAlias(const TypeAliasDecl *Alias) {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
llvm::SmallString<128> Serializer::getInfoRelativePath(
|
||||
StringRef Serializer::getInfoRelativePath(
|
||||
const llvm::SmallVectorImpl<doc::Reference> &Namespaces) {
|
||||
llvm::SmallString<128> Path;
|
||||
for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R)
|
||||
llvm::sys::path::append(Path, R->Name);
|
||||
return Path;
|
||||
return internString(Path);
|
||||
}
|
||||
|
||||
llvm::SmallString<128> Serializer::getInfoRelativePath(const Decl *D) {
|
||||
StringRef Serializer::getInfoRelativePath(const Decl *D) {
|
||||
llvm::SmallVector<Reference, 4> Namespaces;
|
||||
// The third arg in populateParentNamespaces is a boolean passed by reference,
|
||||
// its value is not relevant in here so it's not used anywhere besides the
|
||||
@ -220,7 +219,7 @@ public:
|
||||
void visitVerbatimLineComment(const VerbatimLineComment *C);
|
||||
|
||||
private:
|
||||
std::string getCommandName(unsigned CommandID) const;
|
||||
StringRef getCommandName(unsigned CommandID) const;
|
||||
bool isWhitespaceOnly(StringRef S) const;
|
||||
|
||||
CommentInfo &CurrentCI;
|
||||
@ -244,87 +243,86 @@ void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
|
||||
|
||||
void ClangDocCommentVisitor::visitInlineCommandComment(
|
||||
const InlineCommandComment *C) {
|
||||
CurrentCI.Name = getCommandName(C->getCommandID());
|
||||
CurrentCI.Name = internString(getCommandName(C->getCommandID()));
|
||||
for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
|
||||
CurrentCI.Args.push_back(C->getArgText(I).trim());
|
||||
CurrentCI.Args.push_back(internString(C->getArgText(I).trim()));
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitHTMLStartTagComment(
|
||||
const HTMLStartTagComment *C) {
|
||||
CurrentCI.Name = C->getTagName();
|
||||
CurrentCI.Name = internString(C->getTagName());
|
||||
CurrentCI.SelfClosing = C->isSelfClosing();
|
||||
for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
|
||||
const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
|
||||
CurrentCI.AttrKeys.push_back(Attr.Name);
|
||||
CurrentCI.AttrValues.push_back(Attr.Value);
|
||||
CurrentCI.AttrKeys.push_back(internString(Attr.Name));
|
||||
CurrentCI.AttrValues.push_back(internString(Attr.Value));
|
||||
}
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitHTMLEndTagComment(
|
||||
const HTMLEndTagComment *C) {
|
||||
CurrentCI.Name = C->getTagName();
|
||||
CurrentCI.Name = internString(C->getTagName());
|
||||
CurrentCI.SelfClosing = true;
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitBlockCommandComment(
|
||||
const BlockCommandComment *C) {
|
||||
CurrentCI.Name = getCommandName(C->getCommandID());
|
||||
CurrentCI.Name = internString(getCommandName(C->getCommandID()));
|
||||
for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
|
||||
CurrentCI.Args.push_back(C->getArgText(I).trim());
|
||||
CurrentCI.Args.push_back(internString(C->getArgText(I).trim()));
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitParamCommandComment(
|
||||
const ParamCommandComment *C) {
|
||||
CurrentCI.Direction =
|
||||
ParamCommandComment::getDirectionAsString(C->getDirection());
|
||||
CurrentCI.Direction = internString(
|
||||
ParamCommandComment::getDirectionAsString(C->getDirection()));
|
||||
CurrentCI.Explicit = C->isDirectionExplicit();
|
||||
if (C->hasParamName())
|
||||
CurrentCI.ParamName = C->getParamNameAsWritten();
|
||||
CurrentCI.ParamName = internString(C->getParamNameAsWritten());
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitTParamCommandComment(
|
||||
const TParamCommandComment *C) {
|
||||
if (C->hasParamName())
|
||||
CurrentCI.ParamName = C->getParamNameAsWritten();
|
||||
CurrentCI.ParamName = internString(C->getParamNameAsWritten());
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitVerbatimBlockComment(
|
||||
const VerbatimBlockComment *C) {
|
||||
CurrentCI.Name = getCommandName(C->getCommandID());
|
||||
CurrentCI.CloseName = C->getCloseName();
|
||||
CurrentCI.Name = internString(getCommandName(C->getCommandID()));
|
||||
CurrentCI.CloseName = internString(C->getCloseName());
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
|
||||
const VerbatimBlockLineComment *C) {
|
||||
if (!isWhitespaceOnly(C->getText()))
|
||||
CurrentCI.Text = C->getText();
|
||||
CurrentCI.Text = internString(C->getText());
|
||||
}
|
||||
|
||||
void ClangDocCommentVisitor::visitVerbatimLineComment(
|
||||
const VerbatimLineComment *C) {
|
||||
if (!isWhitespaceOnly(C->getText()))
|
||||
CurrentCI.Text = C->getText();
|
||||
CurrentCI.Text = internString(C->getText());
|
||||
}
|
||||
|
||||
bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
|
||||
return llvm::all_of(S, isspace);
|
||||
}
|
||||
|
||||
std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
|
||||
StringRef ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
|
||||
const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
|
||||
if (Info)
|
||||
return Info->Name;
|
||||
return internString(Info->Name);
|
||||
// TODO: Add parsing for \file command.
|
||||
return "<not a builtin command>";
|
||||
}
|
||||
|
||||
// Serializing functions.
|
||||
|
||||
std::string Serializer::getSourceCode(const Decl *D, const SourceRange &R) {
|
||||
return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
|
||||
D->getASTContext().getSourceManager(),
|
||||
D->getASTContext().getLangOpts())
|
||||
.str();
|
||||
StringRef Serializer::getSourceCode(const Decl *D, const SourceRange &R) {
|
||||
return internString(Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(R), D->getASTContext().getSourceManager(),
|
||||
D->getASTContext().getLangOpts()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -590,7 +588,9 @@ void Serializer::parseParameters(FunctionInfo &I, const FunctionDecl *D) {
|
||||
for (const ParmVarDecl *P : D->parameters()) {
|
||||
FieldTypeInfo &FieldInfo = I.Params.emplace_back(
|
||||
getTypeInfoForType(P->getOriginalType(), LO), P->getNameAsString());
|
||||
FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange());
|
||||
if (std::optional<StringRef> DefaultValue =
|
||||
getSourceCode(D, P->getDefaultArgRange()))
|
||||
FieldInfo.DefaultValue = *DefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -611,7 +611,7 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
|
||||
} else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
|
||||
I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
|
||||
InfoType::IT_record, P->getQualifiedNameAsString(),
|
||||
getInfoRelativePath(P));
|
||||
internString(getInfoRelativePath(P)));
|
||||
else
|
||||
I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
|
||||
}
|
||||
@ -619,7 +619,7 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D) {
|
||||
if (const RecordDecl *P = getRecordDeclForType(B.getType()))
|
||||
I.VirtualParents.emplace_back(
|
||||
getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
|
||||
P->getQualifiedNameAsString(), getInfoRelativePath(P));
|
||||
P->getQualifiedNameAsString(), internString(getInfoRelativePath(P)));
|
||||
else
|
||||
I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
|
||||
}
|
||||
@ -732,9 +732,10 @@ void Serializer::populateInfo(Info &I, const T *D, const FullComment *C,
|
||||
ConversionDecl && ConversionDecl->getConversionType()
|
||||
.getTypePtr()
|
||||
->isTemplateTypeParmType())
|
||||
I.Name = "operator " + ConversionDecl->getConversionType().getAsString();
|
||||
I.Name = internString("operator " +
|
||||
ConversionDecl->getConversionType().getAsString());
|
||||
else
|
||||
I.Name = D->getNameAsString();
|
||||
I.Name = internString(D->getNameAsString());
|
||||
populateParentNamespaces(I.Namespace, D, IsInAnonymousNamespace);
|
||||
if (C) {
|
||||
I.Description.emplace_back();
|
||||
@ -764,9 +765,10 @@ void Serializer::populateSymbolInfo(SymbolInfo &I, const T *D,
|
||||
// different filesystems, with a 5 character buffer for file extensions.
|
||||
if (MangledName.size() > 250) {
|
||||
auto SymbolID = llvm::toStringRef(llvm::toHex(I.USR)).str();
|
||||
I.MangledName = MangledName.substr(0, 250 - SymbolID.size()) + SymbolID;
|
||||
I.MangledName =
|
||||
internString(MangledName.substr(0, 250 - SymbolID.size()) + SymbolID);
|
||||
} else
|
||||
I.MangledName = MangledName;
|
||||
I.MangledName = internString(MangledName);
|
||||
delete Mangler;
|
||||
}
|
||||
|
||||
@ -784,7 +786,7 @@ void Serializer::handleCompoundConstraints(
|
||||
auto *Concept = dyn_cast<ConceptSpecializationExpr>(Constraint);
|
||||
ConstraintInfo CI(getUSRForDecl(Concept->getNamedConcept()),
|
||||
Concept->getNamedConcept()->getNameAsString());
|
||||
CI.ConstraintExpr = exprToString(Concept);
|
||||
CI.ConstraintExpr = internString(exprToString(Concept));
|
||||
ConstraintInfos.push_back(CI);
|
||||
}
|
||||
}
|
||||
@ -805,7 +807,7 @@ void Serializer::populateConstraints(TemplateInfo &I, const TemplateDecl *D) {
|
||||
Constraint.ConstraintExpr)) {
|
||||
ConstraintInfo CI(getUSRForDecl(ConstraintExpr->getNamedConcept()),
|
||||
ConstraintExpr->getNamedConcept()->getNameAsString());
|
||||
CI.ConstraintExpr = exprToString(ConstraintExpr);
|
||||
CI.ConstraintExpr = internString(exprToString(ConstraintExpr));
|
||||
I.Constraints.push_back(std::move(CI));
|
||||
} else {
|
||||
handleCompoundConstraints(Constraint.ConstraintExpr, I.Constraints);
|
||||
@ -890,16 +892,16 @@ void Serializer::parseBases(RecordInfo &I, const CXXRecordDecl *D,
|
||||
// Initialized without USR and name, this will be set in the following
|
||||
// if-else stmt.
|
||||
BaseRecordInfo BI(
|
||||
{}, "", getInfoRelativePath(Base), B.isVirtual(),
|
||||
{}, "", internString(getInfoRelativePath(Base)), B.isVirtual(),
|
||||
getFinalAccessSpecifier(ParentAccess, B.getAccessSpecifier()),
|
||||
IsParent);
|
||||
if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
|
||||
const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
|
||||
BI.USR = getUSRForDecl(D);
|
||||
BI.Name = B.getType().getAsString();
|
||||
BI.Name = internString(B.getType().getAsString());
|
||||
} else {
|
||||
BI.USR = getUSRForDecl(Base);
|
||||
BI.Name = Base->getNameAsString();
|
||||
BI.Name = internString(Base->getNameAsString());
|
||||
}
|
||||
parseFields(BI, Base, PublicOnly, BI.Access);
|
||||
for (const auto &Decl : Base->decls())
|
||||
@ -941,9 +943,7 @@ Serializer::emitInfo(const NamespaceDecl *D, const FullComment *FC,
|
||||
if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
|
||||
return {};
|
||||
|
||||
NSI->Name = D->isAnonymousNamespace()
|
||||
? llvm::SmallString<16>("@nonymous_namespace")
|
||||
: NSI->Name;
|
||||
NSI->Name = D->isAnonymousNamespace() ? "@nonymous_namespace" : NSI->Name;
|
||||
NSI->Path = getInfoRelativePath(NSI->Namespace);
|
||||
if (NSI->Namespace.empty() && NSI->USR == SymbolID())
|
||||
return {OwnedPtr<Info>{std::move(NSI)}, nullptr};
|
||||
@ -1019,7 +1019,7 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
|
||||
|
||||
if (const auto *C = dyn_cast<CXXRecordDecl>(D)) {
|
||||
if (const TypedefNameDecl *TD = C->getTypedefNameForAnonDecl()) {
|
||||
RI->Name = TD->getNameAsString();
|
||||
RI->Name = internString(TD->getNameAsString());
|
||||
RI->IsTypeDef = true;
|
||||
}
|
||||
// TODO: remove first call to parseBases, that function should be deleted
|
||||
@ -1027,7 +1027,7 @@ Serializer::emitInfo(const RecordDecl *D, const FullComment *FC, Location Loc,
|
||||
parseBases(*RI, C, /*IsFileInRootDir=*/true, PublicOnly, /*IsParent=*/true);
|
||||
parseFriends(*RI, C);
|
||||
}
|
||||
RI->Path = getInfoRelativePath(RI->Namespace);
|
||||
RI->Path = internString(getInfoRelativePath(RI->Namespace));
|
||||
|
||||
populateTemplateParameters(RI->Template, D);
|
||||
if (RI->Template)
|
||||
|
||||
@ -90,16 +90,16 @@ private:
|
||||
void getTemplateParameters(const TemplateParameterList *TemplateParams,
|
||||
llvm::raw_ostream &Stream);
|
||||
|
||||
llvm::SmallString<256> getFunctionPrototype(const FunctionDecl *FuncDecl);
|
||||
StringRef getFunctionPrototype(const FunctionDecl *FuncDecl);
|
||||
|
||||
llvm::SmallString<16> getTypeAlias(const TypeAliasDecl *Alias);
|
||||
StringRef getTypeAlias(const TypeAliasDecl *Alias);
|
||||
|
||||
llvm::SmallString<128>
|
||||
StringRef
|
||||
getInfoRelativePath(const llvm::SmallVectorImpl<doc::Reference> &Namespaces);
|
||||
|
||||
llvm::SmallString<128> getInfoRelativePath(const Decl *D);
|
||||
StringRef getInfoRelativePath(const Decl *D);
|
||||
|
||||
std::string getSourceCode(const Decl *D, const SourceRange &R);
|
||||
llvm::StringRef getSourceCode(const Decl *D, const SourceRange &R);
|
||||
|
||||
void parseFullComment(const FullComment *C, CommentInfo &CI);
|
||||
|
||||
|
||||
@ -29,7 +29,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(OwnedPtr<CommentInfo>)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
@ -94,20 +93,6 @@ template <> struct ScalarEnumerationTraits<clang::doc::CommentKind> {
|
||||
};
|
||||
|
||||
// Scalars to YAML output.
|
||||
template <unsigned U> struct ScalarTraits<SmallString<U>> {
|
||||
|
||||
static void output(const SmallString<U> &S, void *, llvm::raw_ostream &OS) {
|
||||
for (const auto &C : S)
|
||||
OS << C;
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *, SmallString<U> &Value) {
|
||||
Value.assign(Scalar.begin(), Scalar.end());
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<SymbolID> {
|
||||
|
||||
@ -132,6 +117,33 @@ template <> struct ScalarTraits<SymbolID> {
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
|
||||
};
|
||||
|
||||
/// A wrapper for StringRef to force YAML traits to single-quote the string.
|
||||
struct QuotedString {
|
||||
StringRef Ref;
|
||||
QuotedString() = default;
|
||||
QuotedString(StringRef R) : Ref(R) {}
|
||||
operator StringRef() const { return Ref; }
|
||||
bool operator==(const QuotedString &Other) const { return Ref == Other.Ref; }
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<QuotedString> {
|
||||
static void output(const QuotedString &S, void *, llvm::raw_ostream &OS) {
|
||||
OS << S.Ref;
|
||||
}
|
||||
static StringRef input(StringRef Scalar, void *, QuotedString &Value) {
|
||||
Value.Ref = Scalar;
|
||||
return StringRef();
|
||||
}
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
|
||||
};
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::QuotedString)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
// Helper functions to map infos to YAML.
|
||||
|
||||
static void typeInfoMapping(IO &IO, TypeInfo &I) {
|
||||
@ -140,14 +152,31 @@ static void typeInfoMapping(IO &IO, TypeInfo &I) {
|
||||
|
||||
static void fieldTypeInfoMapping(IO &IO, FieldTypeInfo &I) {
|
||||
typeInfoMapping(IO, I);
|
||||
IO.mapOptional("Name", I.Name, SmallString<16>());
|
||||
IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
|
||||
|
||||
QuotedString QName(I.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Name = QName.Ref;
|
||||
|
||||
QuotedString QDefault(I.DefaultValue);
|
||||
IO.mapOptional("DefaultValue", QDefault, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.DefaultValue = QDefault.Ref;
|
||||
}
|
||||
|
||||
static void infoMapping(IO &IO, Info &I) {
|
||||
IO.mapRequired("USR", I.USR);
|
||||
IO.mapOptional("Name", I.Name, SmallString<16>());
|
||||
IO.mapOptional("Path", I.Path, SmallString<128>());
|
||||
|
||||
QuotedString QName(I.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Name = QName.Ref;
|
||||
|
||||
QuotedString QPath(I.Path);
|
||||
IO.mapOptional("Path", QPath, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Path = QPath.Ref;
|
||||
|
||||
IO.mapOptional("Namespace", I.Namespace, llvm::SmallVector<Reference, 4>());
|
||||
IO.mapOptional("Description", I.Description);
|
||||
}
|
||||
@ -176,18 +205,71 @@ static void recordInfoMapping(IO &IO, RecordInfo &I) {
|
||||
|
||||
static void commentInfoMapping(IO &IO, CommentInfo &I) {
|
||||
IO.mapOptional("Kind", I.Kind, CommentKind::CK_Unknown);
|
||||
IO.mapOptional("Text", I.Text, SmallString<64>());
|
||||
IO.mapOptional("Name", I.Name, SmallString<16>());
|
||||
IO.mapOptional("Direction", I.Direction, SmallString<8>());
|
||||
IO.mapOptional("ParamName", I.ParamName, SmallString<16>());
|
||||
IO.mapOptional("CloseName", I.CloseName, SmallString<16>());
|
||||
|
||||
QuotedString QText(I.Text);
|
||||
IO.mapOptional("Text", QText, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Text = QText.Ref;
|
||||
|
||||
QuotedString QName(I.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Name = QName.Ref;
|
||||
|
||||
QuotedString QDirection(I.Direction);
|
||||
IO.mapOptional("Direction", QDirection, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Direction = QDirection.Ref;
|
||||
|
||||
QuotedString QParamName(I.ParamName);
|
||||
IO.mapOptional("ParamName", QParamName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.ParamName = QParamName.Ref;
|
||||
|
||||
QuotedString QCloseName(I.CloseName);
|
||||
IO.mapOptional("CloseName", QCloseName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.CloseName = QCloseName.Ref;
|
||||
|
||||
IO.mapOptional("SelfClosing", I.SelfClosing, false);
|
||||
IO.mapOptional("Explicit", I.Explicit, false);
|
||||
IO.mapOptional("Args", I.Args, llvm::SmallVector<SmallString<16>, 4>());
|
||||
IO.mapOptional("AttrKeys", I.AttrKeys,
|
||||
llvm::SmallVector<SmallString<16>, 4>());
|
||||
IO.mapOptional("AttrValues", I.AttrValues,
|
||||
llvm::SmallVector<SmallString<16>, 4>());
|
||||
|
||||
std::vector<QuotedString> QArgs;
|
||||
if (IO.outputting()) {
|
||||
for (auto &S : I.Args)
|
||||
QArgs.push_back(QuotedString(S));
|
||||
}
|
||||
IO.mapOptional("Args", QArgs, std::vector<QuotedString>());
|
||||
if (!IO.outputting()) {
|
||||
I.Args.clear();
|
||||
for (auto &Q : QArgs)
|
||||
I.Args.push_back(Q.Ref);
|
||||
}
|
||||
|
||||
std::vector<QuotedString> QAttrKeys;
|
||||
if (IO.outputting()) {
|
||||
for (auto &S : I.AttrKeys)
|
||||
QAttrKeys.push_back(QuotedString(S));
|
||||
}
|
||||
IO.mapOptional("AttrKeys", QAttrKeys, std::vector<QuotedString>());
|
||||
if (!IO.outputting()) {
|
||||
I.AttrKeys.clear();
|
||||
for (auto &Q : QAttrKeys)
|
||||
I.AttrKeys.push_back(Q.Ref);
|
||||
}
|
||||
|
||||
std::vector<QuotedString> QAttrValues;
|
||||
if (IO.outputting()) {
|
||||
for (auto &S : I.AttrValues)
|
||||
QAttrValues.push_back(QuotedString(S));
|
||||
}
|
||||
IO.mapOptional("AttrValues", QAttrValues, std::vector<QuotedString>());
|
||||
if (!IO.outputting()) {
|
||||
I.AttrValues.clear();
|
||||
for (auto &Q : QAttrValues)
|
||||
I.AttrValues.push_back(Q.Ref);
|
||||
}
|
||||
|
||||
IO.mapOptional("Children", I.Children);
|
||||
}
|
||||
|
||||
@ -196,17 +278,34 @@ static void commentInfoMapping(IO &IO, CommentInfo &I) {
|
||||
template <> struct MappingTraits<Location> {
|
||||
static void mapping(IO &IO, Location &Loc) {
|
||||
IO.mapOptional("LineNumber", Loc.StartLineNumber, 0);
|
||||
IO.mapOptional("Filename", Loc.Filename, SmallString<32>());
|
||||
|
||||
QuotedString QFilename(Loc.Filename);
|
||||
IO.mapOptional("Filename", QFilename, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
Loc.Filename = QFilename.Ref;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<Reference> {
|
||||
static void mapping(IO &IO, Reference &Ref) {
|
||||
IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
|
||||
IO.mapOptional("Name", Ref.Name, SmallString<16>());
|
||||
IO.mapOptional("QualName", Ref.QualName, SmallString<16>());
|
||||
|
||||
QuotedString QName(Ref.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
Ref.Name = QName.Ref;
|
||||
|
||||
QuotedString QQualName(Ref.QualName);
|
||||
IO.mapOptional("QualName", QQualName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
Ref.QualName = QQualName.Ref;
|
||||
|
||||
IO.mapOptional("USR", Ref.USR, SymbolID());
|
||||
IO.mapOptional("Path", Ref.Path, SmallString<128>());
|
||||
|
||||
QuotedString QPath(Ref.Path);
|
||||
IO.mapOptional("Path", QPath, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
Ref.Path = QPath.Ref;
|
||||
}
|
||||
};
|
||||
|
||||
@ -217,8 +316,16 @@ template <> struct MappingTraits<TypeInfo> {
|
||||
template <> struct MappingTraits<FieldTypeInfo> {
|
||||
static void mapping(IO &IO, FieldTypeInfo &I) {
|
||||
typeInfoMapping(IO, I);
|
||||
IO.mapOptional("Name", I.Name, SmallString<16>());
|
||||
IO.mapOptional("DefaultValue", I.DefaultValue, SmallString<16>());
|
||||
|
||||
QuotedString QName(I.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Name = QName.Ref;
|
||||
|
||||
QuotedString QDefault(I.DefaultValue);
|
||||
IO.mapOptional("DefaultValue", QDefault, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.DefaultValue = QDefault.Ref;
|
||||
}
|
||||
};
|
||||
|
||||
@ -263,9 +370,20 @@ template <> struct MappingTraits<BaseRecordInfo> {
|
||||
|
||||
template <> struct MappingTraits<EnumValueInfo> {
|
||||
static void mapping(IO &IO, EnumValueInfo &I) {
|
||||
IO.mapOptional("Name", I.Name);
|
||||
IO.mapOptional("Value", I.Value);
|
||||
IO.mapOptional("Expr", I.ValueExpr, SmallString<16>());
|
||||
QuotedString QName(I.Name);
|
||||
IO.mapOptional("Name", QName, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Name = QName.Ref;
|
||||
|
||||
QuotedString QValue(I.Value);
|
||||
IO.mapOptional("Value", QValue, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Value = QValue.Ref;
|
||||
|
||||
QuotedString QExpr(I.ValueExpr);
|
||||
IO.mapOptional("Expr", QExpr, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.ValueExpr = QExpr.Ref;
|
||||
}
|
||||
};
|
||||
|
||||
@ -303,7 +421,10 @@ template <> struct MappingTraits<FunctionInfo> {
|
||||
|
||||
template <> struct MappingTraits<TemplateParamInfo> {
|
||||
static void mapping(IO &IO, TemplateParamInfo &I) {
|
||||
IO.mapOptional("Contents", I.Contents);
|
||||
QuotedString QContents(I.Contents);
|
||||
IO.mapOptional("Contents", QContents, QuotedString(StringRef()));
|
||||
if (!IO.outputting())
|
||||
I.Contents = QContents.Ref;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ static void BM_BitcodeReader_Scale(benchmark::State &State) {
|
||||
ClangDocBitcodeWriter Writer(Stream, Diags);
|
||||
for (int i = 0; i < NumRecords; ++i) {
|
||||
RecordInfo RI;
|
||||
RI.Name = "Record" + std::to_string(i);
|
||||
RI.Name = internString("Record" + std::to_string(i));
|
||||
RI.USR = {(uint8_t)(i & 0xFF)};
|
||||
Writer.emitBlock(RI);
|
||||
}
|
||||
@ -180,7 +180,6 @@ static void BM_JSONGenerator_Scale(benchmark::State &State) {
|
||||
llvm::consumeError(G.takeError());
|
||||
return;
|
||||
}
|
||||
|
||||
int NumRecords = State.range(0);
|
||||
auto NI = allocatePtr<NamespaceInfo>();
|
||||
NI->Name = "GlobalNamespace";
|
||||
@ -218,10 +217,10 @@ static void BM_Index_Insertion(benchmark::State &State) {
|
||||
Index Idx;
|
||||
for (int i = 0; i < State.range(0); ++i) {
|
||||
RecordInfo I;
|
||||
I.Name = "Record" + std::to_string(i);
|
||||
I.Name = internString("Record" + std::to_string(i));
|
||||
// Vary USR to ensure unique entries
|
||||
I.USR = {(uint8_t)(i & 0xFF), (uint8_t)((i >> 8) & 0xFF)};
|
||||
I.Path = "path/to/record";
|
||||
I.Path = internString("path/to/record");
|
||||
Generator::addInfoToIndex(Idx, &I);
|
||||
}
|
||||
benchmark::DoNotOptimize(Idx);
|
||||
|
||||
@ -15,7 +15,9 @@
|
||||
namespace clang {
|
||||
namespace doc {
|
||||
|
||||
TEST(GeneratorTest, emitIndex) {
|
||||
class GeneratorTest : public ClangDocContextTest {};
|
||||
|
||||
TEST_F(GeneratorTest, emitIndex) {
|
||||
Index Idx;
|
||||
auto InfoA = std::make_unique<Info>();
|
||||
InfoA->Name = "A";
|
||||
@ -80,7 +82,7 @@ TEST(GeneratorTest, emitIndex) {
|
||||
CheckIndex(ExpectedIdx, Idx);
|
||||
}
|
||||
|
||||
TEST(GeneratorTest, sortIndex) {
|
||||
TEST_F(GeneratorTest, sortIndex) {
|
||||
Index Idx;
|
||||
Index IndexA;
|
||||
IndexA.Name = "a";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user