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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Frontend/CompilerInstance.h" 10 #include "clang/Basic/FileManager.h" 11 #include "clang/Frontend/CompilerInvocation.h" 12 #include "clang/Frontend/TextDiagnosticPrinter.h" 13 #include "llvm/Support/FileSystem.h" 14 #include "llvm/Support/Format.h" 15 #include "llvm/Support/ToolOutputFile.h" 16 #include "llvm/Support/VirtualFileSystem.h" 17 #include "gtest/gtest.h" 18 19 using namespace llvm; 20 using namespace clang; 21 22 namespace { 23 24 TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) { 25 // Create a temporary VFS overlay yaml file. 26 int FD; 27 SmallString<256> FileName; 28 ASSERT_FALSE(sys::fs::createTemporaryFile("vfs", "yaml", FD, FileName)); 29 ToolOutputFile File(FileName, FD); 30 31 SmallString<256> CurrentPath; 32 sys::fs::current_path(CurrentPath); 33 sys::fs::make_absolute(CurrentPath, FileName); 34 35 // Mount the VFS file itself on the path 'virtual.file'. Makes this test 36 // a bit shorter than creating a new dummy file just for this purpose. 37 const std::string CurrentPathStr = std::string(CurrentPath.str()); 38 const std::string FileNameStr = std::string(FileName.str()); 39 const char *VFSYaml = "{ 'version': 0, 'roots': [\n" 40 " { 'name': '%s',\n" 41 " 'type': 'directory',\n" 42 " 'contents': [\n" 43 " { 'name': 'vfs-virtual.file', 'type': 'file',\n" 44 " 'external-contents': '%s'\n" 45 " }\n" 46 " ]\n" 47 " }\n" 48 "]}\n"; 49 File.os() << format(VFSYaml, CurrentPathStr.c_str(), FileName.c_str()); 50 File.os().flush(); 51 52 // Create a CompilerInvocation that uses this overlay file. 53 const std::string VFSArg = "-ivfsoverlay" + FileNameStr; 54 const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"}; 55 56 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 57 CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(), 58 new DiagnosticOptions()); 59 60 CreateInvocationOptions CIOpts; 61 CIOpts.Diags = Diags; 62 std::shared_ptr<CompilerInvocation> CInvok = 63 createInvocation(Args, std::move(CIOpts)); 64 65 if (!CInvok) 66 FAIL() << "could not create compiler invocation"; 67 // Create a minimal CompilerInstance which should use the VFS we specified 68 // in the CompilerInvocation (as we don't explicitly set our own). 69 CompilerInstance Instance; 70 Instance.setDiagnostics(Diags.get()); 71 Instance.setInvocation(CInvok); 72 Instance.createFileManager(); 73 74 // Check if the virtual file exists which means that our VFS is used by the 75 // CompilerInstance. 76 ASSERT_TRUE(Instance.getFileManager().getOptionalFileRef("vfs-virtual.file")); 77 } 78 79 TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) { 80 auto DiagOpts = new DiagnosticOptions(); 81 // Tell the diagnostics engine to emit the diagnostic log to STDERR. This 82 // ensures that a chained diagnostic consumer is created so that the test can 83 // exercise the unowned diagnostic consumer in a chained consumer. 84 DiagOpts->DiagnosticLogFile = "-"; 85 86 // Create the diagnostic engine with unowned consumer. 87 std::string DiagnosticOutput; 88 llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); 89 auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>( 90 DiagnosticsOS, new DiagnosticOptions()); 91 CompilerInstance Instance; 92 IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 93 Instance.createDiagnostics(*llvm::vfs::getRealFileSystem(), DiagOpts, 94 DiagPrinter.get(), /*ShouldOwnClient=*/false); 95 96 Diags->Report(diag::err_expected) << "no crash"; 97 ASSERT_EQ(DiagnosticOutput, "error: expected no crash\n"); 98 } 99 100 } // anonymous namespace 101