mnauw updated this revision to Diff 255019.
mnauw retitled this revision from "[clangd] Add index inspection helper tool" 
to "[clangd] Add index export to dexp".
mnauw edited the summary of this revision.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77385/new/

https://reviews.llvm.org/D77385

Files:
  clang-tools-extra/clangd/index/YAMLSerialization.cpp
  clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp

Index: clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
===================================================================
--- clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
+++ clang-tools-extra/clangd/index/dex/dexp/Dexp.cpp
@@ -25,6 +25,10 @@
 namespace clangd {
 namespace {
 
+static llvm::cl::opt<bool>
+    Export("export", llvm::cl::desc("Export index non-interactively"),
+           llvm::cl::init(false));
+
 llvm::cl::opt<std::string> IndexPath("index-path",
                                      llvm::cl::desc("Path to the index"),
                                      llvm::cl::Positional, llvm::cl::Required);
@@ -252,6 +256,44 @@
   }
 };
 
+class ExportImpl {
+  llvm::cl::opt<IndexFileFormat> Format{
+      "format", llvm::cl::desc("Format of index export"),
+      llvm::cl::values(
+          clEnumValN(IndexFileFormat::YAML, "yaml",
+                     "human-readable YAML format"),
+          clEnumValN(IndexFileFormat::RIFF, "binary", "binary RIFF format")),
+      llvm::cl::init(IndexFileFormat::YAML)};
+
+public:
+  int dump() {
+    using namespace clang::clangd;
+    // Read input file (as specified in global option)
+    auto Buffer = llvm::MemoryBuffer::getFile(IndexPath);
+    if (!Buffer) {
+      llvm::errs() << llvm::formatv("Can't open {0}", IndexPath) << "\n";
+      return 1;
+    }
+
+    // Auto-detects input format when parsing
+    auto IndexIn = clang::clangd::readIndexFile(Buffer->get()->getBuffer());
+    if (!IndexIn) {
+      llvm::errs() << llvm::toString(IndexIn.takeError()) << "\n";
+      return 1;
+    }
+
+    // Dump output file
+    clang::clangd::IndexFileOut IndexOut(IndexIn.get());
+    IndexOut.Format = Format;
+    llvm::outs() << IndexOut;
+    return 0;
+  }
+};
+
+class ExportCmd : public ExportImpl, public Command {
+  void run() override { dump(); }
+};
+
 struct {
   const char *Name;
   const char *Description;
@@ -262,6 +304,7 @@
      std::make_unique<Lookup>},
     {"refs", "Find references by ID or qualified name",
      std::make_unique<Refs>},
+    {"export", "Export index", std::make_unique<ExportCmd>},
 };
 
 std::unique_ptr<SymbolIndex> openIndex(llvm::StringRef Index) {
@@ -275,10 +318,20 @@
 int main(int argc, const char *argv[]) {
   using namespace clang::clangd;
 
+  // Make Export command option(s) available on command line.
+  // That allows for convenient (piping/redirecting) a dump non-interactively
+  // without passing through REPL.
+  auto NonInteractiveExport = std::make_unique<ExportImpl>();
   llvm::cl::ParseCommandLineOptions(argc, argv, Overview);
-  llvm::cl::ResetCommandLineParser(); // We reuse it for REPL commands.
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
 
+  if (Export)
+    return NonInteractiveExport->dump();
+
+  // Back to normal
+  llvm::cl::ResetCommandLineParser(); // We reuse it for REPL commands.
+  NonInteractiveExport.reset();
+
   std::unique_ptr<SymbolIndex> Index;
   reportTime("Dex build", [&]() {
     Index = openIndex(IndexPath);
Index: clang-tools-extra/clangd/index/YAMLSerialization.cpp
===================================================================
--- clang-tools-extra/clangd/index/YAMLSerialization.cpp
+++ clang-tools-extra/clangd/index/YAMLSerialization.cpp
@@ -41,6 +41,8 @@
   llvm::Optional<clang::clangd::Symbol> Symbol;
   llvm::Optional<RefBundle> Refs;
   llvm::Optional<clang::clangd::Relation> Relation;
+  llvm::Optional<clang::clangd::IncludeGraphNode> Source;
+  llvm::Optional<clang::tooling::CompileCommand> Cmd;
 };
 // A class helps YAML to serialize the 32-bit encoded position (Line&Column),
 // as YAMLIO can't directly map bitfields.
@@ -53,6 +55,9 @@
 namespace llvm {
 namespace yaml {
 
+using clang::clangd::FileDigest;
+using clang::clangd::IncludeGraph;
+using clang::clangd::IncludeGraphNode;
 using clang::clangd::Ref;
 using clang::clangd::RefKind;
 using clang::clangd::Relation;
@@ -65,6 +70,7 @@
 using clang::index::SymbolKind;
 using clang::index::SymbolLanguage;
 using clang::index::SymbolRole;
+using clang::tooling::CompileCommand;
 
 // Helper to (de)serialize the SymbolID. We serialize it as a hex string.
 struct NormalizedSymbolID {
@@ -308,6 +314,76 @@
   }
 };
 
+struct NormalizedSourceFlag {
+  NormalizedSourceFlag(IO &) {}
+  NormalizedSourceFlag(IO &, IncludeGraphNode::SourceFlag O) {
+    Flag = static_cast<uint8_t>(O);
+  }
+
+  IncludeGraphNode::SourceFlag denormalize(IO &) {
+    return static_cast<IncludeGraphNode::SourceFlag>(Flag);
+  }
+
+  uint8_t Flag = 0;
+};
+
+struct NormalizedFileDigest {
+  NormalizedFileDigest(IO &) {}
+  NormalizedFileDigest(IO &, const FileDigest &Digest) {
+    HexString = llvm::toHex(Digest);
+  }
+
+  static FileDigest fromRaw(llvm::StringRef Raw) {
+    FileDigest Digest;
+    assert(Raw.size() == sizeof(Digest));
+    memcpy(Digest.data(), Raw.data(), Raw.size());
+    return Digest;
+  }
+
+  static llvm::Expected<FileDigest> fromStr(llvm::StringRef Str) {
+    const int RawSize = sizeof(FileDigest);
+    if (Str.size() != RawSize * 2)
+      return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                     "Bad ID length");
+    for (char C : Str)
+      if (!llvm::isHexDigit(C))
+        return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                       "Bad hex ID");
+    return fromRaw(llvm::fromHex(Str));
+  }
+
+  FileDigest denormalize(IO &I) {
+    auto Digest = fromStr(HexString);
+    if (!Digest) {
+      I.setError(llvm::toString(Digest.takeError()));
+      return FileDigest();
+    }
+    return *Digest;
+  }
+
+  std::string HexString;
+};
+
+template <> struct MappingTraits<IncludeGraphNode> {
+  static void mapping(IO &IO, IncludeGraphNode &Node) {
+    IO.mapRequired("URI", Node.URI);
+    MappingNormalization<NormalizedSourceFlag, IncludeGraphNode::SourceFlag>
+        NSourceFlag(IO, Node.Flags);
+    IO.mapRequired("Flags", NSourceFlag->Flag);
+    MappingNormalization<NormalizedFileDigest, FileDigest> NDigest(IO,
+                                                                   Node.Digest);
+    IO.mapRequired("Digest", NDigest->HexString);
+    IO.mapRequired("DirectIncludes", Node.DirectIncludes);
+  }
+};
+
+template <> struct MappingTraits<CompileCommand> {
+  static void mapping(IO &IO, CompileCommand &Cmd) {
+    IO.mapRequired("Directory", Cmd.Directory);
+    IO.mapRequired("CommandLine", Cmd.CommandLine);
+  }
+};
+
 template <> struct MappingTraits<VariantEntry> {
   static void mapping(IO &IO, VariantEntry &Variant) {
     if (IO.mapTag("!Symbol", Variant.Symbol.hasValue())) {
@@ -322,6 +398,14 @@
       if (!IO.outputting())
         Variant.Relation.emplace();
       MappingTraits<Relation>::mapping(IO, *Variant.Relation);
+    } else if (IO.mapTag("!Source", Variant.Source.hasValue())) {
+      if (!IO.outputting())
+        Variant.Source.emplace();
+      MappingTraits<IncludeGraphNode>::mapping(IO, *Variant.Source);
+    } else if (IO.mapTag("!Cmd", Variant.Cmd.hasValue())) {
+      if (!IO.outputting())
+        Variant.Cmd.emplace();
+      MappingTraits<CompileCommand>::mapping(IO, *Variant.Cmd);
     }
   }
 };
@@ -351,6 +435,18 @@
       Entry.Relation = R;
       Yout << Entry;
     }
+  if (O.Sources) {
+    for (const auto &Source : *O.Sources) {
+      VariantEntry Entry;
+      Entry.Source = Source.getValue();
+      Yout << Entry;
+    }
+  }
+  if (O.Cmd) {
+    VariantEntry Entry;
+    Entry.Cmd = *O.Cmd;
+    Yout << Entry;
+  }
 }
 
 llvm::Expected<IndexFileIn> readYAML(llvm::StringRef Data) {
@@ -361,6 +457,8 @@
       Arena; // store the underlying data of Position::FileURI.
   llvm::UniqueStringSaver Strings(Arena);
   llvm::yaml::Input Yin(Data, &Strings);
+  IncludeGraph Sources;
+  llvm::Optional<tooling::CompileCommand> Cmd;
   while (Yin.setCurrentDocument()) {
     llvm::yaml::EmptyContext Ctx;
     VariantEntry Variant;
@@ -375,6 +473,17 @@
         Refs.insert(Variant.Refs->first, Ref);
     if (Variant.Relation)
       Relations.insert(*Variant.Relation);
+    if (Variant.Source) {
+      auto &IGN = Variant.Source.getValue();
+      auto Entry = Sources.try_emplace(IGN.URI).first;
+      Entry->getValue() = std::move(IGN);
+      // Fixup refs to refer to map keys which will live on
+      Entry->getValue().URI = Entry->getKey();
+      for (auto &Include : Entry->getValue().DirectIncludes)
+        Include = Sources.try_emplace(Include).first->getKey();
+    }
+    if (Variant.Cmd)
+      Cmd = *Variant.Cmd;
     Yin.nextDocument();
   }
 
@@ -382,6 +491,9 @@
   Result.Symbols.emplace(std::move(Symbols).build());
   Result.Refs.emplace(std::move(Refs).build());
   Result.Relations.emplace(std::move(Relations).build());
+  if (Sources.size())
+    Result.Sources = std::move(Sources);
+  Result.Cmd = std::move(Cmd);
   return std::move(Result);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to