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