Skip to content

[clangd] [Modules] Use ASTReader directly in IsModuleFileUpToDate #113879

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 31, 2024

Conversation

ChuanqiXu9
Copy link
Member

@ChuanqiXu9 ChuanqiXu9 commented Oct 28, 2024

@kadircet mentioned in 448d8fa#diff-fb3ba8a781117ff04736f951a274812cb7ad1678f9d71d4d91870b711ab45da0L285 that:

this is definitely a functional change, clangd is used in environments that solely relies on VFS, and doesn't depend on ASTUnit at all.

right now this is both introducing a dependency on ASTUnit, and making all the logical IO physical instead. can you instead use the regular compiler utilities in clangd, and get the astreader from CompilerInstance directly, which is VFS-aware, and doesn't depend on ASTUnit ?

This tries to resolve the problem by creating ASTReader directly and use VFS to create the FileManager.


// Original comments

But I like ASTUnit since I feel it is a better abstract here. For compiler instance, we need to provide the compiler invocation. But for the purpose here. we're just trying to open the BMI file to verify if the source files are out of date or not. We don't need compiler invocation here completely. So I prefer ASTUnit here especially clangd already depends on clangFrontend already so I feel like I didn't introduce a new dependency.

Then I added the VFS argument to ASTUnit to address the Virtual/Physical FS problem.

@llvmbot
Copy link
Member

llvmbot commented Oct 28, 2024

@llvm/pr-subscribers-clangd

@llvm/pr-subscribers-clang-tools-extra

Author: Chuanqi Xu (ChuanqiXu9)

Changes

@kadircet mentioned in 448d8fa#diff-fb3ba8a781117ff04736f951a274812cb7ad1678f9d71d4d91870b711ab45da0L285 that:

> this is definitely a functional change, clangd is used in environments that solely relies on VFS, and doesn't depend on ASTUnit at all.

> right now this is both introducing a dependency on ASTUnit, and making all the logical IO physical instead. can you instead use the regular compiler utilities in clangd, and get the astreader from CompilerInstance directly, which is VFS-aware, and doesn't depend on ASTUnit ?

But I like ASTUnit since I feel it is a better abstract here. For compiler instance, we need to provide the compiler invocation. But for the purpose here. we're just trying to open the BMI file to verify if the source files are out of date or not. We don't need compiler invocation here completely. So I prefer ASTUnit here especially clangd already depends on clangFrontend already so I feel like I didn't introduce a new dependency.

Then I added the VFS argument to ASTUnit to address the Virtual/Physical FS problem.


Full diff: https://github.com/llvm/llvm-project/pull/113879.diff

1 Files Affected:

  • (modified) clang-tools-extra/clangd/ModulesBuilder.cpp (+16-10)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index 1eeff468ef1236..25f9ab6631fca7 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -127,10 +127,10 @@ struct ModuleFile {
   std::string ModuleFilePath;
 };
 
-bool IsModuleFileUpToDate(
-    PathRef ModuleFilePath,
-    const PrerequisiteModules &RequisiteModules) {
-IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+bool IsModuleFileUpToDate(PathRef ModuleFilePath,
+                          const PrerequisiteModules &RequisiteModules,
+                          llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(new DiagnosticOptions());
 
   auto HSOpts = std::make_shared<HeaderSearchOptions>();
@@ -141,7 +141,11 @@ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
   PCHContainerOperations PCHOperations;
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
       ModuleFilePath.str(), PCHOperations.getRawReader(), ASTUnit::LoadASTOnly,
-      Diags, FileSystemOptions(), std::move(HSOpts));
+      Diags, FileSystemOptions(), std::move(HSOpts),
+      /*LangOpts=*/nullptr, /*OnlyLocalDecls=*/false,
+      /*CaptureDiagnostics=*/CaptureDiagsKind::None,
+      /*AllowASTWithCompilerErrors=*/false, /*UserFilesAreVolatile=*/false,
+      VFS);
 
   if (!Unit)
     return false;
@@ -167,10 +171,12 @@ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
 
 bool IsModuleFilesUpToDate(
     llvm::SmallVector<PathRef> ModuleFilePaths,
-    const PrerequisiteModules &RequisiteModules) {
-  return llvm::all_of(ModuleFilePaths, [&RequisiteModules](auto ModuleFilePath) {
-    return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules);
-  });
+    const PrerequisiteModules &RequisiteModules,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+  return llvm::all_of(
+      ModuleFilePaths, [&RequisiteModules, VFS](auto ModuleFilePath) {
+        return IsModuleFileUpToDate(ModuleFilePath, RequisiteModules, VFS);
+      });
 }
 
 // StandalonePrerequisiteModules - stands for PrerequisiteModules for which all
@@ -347,7 +353,7 @@ bool StandalonePrerequisiteModules::canReuse(
   SmallVector<StringRef> BMIPaths;
   for (auto &MF : RequiredModules)
     BMIPaths.push_back(MF.ModuleFilePath);
-  return IsModuleFilesUpToDate(BMIPaths, *this);
+  return IsModuleFilesUpToDate(BMIPaths, *this, VFS);
 }
 
 } // namespace clangd

@kadircet
Copy link
Member

So I prefer ASTUnit here especially clangd already depends on clangFrontend already so I feel like I didn't introduce a new dependency.

It isn't at all about having this dependency in terms of "build graph", but rather about mental complexity and maintenance burden of that.

Clangd already has its own primitives for dealing with preambles, keeping ASTcontexts alive and even handling modules (and soon also module caches!). ASTUnit has its own way of doing all of these. So if we introduced any semantic dependency here, everytime someone is chaging those core primitives in clangd will need to think about how all of these going to interact with each other.

Moreover, if this was sent with a review, I would've surely objected to that.

For compiler instance, we need to provide the compiler invocation

We already have the compiler invocation available. I am not sure about the implications of loading a PCM with a "vanilla" compiler instance (that's what ASTUnit does underneath, creates a preprocessor, astcontext, diagsengine, ... with default options), I'd be much more comfortable if we created that ASTReader and loaded the AST with some relevant compilerinvocation that describes user's intent.

But you definitely know much more about modules, if you think that's fine, i think we can always create that astreader directly here, without a compilerinstance as well.

Copy link
Member

@kadircet kadircet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(need to write something here apparently)

@ChuanqiXu9
Copy link
Member Author

(Update too quickly)

Copy link

github-actions bot commented Oct 28, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

return false;

auto Reader = Unit->getASTReader();
auto Reader = Clang.getASTReader();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should call Clang.createASTReader() first. I don't see any of the previous call creating that.

@ChuanqiXu9 ChuanqiXu9 changed the title [clangd] [Modules] Add VFS to ASTUnit::LoadFromASTFile [clangd] [Modules] Use ASTReader directly in IsModuleFileUpToDate Oct 28, 2024
@ChuanqiXu9
Copy link
Member Author

ChuanqiXu9 commented Oct 28, 2024

if you think that's fine, i think we can always create that astreader directly here, without a compilerinstance as well.

I like the idea more. (so I typed 'updated too quickly') The most important reason I did the previous change is, I think the compiler invocation and compiler instance are not needed to check if source files recorded in BMI are out dated or not. They are fake parameters here. I feel they are redundant and want to get rid of that. And now you pointed out that, actually ASTUnit may be redundant too and what we need actually is the ASTReader only. I like the idea. (Although it introduces the codes a little bit longer)

Copy link
Member

@kadircet kadircet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!


if (!Unit)
return false;
Reader.setListener(std::make_unique<PPIntializer>(PP));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need a Listener? and where's PPIntializer defined?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. It was not updated. I guess I had a typo when verify it by typing check-clangd into check-clang : (

Copy link
Member

@kadircet kadircet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, lgtm!

@ChuanqiXu9
Copy link
Member Author

Thanks : )

@ChuanqiXu9 ChuanqiXu9 merged commit e9b7fe8 into llvm:main Oct 31, 2024
8 checks passed
smallp-o-p pushed a commit to smallp-o-p/llvm-project that referenced this pull request Nov 3, 2024
…vm#113879)

@kadircet mentioned in
llvm@448d8fa#diff-fb3ba8a781117ff04736f951a274812cb7ad1678f9d71d4d91870b711ab45da0L285
that:

> this is definitely a functional change, clangd is used in environments
that solely relies on VFS, and doesn't depend on ASTUnit at all.

> right now this is both introducing a dependency on ASTUnit, and making
all the logical IO physical instead. can you instead use the regular
compiler utilities in clangd, and get the astreader from
CompilerInstance directly, which is VFS-aware, and doesn't depend on
ASTUnit ?

This tries to resolve the problem by creating ASTReader directly and use
VFS to create the FileManager.
NoumanAmir657 pushed a commit to NoumanAmir657/llvm-project that referenced this pull request Nov 4, 2024
…vm#113879)

@kadircet mentioned in
llvm@448d8fa#diff-fb3ba8a781117ff04736f951a274812cb7ad1678f9d71d4d91870b711ab45da0L285
that:

> this is definitely a functional change, clangd is used in environments
that solely relies on VFS, and doesn't depend on ASTUnit at all.

> right now this is both introducing a dependency on ASTUnit, and making
all the logical IO physical instead. can you instead use the regular
compiler utilities in clangd, and get the astreader from
CompilerInstance directly, which is VFS-aware, and doesn't depend on
ASTUnit ?

This tries to resolve the problem by creating ASTReader directly and use
VFS to create the FileManager.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants