brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.7 KiB · f55925a Raw
266 lines · cpp
1//== unittests/Serialization/LoadSpecLazily.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Driver/CreateInvocationFromArgs.h"10#include "clang/Frontend/CompilerInstance.h"11#include "clang/Frontend/FrontendAction.h"12#include "clang/Frontend/FrontendActions.h"13#include "clang/Parse/ParseAST.h"14#include "clang/Serialization/ASTDeserializationListener.h"15#include "clang/Tooling/Tooling.h"16#include "gtest/gtest.h"17 18using namespace llvm;19using namespace clang;20using namespace clang::tooling;21 22namespace {23 24class LoadSpecLazilyTest : public ::testing::Test {25  void SetUp() override {26    ASSERT_FALSE(27        sys::fs::createUniqueDirectory("load-spec-lazily-test", TestDir));28  }29 30  void TearDown() override { sys::fs::remove_directories(TestDir); }31 32public:33  SmallString<256> TestDir;34 35  void addFile(StringRef Path, StringRef Contents) {36    ASSERT_FALSE(sys::path::is_absolute(Path));37 38    SmallString<256> AbsPath(TestDir);39    sys::path::append(AbsPath, Path);40 41    ASSERT_FALSE(42        sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));43 44    std::error_code EC;45    llvm::raw_fd_ostream OS(AbsPath, EC);46    ASSERT_FALSE(EC);47    OS << Contents;48  }49 50  std::string GenerateModuleInterface(StringRef ModuleName,51                                      StringRef Contents) {52    std::string FileName = llvm::Twine(ModuleName + ".cppm").str();53    addFile(FileName, Contents);54 55    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =56        llvm::vfs::createPhysicalFileSystem();57    DiagnosticOptions DiagOpts;58    IntrusiveRefCntPtr<DiagnosticsEngine> Diags =59        CompilerInstance::createDiagnostics(*VFS, DiagOpts);60    CreateInvocationOptions CIOpts;61    CIOpts.Diags = Diags;62    CIOpts.VFS = VFS;63 64    std::string CacheBMIPath =65        llvm::Twine(TestDir + "/" + ModuleName + ".pcm").str();66    std::string PrebuiltModulePath =67        "-fprebuilt-module-path=" + TestDir.str().str();68    const char *Args[] = {"clang++",69                          "-std=c++20",70                          "--precompile",71                          PrebuiltModulePath.c_str(),72                          "-working-directory",73                          TestDir.c_str(),74                          "-I",75                          TestDir.c_str(),76                          FileName.c_str(),77                          "-o",78                          CacheBMIPath.c_str()};79    std::shared_ptr<CompilerInvocation> Invocation =80        createInvocation(Args, CIOpts);81    EXPECT_TRUE(Invocation);82 83    CompilerInstance Instance(std::move(Invocation));84    Instance.setDiagnostics(Diags);85    Instance.getFrontendOpts().OutputFile = CacheBMIPath;86    // Avoid memory leaks.87    Instance.getFrontendOpts().DisableFree = false;88    GenerateModuleInterfaceAction Action;89    EXPECT_TRUE(Instance.ExecuteAction(Action));90    EXPECT_FALSE(Diags->hasErrorOccurred());91 92    return CacheBMIPath;93  }94};95 96enum class CheckingMode { Forbidden, Required };97 98class DeclsReaderListener : public ASTDeserializationListener {99  StringRef SpeficiedName;100  CheckingMode Mode;101 102  bool ReadedSpecifiedName = false;103 104public:105  void DeclRead(GlobalDeclID ID, const Decl *D) override {106    auto *ND = dyn_cast<NamedDecl>(D);107    if (!ND)108      return;109 110    ReadedSpecifiedName |= ND->getName().contains(SpeficiedName);111    if (Mode == CheckingMode::Forbidden) {112      EXPECT_FALSE(ReadedSpecifiedName);113    }114  }115 116  DeclsReaderListener(StringRef SpeficiedName, CheckingMode Mode)117      : SpeficiedName(SpeficiedName), Mode(Mode) {}118 119  ~DeclsReaderListener() {120    if (Mode == CheckingMode::Required) {121      EXPECT_TRUE(ReadedSpecifiedName);122    }123  }124};125 126class LoadSpecLazilyConsumer : public ASTConsumer {127  DeclsReaderListener Listener;128 129public:130  LoadSpecLazilyConsumer(StringRef SpecifiedName, CheckingMode Mode)131      : Listener(SpecifiedName, Mode) {}132 133  ASTDeserializationListener *GetASTDeserializationListener() override {134    return &Listener;135  }136};137 138class CheckLoadSpecLazilyAction : public ASTFrontendAction {139  StringRef SpecifiedName;140  CheckingMode Mode;141 142public:143  std::unique_ptr<ASTConsumer>144  CreateASTConsumer(CompilerInstance &CI, StringRef /*Unused*/) override {145    return std::make_unique<LoadSpecLazilyConsumer>(SpecifiedName, Mode);146  }147 148  CheckLoadSpecLazilyAction(StringRef SpecifiedName, CheckingMode Mode)149      : SpecifiedName(SpecifiedName), Mode(Mode) {}150};151 152TEST_F(LoadSpecLazilyTest, BasicTest) {153  GenerateModuleInterface("M", R"cpp(154export module M;155export template <class T>156class A {};157export class ShouldNotBeLoaded {};158export class Temp {159   A<ShouldNotBeLoaded> AS;160};161  )cpp");162 163  const char *test_file_contents = R"cpp(164import M;165A<int> a;166  )cpp";167  std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();168  EXPECT_TRUE(169      runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>(170                                "ShouldNotBeLoaded", CheckingMode::Forbidden),171                            test_file_contents,172                            {173                                "-std=c++20",174                                DepArg.c_str(),175                                "-I",176                                TestDir.c_str(),177                            },178                            "test.cpp"));179}180 181TEST_F(LoadSpecLazilyTest, ChainedTest) {182  GenerateModuleInterface("M", R"cpp(183export module M;184export template <class T>185class A {};186  )cpp");187 188  GenerateModuleInterface("N", R"cpp(189export module N;190export import M;191export class ShouldNotBeLoaded {};192export class Temp {193   A<ShouldNotBeLoaded> AS;194};195  )cpp");196 197  const char *test_file_contents = R"cpp(198import N;199A<int> a;200  )cpp";201  std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();202  EXPECT_TRUE(203      runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>(204                                "ShouldNotBeLoaded", CheckingMode::Forbidden),205                            test_file_contents,206                            {207                                "-std=c++20",208                                DepArg.c_str(),209                                "-I",210                                TestDir.c_str(),211                            },212                            "test.cpp"));213}214 215/// Test that we won't crash due to we may invalidate the lazy specialization216/// lookup table during the loading process.217TEST_F(LoadSpecLazilyTest, ChainedTest2) {218  GenerateModuleInterface("M", R"cpp(219export module M;220export template <class T>221class A {};222 223export class B {};224 225export class C {226  A<B> D;227};228  )cpp");229 230  GenerateModuleInterface("N", R"cpp(231export module N;232export import M;233export class MayBeLoaded {};234 235export class Temp {236   A<MayBeLoaded> AS;237};238 239export class ExportedClass {};240 241export template<> class A<ExportedClass> {242   A<MayBeLoaded> AS;243   A<B>           AB;244};245  )cpp");246 247  const char *test_file_contents = R"cpp(248import N;249Temp T;250A<ExportedClass> a;251  )cpp";252  std::string DepArg = "-fprebuilt-module-path=" + TestDir.str().str();253  EXPECT_TRUE(runToolOnCodeWithArgs(std::make_unique<CheckLoadSpecLazilyAction>(254                                        "MayBeLoaded", CheckingMode::Required),255                                    test_file_contents,256                                    {257                                        "-std=c++20",258                                        DepArg.c_str(),259                                        "-I",260                                        TestDir.c_str(),261                                    },262                                    "test.cpp"));263}264 265} // namespace266