[clang-tools-extra] [clangd] [C++20] [Modules] Introduce initial support for C++20 Modules (PR #66462)
kadir çetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 13 06:07:03 PDT 2024
================
@@ -0,0 +1,199 @@
+//===------------------ ProjectModules.h -------------------------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProjectModules.h"
+
+#include "support/Logger.h"
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+
+namespace clang::clangd {
+namespace {
+/// A scanner to query the dependency information for C++20 Modules.
+///
+/// The scanner can scan a single file with `scan(PathRef)` member function
+/// or scan the whole project with `globalScan(vector<PathRef>)` member
+/// function. See the comments of `globalScan` to see the details.
+///
+/// The ModuleDependencyScanner can get the directly required module names for a
+/// specific source file. Also the ModuleDependencyScanner can get the source
+/// file declaring the primary module interface for a specific module name.
+///
+/// IMPORTANT NOTE: we assume that every module unit is only declared once in a
+/// source file in the project. But the assumption is not strictly true even
+/// besides the invalid projects. The language specification requires that every
+/// module unit should be unique in a valid program. But a project can contain
+/// multiple programs. Then it is valid that we can have multiple source files
+/// declaring the same module in a project as long as these source files don't
+/// interfere with each other.
+class ModuleDependencyScanner {
+public:
+ ModuleDependencyScanner(
+ std::shared_ptr<const clang::tooling::CompilationDatabase> CDB,
+ const ThreadsafeFS &TFS)
+ : CDB(CDB), TFS(TFS),
+ Service(tooling::dependencies::ScanningMode::CanonicalPreprocessing,
+ tooling::dependencies::ScanningOutputFormat::P1689) {}
+
+ /// The scanned modules dependency information for a specific source file.
+ struct ModuleDependencyInfo {
+ /// The name of the module if the file is a module unit.
+ std::optional<std::string> ModuleName;
+ /// A list of names for the modules that the file directly depends.
+ std::vector<std::string> RequiredModules;
+ };
+
+ /// Scanning the single file specified by \param FilePath.
+ std::optional<ModuleDependencyInfo> scan(PathRef FilePath);
+
+ /// Scanning every source file in the current project to get the
+ /// <module-name> to <module-unit-source> map.
+ /// TODO: We should find an efficient method to get the <module-name>
+ /// to <module-unit-source> map. We can make it either by providing
+ /// a global module dependency scanner to monitor every file. Or we
+ /// can simply require the build systems (or even the end users)
+ /// to provide the map.
+ void globalScan();
+
+ /// Get the source file from the module name. Note that the language
+ /// guarantees all the module names are unique in a valid program.
+ /// This function should only be called after globalScan.
+ ///
+ /// TODO: We should handle the case that there are multiple source files
+ /// declaring the same module.
+ PathRef getSourceForModuleName(llvm::StringRef ModuleName) const;
+
+ /// Return the direct required modules. Indirect required modules are not
+ /// included.
+ std::vector<std::string> getRequiredModules(PathRef File);
+
+private:
+ std::shared_ptr<const clang::tooling::CompilationDatabase> CDB;
+ const ThreadsafeFS &TFS;
+
+ // Whether the scanner has scanned the project globally.
+ bool GlobalScanned = false;
+
+ clang::tooling::dependencies::DependencyScanningService Service;
+
+ // TODO: Add a scanning cache.
+
+ // Map module name to source file path.
+ llvm::StringMap<std::string> ModuleNameToSource;
+};
+
+std::optional<ModuleDependencyScanner::ModuleDependencyInfo>
+ModuleDependencyScanner::scan(PathRef FilePath) {
+ auto Candidates = CDB->getCompileCommands(FilePath);
+ if (Candidates.empty())
+ return std::nullopt;
+
+ // Choose the first candidates as the compile commands as the file.
+ // Following the same logic with
+ // DirectoryBasedGlobalCompilationDatabase::getCompileCommand.
+ tooling::CompileCommand Cmd = std::move(Candidates.front());
----------------
kadircet wrote:
can you also inject `-resource-dir` via `CompilerInvocation::GetResourcesPath` ? i think it's worth calling it once during constructor of `ModuleDependencyScanner` and storing as a member.
https://github.com/llvm/llvm-project/pull/66462
More information about the cfe-commits
mailing list