https://github.com/Decodetalkers updated 
https://github.com/llvm/llvm-project/pull/200001

>From 857ae1f7e487d49aa1169c7e4da0b7934df9e9a1 Mon Sep 17 00:00:00 2001
From: ShootingStarDragons <[email protected]>
Date: Thu, 28 May 2026 00:16:49 +0900
Subject: [PATCH] feat: add gcc scan rules

this will make completion will work after using gcc to compile the whole
project
---
 clang-tools-extra/clangd/ProjectModules.cpp | 210 +++++++++++++++++++-
 1 file changed, 208 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clangd/ProjectModules.cpp 
b/clang-tools-extra/clangd/ProjectModules.cpp
index d3727171bff12..4e856999a982a 100644
--- a/clang-tools-extra/clangd/ProjectModules.cpp
+++ b/clang-tools-extra/clangd/ProjectModules.cpp
@@ -12,11 +12,16 @@
 #include "clang/DependencyScanning/DependencyScanningService.h"
 #include "clang/Tooling/DependencyScanningTool.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Regex.h"
 #include "llvm/TargetParser/Host.h"
 
 namespace clang::clangd {
@@ -171,6 +176,8 @@ class ModuleDependencyScanner {
   /// Scanning the single file specified by \param FilePath.
   std::optional<ModuleDependencyInfo>
   scan(PathRef FilePath, const ProjectModules::CommandMangler &Mangler);
+  std::optional<ModuleDependencyInfo> scanGcc(tooling::CompileCommand Cmd,
+                                              PathRef MapFile);
 
   /// Scanning every source file in the current project to get the
   /// <module-name> to <module-unit-source> map.
@@ -209,15 +216,214 @@ class ModuleDependencyScanner {
   llvm::StringMap<std::string> ModuleNameToSource;
 };
 
+namespace gcc {
+static const llvm::Regex ImportRegex =
+    llvm::Regex("import: ([^ ]*) ([^ ]*.gcm)");
+static const llvm::Regex ModuleRegex = llvm::Regex("module: ([^ ]*)");
+static const llvm::Regex SourceRegex = llvm::Regex("source: ([^ ]*)");
+static const llvm::Regex CwdRegex = llvm::Regex("cwd: ([^ ]*)");
+
+static const llvm::Regex ModmapRegex = llvm::Regex("([^ ^$^\n]*) ([^ ]*.gcm)");
+
+struct RoadMapInfo {
+  std::string Name;
+  std::string Path;
+};
+
+struct ReadElfInfo {
+  std::string Source;
+  std::string ModuleName;
+  std::vector<std::string> Imports;
+
+  static std::optional<ReadElfInfo> get(llvm::StringRef Source);
+};
+
+std::optional<ReadElfInfo> ReadElfInfo::get(llvm::StringRef Content) {
+  std::vector<std::string> Imports = {};
+  std::string Source;
+  std::string ModuleName;
+  std::string Cwd;
+  {
+    llvm::StringRef CwdText = Content;
+    llvm::SmallVector<llvm::StringRef, 1> Matches;
+    std::string Error;
+    if (!CwdRegex.match(CwdText, &Matches, &Error)) {
+      return std::nullopt;
+    }
+    Cwd = Matches[1].trim().str();
+  }
+  {
+    llvm::StringRef ImportText = Content;
+    while (!ImportText.empty()) {
+      llvm::SmallVector<llvm::StringRef, 2> Matches;
+      std::string Error;
+      if (!ImportRegex.match(ImportText, &Matches, &Error)) {
+        break;
+      }
+
+      auto ImportModule = Matches[1].trim().str();
+      Imports.push_back(ImportModule);
+      size_t Pos = ImportText.find(Matches[0]);
+      ImportText = ImportText.drop_front(Pos + Matches[0].size());
+    }
+  }
+
+  {
+    llvm::StringRef SourceText = Content;
+    llvm::SmallVector<llvm::StringRef, 1> Matches;
+    std::string Error;
+    if (!SourceRegex.match(SourceText, &Matches, &Error)) {
+      return std::nullopt;
+    }
+
+    llvm::StringRef SourcePa = Matches[1].trim();
+    if (llvm::sys::path::is_absolute(SourcePa)) {
+      Source = SourcePa.str();
+
+    } else {
+      llvm::StringRef PathRef = Cwd;
+      llvm::SmallString<128> CurrentPath = PathRef;
+      llvm::sys::path::append(CurrentPath, SourcePa);
+      Source = CurrentPath.str();
+    }
+  }
+  {
+    llvm::StringRef ModuleText = Content;
+    llvm::SmallVector<llvm::StringRef, 1> Matches;
+    std::string Error;
+    if (!ModuleRegex.match(ModuleText, &Matches, &Error)) {
+      return std::nullopt;
+    }
+    ModuleName = Matches[1].trim().str();
+  }
+  return ReadElfInfo{Source, ModuleName, Imports};
+}
+
+static bool fitGccModulePath(std::string Cmd) {
+  llvm::StringRef Arg = Cmd;
+  return Arg.starts_with("-fmodule-mapper=") && Arg.ends_with("modmap");
+}
+
+std::optional<ReadElfInfo> scanGcm(llvm::StringRef GCMPath) {
+  llvm::SmallString<64> OutputFile;
+  llvm::sys::fs::createTemporaryFile("readref", "", OutputFile);
+  llvm::FileRemover OutRemover(OutputFile);
+  std::optional<llvm::StringRef> Redirects[3] = {
+      /*Stdin*/ {""}, {OutputFile.str()}, {}};
+  std::string ErrorMessage;
+  auto Readelf = llvm::sys::findProgramByName("readelf");
+  if (!Readelf) {
+    return std::nullopt;
+  }
+  int Ret = llvm::sys::ExecuteAndWait(
+      *Readelf, {"readelf", "-p.gnu.c++.README", GCMPath}, std::nullopt,
+      Redirects, 10, 0, &ErrorMessage);
+  if (Ret != 0) {
+    return std::nullopt;
+  }
+  auto Buf = llvm::MemoryBuffer::getFile(OutputFile);
+
+  if (!Buf) {
+    return std::nullopt;
+  }
+  llvm::StringRef Path = Buf->get()->getBuffer().trim();
+  if (Path.empty()) {
+    return std::nullopt;
+  }
+  llvm::StringRef Text = Path;
+  return ReadElfInfo::get(Text);
+}
+
+struct ModuleResult {
+  std::optional<std::string> ModuleName;
+  std::vector<std::string> RequiredModules;
+};
+
+} // namespace gcc
+std::optional<ModuleDependencyScanner::ModuleDependencyInfo>
+ModuleDependencyScanner::scanGcc(tooling::CompileCommand Cmd, PathRef MapFile) 
{
+  using namespace gcc;
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      llvm::MemoryBuffer::getFile(MapFile);
+  if (std::error_code Result = File.getError()) {
+    elog("File Not Found, {0}", MapFile);
+    return std::nullopt;
+  }
+  auto Content = (*File)->getBuffer();
+  llvm::StringRef CurrentDir = Cmd.Directory;
+  std::vector<gcc::RoadMapInfo> RoadMapInfos = {};
+  llvm::StringRef Text = Content;
+  while (!Text.empty()) {
+    llvm::SmallVector<llvm::StringRef, 2> Matches;
+    std::string Error;
+    if (!gcc::ModmapRegex.match(Text, &Matches, &Error)) {
+      break;
+    }
+
+    auto Name = Matches[1].trim().str();
+
+    auto ReadPath = Matches[2].trim();
+    std::string Path;
+    if (llvm::sys::path::is_absolute(ReadPath)) {
+      Path = ReadPath.str();
+    } else {
+      llvm::SmallString<128> CurrentPath = CurrentDir;
+      llvm::sys::path::append(CurrentPath, ReadPath);
+      Path = CurrentPath.str();
+    }
+    RoadMapInfos.push_back(RoadMapInfo{Name, Path});
+
+    size_t Pos = Text.find(Matches[0]);
+    Text = Text.drop_front(Pos + Matches[0].size());
+  }
+  elog("fileName: {0} ", Cmd.Filename);
+  ModuleDependencyScanner::ModuleDependencyInfo Result;
+  for (const RoadMapInfo &Info : RoadMapInfos) {
+    auto GCMInfo = scanGcm(Info.Path);
+    if (!GCMInfo) {
+      continue;
+    }
+
+    ModuleNameToSource.try_emplace(GCMInfo->ModuleName, GCMInfo->Source);
+    elog("Info {0}, CurrentPath: {1}, source: {2}", Info.Name, Cmd.Filename,
+         GCMInfo->Source);
+    if (GCMInfo->Source == Cmd.Filename) {
+      elog("Hello? {0}, {1}", GCMInfo->Source, GCMInfo->ModuleName);
+      Result.ModuleName = GCMInfo->ModuleName;
+    }
+    Result.RequiredModules.push_back(Info.Name);
+  }
+  return Result;
+}
+
+// I need to read deeper here
+// problem is here
+// We can read the data from modmap
+// But we cannot get the the required module
+// it can be itself
 std::optional<ModuleDependencyScanner::ModuleDependencyInfo>
 ModuleDependencyScanner::scan(PathRef FilePath,
                               const ProjectModules::CommandMangler &Mangler) {
+  // FIXME: why it always become clang++? or it it the problem here?
   auto Cmd = getCompileCommandForFile(*CDB, FilePath, Mangler);
-  if (!Cmd)
-    return std::nullopt;
+
+  elog("filepath: {0}, dir: {1}", FilePath, Cmd->Directory);
 
   using namespace clang::tooling;
 
+  auto CmdLine = Cmd->CommandLine;
+  auto It = llvm::find_if(CmdLine, gcc::fitGccModulePath);
+  if (It != CmdLine.end()) {
+    llvm::StringRef Module = *It;
+    // NOTE: we can use it to check the module Name, and its name
+    if (Module.consume_front("-fmodule-mapper=")) {
+      elog("Enter: filepath: {0}, dir: {1}", FilePath, Cmd->Directory);
+      llvm::StringRef Cwd = Cmd->Directory;
+      llvm::SmallString<128> MapFile = Cwd;
+      llvm::sys::path::append(MapFile, Module);
+      return scanGcc(*Cmd, MapFile);
+    }
+  }
   DependencyScanningTool ScanningTool(Service);
 
   std::string S;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to