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 | |