xref: /llvm-project/clang-tools-extra/clangd/unittests/ModulesTests.cpp (revision 23459f13fcd9c424a41debb2d11eb56843d4e679)
1 //===-- ModulesTests.cpp  ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "TestFS.h"
10 #include "TestTU.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 #include <memory>
16 #include <string>
17 
18 namespace clang {
19 namespace clangd {
20 namespace {
21 
TEST(Modules,TextualIncludeInPreamble)22 TEST(Modules, TextualIncludeInPreamble) {
23   TestTU TU = TestTU::withCode(R"cpp(
24     #include "Textual.h"
25 
26     void foo() {}
27 )cpp");
28   TU.ExtraArgs.push_back("-fmodule-name=M");
29   TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("m.modulemap"));
30   TU.AdditionalFiles["Textual.h"] = "void foo();";
31   TU.AdditionalFiles["m.modulemap"] = R"modulemap(
32     module M {
33       module Textual {
34         textual header "Textual.h"
35       }
36     }
37 )modulemap";
38   // Test that we do not crash.
39   TU.index();
40 }
41 
42 // Verify that visibility of AST nodes belonging to modules, but loaded from
43 // preamble PCH, is restored.
TEST(Modules,PreambleBuildVisibility)44 TEST(Modules, PreambleBuildVisibility) {
45   TestTU TU = TestTU::withCode(R"cpp(
46     #include "module.h"
47 
48     foo x;
49 )cpp");
50   TU.OverlayRealFileSystemForModules = true;
51   TU.ExtraArgs.push_back("-fmodules");
52   TU.ExtraArgs.push_back("-fmodules-strict-decluse");
53   TU.ExtraArgs.push_back("-Xclang");
54   TU.ExtraArgs.push_back("-fmodules-local-submodule-visibility");
55   TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("m.modulemap"));
56   TU.AdditionalFiles["module.h"] = R"cpp(
57     typedef int foo;
58 )cpp";
59   TU.AdditionalFiles["m.modulemap"] = R"modulemap(
60     module M {
61       header "module.h"
62     }
63 )modulemap";
64   EXPECT_TRUE(TU.build().getDiagnostics().empty());
65 }
66 
TEST(Modules,Diagnostic)67 TEST(Modules, Diagnostic) {
68   // Produce a diagnostic while building an implicit module. Use
69   // -fmodules-strict-decluse, but any non-silenced diagnostic will do.
70   TestTU TU = TestTU::withCode(R"cpp(
71     /*error-ok*/
72     #include "modular.h"
73 
74     void bar() {}
75 )cpp");
76   TU.OverlayRealFileSystemForModules = true;
77   TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("m.modulemap"));
78   TU.ExtraArgs.push_back("-fmodules");
79   TU.ExtraArgs.push_back("-fimplicit-modules");
80   TU.ExtraArgs.push_back("-fmodules-strict-decluse");
81   TU.AdditionalFiles["modular.h"] = R"cpp(
82     #include "non-modular.h"
83   )cpp";
84   TU.AdditionalFiles["non-modular.h"] = "";
85   TU.AdditionalFiles["m.modulemap"] = R"modulemap(
86     module M {
87       header "modular.h"
88     }
89 )modulemap";
90 
91   // Test that we do not crash.
92   TU.build();
93 }
94 
95 // Unknown module formats are a fatal failure for clang. Ensure we don't crash.
TEST(Modules,UnknownFormat)96 TEST(Modules, UnknownFormat) {
97   TestTU TU = TestTU::withCode(R"(#include "modular.h")");
98   TU.OverlayRealFileSystemForModules = true;
99   TU.ExtraArgs.push_back("-Xclang");
100   TU.ExtraArgs.push_back("-fmodule-format=obj");
101   TU.ExtraArgs.push_back("-fmodule-map-file=" + testPath("m.modulemap"));
102   TU.ExtraArgs.push_back("-fmodules");
103   TU.ExtraArgs.push_back("-fimplicit-modules");
104   TU.AdditionalFiles["modular.h"] = "";
105   TU.AdditionalFiles["m.modulemap"] = R"modulemap(
106     module M {
107       header "modular.h"
108     })modulemap";
109 
110   // Test that we do not crash.
111   TU.build();
112 }
113 
114 // Test that we can build and use a preamble for a module unit.
TEST(Modules,ModulePreamble)115 TEST(Modules, ModulePreamble) {
116   TestTU TU = TestTU::withCode(R"cpp(
117     module;
118     #define PREAMBLE_MACRO 1
119     export module foo;
120     #define MODULE_MACRO 2
121     module :private;
122     #define PRIVATE_MACRO 3
123   )cpp");
124   TU.ExtraArgs.push_back("-std=c++20");
125   TU.ExtraArgs.push_back("--precompile");
126 
127   auto AST = TU.build();
128   auto &SM = AST.getSourceManager();
129   auto GetMacroFile = [&](llvm::StringRef Name) -> FileID {
130     if (auto *MI = AST.getPreprocessor().getMacroInfo(
131             &AST.getASTContext().Idents.get(Name)))
132       return SM.getFileID(MI->getDefinitionLoc());
133     return {};
134   };
135 
136   EXPECT_EQ(GetMacroFile("PREAMBLE_MACRO"), SM.getPreambleFileID());
137   EXPECT_EQ(GetMacroFile("MODULE_MACRO"), SM.getMainFileID());
138   EXPECT_EQ(GetMacroFile("PRIVATE_MACRO"), SM.getMainFileID());
139 }
140 
141 } // namespace
142 } // namespace clangd
143 } // namespace clang
144