usaxena95 updated this revision to Diff 315839.
usaxena95 added a comment.

Documentation change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D94424

Files:
  clang-tools-extra/clangd/TUScheduler.cpp
  clang-tools-extra/clangd/TUScheduler.h
  clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp

Index: clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -14,6 +14,7 @@
 #include "Preamble.h"
 #include "TUScheduler.h"
 #include "TestFS.h"
+#include "TestIndex.h"
 #include "support/Cancellation.h"
 #include "support/Context.h"
 #include "support/Path.h"
@@ -42,12 +43,14 @@
 namespace clangd {
 namespace {
 
+using ::testing::_;
 using ::testing::AnyOf;
 using ::testing::Each;
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::Field;
 using ::testing::IsEmpty;
+using ::testing::Pair;
 using ::testing::Pointee;
 using ::testing::SizeIs;
 using ::testing::UnorderedElementsAre;
@@ -696,6 +699,70 @@
       });
 }
 
+TEST_F(TUSchedulerTests, ASTSignals) {
+  TUScheduler S(CDB, optsForTest());
+  auto Foo = testPath("foo.cpp");
+  auto Header = testPath("foo.h");
+
+  FS.Files[Header] = R"cpp(
+  #define ADD(x, y, z) (x + y + z)
+  namespace tar {  // A related namespace.
+  int kConst = 5;
+  int foo();
+  void bar();
+  class X {
+    public: int Y;
+  };
+  } // namespace bar
+  )cpp";
+  const char *Contents = R"cpp(
+  #include "foo.h"
+  namespace ns1 {
+  namespace ns2 {
+    void func() {
+      tar::X a;
+      tar::X b;
+      a.Y = 1;
+      b.Y = ADD(tar::kConst, a.Y, tar::foo());
+    }
+  } // namespace ns2
+  } // namespace ns1
+  )cpp";
+  // Update the file which results in an empty preamble.
+  S.update(Foo, getInputs(Foo, Contents), WantDiagnostics::Yes);
+  // Wait for the preamble is being built.
+  ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
+  Notification TaskRun;
+  S.runWithPreamble(
+      "ASTSignals", Foo, TUScheduler::Stale,
+      [&](Expected<InputsAndPreamble> IP) {
+        ASSERT_FALSE(!IP);
+        std::vector<std::pair<StringRef, int>> NS;
+        for (const auto &P : IP->Signals->RelatedNamespaces)
+          NS.emplace_back(P.getKey(), P.getValue());
+        EXPECT_THAT(NS, UnorderedElementsAre(Pair("ns1::", 1),
+                                             Pair("ns1::ns2::", 1),
+                                             Pair("tar::", 4)));
+
+        std::vector<std::pair<SymbolID, int>> Sym;
+        for (const auto &P : IP->Signals->Symbols)
+          Sym.emplace_back(P.getFirst(), P.getSecond());
+        EXPECT_THAT(
+            Sym,
+            UnorderedElementsAre(
+                Pair(ns("tar").ID, 4), Pair(ns("ns1").ID, 1),
+                Pair(ns("ns1::ns2").ID, 1), Pair(func("ns1::ns2::func").ID, 1),
+                Pair(cls("tar::X").ID, 2), Pair(var("tar::kConst").ID, 1),
+                Pair(func("tar::foo").ID, 1),
+                Pair(sym("Y", index::SymbolKind::Variable, "@N@tar@S@X@FI@\\0")
+                         .ID,
+                     3),
+                Pair(_ /*a*/, 3), Pair(_ /*b*/, 2)));
+        TaskRun.notify();
+      });
+  TaskRun.wait();
+}
+
 TEST_F(TUSchedulerTests, RunWaitsForPreamble) {
   // Testing strategy: we update the file and schedule a few preamble reads at
   // the same time. All reads should get the same non-null preamble.
Index: clang-tools-extra/clangd/TUScheduler.h
===================================================================
--- clang-tools-extra/clangd/TUScheduler.h
+++ clang-tools-extra/clangd/TUScheduler.h
@@ -13,10 +13,12 @@
 #include "Diagnostics.h"
 #include "GlobalCompilationDatabase.h"
 #include "index/CanonicalIncludes.h"
+#include "index/SymbolID.h"
 #include "support/Function.h"
 #include "support/MemoryTree.h"
 #include "support/Path.h"
 #include "support/Threading.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringMap.h"
@@ -33,6 +35,14 @@
 /// synchronously).
 unsigned getDefaultAsyncThreadsCount();
 
+/// Signals derived from a valid AST of a file.
+struct ASTSignals {
+  /// Number of occurrences of each Symbol present in the file.
+  llvm::DenseMap<SymbolID, unsigned> Symbols;
+  /// Number of Symbols belonging to each namespace present in the file.
+  llvm::StringMap<unsigned> RelatedNamespaces;
+};
+
 struct InputsAndAST {
   const ParseInputs &Inputs;
   ParsedAST &AST;
@@ -43,6 +53,8 @@
   const tooling::CompileCommand &Command;
   // This can be nullptr if no preamble is available.
   const PreambleData *Preamble;
+  // This can be nullptr if no ASTSignals are available.
+  const ASTSignals *Signals;
 };
 
 /// Determines whether diagnostics should be generated for a file snapshot.
Index: clang-tools-extra/clangd/TUScheduler.cpp
===================================================================
--- clang-tools-extra/clangd/TUScheduler.cpp
+++ clang-tools-extra/clangd/TUScheduler.cpp
@@ -47,8 +47,10 @@
 // requests will receive latest build preamble, which might possibly be stale.
 
 #include "TUScheduler.h"
+#include "AST.h"
 #include "Compiler.h"
 #include "Diagnostics.h"
+#include "FindTarget.h"
 #include "GlobalCompilationDatabase.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
@@ -60,6 +62,7 @@
 #include "support/Path.h"
 #include "support/Threading.h"
 #include "support/Trace.h"
+#include "clang/AST/Decl.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/FunctionExtras.h"
@@ -415,6 +418,10 @@
   /// getPossiblyStalePreamble() can be null even after this function returns.
   void waitForFirstPreamble() const;
 
+  std::shared_ptr<const ASTSignals> getASTSignals() const;
+
+  void updateASTSignals(ParsedAST &AST);
+
   TUScheduler::FileStats stats() const;
   bool isASTCached() const;
 
@@ -499,6 +506,7 @@
   /// Signalled whenever a new request has been scheduled or processing of a
   /// request has completed.
   mutable std::condition_variable RequestsCV;
+  std::shared_ptr<const ASTSignals> LatestASTSignals; /* GUARDED_BY(Mutex) */
   /// Latest build preamble for current TU.
   /// None means no builds yet, null means there was an error while building.
   /// Only written by ASTWorker's thread.
@@ -830,6 +838,35 @@
   RequestsCV.notify_all();
 }
 
+void ASTWorker::updateASTSignals(ParsedAST &AST) {
+  ASTSignals Signals;
+  const SourceManager &SM = AST.getSourceManager();
+  findExplicitReferences(
+      AST.getASTContext(), [&Signals, &SM](ReferenceLoc Ref) {
+        for (const NamedDecl *ND : Ref.Targets) {
+          if (!isInsideMainFile(Ref.NameLoc, SM))
+            continue;
+          if (auto ID = getSymbolID(ND))
+            Signals.Symbols[ID] += 1;
+          // FIXME: Do not count the primary namespace as a related namespace.
+          // Eg. clang::clangd:: for this file.
+          if (const auto *NSD = dyn_cast<NamespaceDecl>(ND->getDeclContext())) {
+            std::string NS;
+            llvm::raw_string_ostream OS(NS);
+            NSD->printQualifiedName(OS);
+            std::string RelatedNS = OS.str();
+            if (!RelatedNS.empty()) {
+              Signals.RelatedNamespaces[RelatedNS + "::"] += 1;
+            }
+          }
+        }
+      });
+  // Existing readers of ASTSignals will have their copy preserved until the
+  // read is completed. The last reader deletes the old ASTSignals.
+  std::lock_guard<std::mutex> Lock(Mutex);
+  LatestASTSignals = std::make_shared<ASTSignals>(std::move(Signals));
+}
+
 void ASTWorker::generateDiagnostics(
     std::unique_ptr<CompilerInvocation> Invocation, ParseInputs Inputs,
     std::vector<Diag> CIDiags) {
@@ -908,6 +945,7 @@
   if (*AST) {
     trace::Span Span("Running main AST callback");
     Callbacks.onMainAST(FileName, **AST, RunPublish);
+    updateASTSignals(**AST);
   } else {
     // Failed to build the AST, at least report diagnostics from the
     // command line if there were any.
@@ -931,6 +969,11 @@
   return LatestPreamble ? *LatestPreamble : nullptr;
 }
 
+std::shared_ptr<const ASTSignals> ASTWorker::getASTSignals() const {
+  std::lock_guard<std::mutex> Lock(Mutex);
+  return LatestASTSignals;
+}
+
 void ASTWorker::waitForFirstPreamble() const {
   std::unique_lock<std::mutex> Lock(Mutex);
   PreambleCV.wait(Lock, [this] { return LatestPreamble.hasValue() || Done; });
@@ -1366,36 +1409,39 @@
     SPAN_ATTACH(Tracer, "file", File);
     std::shared_ptr<const PreambleData> Preamble =
         It->second->Worker->getPossiblyStalePreamble();
+    std::shared_ptr<const ASTSignals> Signals =
+        It->second->Worker->getASTSignals();
     WithContext WithProvidedContext(Opts.ContextProvider(File));
     Action(InputsAndPreamble{It->second->Contents,
                              It->second->Worker->getCurrentCompileCommand(),
-                             Preamble.get()});
+                             Preamble.get(), Signals.get()});
     return;
   }
 
   std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
-  auto Task =
-      [Worker, Consistency, Name = Name.str(), File = File.str(),
-       Contents = It->second->Contents,
-       Command = Worker->getCurrentCompileCommand(),
-       Ctx = Context::current().derive(kFileBeingProcessed, std::string(File)),
-       Action = std::move(Action), this]() mutable {
-        std::shared_ptr<const PreambleData> Preamble;
-        if (Consistency == PreambleConsistency::Stale) {
-          // Wait until the preamble is built for the first time, if preamble
-          // is required. This avoids extra work of processing the preamble
-          // headers in parallel multiple times.
-          Worker->waitForFirstPreamble();
-        }
-        Preamble = Worker->getPossiblyStalePreamble();
-
-        std::lock_guard<Semaphore> BarrierLock(Barrier);
-        WithContext Guard(std::move(Ctx));
-        trace::Span Tracer(Name);
-        SPAN_ATTACH(Tracer, "file", File);
-        WithContext WithProvidedContext(Opts.ContextProvider(File));
-        Action(InputsAndPreamble{Contents, Command, Preamble.get()});
-      };
+  auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(),
+               Contents = It->second->Contents,
+               Command = Worker->getCurrentCompileCommand(),
+               Ctx = Context::current().derive(kFileBeingProcessed,
+                                               std::string(File)),
+               Action = std::move(Action), this]() mutable {
+    std::shared_ptr<const PreambleData> Preamble;
+    if (Consistency == PreambleConsistency::Stale) {
+      // Wait until the preamble is built for the first time, if preamble
+      // is required. This avoids extra work of processing the preamble
+      // headers in parallel multiple times.
+      Worker->waitForFirstPreamble();
+    }
+    Preamble = Worker->getPossiblyStalePreamble();
+    std::shared_ptr<const ASTSignals> Signals = Worker->getASTSignals();
+
+    std::lock_guard<Semaphore> BarrierLock(Barrier);
+    WithContext Guard(std::move(Ctx));
+    trace::Span Tracer(Name);
+    SPAN_ATTACH(Tracer, "file", File);
+    WithContext WithProvidedContext(Opts.ContextProvider(File));
+    Action(InputsAndPreamble{Contents, Command, Preamble.get(), Signals.get()});
+  };
 
   PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
                           std::move(Task));
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to