sammccall created this revision.
Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman, jkorous, 
MaskRay, ilya-biryukov.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75735

Files:
  clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
  clang-tools-extra/clangd/GlobalCompilationDatabase.h

Index: clang-tools-extra/clangd/GlobalCompilationDatabase.h
===================================================================
--- clang-tools-extra/clangd/GlobalCompilationDatabase.h
+++ clang-tools-extra/clangd/GlobalCompilationDatabase.h
@@ -86,6 +86,7 @@
     std::string Path; // Not case-folded.
     std::unique_ptr<clang::tooling::CompilationDatabase> CDB = nullptr;
     bool SentBroadcast = false;
+    bool Diagnosed = false;
   };
   CachedCDB &getCDBInDirLocked(PathRef File) const;
 
@@ -93,6 +94,8 @@
     PathRef FileName;
     // Whether this lookup should trigger discovery of the CDB found.
     bool ShouldBroadcast = false;
+    // If no CDB is found, attempt diagnosis of the directories searched.
+    bool ShouldDiagnose = false;
   };
   struct CDBLookupResult {
     tooling::CompilationDatabase *CDB = nullptr;
@@ -100,6 +103,9 @@
   };
   llvm::Optional<CDBLookupResult> lookupCDB(CDBLookupRequest Request) const;
 
+  // Examines a directory where a CDB was not found, to suggest fixes.
+  bool diagnose(llvm::StringRef Path) const;
+
   // Performs broadcast on governed files.
   void broadcastCDB(CDBLookupResult Res) const;
 
Index: clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
===================================================================
--- clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
+++ clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
@@ -16,6 +16,7 @@
 #include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
@@ -71,6 +72,7 @@
   CDBLookupRequest Req;
   Req.FileName = File;
   Req.ShouldBroadcast = true;
+  Req.ShouldDiagnose = true;
 
   auto Res = lookupCDB(Req);
   if (!Res) {
@@ -129,10 +131,18 @@
     CDBLookupRequest Request) const {
   assert(llvm::sys::path::is_absolute(Request.FileName) &&
          "path must be absolute");
+  std::string CanonicalName = removeDots(Request.FileName);
 
   bool ShouldBroadcast = false;
   CDBLookupResult Result;
 
+  llvm::SmallVector<PathRef, 8> DiagnoseDirs;
+  auto DiagnoseBeforeReturn = llvm::make_scope_exit([&]{
+    for (PathRef Dir : DiagnoseDirs)
+      if (diagnose(Dir))
+        break;
+  });
+
   {
     std::lock_guard<std::mutex> Lock(Mutex);
     CachedCDB *Entry = nullptr;
@@ -142,16 +152,22 @@
       // Traverse the canonical version to prevent false positives. i.e.:
       // src/build/../a.cc can detect a CDB in /src/build if not canonicalized.
       // FIXME(sammccall): this loop is hot, use a union-find-like structure.
-      actOnAllParentDirectories(removeDots(Request.FileName),
-                                [&](PathRef Path) {
-                                  Entry = &getCDBInDirLocked(Path);
-                                  return Entry->CDB != nullptr;
-                                });
+      actOnAllParentDirectories(CanonicalName, [&](PathRef Path) {
+        Entry = &getCDBInDirLocked(Path);
+        if (Request.ShouldDiagnose && !Entry->CDB && !Entry->Diagnosed) {
+          Entry->Diagnosed = true;
+          DiagnoseDirs.push_back(Path);
+        }
+        return Entry->CDB != nullptr;
+      });
     }
 
     if (!Entry || !Entry->CDB)
       return llvm::None;
 
+    // Don't diagnose if we found a CDB in the end.
+    DiagnoseDirs.clear();
+
     // Mark CDB as broadcasted to make sure discovery is performed once.
     if (Request.ShouldBroadcast && !Entry->SentBroadcast) {
       Entry->SentBroadcast = true;
@@ -231,6 +247,29 @@
   return Res->PI;
 }
 
+bool DirectoryBasedGlobalCompilationDatabase::diagnose(PathRef Dir) const {
+  vlog("Diagnosing missing CDB in {0}", Dir);
+
+  namespace fs = llvm::sys::fs;
+  namespace path = llvm::sys::path;
+  llvm::SmallString<256> Path = Dir;
+  auto Exists = [&](llvm::StringRef Filename){
+    auto Size = Path.size();
+    path::append(Path, Filename);
+    bool Ret = fs::exists(Path);
+    Path.resize(Size);
+    return Ret;
+  };
+  if (Exists("CMakeLists.txt")) {
+    Path.resize(path::parent_path(Path).size());
+    if (!Exists("CMakeLists.txt")) {
+      elog("Missing compile_commands.json in {0}", Dir);
+      return true;
+    }
+  }
+  return false;
+}
+
 OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
                        std::vector<std::string> FallbackFlags,
                        tooling::ArgumentsAdjuster Adjuster)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to