| 1 | //===- unittests/Frontend/CodeGenActionTest.cpp --- FrontendAction 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 | // Unit tests for CodeGenAction. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "clang/CodeGen/CodeGenAction.h" |
| 14 | #include "clang/Basic/LangStandard.h" |
| 15 | #include "clang/CodeGen/BackendUtil.h" |
| 16 | #include "clang/Frontend/CompilerInstance.h" |
| 17 | #include "clang/Lex/PreprocessorOptions.h" |
| 18 | #include "llvm/Support/FormatVariadic.h" |
| 19 | #include "llvm/Support/VirtualFileSystem.h" |
| 20 | #include "gtest/gtest.h" |
| 21 | |
| 22 | using namespace llvm; |
| 23 | using namespace clang; |
| 24 | using namespace clang::frontend; |
| 25 | |
| 26 | namespace { |
| 27 | |
| 28 | |
| 29 | class NullCodeGenAction : public CodeGenAction { |
| 30 | public: |
| 31 | NullCodeGenAction(llvm::LLVMContext *_VMContext = nullptr) |
| 32 | : CodeGenAction(Backend_EmitMCNull, _VMContext) {} |
| 33 | |
| 34 | // The action does not call methods of ATContext. |
| 35 | void ExecuteAction() override { |
| 36 | CompilerInstance &CI = getCompilerInstance(); |
| 37 | if (!CI.hasPreprocessor()) |
| 38 | return; |
| 39 | if (!CI.hasSema()) |
| 40 | CI.createSema(TUKind: getTranslationUnitKind(), CompletionConsumer: nullptr); |
| 41 | } |
| 42 | }; |
| 43 | |
| 44 | |
| 45 | TEST(CodeGenTest, TestNullCodeGen) { |
| 46 | auto Invocation = std::make_shared<CompilerInvocation>(); |
| 47 | Invocation->getPreprocessorOpts().addRemappedFile( |
| 48 | From: "test.cc" , |
| 49 | To: MemoryBuffer::getMemBuffer(InputData: "" ).release()); |
| 50 | Invocation->getFrontendOpts().Inputs.push_back( |
| 51 | Elt: FrontendInputFile("test.cc" , Language::CXX)); |
| 52 | Invocation->getFrontendOpts().ProgramAction = EmitLLVM; |
| 53 | Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu" ; |
| 54 | CompilerInstance Compiler(std::move(Invocation)); |
| 55 | Compiler.createDiagnostics(VFS&: *llvm::vfs::getRealFileSystem()); |
| 56 | EXPECT_TRUE(Compiler.hasDiagnostics()); |
| 57 | |
| 58 | std::unique_ptr<FrontendAction> Act(new NullCodeGenAction); |
| 59 | bool Success = Compiler.ExecuteAction(Act&: *Act); |
| 60 | EXPECT_TRUE(Success); |
| 61 | } |
| 62 | |
| 63 | TEST(CodeGenTest, CodeGenFromIRMemBuffer) { |
| 64 | auto Invocation = std::make_shared<CompilerInvocation>(); |
| 65 | std::unique_ptr<MemoryBuffer> MemBuffer = |
| 66 | MemoryBuffer::getMemBuffer(InputData: "" , BufferName: "test.ll" ); |
| 67 | Invocation->getFrontendOpts().Inputs.push_back( |
| 68 | Elt: FrontendInputFile(*MemBuffer, Language::LLVM_IR)); |
| 69 | Invocation->getFrontendOpts().ProgramAction = frontend::EmitLLVMOnly; |
| 70 | Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu" ; |
| 71 | CompilerInstance Compiler(std::move(Invocation)); |
| 72 | Compiler.createDiagnostics(VFS&: *llvm::vfs::getRealFileSystem()); |
| 73 | EXPECT_TRUE(Compiler.hasDiagnostics()); |
| 74 | |
| 75 | EmitLLVMOnlyAction Action; |
| 76 | bool Success = Compiler.ExecuteAction(Act&: Action); |
| 77 | EXPECT_TRUE(Success); |
| 78 | } |
| 79 | |
| 80 | TEST(CodeGenTest, DebugInfoCWDCodeGen) { |
| 81 | // Check that debug info is accessing the current working directory from the |
| 82 | // VFS instead of calling \p llvm::sys::fs::current_path() directly. |
| 83 | |
| 84 | auto Sept = llvm::sys::path::get_separator(); |
| 85 | auto VFS = std::make_unique<llvm::vfs::InMemoryFileSystem>(); |
| 86 | VFS->setCurrentWorkingDirectory( |
| 87 | std::string(llvm::formatv(Fmt: "{0}in-memory-fs-cwd" , Vals&: Sept))); |
| 88 | std::string TestPath = |
| 89 | std::string(llvm::formatv(Fmt: "{0}in-memory-fs-cwd{0}test.cpp" , Vals&: Sept)); |
| 90 | VFS->addFile(Path: TestPath, ModificationTime: 0, Buffer: llvm::MemoryBuffer::getMemBuffer(InputData: "int x;\n" )); |
| 91 | |
| 92 | auto Invocation = std::make_shared<CompilerInvocation>(); |
| 93 | Invocation->getFrontendOpts().Inputs.push_back( |
| 94 | Elt: FrontendInputFile("test.cpp" , Language::CXX)); |
| 95 | Invocation->getFrontendOpts().ProgramAction = EmitLLVM; |
| 96 | Invocation->getTargetOpts().Triple = "x86_64-unknown-linux-gnu" ; |
| 97 | Invocation->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); |
| 98 | CompilerInstance Compiler(std::move(Invocation)); |
| 99 | |
| 100 | SmallString<256> IRBuffer; |
| 101 | Compiler.setOutputStream(std::make_unique<raw_svector_ostream>(args&: IRBuffer)); |
| 102 | Compiler.createDiagnostics(VFS&: *VFS); |
| 103 | Compiler.createFileManager(VFS: std::move(VFS)); |
| 104 | |
| 105 | EmitLLVMAction Action; |
| 106 | bool Success = Compiler.ExecuteAction(Act&: Action); |
| 107 | EXPECT_TRUE(Success); |
| 108 | |
| 109 | SmallString<128> RealCWD; |
| 110 | llvm::sys::fs::current_path(result&: RealCWD); |
| 111 | EXPECT_TRUE(!RealCWD.empty()); |
| 112 | EXPECT_FALSE(IRBuffer.str().contains(RealCWD)); |
| 113 | EXPECT_TRUE(IRBuffer.str().contains("in-memory-fs-cwd" )); |
| 114 | } |
| 115 | } |
| 116 | |