//===- unittest/Format/FormatTestVerilog.cpp ------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "FormatTestUtils.h" #include "clang/Format/Format.h" #include "llvm/Support/Debug.h" #include "gtest/gtest.h" #define DEBUG_TYPE "format-test" namespace clang { namespace format { class FormatTestVerilog : public ::testing::Test { protected: static std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length, const FormatStyle &Style) { LLVM_DEBUG(llvm::errs() << "---\n"); LLVM_DEBUG(llvm::errs() << Code << "\n\n"); std::vector Ranges(1, tooling::Range(Offset, Length)); tooling::Replacements Replaces = reformat(Style, Code, Ranges); auto Result = applyAllReplacements(Code, Replaces); EXPECT_TRUE(static_cast(Result)); LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); return *Result; } static std::string format(llvm::StringRef Code, const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) { return format(Code, 0, Code.size(), Style); } static void verifyFormat( llvm::StringRef Code, const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) { EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; EXPECT_EQ(Code.str(), format(test::messUp(Code, /*HandleHash=*/false), Style)); } }; TEST_F(FormatTestVerilog, BasedLiteral) { verifyFormat("x = '0;"); verifyFormat("x = '1;"); verifyFormat("x = 'X;"); verifyFormat("x = 'x;"); verifyFormat("x = 'Z;"); verifyFormat("x = 'z;"); verifyFormat("x = 659;"); verifyFormat("x = 'h837ff;"); verifyFormat("x = 'o7460;"); verifyFormat("x = 4'b1001;"); verifyFormat("x = 5'D3;"); verifyFormat("x = 3'b01x;"); verifyFormat("x = 12'hx;"); verifyFormat("x = 16'hz;"); verifyFormat("x = -8'd6;"); verifyFormat("x = 4'shf;"); verifyFormat("x = -4'sd15;"); verifyFormat("x = 16'sd?;"); } TEST_F(FormatTestVerilog, Block) { verifyFormat("begin\n" " x = x;\n" "end"); verifyFormat("begin : x\n" " x = x;\n" "end : x"); verifyFormat("begin\n" " x = x;\n" " x = x;\n" "end"); verifyFormat("fork\n" " x = x;\n" "join"); verifyFormat("fork\n" " x = x;\n" "join_any"); verifyFormat("fork\n" " x = x;\n" "join_none"); verifyFormat("generate\n" " x = x;\n" "endgenerate"); verifyFormat("generate : x\n" " x = x;\n" "endgenerate : x"); // Nested blocks. verifyFormat("begin\n" " begin\n" " end\n" "end"); verifyFormat("begin : x\n" " begin\n" " end\n" "end : x"); verifyFormat("begin : x\n" " begin : x\n" " end : x\n" "end : x"); verifyFormat("begin\n" " begin : x\n" " end : x\n" "end"); // Test that 'disable fork' and 'rand join' don't get mistaken as blocks. verifyFormat("disable fork;\n" "x = x;"); verifyFormat("rand join x x;\n" "x = x;"); } TEST_F(FormatTestVerilog, Delay) { // Delay by the default unit. verifyFormat("#0;"); verifyFormat("#1;"); verifyFormat("#10;"); verifyFormat("#1.5;"); // Explicit unit. verifyFormat("#1fs;"); verifyFormat("#1.5fs;"); verifyFormat("#1ns;"); verifyFormat("#1.5ns;"); verifyFormat("#1us;"); verifyFormat("#1.5us;"); verifyFormat("#1ms;"); verifyFormat("#1.5ms;"); verifyFormat("#1s;"); verifyFormat("#1.5s;"); // The following expression should be on the same line. verifyFormat("#1 x = x;"); EXPECT_EQ("#1 x = x;", format("#1\n" "x = x;")); } TEST_F(FormatTestVerilog, If) { verifyFormat("if (x)\n" " x = x;"); verifyFormat("if (x)\n" " x = x;\n" "x = x;"); // Test else verifyFormat("if (x)\n" " x = x;\n" "else if (x)\n" " x = x;\n" "else\n" " x = x;"); verifyFormat("if (x) begin\n" " x = x;\n" "end else if (x) begin\n" " x = x;\n" "end else begin\n" " x = x;\n" "end"); verifyFormat("if (x) begin : x\n" " x = x;\n" "end : x else if (x) begin : x\n" " x = x;\n" "end : x else begin : x\n" " x = x;\n" "end : x"); // Test block keywords. verifyFormat("if (x) begin\n" " x = x;\n" "end"); verifyFormat("if (x) begin : x\n" " x = x;\n" "end : x"); verifyFormat("if (x) begin\n" " x = x;\n" " x = x;\n" "end"); verifyFormat("if (x) fork\n" " x = x;\n" "join"); verifyFormat("if (x) fork\n" " x = x;\n" "join_any"); verifyFormat("if (x) fork\n" " x = x;\n" "join_none"); verifyFormat("if (x) generate\n" " x = x;\n" "endgenerate"); verifyFormat("if (x) generate : x\n" " x = x;\n" "endgenerate : x"); // Test that concatenation braces don't get regarded as blocks. verifyFormat("if (x)\n" " {x} = x;"); verifyFormat("if (x)\n" " x = {x};"); verifyFormat("if (x)\n" " x = {x};\n" "else\n" " {x} = {x};"); } TEST_F(FormatTestVerilog, Operators) { // Test that unary operators are not followed by space. verifyFormat("x = +x;"); verifyFormat("x = -x;"); verifyFormat("x = !x;"); verifyFormat("x = ~x;"); verifyFormat("x = &x;"); verifyFormat("x = ~&x;"); verifyFormat("x = |x;"); verifyFormat("x = ~|x;"); verifyFormat("x = ^x;"); verifyFormat("x = ~^x;"); verifyFormat("x = ^~x;"); verifyFormat("x = ++x;"); verifyFormat("x = --x;"); // Test that operators don't get split. verifyFormat("x = x++;"); verifyFormat("x = x--;"); verifyFormat("x = x ** x;"); verifyFormat("x = x << x;"); verifyFormat("x = x >> x;"); verifyFormat("x = x <<< x;"); verifyFormat("x = x >>> x;"); verifyFormat("x = x <= x;"); verifyFormat("x = x >= x;"); verifyFormat("x = x == x;"); verifyFormat("x = x != x;"); verifyFormat("x = x === x;"); verifyFormat("x = x !== x;"); verifyFormat("x = x ==? x;"); verifyFormat("x = x !=? x;"); verifyFormat("x = x ~^ x;"); verifyFormat("x = x ^~ x;"); verifyFormat("x = x && x;"); verifyFormat("x = x || x;"); verifyFormat("x = x->x;"); verifyFormat("x = x <-> x;"); verifyFormat("x += x;"); verifyFormat("x -= x;"); verifyFormat("x *= x;"); verifyFormat("x /= x;"); verifyFormat("x %= x;"); verifyFormat("x &= x;"); verifyFormat("x ^= x;"); verifyFormat("x |= x;"); verifyFormat("x <<= x;"); verifyFormat("x >>= x;"); verifyFormat("x <<<= x;"); verifyFormat("x >>>= x;"); verifyFormat("x <= x;"); // Test that space is added between operators. EXPECT_EQ("x = x < -x;", format("x=x<-x;")); EXPECT_EQ("x = x << -x;", format("x=x<<-x;")); EXPECT_EQ("x = x <<< -x;", format("x=x<<<-x;")); } TEST_F(FormatTestVerilog, Preprocessor) { auto Style = getLLVMStyle(FormatStyle::LK_Verilog); Style.ColumnLimit = 20; // Macro definitions. EXPECT_EQ("`define X \\\n" " if (x) \\\n" " x = x;", format("`define X if(x)x=x;", Style)); EXPECT_EQ("`define X(x) \\\n" " if (x) \\\n" " x = x;", format("`define X(x) if(x)x=x;", Style)); EXPECT_EQ("`define X \\\n" " x = x; \\\n" " x = x;", format("`define X x=x;x=x;", Style)); // Macro definitions with invocations inside. EXPECT_EQ("`define LIST \\\n" " `ENTRY \\\n" " `ENTRY", format("`define LIST \\\n" "`ENTRY \\\n" "`ENTRY", Style)); EXPECT_EQ("`define LIST \\\n" " `x = `x; \\\n" " `x = `x;", format("`define LIST \\\n" "`x = `x; \\\n" "`x = `x;", Style)); EXPECT_EQ("`define LIST \\\n" " `x = `x; \\\n" " `x = `x;", format("`define LIST `x=`x;`x=`x;", Style)); // Macro invocations. verifyFormat("`x = (`x1 + `x2 + x);"); // Lines starting with a preprocessor directive should not be indented. std::string Directives[] = { "begin_keywords", "celldefine", "default_nettype", "define", "else", "elsif", "end_keywords", "endcelldefine", "endif", "ifdef", "ifndef", "include", "line", "nounconnected_drive", "pragma", "resetall", "timescale", "unconnected_drive", "undef", "undefineall", }; for (auto &Name : Directives) { EXPECT_EQ("if (x)\n" "`" + Name + "\n" " ;", format("if (x)\n" "`" + Name + "\n" ";", Style)); } // Lines starting with a regular macro invocation should be indented as a // normal line. EXPECT_EQ("if (x)\n" " `x = `x;\n" "`timescale 1ns / 1ps", format("if (x)\n" "`x = `x;\n" "`timescale 1ns / 1ps", Style)); EXPECT_EQ("if (x)\n" "`timescale 1ns / 1ps\n" " `x = `x;", format("if (x)\n" "`timescale 1ns / 1ps\n" "`x = `x;", Style)); std::string NonDirectives[] = { // For `__FILE__` and `__LINE__`, although the standard classifies them as // preprocessor directives, they are used like regular macros. "__FILE__", "__LINE__", "elif", "foo", "x", }; for (auto &Name : NonDirectives) { EXPECT_EQ("if (x)\n" " `" + Name + ";", format("if (x)\n" "`" + Name + "\n" ";", Style)); } } } // namespace format } // end namespace clang