180814287SRaphael Isemann //===-- CppModuleConfigurationTest.cpp ------------------------------------===// 29379d19fSRaphael Isemann // 39379d19fSRaphael Isemann // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49379d19fSRaphael Isemann // See https://llvm.org/LICENSE.txt for license information. 59379d19fSRaphael Isemann // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69379d19fSRaphael Isemann // 79379d19fSRaphael Isemann //===----------------------------------------------------------------------===// 89379d19fSRaphael Isemann 99379d19fSRaphael Isemann #include "Plugins/ExpressionParser/Clang/CppModuleConfiguration.h" 109379d19fSRaphael Isemann #include "Plugins/ExpressionParser/Clang/ClangHost.h" 115dca0596SRaphael Isemann #include "TestingSupport/SubsystemRAII.h" 129379d19fSRaphael Isemann #include "lldb/Host/FileSystem.h" 139379d19fSRaphael Isemann #include "lldb/Host/HostInfo.h" 149379d19fSRaphael Isemann 159379d19fSRaphael Isemann #include "gmock/gmock.h" 169379d19fSRaphael Isemann #include "gtest/gtest.h" 179379d19fSRaphael Isemann 189379d19fSRaphael Isemann using namespace lldb_private; 199379d19fSRaphael Isemann 209379d19fSRaphael Isemann namespace { 219379d19fSRaphael Isemann struct CppModuleConfigurationTest : public testing::Test { 225dca0596SRaphael Isemann SubsystemRAII<FileSystem, HostInfo> subsystems; 239379d19fSRaphael Isemann }; 249379d19fSRaphael Isemann } // namespace 259379d19fSRaphael Isemann 269379d19fSRaphael Isemann /// Returns the Clang resource include directory. 279379d19fSRaphael Isemann static std::string ResourceInc() { 289379d19fSRaphael Isemann llvm::SmallString<256> resource_dir; 299379d19fSRaphael Isemann llvm::sys::path::append(resource_dir, GetClangResourceDir().GetPath(), 309379d19fSRaphael Isemann "include"); 31*e28d8f90SJonas Devlieghere return std::string(resource_dir); 329379d19fSRaphael Isemann } 339379d19fSRaphael Isemann 349379d19fSRaphael Isemann /// Utility function turningn a list of paths into a FileSpecList. 359379d19fSRaphael Isemann static FileSpecList makeFiles(llvm::ArrayRef<std::string> paths) { 369379d19fSRaphael Isemann FileSpecList result; 379379d19fSRaphael Isemann for (const std::string &path : paths) 381a2805b8SRaphael Isemann result.Append(FileSpec(path, FileSpec::Style::posix)); 399379d19fSRaphael Isemann return result; 409379d19fSRaphael Isemann } 419379d19fSRaphael Isemann 429379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Linux) { 439379d19fSRaphael Isemann // Test the average Linux configuration. 449379d19fSRaphael Isemann std::string libcpp = "/usr/include/c++/v1"; 459379d19fSRaphael Isemann std::string usr = "/usr/include"; 469379d19fSRaphael Isemann CppModuleConfiguration config( 479379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 489379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 499379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 509379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 519379d19fSRaphael Isemann } 529379d19fSRaphael Isemann 539379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Sysroot) { 549379d19fSRaphael Isemann // Test that having a sysroot for the whole system works fine. 559379d19fSRaphael Isemann std::string libcpp = "/home/user/sysroot/usr/include/c++/v1"; 569379d19fSRaphael Isemann std::string usr = "/home/user/sysroot/usr/include"; 579379d19fSRaphael Isemann CppModuleConfiguration config( 589379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 599379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 609379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 619379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 629379d19fSRaphael Isemann } 639379d19fSRaphael Isemann 649379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) { 659379d19fSRaphael Isemann // Test that a locally build libc++ is detected. 669379d19fSRaphael Isemann std::string libcpp = "/home/user/llvm-build/include/c++/v1"; 679379d19fSRaphael Isemann std::string usr = "/usr/include"; 689379d19fSRaphael Isemann CppModuleConfiguration config( 699379d19fSRaphael Isemann makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); 709379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 719379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 729379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 739379d19fSRaphael Isemann } 749379d19fSRaphael Isemann 759379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) { 769379d19fSRaphael Isemann // Test that having an unrelated library in /usr/include doesn't break. 779379d19fSRaphael Isemann std::string libcpp = "/home/user/llvm-build/include/c++/v1"; 789379d19fSRaphael Isemann std::string usr = "/usr/include"; 799379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 809379d19fSRaphael Isemann {usr + "/bits/types.h", libcpp + "/vector", usr + "/boost/vector"})); 819379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 829379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 839379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 849379d19fSRaphael Isemann } 859379d19fSRaphael Isemann 869379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, Xcode) { 879379d19fSRaphael Isemann // Test detection of libc++ coming from Xcode with generic platform names. 889379d19fSRaphael Isemann std::string p = "/Applications/Xcode.app/Contents/Developer/"; 899379d19fSRaphael Isemann std::string libcpp = p + "Toolchains/B.xctoolchain/usr/include/c++/v1"; 909379d19fSRaphael Isemann std::string usr = 919379d19fSRaphael Isemann p + "Platforms/A.platform/Developer/SDKs/OSVers.sdk/usr/include"; 929379d19fSRaphael Isemann CppModuleConfiguration config( 939379d19fSRaphael Isemann makeFiles({libcpp + "/unordered_map", usr + "/stdio.h"})); 949379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 959379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 969379d19fSRaphael Isemann testing::ElementsAre(libcpp, ResourceInc(), usr)); 979379d19fSRaphael Isemann } 989379d19fSRaphael Isemann 999379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, LibCppV2) { 1009379d19fSRaphael Isemann // Test that a "v2" of libc++ is still correctly detected. 1019379d19fSRaphael Isemann CppModuleConfiguration config( 1029379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v2/vector"})); 1039379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 1049379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 1059379d19fSRaphael Isemann testing::ElementsAre("/usr/include/c++/v2", ResourceInc(), 1069379d19fSRaphael Isemann "/usr/include")); 1079379d19fSRaphael Isemann } 1089379d19fSRaphael Isemann 1099379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) { 1109379d19fSRaphael Isemann // Test that having some unknown file in the libc++ path doesn't break 1119379d19fSRaphael Isemann // anything. 1129379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 1139379d19fSRaphael Isemann {"/usr/include/bits/types.h", "/usr/include/c++/v1/non_existing_file"})); 1149379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); 1159379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), 1169379d19fSRaphael Isemann testing::ElementsAre("/usr/include/c++/v1", ResourceInc(), 1179379d19fSRaphael Isemann "/usr/include")); 1189379d19fSRaphael Isemann } 1199379d19fSRaphael Isemann 1209379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, MissingUsrInclude) { 1219379d19fSRaphael Isemann // Test that we don't load 'std' if we can't find the C standard library. 1229379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles({"/usr/include/c++/v1/vector"})); 1239379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1249379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1259379d19fSRaphael Isemann } 1269379d19fSRaphael Isemann 1279379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, MissingLibCpp) { 1289379d19fSRaphael Isemann // Test that we don't load 'std' if we don't have a libc++. 1299379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles({"/usr/include/bits/types.h"})); 1309379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1319379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1329379d19fSRaphael Isemann } 1339379d19fSRaphael Isemann 1349379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) { 1359379d19fSRaphael Isemann // Test that we don't do anything bad when we encounter libstdc++ paths. 1369379d19fSRaphael Isemann CppModuleConfiguration config(makeFiles( 1379379d19fSRaphael Isemann {"/usr/include/bits/types.h", "/usr/include/c++/8.0.1/vector"})); 1389379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1399379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1409379d19fSRaphael Isemann } 1419379d19fSRaphael Isemann 1429379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, AmbiguousCLib) { 1439379d19fSRaphael Isemann // Test that we don't do anything when we are not sure where the 1449379d19fSRaphael Isemann // right C standard library is. 1459379d19fSRaphael Isemann CppModuleConfiguration config( 1469379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", 1479379d19fSRaphael Isemann "/sysroot/usr/include/bits/types.h"})); 1489379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1499379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1509379d19fSRaphael Isemann } 1519379d19fSRaphael Isemann 1529379d19fSRaphael Isemann TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) { 1539379d19fSRaphael Isemann // Test that we don't do anything when we are not sure where the 1549379d19fSRaphael Isemann // right libc++ is. 1559379d19fSRaphael Isemann CppModuleConfiguration config( 1569379d19fSRaphael Isemann makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", 1579379d19fSRaphael Isemann "/usr/include/c++/v2/vector"})); 1589379d19fSRaphael Isemann EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); 1599379d19fSRaphael Isemann EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); 1609379d19fSRaphael Isemann } 161