brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · 39d35b4 Raw
155 lines · cpp
1//===- unittests/Frontend/CompilerInstanceTest.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/Frontend/CompilerInstance.h"10#include "clang/Basic/FileManager.h"11#include "clang/Driver/CreateInvocationFromArgs.h"12#include "clang/Frontend/CompilerInvocation.h"13#include "clang/Frontend/FrontendActions.h"14#include "clang/Frontend/TextDiagnosticPrinter.h"15#include "llvm/ADT/IntrusiveRefCntPtr.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Format.h"18#include "llvm/Support/MemoryBuffer.h"19#include "llvm/Support/ToolOutputFile.h"20#include "llvm/Support/VirtualFileSystem.h"21#include "gtest/gtest.h"22 23using namespace llvm;24using namespace clang;25 26namespace {27 28TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {29  // Create a temporary VFS overlay yaml file.30  int FD;31  SmallString<256> FileName;32  ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName));33  ToolOutputFile File(FileName, FD);34 35  SmallString<256> CurrentPath;36  sys::fs::current_path(CurrentPath);37  sys::path::make_absolute(CurrentPath, FileName);38 39  // Mount the VFS file itself on the path 'virtual.file'. Makes this test40  // a bit shorter than creating a new dummy file just for this purpose.41  const std::string CurrentPathStr = std::string(CurrentPath.str());42  const std::string FileNameStr = std::string(FileName.str());43  const char *VFSYaml = "{ 'version': 0, 'roots': [\n"44                        "  { 'name': '%s',\n"45                        "    'type': 'directory',\n"46                        "    'contents': [\n"47                        "      { 'name': 'vfs-virtual.file', 'type': 'file',\n"48                        "        'external-contents': '%s'\n"49                        "      }\n"50                        "    ]\n"51                        "  }\n"52                        "]}\n";53  File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str());54  File.os().flush();55 56  // Create a CompilerInvocation that uses this overlay file.57  const std::string VFSArg = "-ivfsoverlay" + FileNameStr;58  const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};59 60  DiagnosticOptions DiagOpts;61  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =62      CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),63                                          DiagOpts);64 65  CreateInvocationOptions CIOpts;66  CIOpts.Diags = Diags;67  std::shared_ptr<CompilerInvocation> CInvok =68      createInvocation(Args, std::move(CIOpts));69 70  if (!CInvok)71    FAIL() << "could not create compiler invocation";72  // Create a minimal CompilerInstance which should use the VFS we specified73  // in the CompilerInvocation (as we don't explicitly set our own).74  CompilerInstance Instance(std::move(CInvok));75  Instance.setDiagnostics(Diags);76  Instance.createVirtualFileSystem();77  Instance.createFileManager();78 79  // Check if the virtual file exists which means that our VFS is used by the80  // CompilerInstance.81  ASSERT_TRUE(Instance.getFileManager().getOptionalFileRef("vfs-virtual.file"));82}83 84TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {85  DiagnosticOptions DiagOpts;86  // Tell the diagnostics engine to emit the diagnostic log to STDERR. This87  // ensures that a chained diagnostic consumer is created so that the test can88  // exercise the unowned diagnostic consumer in a chained consumer.89  DiagOpts.DiagnosticLogFile = "-";90 91  // Create the diagnostic engine with unowned consumer.92  std::string DiagnosticOutput;93  llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);94  auto DiagPrinter =95      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);96  CompilerInstance Instance;97  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =98      Instance.createDiagnostics(*llvm::vfs::getRealFileSystem(), DiagOpts,99                                 DiagPrinter.get(), /*ShouldOwnClient=*/false);100 101  Diags->Report(diag::err_expected) << "no crash";102  ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n");103}104 105TEST(CompilerInstance, MultipleInputsCleansFileIDs) {106  auto VFS = makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();107  VFS->addFile("a.cc", /*ModificationTime=*/{},108               MemoryBuffer::getMemBuffer(R"cpp(109      #include "a.h"110      )cpp"));111  // Paddings of `void foo();` in the sources below are "important". We're112  // testing against source locations from previous compilations colliding.113  // Hence the `unused` variable in `b.h` needs to be within `#pragma clang114  // diagnostic` block from `a.h`.115  VFS->addFile("a.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp(116      #include "b.h"117      #pragma clang diagnostic push118      #pragma clang diagnostic warning "-Wunused"119      void foo();120      #pragma clang diagnostic pop121      )cpp"));122  VFS->addFile("b.h", /*ModificationTime=*/{}, MemoryBuffer::getMemBuffer(R"cpp(123      void foo(); void foo(); void foo(); void foo();124      inline void foo() { int unused = 2; }125      )cpp"));126 127  DiagnosticOptions DiagOpts;128  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =129      CompilerInstance::createDiagnostics(*VFS, DiagOpts);130 131  CreateInvocationOptions CIOpts;132  CIOpts.Diags = Diags;133 134  const char *Args[] = {"clang", "-xc++", "a.cc"};135  std::shared_ptr<CompilerInvocation> CInvok =136      createInvocation(Args, std::move(CIOpts));137  ASSERT_TRUE(CInvok) << "could not create compiler invocation";138 139  CompilerInstance Instance(std::move(CInvok));140  Instance.setVirtualFileSystem(VFS);141  Instance.setDiagnostics(Diags);142  Instance.createFileManager();143 144  // Run once for `a.cc` and then for `a.h`. This makes sure we get the same145  // file ID for `b.h` in the second run as `a.h` from first run.146  const auto &OrigInputKind = Instance.getFrontendOpts().Inputs[0].getKind();147  Instance.getFrontendOpts().Inputs.emplace_back("a.h", OrigInputKind);148 149  SyntaxOnlyAction Act;150  EXPECT_TRUE(Instance.ExecuteAction(Act)) << "Failed to execute action";151  EXPECT_FALSE(Diags->hasErrorOccurred());152  EXPECT_EQ(Diags->getNumWarnings(), 0u);153}154} // anonymous namespace155