llvm-project
568 строк · 17.2 Кб
1//===-- YAMLSerialization.cpp ------------------------------------*- C++-*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// A YAML index file is a sequence of tagged entries.
10// Each entry either encodes a Symbol or the list of references to a symbol
11// (a "ref bundle").
12//
13//===----------------------------------------------------------------------===//
14
15#include "Headers.h"16#include "index/Ref.h"17#include "index/Relation.h"18#include "index/Serialization.h"19#include "index/Symbol.h"20#include "index/SymbolLocation.h"21#include "index/SymbolOrigin.h"22#include "clang/Tooling/CompilationDatabase.h"23#include "llvm/ADT/StringRef.h"24#include "llvm/Support/Allocator.h"25#include "llvm/Support/StringSaver.h"26#include "llvm/Support/YAMLTraits.h"27#include "llvm/Support/raw_ostream.h"28#include <cstdint>29#include <optional>30
31namespace {32struct YIncludeHeaderWithReferences;33}
34
35LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Symbol::IncludeHeaderWithReferences)36LLVM_YAML_IS_SEQUENCE_VECTOR(clang::clangd::Ref)37LLVM_YAML_IS_SEQUENCE_VECTOR(YIncludeHeaderWithReferences)38
39namespace {40using RefBundle =41std::pair<clang::clangd::SymbolID, std::vector<clang::clangd::Ref>>;42// This is a pale imitation of std::variant<Symbol, RefBundle, Relation>
43struct VariantEntry {44std::optional<clang::clangd::Symbol> Symbol;45std::optional<RefBundle> Refs;46std::optional<clang::clangd::Relation> Relation;47std::optional<clang::clangd::IncludeGraphNode> Source;48std::optional<clang::tooling::CompileCommand> Cmd;49};50// A class helps YAML to serialize the 32-bit encoded position (Line&Column),
51// as YAMLIO can't directly map bitfields.
52struct YPosition {53uint32_t Line;54uint32_t Column;55};56// A class helps YAML to serialize the IncludeHeaderWithReferences as YAMLIO
57// can't directly map bitfields.
58struct YIncludeHeaderWithReferences {59llvm::StringRef IncludeHeader;60uint32_t References;61clang::clangd::Symbol::IncludeDirective SupportedDirectives;62
63YIncludeHeaderWithReferences() = default;64
65YIncludeHeaderWithReferences(66llvm::StringRef IncludeHeader, uint32_t References,67clang::clangd::Symbol::IncludeDirective SupportedDirectives)68: IncludeHeader(IncludeHeader), References(References),69SupportedDirectives(SupportedDirectives) {}70};71
72// avoid ODR violation of specialization for non-owned CompileCommand
73struct CompileCommandYAML : clang::tooling::CompileCommand {};74
75} // namespace76namespace llvm {77namespace yaml {78
79using clang::clangd::FileDigest;80using clang::clangd::IncludeGraph;81using clang::clangd::IncludeGraphNode;82using clang::clangd::Ref;83using clang::clangd::RefKind;84using clang::clangd::Relation;85using clang::clangd::RelationKind;86using clang::clangd::Symbol;87using clang::clangd::SymbolID;88using clang::clangd::SymbolLocation;89using clang::index::SymbolInfo;90using clang::index::SymbolKind;91using clang::index::SymbolLanguage;92using clang::tooling::CompileCommand;93
94// Helper to (de)serialize the SymbolID. We serialize it as a hex string.
95struct NormalizedSymbolID {96NormalizedSymbolID(IO &) {}97NormalizedSymbolID(IO &, const SymbolID &ID) {98llvm::raw_string_ostream OS(HexString);99OS << ID;100}101
102SymbolID denormalize(IO &I) {103auto ID = SymbolID::fromStr(HexString);104if (!ID) {105I.setError(llvm::toString(ID.takeError()));106return SymbolID();107}108return *ID;109}110
111std::string HexString;112};113
114struct NormalizedSymbolFlag {115NormalizedSymbolFlag(IO &) {}116NormalizedSymbolFlag(IO &, Symbol::SymbolFlag F) {117Flag = static_cast<uint8_t>(F);118}119
120Symbol::SymbolFlag denormalize(IO &) {121return static_cast<Symbol::SymbolFlag>(Flag);122}123
124uint8_t Flag = 0;125};126
127template <> struct MappingTraits<YPosition> {128static void mapping(IO &IO, YPosition &Value) {129IO.mapRequired("Line", Value.Line);130IO.mapRequired("Column", Value.Column);131}132};133
134struct NormalizedPosition {135using Position = clang::clangd::SymbolLocation::Position;136NormalizedPosition(IO &) {}137NormalizedPosition(IO &, const Position &Pos) {138P.Line = Pos.line();139P.Column = Pos.column();140}141
142Position denormalize(IO &) {143Position Pos;144Pos.setLine(P.Line);145Pos.setColumn(P.Column);146return Pos;147}148YPosition P;149};150
151struct NormalizedFileURI {152NormalizedFileURI(IO &) {}153NormalizedFileURI(IO &, const char *FileURI) { URI = FileURI; }154
155const char *denormalize(IO &IO) {156assert(IO.getContext() &&157"Expecting an UniqueStringSaver to allocate data");158return static_cast<llvm::UniqueStringSaver *>(IO.getContext())159->save(URI)160.data();161}162
163std::string URI;164};165
166template <> struct MappingTraits<SymbolLocation> {167static void mapping(IO &IO, SymbolLocation &Value) {168MappingNormalization<NormalizedFileURI, const char *> NFile(IO,169Value.FileURI);170IO.mapRequired("FileURI", NFile->URI);171MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart(172IO, Value.Start);173IO.mapRequired("Start", NStart->P);174MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd(175IO, Value.End);176IO.mapRequired("End", NEnd->P);177}178};179
180template <> struct MappingTraits<SymbolInfo> {181static void mapping(IO &IO, SymbolInfo &SymInfo) {182// FIXME: expose other fields?183IO.mapRequired("Kind", SymInfo.Kind);184IO.mapRequired("Lang", SymInfo.Lang);185}186};187
188template <> struct ScalarBitSetTraits<clang::clangd::Symbol::IncludeDirective> {189static void bitset(IO &IO, clang::clangd::Symbol::IncludeDirective &Value) {190IO.bitSetCase(Value, "Include", clang::clangd::Symbol::Include);191IO.bitSetCase(Value, "Import", clang::clangd::Symbol::Import);192}193};194
195template <> struct MappingTraits<YIncludeHeaderWithReferences> {196static void mapping(IO &IO, YIncludeHeaderWithReferences &Inc) {197IO.mapRequired("Header", Inc.IncludeHeader);198IO.mapRequired("References", Inc.References);199IO.mapOptional("Directives", Inc.SupportedDirectives,200clang::clangd::Symbol::Include);201}202};203
204struct NormalizedIncludeHeaders {205using IncludeHeader = clang::clangd::Symbol::IncludeHeaderWithReferences;206NormalizedIncludeHeaders(IO &) {}207NormalizedIncludeHeaders(208IO &, const llvm::SmallVector<IncludeHeader, 1> &IncludeHeaders) {209for (auto &I : IncludeHeaders) {210Headers.emplace_back(I.IncludeHeader, I.References,211I.supportedDirectives());212}213}214
215llvm::SmallVector<IncludeHeader, 1> denormalize(IO &) {216llvm::SmallVector<IncludeHeader, 1> Result;217for (auto &H : Headers)218Result.emplace_back(H.IncludeHeader, H.References, H.SupportedDirectives);219return Result;220}221llvm::SmallVector<YIncludeHeaderWithReferences, 1> Headers;222};223
224template <> struct MappingTraits<Symbol> {225static void mapping(IO &IO, Symbol &Sym) {226MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, Sym.ID);227MappingNormalization<NormalizedSymbolFlag, Symbol::SymbolFlag> NSymbolFlag(228IO, Sym.Flags);229MappingNormalization<230NormalizedIncludeHeaders,231llvm::SmallVector<Symbol::IncludeHeaderWithReferences, 1>>232NIncludeHeaders(IO, Sym.IncludeHeaders);233IO.mapRequired("ID", NSymbolID->HexString);234IO.mapRequired("Name", Sym.Name);235IO.mapRequired("Scope", Sym.Scope);236IO.mapRequired("SymInfo", Sym.SymInfo);237IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,238SymbolLocation());239IO.mapOptional("Definition", Sym.Definition, SymbolLocation());240IO.mapOptional("References", Sym.References, 0u);241IO.mapOptional("Flags", NSymbolFlag->Flag);242IO.mapOptional("Signature", Sym.Signature);243IO.mapOptional("TemplateSpecializationArgs",244Sym.TemplateSpecializationArgs);245IO.mapOptional("CompletionSnippetSuffix", Sym.CompletionSnippetSuffix);246IO.mapOptional("Documentation", Sym.Documentation);247IO.mapOptional("ReturnType", Sym.ReturnType);248IO.mapOptional("Type", Sym.Type);249IO.mapOptional("IncludeHeaders", NIncludeHeaders->Headers);250}251};252
253template <> struct ScalarEnumerationTraits<SymbolLanguage> {254static void enumeration(IO &IO, SymbolLanguage &Value) {255IO.enumCase(Value, "C", SymbolLanguage::C);256IO.enumCase(Value, "Cpp", SymbolLanguage::CXX);257IO.enumCase(Value, "ObjC", SymbolLanguage::ObjC);258IO.enumCase(Value, "Swift", SymbolLanguage::Swift);259}260};261
262template <> struct ScalarEnumerationTraits<SymbolKind> {263static void enumeration(IO &IO, SymbolKind &Value) {264#define DEFINE_ENUM(name) IO.enumCase(Value, #name, SymbolKind::name)265
266DEFINE_ENUM(Unknown);267DEFINE_ENUM(Function);268DEFINE_ENUM(Module);269DEFINE_ENUM(Namespace);270DEFINE_ENUM(NamespaceAlias);271DEFINE_ENUM(Macro);272DEFINE_ENUM(Enum);273DEFINE_ENUM(Struct);274DEFINE_ENUM(Class);275DEFINE_ENUM(Protocol);276DEFINE_ENUM(Extension);277DEFINE_ENUM(Union);278DEFINE_ENUM(TypeAlias);279DEFINE_ENUM(Function);280DEFINE_ENUM(Variable);281DEFINE_ENUM(Field);282DEFINE_ENUM(EnumConstant);283DEFINE_ENUM(InstanceMethod);284DEFINE_ENUM(ClassMethod);285DEFINE_ENUM(StaticMethod);286DEFINE_ENUM(InstanceProperty);287DEFINE_ENUM(ClassProperty);288DEFINE_ENUM(StaticProperty);289DEFINE_ENUM(Constructor);290DEFINE_ENUM(Destructor);291DEFINE_ENUM(ConversionFunction);292DEFINE_ENUM(Parameter);293DEFINE_ENUM(Using);294
295#undef DEFINE_ENUM296}297};298
299template <> struct MappingTraits<RefBundle> {300static void mapping(IO &IO, RefBundle &Refs) {301MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO,302Refs.first);303IO.mapRequired("ID", NSymbolID->HexString);304IO.mapRequired("References", Refs.second);305}306};307
308struct NormalizedRefKind {309NormalizedRefKind(IO &) {}310NormalizedRefKind(IO &, RefKind O) { Kind = static_cast<uint8_t>(O); }311
312RefKind denormalize(IO &) { return static_cast<RefKind>(Kind); }313
314uint8_t Kind = 0;315};316
317template <> struct MappingTraits<Ref> {318static void mapping(IO &IO, Ref &R) {319MappingNormalization<NormalizedRefKind, RefKind> NKind(IO, R.Kind);320IO.mapRequired("Kind", NKind->Kind);321IO.mapRequired("Location", R.Location);322}323};324
325struct NormalizedSymbolRole {326NormalizedSymbolRole(IO &) {}327NormalizedSymbolRole(IO &IO, RelationKind R) {328Kind = static_cast<uint8_t>(R);329}330
331RelationKind denormalize(IO &IO) { return static_cast<RelationKind>(Kind); }332
333uint8_t Kind = 0;334};335
336template <> struct MappingTraits<SymbolID> {337static void mapping(IO &IO, SymbolID &ID) {338MappingNormalization<NormalizedSymbolID, SymbolID> NSymbolID(IO, ID);339IO.mapRequired("ID", NSymbolID->HexString);340}341};342
343template <> struct MappingTraits<Relation> {344static void mapping(IO &IO, Relation &Relation) {345MappingNormalization<NormalizedSymbolRole, RelationKind> NRole(346IO, Relation.Predicate);347IO.mapRequired("Subject", Relation.Subject);348IO.mapRequired("Predicate", NRole->Kind);349IO.mapRequired("Object", Relation.Object);350}351};352
353struct NormalizedSourceFlag {354NormalizedSourceFlag(IO &) {}355NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) {356Flag = static_cast<uint8_t>(O);357}358
359IncludeGraphNode::SourceFlag denormalize(IO &) {360return static_cast<IncludeGraphNode::SourceFlag>(Flag);361}362
363uint8_t Flag = 0;364};365
366struct NormalizedFileDigest {367NormalizedFileDigest(IO &) {}368NormalizedFileDigest(IO &, const FileDigest &Digest) {369HexString = llvm::toHex(Digest);370}371
372FileDigest denormalize(IO &I) {373FileDigest Digest;374if (HexString.size() == Digest.size() * 2 &&375llvm::all_of(HexString, llvm::isHexDigit)) {376memcpy(Digest.data(), llvm::fromHex(HexString).data(), Digest.size());377} else {378I.setError(std::string("Bad hex file digest: ") + HexString);379}380return Digest;381}382
383std::string HexString;384};385
386template <> struct MappingTraits<IncludeGraphNode> {387static void mapping(IO &IO, IncludeGraphNode &Node) {388IO.mapRequired("URI", Node.URI);389MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag>390NSourceFlag(IO, Node.Flags);391IO.mapRequired("Flags", NSourceFlag->Flag);392MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO,393Node.Digest);394IO.mapRequired("Digest", NDigest->HexString);395IO.mapRequired("DirectIncludes", Node.DirectIncludes);396}397};398
399template <> struct MappingTraits<CompileCommandYAML> {400static void mapping(IO &IO, CompileCommandYAML &Cmd) {401IO.mapRequired("Directory", Cmd.Directory);402IO.mapRequired("CommandLine", Cmd.CommandLine);403}404};405
406template <> struct MappingTraits<VariantEntry> {407static void mapping(IO &IO, VariantEntry &Variant) {408if (IO.mapTag("!Symbol", Variant.Symbol.has_value())) {409if (!IO.outputting())410Variant.Symbol.emplace();411MappingTraits<Symbol>::mapping(IO, *Variant.Symbol);412} else if (IO.mapTag("!Refs", Variant.Refs.has_value())) {413if (!IO.outputting())414Variant.Refs.emplace();415MappingTraits<RefBundle>::mapping(IO, *Variant.Refs);416} else if (IO.mapTag("!Relations", Variant.Relation.has_value())) {417if (!IO.outputting())418Variant.Relation.emplace();419MappingTraits<Relation>::mapping(IO, *Variant.Relation);420} else if (IO.mapTag("!Source", Variant.Source.has_value())) {421if (!IO.outputting())422Variant.Source.emplace();423MappingTraits<IncludeGraphNode>::mapping(IO, *Variant.Source);424} else if (IO.mapTag("!Cmd", Variant.Cmd.has_value())) {425if (!IO.outputting())426Variant.Cmd.emplace();427MappingTraits<CompileCommandYAML>::mapping(428IO, static_cast<CompileCommandYAML &>(*Variant.Cmd));429}430}431};432
433} // namespace yaml434} // namespace llvm435
436namespace clang {437namespace clangd {438
439void writeYAML(const IndexFileOut &O, llvm::raw_ostream &OS) {440llvm::yaml::Output Yout(OS);441for (const auto &Sym : *O.Symbols) {442VariantEntry Entry;443Entry.Symbol = Sym;444Yout << Entry;445}446if (O.Refs)447for (auto &Sym : *O.Refs) {448VariantEntry Entry;449Entry.Refs = Sym;450Yout << Entry;451}452if (O.Relations)453for (auto &R : *O.Relations) {454VariantEntry Entry;455Entry.Relation = R;456Yout << Entry;457}458if (O.Sources) {459for (const auto &Source : *O.Sources) {460VariantEntry Entry;461Entry.Source = Source.getValue();462Yout << Entry;463}464}465if (O.Cmd) {466VariantEntry Entry;467Entry.Cmd = *O.Cmd;468Yout << Entry;469}470}
471
472llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data,473SymbolOrigin Origin) {474SymbolSlab::Builder Symbols;475RefSlab::Builder Refs;476RelationSlab::Builder Relations;477llvm::BumpPtrAllocator478Arena; // store the underlying data of Position::FileURI.479llvm::UniqueStringSaver Strings(Arena);480llvm::yaml::Input Yin(Data, &Strings);481IncludeGraph Sources;482std::optional<tooling::CompileCommand> Cmd;483while (Yin.setCurrentDocument()) {484llvm::yaml::EmptyContext Ctx;485VariantEntry Variant;486yamlize(Yin, Variant, true, Ctx);487if (Yin.error())488return llvm::errorCodeToError(Yin.error());489
490if (Variant.Symbol) {491Variant.Symbol->Origin = Origin;492Symbols.insert(*Variant.Symbol);493}494if (Variant.Refs)495for (const auto &Ref : Variant.Refs->second)496Refs.insert(Variant.Refs->first, Ref);497if (Variant.Relation)498Relations.insert(*Variant.Relation);499if (Variant.Source) {500auto &IGN = *Variant.Source;501auto Entry = Sources.try_emplace(IGN.URI).first;502Entry->getValue() = std::move(IGN);503// Fixup refs to refer to map keys which will live on504Entry->getValue().URI = Entry->getKey();505for (auto &Include : Entry->getValue().DirectIncludes)506Include = Sources.try_emplace(Include).first->getKey();507}508if (Variant.Cmd)509Cmd = *Variant.Cmd;510Yin.nextDocument();511}512
513IndexFileIn Result;514Result.Symbols.emplace(std::move(Symbols).build());515Result.Refs.emplace(std::move(Refs).build());516Result.Relations.emplace(std::move(Relations).build());517if (Sources.size())518Result.Sources = std::move(Sources);519Result.Cmd = std::move(Cmd);520return std::move(Result);521}
522
523std::string toYAML(const Symbol &S) {524std::string Buf;525{526llvm::raw_string_ostream OS(Buf);527llvm::yaml::Output Yout(OS);528Symbol Sym = S; // copy: Yout<< requires mutability.529Yout << Sym;530}531return Buf;532}
533
534std::string toYAML(const std::pair<SymbolID, llvm::ArrayRef<Ref>> &Data) {535RefBundle Refs = {Data.first, Data.second};536std::string Buf;537{538llvm::raw_string_ostream OS(Buf);539llvm::yaml::Output Yout(OS);540Yout << Refs;541}542return Buf;543}
544
545std::string toYAML(const Relation &R) {546std::string Buf;547{548llvm::raw_string_ostream OS(Buf);549llvm::yaml::Output Yout(OS);550Relation Rel = R; // copy: Yout<< requires mutability.551Yout << Rel;552}553return Buf;554}
555
556std::string toYAML(const Ref &R) {557std::string Buf;558{559llvm::raw_string_ostream OS(Buf);560llvm::yaml::Output Yout(OS);561Ref Reference = R; // copy: Yout<< requires mutability.562Yout << Reference;563}564return Buf;565}
566
567} // namespace clangd568} // namespace clang569