brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · df26e54 Raw
204 lines · cpp
1//===- unittests/Serialization/ModuleCacheTest.cpp - CI tests -------------===//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/Basic/FileManager.h"10#include "clang/Driver/CreateInvocationFromArgs.h"11#include "clang/Frontend/CompilerInstance.h"12#include "clang/Frontend/CompilerInvocation.h"13#include "clang/Frontend/FrontendActions.h"14#include "clang/Frontend/Utils.h"15#include "clang/Lex/HeaderSearch.h"16#include "llvm/ADT/SmallString.h"17#include "llvm/Support/FileSystem.h"18#include "llvm/Support/VirtualFileSystem.h"19#include "llvm/Support/raw_ostream.h"20 21#include "gtest/gtest.h"22 23using namespace llvm;24using namespace clang;25 26namespace {27 28class ModuleCacheTest : public ::testing::Test {29  void SetUp() override {30    ASSERT_FALSE(sys::fs::createUniqueDirectory("modulecache-test", TestDir));31 32    ModuleCachePath = SmallString<256>(TestDir);33    sys::path::append(ModuleCachePath, "mcp");34    ASSERT_FALSE(sys::fs::create_directories(ModuleCachePath));35  }36 37  void TearDown() override { sys::fs::remove_directories(TestDir); }38 39public:40  SmallString<256> TestDir;41  SmallString<256> ModuleCachePath;42 43  void addFile(StringRef Path, StringRef Contents) {44    ASSERT_FALSE(sys::path::is_absolute(Path));45 46    SmallString<256> AbsPath(TestDir);47    sys::path::append(AbsPath, Path);48 49    std::error_code EC;50    ASSERT_FALSE(51        sys::fs::create_directories(llvm::sys::path::parent_path(AbsPath)));52    llvm::raw_fd_ostream OS(AbsPath, EC);53    ASSERT_FALSE(EC);54    OS << Contents;55  }56 57  void addDuplicateFrameworks() {58    addFile("test.m", R"cpp(59        @import Top;60    )cpp");61 62    addFile("frameworks/Top.framework/Headers/top.h", R"cpp(63        @import M;64    )cpp");65    addFile("frameworks/Top.framework/Modules/module.modulemap", R"cpp(66        framework module Top [system] {67          header "top.h"68          export *69        }70    )cpp");71 72    addFile("frameworks/M.framework/Headers/m.h", R"cpp(73        void foo();74    )cpp");75    addFile("frameworks/M.framework/Modules/module.modulemap", R"cpp(76        framework module M [system] {77          header "m.h"78          export *79        }80    )cpp");81 82    addFile("frameworks2/M.framework/Headers/m.h", R"cpp(83        void foo();84    )cpp");85    addFile("frameworks2/M.framework/Modules/module.modulemap", R"cpp(86        framework module M [system] {87          header "m.h"88          export *89        }90    )cpp");91  }92 93  std::unique_ptr<CompilerInvocation>94  createInvocationAndEnableFree(ArrayRef<const char *> Args,95                                CreateInvocationOptions Opts) {96    std::unique_ptr<CompilerInvocation> Invocation =97        createInvocation(Args, Opts);98    if (Invocation)99      Invocation->getFrontendOpts().DisableFree = false;100 101    return Invocation;102  }103};104 105TEST_F(ModuleCacheTest, CachedModuleNewPath) {106  addDuplicateFrameworks();107 108  SmallString<256> MCPArg("-fmodules-cache-path=");109  MCPArg.append(ModuleCachePath);110  CreateInvocationOptions CIOpts;111  CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();112  DiagnosticOptions DiagOpts;113  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =114      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);115  CIOpts.Diags = Diags;116 117  // First run should pass with no errors118  const char *Args[] = {"clang",        "-fmodules",          "-Fframeworks",119                        MCPArg.c_str(), "-working-directory", TestDir.c_str(),120                        "test.m"};121  std::shared_ptr<CompilerInvocation> Invocation =122      createInvocationAndEnableFree(Args, CIOpts);123  ASSERT_TRUE(Invocation);124  CompilerInstance Instance(std::move(Invocation));125  Instance.setVirtualFileSystem(CIOpts.VFS);126  Instance.setDiagnostics(Diags);127  SyntaxOnlyAction Action;128  ASSERT_TRUE(Instance.ExecuteAction(Action));129  ASSERT_FALSE(Diags->hasErrorOccurred());130 131  // Now add `frameworks2` to the search path. `Top.pcm` will have a reference132  // to the `M` from `frameworks`, but a search will find the `M` from133  // `frameworks2` - causing a mismatch and it to be considered out of date.134  //135  // Normally this would be fine - `M` and the modules it depends on would be136  // rebuilt. However, since we have a shared module cache and thus an already137  // finalized `Top`, recompiling `Top` will cause the existing module to be138  // removed from the cache, causing possible crashed if it is ever used.139  //140  // Make sure that an error occurs instead.141  const char *Args2[] = {"clang",         "-fmodules",    "-Fframeworks2",142                         "-Fframeworks",  MCPArg.c_str(), "-working-directory",143                         TestDir.c_str(), "test.m"};144  std::shared_ptr<CompilerInvocation> Invocation2 =145      createInvocationAndEnableFree(Args2, CIOpts);146  ASSERT_TRUE(Invocation2);147  CompilerInstance Instance2(std::move(Invocation2),148                             Instance.getPCHContainerOperations(),149                             &Instance.getModuleCache());150  Instance2.setVirtualFileSystem(CIOpts.VFS);151  Instance2.setDiagnostics(Diags);152  SyntaxOnlyAction Action2;153  ASSERT_FALSE(Instance2.ExecuteAction(Action2));154  ASSERT_TRUE(Diags->hasErrorOccurred());155}156 157TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) {158  addDuplicateFrameworks();159 160  SmallString<256> MCPArg("-fmodules-cache-path=");161  MCPArg.append(ModuleCachePath);162  CreateInvocationOptions CIOpts;163  CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();164  DiagnosticOptions DiagOpts;165  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =166      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);167  CIOpts.Diags = Diags;168 169  // First run should pass with no errors170  const char *Args[] = {"clang",        "-fmodules",          "-Fframeworks",171                        MCPArg.c_str(), "-working-directory", TestDir.c_str(),172                        "test.m"};173  std::shared_ptr<CompilerInvocation> Invocation =174      createInvocationAndEnableFree(Args, CIOpts);175  ASSERT_TRUE(Invocation);176  CompilerInstance Instance(std::move(Invocation));177  Instance.setVirtualFileSystem(CIOpts.VFS);178  Instance.setDiagnostics(Diags);179  SyntaxOnlyAction Action;180  ASSERT_TRUE(Instance.ExecuteAction(Action));181  ASSERT_FALSE(Diags->hasErrorOccurred());182 183  // Same as `CachedModuleNewPath` but while allowing errors. This is a hard184  // failure where the module wasn't created, so it should still fail.185  const char *Args2[] = {186      "clang",         "-fmodules",    "-Fframeworks2",187      "-Fframeworks",  MCPArg.c_str(), "-working-directory",188      TestDir.c_str(), "-Xclang",      "-fallow-pcm-with-compiler-errors",189      "test.m"};190  std::shared_ptr<CompilerInvocation> Invocation2 =191      createInvocationAndEnableFree(Args2, CIOpts);192  ASSERT_TRUE(Invocation2);193  CompilerInstance Instance2(std::move(Invocation2),194                             Instance.getPCHContainerOperations(),195                             &Instance.getModuleCache());196  Instance2.setVirtualFileSystem(CIOpts.VFS);197  Instance2.setDiagnostics(Diags);198  SyntaxOnlyAction Action2;199  ASSERT_FALSE(Instance2.ExecuteAction(Action2));200  ASSERT_TRUE(Diags->hasErrorOccurred());201}202 203} // anonymous namespace204