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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits