Index: clangd/index/Index.h =================================================================== --- clangd/index/Index.h +++ clangd/index/Index.h @@ -156,7 +156,7 @@ }; // Optional details of the symbol. - Details *Detail = nullptr; // FIXME: should be const + const Details *Detail = nullptr; // FIXME: add definition location of the symbol. // FIXME: add all occurrences support. Index: clangd/index/Index.cpp =================================================================== --- clangd/index/Index.cpp +++ clangd/index/Index.cpp @@ -64,13 +64,12 @@ if (S.Detail) { // Copy values of StringRefs into arena. auto *Detail = Arena.Allocate(); - Detail->Documentation = S.Detail->Documentation; - Detail->CompletionDetail = S.Detail->CompletionDetail; - S.Detail = Detail; - + *Detail = *S.Detail; // Intern the actual strings. - Intern(S.Detail->Documentation); - Intern(S.Detail->CompletionDetail); + Intern(Detail->Documentation); + Intern(Detail->CompletionDetail); + // Replace the detail pointer with our copy. + S.Detail = Detail; } } Index: clangd/index/SymbolYAML.cpp =================================================================== --- clangd/index/SymbolYAML.cpp +++ clangd/index/SymbolYAML.cpp @@ -60,27 +60,39 @@ } }; -template <> -struct MappingTraits { - static void mapping(IO &io, Symbol::Details *&Detail) { - if (!io.outputting()) { - assert(io.getContext() && "Expecting an arena (as context) to allocate " - "data for new symbols."); - Detail = static_cast(io.getContext()) - ->Allocate(); - } else if (!Detail) { - // Detail is optional in outputting. - return; - } - assert(Detail); - io.mapOptional("Documentation", Detail->Documentation); - io.mapOptional("CompletionDetail", Detail->CompletionDetail); +template <> struct MappingTraits { + static void mapping(IO &io, Symbol::Details &Detail) { + io.mapOptional("Documentation", Detail.Documentation); + io.mapOptional("CompletionDetail", Detail.CompletionDetail); } }; +// A YamlIO normalizer for fields of type "const T*" allocated on an arena. +// Normalizes to Optional, so traits should be provided for T. +template struct ArenaPtr { + ArenaPtr(IO &) {} + ArenaPtr(IO &, const T *D) { + if (D) + Opt = *D; + } + + const T *denormalize(IO &IO) { + assert(IO.getContext() && "Expecting an arena (as context) to allocate " + "data for read symbols."); + if (!Opt) + return nullptr; + return new (*static_cast(IO.getContext())) + T(std::move(*Opt)); // Allocate a copy of Opt on the arena. + } + + llvm::Optional Opt; +}; + template <> struct MappingTraits { static void mapping(IO &IO, Symbol &Sym) { MappingNormalization NSymbolID(IO, Sym.ID); + MappingNormalization, const Symbol::Details *> + NDetail(IO, Sym.Detail); IO.mapRequired("ID", NSymbolID->HexString); IO.mapRequired("Name", Sym.Name); IO.mapRequired("Scope", Sym.Scope); @@ -92,8 +104,7 @@ IO.mapOptional("CompletionSnippetInsertText", Sym.CompletionSnippetInsertText); - if (!IO.outputting() || Sym.Detail) - IO.mapOptional("Detail", Sym.Detail); + IO.mapOptional("Detail", NDetail->Opt); } };