xref: /llvm-project/lldb/unittests/Expression/CppModuleConfigurationTest.cpp (revision 1a2805b887d31c886e9df476b8262bc01d016df0)
1 //===-- CppModuleConfigurationTest.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 "Plugins/ExpressionParser/Clang/CppModuleConfiguration.h"
10 #include "Plugins/ExpressionParser/Clang/ClangHost.h"
11 #include "lldb/Host/FileSystem.h"
12 #include "lldb/Host/HostInfo.h"
13 
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 using namespace lldb_private;
18 
19 namespace {
20 struct CppModuleConfigurationTest : public testing::Test {
21   static void SetUpTestCase() {
22     // Getting the resource directory uses those subsystems, so we should
23     // initialize them.
24     FileSystem::Initialize();
25     HostInfo::Initialize();
26   }
27   static void TearDownTestCase() {
28     HostInfo::Terminate();
29     FileSystem::Terminate();
30   }
31 };
32 } // namespace
33 
34 /// Returns the Clang resource include directory.
35 static std::string ResourceInc() {
36   llvm::SmallString<256> resource_dir;
37   llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(),
38                           "include");
39   return resource_dir.str().str();
40 }
41 
42 /// Utility function turningn a list of paths into a FileSpecList.
43 static FileSpecList makeFiles(llvm::ArrayRef<std::string> paths) {
44   FileSpecList result;
45   for (const std::string &path : paths)
46     result.Append(FileSpec(path, FileSpec::Style::posix));
47   return result;
48 }
49 
50 TEST_F(CppModuleConfigurationTest, Linux) {
51   // Test the average Linux configuration.
52   std::string libcpp = "/usr/include/c++/v1";
53   std::string usr = "/usr/include";
54   CppModuleConfiguration config(
55       makeFiles({usr + "/bits/types.h", libcpp + "/vector"}));
56   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
57   EXPECT_THAT(config.GetIncludeDirs(),
58               testing::ElementsAre(libcpp, ResourceInc(), usr));
59 }
60 
61 TEST_F(CppModuleConfigurationTest, Sysroot) {
62   // Test that having a sysroot for the whole system works fine.
63   std::string libcpp = "/home/user/sysroot/usr/include/c++/v1";
64   std::string usr = "/home/user/sysroot/usr/include";
65   CppModuleConfiguration config(
66       makeFiles({usr + "/bits/types.h", libcpp + "/vector"}));
67   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
68   EXPECT_THAT(config.GetIncludeDirs(),
69               testing::ElementsAre(libcpp, ResourceInc(), usr));
70 }
71 
72 TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) {
73   // Test that a locally build libc++ is detected.
74   std::string libcpp = "/home/user/llvm-build/include/c++/v1";
75   std::string usr = "/usr/include";
76   CppModuleConfiguration config(
77       makeFiles({usr + "/bits/types.h", libcpp + "/vector"}));
78   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
79   EXPECT_THAT(config.GetIncludeDirs(),
80               testing::ElementsAre(libcpp, ResourceInc(), usr));
81 }
82 
83 TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) {
84   // Test that having an unrelated library in /usr/include doesn't break.
85   std::string libcpp = "/home/user/llvm-build/include/c++/v1";
86   std::string usr = "/usr/include";
87   CppModuleConfiguration config(makeFiles(
88       {usr + "/bits/types.h", libcpp + "/vector", usr + "/boost/vector"}));
89   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
90   EXPECT_THAT(config.GetIncludeDirs(),
91               testing::ElementsAre(libcpp, ResourceInc(), usr));
92 }
93 
94 TEST_F(CppModuleConfigurationTest, Xcode) {
95   // Test detection of libc++ coming from Xcode with generic platform names.
96   std::string p = "/Applications/Xcode.app/Contents/Developer/";
97   std::string libcpp = p + "Toolchains/B.xctoolchain/usr/include/c++/v1";
98   std::string usr =
99       p + "Platforms/A.platform/Developer/SDKs/OSVers.sdk/usr/include";
100   CppModuleConfiguration config(
101       makeFiles({libcpp + "/unordered_map", usr + "/stdio.h"}));
102   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
103   EXPECT_THAT(config.GetIncludeDirs(),
104               testing::ElementsAre(libcpp, ResourceInc(), usr));
105 }
106 
107 TEST_F(CppModuleConfigurationTest, LibCppV2) {
108   // Test that a "v2" of libc++ is still correctly detected.
109   CppModuleConfiguration config(
110       makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v2/vector"}));
111   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
112   EXPECT_THAT(config.GetIncludeDirs(),
113               testing::ElementsAre("/usr/include/c++/v2", ResourceInc(),
114                                    "/usr/include"));
115 }
116 
117 TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) {
118   // Test that having some unknown file in the libc++ path doesn't break
119   // anything.
120   CppModuleConfiguration config(makeFiles(
121       {"/usr/include/bits/types.h", "/usr/include/c++/v1/non_existing_file"}));
122   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std"));
123   EXPECT_THAT(config.GetIncludeDirs(),
124               testing::ElementsAre("/usr/include/c++/v1", ResourceInc(),
125                                    "/usr/include"));
126 }
127 
128 TEST_F(CppModuleConfigurationTest, MissingUsrInclude) {
129   // Test that we don't load 'std' if we can't find the C standard library.
130   CppModuleConfiguration config(makeFiles({"/usr/include/c++/v1/vector"}));
131   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
132   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
133 }
134 
135 TEST_F(CppModuleConfigurationTest, MissingLibCpp) {
136   // Test that we don't load 'std' if we don't have a libc++.
137   CppModuleConfiguration config(makeFiles({"/usr/include/bits/types.h"}));
138   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
139   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
140 }
141 
142 TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) {
143   // Test that we don't do anything bad when we encounter libstdc++ paths.
144   CppModuleConfiguration config(makeFiles(
145       {"/usr/include/bits/types.h", "/usr/include/c++/8.0.1/vector"}));
146   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
147   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
148 }
149 
150 TEST_F(CppModuleConfigurationTest, AmbiguousCLib) {
151   // Test that we don't do anything when we are not sure where the
152   // right C standard library is.
153   CppModuleConfiguration config(
154       makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector",
155                  "/sysroot/usr/include/bits/types.h"}));
156   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
157   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
158 }
159 
160 TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) {
161   // Test that we don't do anything when we are not sure where the
162   // right libc++ is.
163   CppModuleConfiguration config(
164       makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector",
165                  "/usr/include/c++/v2/vector"}));
166   EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre());
167   EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre());
168 }
169