peter klausler | 3338ef9 | 2021-07-23 16:41:04 -0700 | [diff] [blame] | 1 | //===- unittests/Frontend/FrontendActionTest.cpp FrontendAction tests-----===// |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 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 | |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 9 | #include "flang/Frontend/CompilerInstance.h" |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 10 | #include "flang/Frontend/CompilerInvocation.h" |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 11 | #include "flang/Frontend/FrontendOptions.h" |
| 12 | #include "flang/FrontendTool/Utils.h" |
| 13 | #include "llvm/Support/FileSystem.h" |
| 14 | #include "llvm/Support/raw_ostream.h" |
| 15 | |
Andrzej Warzynski | b564b12 | 2021-01-20 18:27:04 +0000 | [diff] [blame] | 16 | #include "gtest/gtest.h" |
| 17 | |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 18 | using namespace Fortran::frontend; |
| 19 | |
| 20 | namespace { |
| 21 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 22 | class FrontendActionTest : public ::testing::Test { |
| 23 | protected: |
| 24 | // AllSources (which is used to manage files inside every compiler |
| 25 | // instance), works with paths. So we need a filename and a path for the |
| 26 | // input file. |
| 27 | // TODO: We could use `-` for inputFilePath_, but then we'd need a way to |
| 28 | // write to stdin that's then read by AllSources. Ideally, AllSources should |
| 29 | // be capable of reading from any stream. |
| 30 | std::string inputFileName_; |
| 31 | std::string inputFilePath_; |
| 32 | // The output stream for the input file. Use this to populate the input. |
| 33 | std::unique_ptr<llvm::raw_fd_ostream> inputFileOs_; |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 34 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 35 | std::error_code ec_; |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 36 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 37 | CompilerInstance compInst_; |
| 38 | std::shared_ptr<CompilerInvocation> invocation_; |
| 39 | |
| 40 | void SetUp() override { |
| 41 | // Generate a unique test file name. |
| 42 | const testing::TestInfo *const test_info = |
| 43 | testing::UnitTest::GetInstance()->current_test_info(); |
Faris Rehman | 443d695 | 2021-01-04 16:49:33 +0000 | [diff] [blame] | 44 | inputFileName_ = std::string(test_info->name()) + "_test-file.f90"; |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 45 | |
| 46 | // Create the input file stream. Note that this stream is populated |
| 47 | // separately in every test (i.e. the input is test specific). |
| 48 | inputFileOs_ = std::make_unique<llvm::raw_fd_ostream>( |
| 49 | inputFileName_, ec_, llvm::sys::fs::OF_None); |
| 50 | if (ec_) |
| 51 | FAIL() << "Failed to create the input file"; |
| 52 | |
| 53 | // Get the path of the input file. |
| 54 | llvm::SmallString<256> cwd; |
| 55 | if (std::error_code ec_ = llvm::sys::fs::current_path(cwd)) |
| 56 | FAIL() << "Failed to obtain the current working directory"; |
| 57 | inputFilePath_ = cwd.c_str(); |
| 58 | inputFilePath_ += "/" + inputFileName_; |
| 59 | |
| 60 | // Prepare the compiler (CompilerInvocation + CompilerInstance) |
| 61 | compInst_.CreateDiagnostics(); |
| 62 | invocation_ = std::make_shared<CompilerInvocation>(); |
| 63 | |
| 64 | compInst_.set_invocation(std::move(invocation_)); |
Andrzej Warzynski | 23d4c4f | 2021-07-29 12:39:10 +0000 | [diff] [blame] | 65 | compInst_.frontendOpts().inputs.push_back( |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 66 | FrontendInputFile(inputFilePath_, Language::Fortran)); |
| 67 | } |
| 68 | |
| 69 | void TearDown() override { |
| 70 | // Clear the input file. |
| 71 | llvm::sys::fs::remove(inputFileName_); |
| 72 | |
| 73 | // Clear the output files. |
| 74 | // Note that these tests use an output buffer (as opposed to an output |
| 75 | // file), hence there are no physical output files to delete and |
| 76 | // `EraseFiles` is set to `false`. Also, some actions (e.g. |
| 77 | // `ParseSyntaxOnly`) don't generated output. In such cases there's no |
| 78 | // output to clear and `ClearOutputFile` returns immediately. |
| 79 | compInst_.ClearOutputFiles(/*EraseFiles=*/false); |
| 80 | } |
| 81 | }; |
| 82 | |
Andrzej Warzynski | b564b12 | 2021-01-20 18:27:04 +0000 | [diff] [blame] | 83 | TEST_F(FrontendActionTest, TestInputOutput) { |
| 84 | // Populate the input file with the pre-defined input and flush it. |
| 85 | *(inputFileOs_) << "End Program arithmetic"; |
| 86 | inputFileOs_.reset(); |
| 87 | |
| 88 | // Set-up the action kind. |
Andrzej Warzynski | 23d4c4f | 2021-07-29 12:39:10 +0000 | [diff] [blame] | 89 | compInst_.invocation().frontendOpts().programAction = InputOutputTest; |
Andrzej Warzynski | b564b12 | 2021-01-20 18:27:04 +0000 | [diff] [blame] | 90 | |
| 91 | // Set-up the output stream. Using output buffer wrapped as an output |
| 92 | // stream, as opposed to an actual file (or a file descriptor). |
| 93 | llvm::SmallVector<char, 256> outputFileBuffer; |
| 94 | std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream( |
| 95 | new llvm::raw_svector_ostream(outputFileBuffer)); |
| 96 | compInst_.set_outputStream(std::move(outputFileStream)); |
| 97 | |
| 98 | // Execute the action. |
| 99 | bool success = ExecuteCompilerInvocation(&compInst_); |
| 100 | |
| 101 | // Validate the expected output. |
| 102 | EXPECT_TRUE(success); |
| 103 | EXPECT_TRUE(!outputFileBuffer.empty()); |
| 104 | EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data()) |
| 105 | .startswith("End Program arithmetic")); |
| 106 | } |
| 107 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 108 | TEST_F(FrontendActionTest, PrintPreprocessedInput) { |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 109 | // Populate the input file with the pre-defined input and flush it. |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 110 | *(inputFileOs_) << "#ifdef NEW\n" |
| 111 | << " Program A \n" |
| 112 | << "#else\n" |
| 113 | << " Program B\n" |
| 114 | << "#endif"; |
| 115 | inputFileOs_.reset(); |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 116 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 117 | // Set-up the action kind. |
Andrzej Warzynski | 23d4c4f | 2021-07-29 12:39:10 +0000 | [diff] [blame] | 118 | compInst_.invocation().frontendOpts().programAction = PrintPreprocessedInput; |
peter klausler | 3338ef9 | 2021-07-23 16:41:04 -0700 | [diff] [blame] | 119 | compInst_.invocation().preprocessorOpts().noReformat = true; |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 120 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 121 | // Set-up the output stream. We are using output buffer wrapped as an output |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 122 | // stream, as opposed to an actual file (or a file descriptor). |
| 123 | llvm::SmallVector<char, 256> outputFileBuffer; |
| 124 | std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream( |
| 125 | new llvm::raw_svector_ostream(outputFileBuffer)); |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 126 | compInst_.set_outputStream(std::move(outputFileStream)); |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 127 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 128 | // Execute the action. |
| 129 | bool success = ExecuteCompilerInvocation(&compInst_); |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 130 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 131 | // Validate the expected output. |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 132 | EXPECT_TRUE(success); |
| 133 | EXPECT_TRUE(!outputFileBuffer.empty()); |
| 134 | EXPECT_TRUE( |
| 135 | llvm::StringRef(outputFileBuffer.data()).startswith("program b\n")); |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 136 | } |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 137 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 138 | TEST_F(FrontendActionTest, ParseSyntaxOnly) { |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 139 | // Populate the input file with the pre-defined input and flush it. |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 140 | *(inputFileOs_) << "IF (A > 0.0) IF (B < 0.0) A = LOG (A)\n" |
| 141 | << "END"; |
| 142 | inputFileOs_.reset(); |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 143 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 144 | // Set-up the action kind. |
Andrzej Warzynski | 23d4c4f | 2021-07-29 12:39:10 +0000 | [diff] [blame] | 145 | compInst_.invocation().frontendOpts().programAction = ParseSyntaxOnly; |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 146 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 147 | // Set-up the output stream for the semantic diagnostics. |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 148 | llvm::SmallVector<char, 256> outputDiagBuffer; |
| 149 | std::unique_ptr<llvm::raw_pwrite_stream> outputStream( |
| 150 | new llvm::raw_svector_ostream(outputDiagBuffer)); |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 151 | compInst_.set_semaOutputStream(std::move(outputStream)); |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 152 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 153 | // Execute the action. |
| 154 | bool success = ExecuteCompilerInvocation(&compInst_); |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 155 | |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 156 | // Validate the expected output. |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 157 | EXPECT_FALSE(success); |
| 158 | EXPECT_TRUE(!outputDiagBuffer.empty()); |
| 159 | EXPECT_TRUE( |
| 160 | llvm::StringRef(outputDiagBuffer.data()) |
peter klausler | 6110e77 | 2021-01-26 13:57:44 -0800 | [diff] [blame] | 161 | .contains( |
Andrzej Warzynski | 44e74c7 | 2020-12-22 11:07:58 +0000 | [diff] [blame] | 162 | ":1:14: error: IF statement is not allowed in IF statement\n")); |
Andrzej Warzynski | 7d246cb | 2020-12-08 16:27:46 +0000 | [diff] [blame] | 163 | } |
Caroline Concatto | d28de0d | 2020-10-27 12:26:47 +0000 | [diff] [blame] | 164 | } // namespace |