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