//===- 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 "FormatTestBase.h"

#define DEBUG_TYPE "format-test"

namespace clang {
namespace format {
namespace test {
namespace {
class FormatTestVerilog : public test::FormatTestBase {
protected:
  FormatStyle getDefaultStyle() const override {
    return getLLVMStyle(FormatStyle::LK_Verilog);
  }
  std::string messUp(StringRef Code) const override {
    return test::messUp(Code, /*HandleHash=*/false);
  }
};

TEST_F(FormatTestVerilog, Align) {
  FormatStyle Style = getDefaultStyle();
  Style.AlignConsecutiveAssignments.Enabled = true;
  verifyFormat("x            <= x;\n"
               "sfdbddfbdfbb <= x;\n"
               "x             = x;",
               Style);
  verifyFormat("x            = x;\n"
               "sfdbddfbdfbb = x;\n"
               "x            = x;",
               Style);
  // Compound assignments are not aligned by default. '<=' is not a compound
  // assignment.
  verifyFormat("x            <= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x += x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x <<= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x <<<= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x >>= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x >>>= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  Style.AlignConsecutiveAssignments.AlignCompound = true;
  verifyFormat("x            <= x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x            += x;\n"
               "sfdbddfbdfbb <= x;",
               Style);
  verifyFormat("x            <<= x;\n"
               "sfdbddfbdfbb  <= x;",
               Style);
  verifyFormat("x            <<<= x;\n"
               "sfdbddfbdfbb   <= x;",
               Style);
  verifyFormat("x            >>= x;\n"
               "sfdbddfbdfbb  <= x;",
               Style);
  verifyFormat("x            >>>= x;\n"
               "sfdbddfbdfbb   <= x;",
               Style);
}

TEST_F(FormatTestVerilog, Assign) {
  verifyFormat("assign mynet = enable;");
  verifyFormat("assign (strong1, pull0) #1 mynet = enable;");
  verifyFormat("assign #1 mynet = enable;");
  verifyFormat("assign mynet = enable;");
  // Test that assignments are on separate lines.
  verifyFormat("assign mynet = enable,\n"
               "       mynet1 = enable1;");
  // Test that `<=` and `,` don't confuse it.
  verifyFormat("assign mynet = enable1 <= enable2;");
  verifyFormat("assign mynet = enable1 <= enable2,\n"
               "       mynet1 = enable3;");
  verifyFormat("assign mynet = enable,\n"
               "       mynet1 = enable2 <= enable3;");
  verifyFormat("assign mynet = enable(enable1, enable2);");
}

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;");
  // The begin keyword should not be indented if it is too long to fit on the
  // same line.
  verifyFormat("while (true) //\n"
               "begin\n"
               "  while (true) //\n"
               "  begin\n"
               "  end\n"
               "end");
  verifyFormat("while (true) //\n"
               "begin : x\n"
               "  while (true) //\n"
               "  begin : x\n"
               "  end : x\n"
               "end : x");
  verifyFormat("while (true) //\n"
               "fork\n"
               "  while (true) //\n"
               "  fork\n"
               "  join\n"
               "join");
  auto Style = getDefaultStyle();
  Style.ColumnLimit = 17;
  verifyFormat("while (true)\n"
               "begin\n"
               "  while (true)\n"
               "  begin\n"
               "  end\n"
               "end",
               "while (true) begin\n"
               "  while (true) begin"
               "  end\n"
               "end",
               Style);
}

TEST_F(FormatTestVerilog, Case) {
  verifyFormat("case (data)\n"
               "endcase");
  verifyFormat("casex (data)\n"
               "endcase");
  verifyFormat("casez (data)\n"
               "endcase");
  verifyFormat("case (data) inside\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result = 10'b0111111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  xxxxxxxx:\n"
               "    result = 10'b0111111111;\n"
               "endcase");
  // Test labels with multiple options.
  verifyFormat("case (data)\n"
               "  16'd0, 16'd1:\n"
               "    result = 10'b0111111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0, //\n"
               "      16'd1:\n"
               "    result = 10'b0111111111;\n"
               "endcase");
  // Test that blocks following labels are indented.
  verifyFormat("case (data)\n"
               "  16'd1: fork\n"
               "    result = 10'b1011111111;\n"
               "  join\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd1: fork : x\n"
               "    result = 10'b1011111111;\n"
               "  join : x\n"
               "endcase");
  // Test default.
  verifyFormat("case (data)\n"
               "  default\n"
               "    result = 10'b1011111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  default:\n"
               "    result = 10'b1011111111;\n"
               "endcase");
  // Test that question marks and colons don't get mistaken as labels.
  verifyFormat("case (data)\n"
               "  8'b1???????:\n"
               "    instruction1(ir);\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  x ? 8'b1??????? : 1:\n"
               "    instruction3(ir);\n"
               "endcase");
  // Test indention options.
  auto Style = getDefaultStyle();
  Style.IndentCaseLabels = false;
  verifyFormat("case (data)\n"
               "16'd0:\n"
               "  result = 10'b0111111111;\n"
               "endcase",
               Style);
  verifyFormat("case (data)\n"
               "16'd0: begin\n"
               "  result = 10'b0111111111;\n"
               "end\n"
               "endcase",
               Style);
  Style.IndentCaseLabels = true;
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result = 10'b0111111111;\n"
               "endcase",
               Style);
  verifyFormat("case (data)\n"
               "  16'd0: begin\n"
               "    result = 10'b0111111111;\n"
               "  end\n"
               "endcase",
               Style);
  // Other colons should not be mistaken as case colons.
  Style = getDefaultStyle();
  Style.BitFieldColonSpacing = FormatStyle::BFCS_None;
  verifyFormat("case (x[1:0])\n"
               "endcase",
               Style);
  verifyFormat("default:\n"
               "  x[1:0] = x[1:0];",
               Style);
  Style.BitFieldColonSpacing = FormatStyle::BFCS_Both;
  verifyFormat("case (x[1 : 0])\n"
               "endcase",
               Style);
  verifyFormat("default:\n"
               "  x[1 : 0] = x[1 : 0];",
               Style);
  Style = getDefaultStyle();
  Style.SpacesInContainerLiterals = true;
  verifyFormat("case ('{x : x, default : 9})\n"
               "endcase",
               Style);
  verifyFormat("x = '{x : x, default : 9};", Style);
  verifyFormat("default:\n"
               "  x = '{x : x, default : 9};",
               Style);
  Style.SpacesInContainerLiterals = false;
  verifyFormat("case ('{x: x, default: 9})\n"
               "endcase",
               Style);
  verifyFormat("x = '{x: x, default: 9};", Style);
  verifyFormat("default:\n"
               "  x = '{x: x, default: 9};",
               Style);
  // When the line following the case label needs to be broken, the continuation
  // should be indented correctly.
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result = //\n"
               "        10'b0111111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0, //\n"
               "      16'd1:\n"
               "    result = //\n"
               "        10'b0111111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result = (10'b0111111111 + //\n"
               "              10'b0111111111 + //\n"
               "              10'b0111111111);\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result =              //\n"
               "        (10'b0111111111 + //\n"
               "         10'b0111111111 + //\n"
               "         10'b0111111111);\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result =          //\n"
               "        longfunction( //\n"
               "            arg);\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    //\n"
               "    result = //\n"
               "        10'b0111111111;\n"
               "endcase");
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    //\n"
               "\n"
               "    //\n"
               "    result = //\n"
               "        10'b0111111111;\n"
               "endcase");
  Style = getDefaultStyle();
  Style.ContinuationIndentWidth = 1;
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result = //\n"
               "     10'b0111111111;\n"
               "endcase",
               Style);
  verifyFormat("case (data)\n"
               "  16'd0:\n"
               "    result =       //\n"
               "     longfunction( //\n"
               "      arg);\n"
               "endcase",
               Style);

  verifyFormat("case (v) matches\n"
               "  tagged Valid .n:\n"
               "    ;\n"
               "endcase");
}

TEST_F(FormatTestVerilog, Coverage) {
  verifyFormat("covergroup x\n"
               "    @@(begin x);\n"
               "endgroup");
}

TEST_F(FormatTestVerilog, Declaration) {
  verifyFormat("wire mynet;");
  verifyFormat("wire mynet, mynet1;");
  verifyFormat("wire mynet, //\n"
               "     mynet1;");
  verifyFormat("wire #0 mynet, mynet1;");
  verifyFormat("wire logic #0 mynet, mynet1;");
  verifyFormat("wire #(1, 2, 3) mynet, mynet1;");
  verifyFormat("wire #0 mynet, //\n"
               "        mynet1;");
  verifyFormat("wire logic #0 mynet, //\n"
               "              mynet1;");
  verifyFormat("wire #(1, 2, 3) mynet, //\n"
               "                mynet1;");
  verifyFormat("wire mynet = enable;");
  verifyFormat("wire mynet = enable, mynet1;");
  verifyFormat("wire mynet = enable, //\n"
               "     mynet1;");
  verifyFormat("wire mynet, mynet1 = enable;");
  verifyFormat("wire mynet, //\n"
               "     mynet1 = enable;");
  verifyFormat("wire mynet = enable, mynet1 = enable;");
  verifyFormat("wire mynet = enable, //\n"
               "     mynet1 = enable;");
  verifyFormat("wire (strong1, pull0) mynet;");
  verifyFormat("wire (strong1, pull0) mynet, mynet1;");
  verifyFormat("wire (strong1, pull0) mynet, //\n"
               "                      mynet1;");
  verifyFormat("wire (strong1, pull0) mynet = enable;");
  verifyFormat("wire (strong1, pull0) mynet = enable, mynet1;");
  verifyFormat("wire (strong1, pull0) mynet = enable, //\n"
               "                      mynet1;");
  verifyFormat("wire (strong1, pull0) mynet, mynet1 = enable;");
  verifyFormat("wire (strong1, pull0) mynet, //\n"
               "                      mynet1 = enable;");
}

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;");
  verifyFormat("#1 x = x;", "#1\n"
                            "x = x;");
}

TEST_F(FormatTestVerilog, Enum) {
  verifyFormat("enum { x } x;");
  verifyFormat("typedef enum { x } x;");
  verifyFormat("enum { red, yellow, green } x;");
  verifyFormat("typedef enum { red, yellow, green } x;");
  verifyFormat("enum integer { x } x;");
  verifyFormat("typedef enum { x = 0 } x;");
  verifyFormat("typedef enum { red = 0, yellow = 1, green = 2 } x;");
  verifyFormat("typedef enum integer { x } x;");
  verifyFormat("typedef enum bit [0 : 1] { x } x;");
  verifyFormat("typedef enum { add = 10, sub[5], jmp[6 : 8] } E1;");
  verifyFormat("typedef enum { add = 10, sub[5] = 0, jmp[6 : 8] = 1 } E1;");
}

TEST_F(FormatTestVerilog, Headers) {
  // Test headers with multiple ports.
  verifyFormat("module mh1\n"
               "    (input var int in1,\n"
               "     input var shortreal in2,\n"
               "     output tagged_st out);\n"
               "endmodule");
  // There should be a space following the type but not the variable name.
  verifyFormat("module test\n"
               "    (input wire [7 : 0] a,\n"
               "     input wire b[7 : 0],\n"
               "     input wire [7 : 0] c[7 : 0]);\n"
               "endmodule");
  // Ports should be grouped by types.
  verifyFormat("module test\n"
               "    (input [7 : 0] a,\n"
               "     input signed [7 : 0] b, c, d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input [7 : 0] a,\n"
               "     (* x = x *) input signed [7 : 0] b, c, d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input [7 : 0] a = 0,\n"
               "     input signed [7 : 0] b = 0, c = 0, d = 0);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    #(parameter x)\n"
               "    (input [7 : 0] a,\n"
               "     input signed [7 : 0] b, c, d);\n"
               "endmodule");
  // When a line needs to be broken, ports of the same type should be aligned to
  // the same column.
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b, c, //\n"
               "                          d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    ((* x = x *) input signed [7 : 0] b, c, //\n"
               "                                      d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b = 0, c, //\n"
               "                          d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b, c = 0, //\n"
               "                          d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b, c, //\n"
               "                          d = 0);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input wire logic signed [7 : 0][0 : 1] b, c, //\n"
               "                                            d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b, //\n"
               "                          c, //\n"
               "                          d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input [7 : 0] a,\n"
               "     input signed [7 : 0] b, //\n"
               "                          c, //\n"
               "                          d);\n"
               "endmodule");
  verifyFormat("module test\n"
               "    (input signed [7 : 0] b, //\n"
               "                          c, //\n"
               "                          d,\n"
               "     output signed [7 : 0] h);\n"
               "endmodule");
  // With a modport.
  verifyFormat("module m\n"
               "    (i2.master i);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2.master i, ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2.master i, //\n"
               "               ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2.master i,\n"
               "     input ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2.master i);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2.master i, ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2.master i, //\n"
               "                   ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2.master i,\n"
               "     input ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2 i);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2 i, ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2 i, //\n"
               "            ii);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (i2::i2 i,\n"
               "     input ii);\n"
               "endmodule");
  // With a macro in the names.
  verifyFormat("module m\n"
               "    (input var `x a, b);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (input var `x a, //\n"
               "                  b);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (input var x `a, b);\n"
               "endmodule");
  verifyFormat("module m\n"
               "    (input var x `a, //\n"
               "                 b);\n"
               "endmodule");
  // A line comment shouldn't disrupt the indentation of the port list.
  verifyFormat("extern module x\n"
               "    (//\n"
               "     output y);");
  verifyFormat("extern module x\n"
               "    #(//\n"
               "      parameter x)\n"
               "    (//\n"
               "     output y);");
  // With a concatenation in the names.
  auto Style = getDefaultStyle();
  Style.ColumnLimit = 40;
  verifyFormat("`define X(x)                           \\\n"
               "  module test                          \\\n"
               "      (input var x``x a, b);",
               Style);
  verifyFormat("`define X(x)                           \\\n"
               "  module test                          \\\n"
               "      (input var x``x aaaaaaaaaaaaaaa, \\\n"
               "                      b);",
               Style);
  verifyFormat("`define X(x)                           \\\n"
               "  module test                          \\\n"
               "      (input var x a``x, b);",
               Style);
  verifyFormat("`define X(x)                           \\\n"
               "  module test                          \\\n"
               "      (input var x aaaaaaaaaaaaaaa``x, \\\n"
               "                   b);",
               Style);
  // When the ports line is not to be formatted, following lines should not take
  // on its indentation.
  verifyFormat("module x\n"
               "    (output x);\n"
               "  assign x = 0;\n"
               "endmodule",
               "module x\n"
               "    (output x);\n"
               "    assign x = 0;\n"
               "endmodule",
               getDefaultStyle(), {tooling::Range(25, 18)});
}

TEST_F(FormatTestVerilog, Hierarchy) {
  verifyFormat("module x;\n"
               "endmodule");
  // Test that the end label is on the same line as the end keyword.
  verifyFormat("module x;\n"
               "endmodule : x");
  // Test that things inside are indented.
  verifyFormat("module x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endmodule");
  verifyFormat("program x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endprogram");
  verifyFormat("interface x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endinterface");
  verifyFormat("task x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endtask");
  verifyFormat("function x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endfunction");
  verifyFormat("class x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endclass");
  // Test that they nest.
  verifyFormat("module x;\n"
               "  program x;\n"
               "    program x;\n"
               "    endprogram\n"
               "  endprogram\n"
               "endmodule");
  // Test that an extern declaration doesn't change the indentation.
  verifyFormat("extern module x;\n"
               "x = x;");
  // Test complex headers
  verifyFormat("extern module x\n"
               "    import x.x::x::*;\n"
               "    import x;\n"
               "    #(parameter x)\n"
               "    (output x);");
  verifyFormat("module x\n"
               "    import x.x::x::*;\n"
               "    import x;\n"
               "    #(parameter x)\n"
               "    (output x);\n"
               "  generate\n"
               "  endgenerate\n"
               "endmodule : x");
  verifyFormat("virtual class x\n"
               "    (x)\n"
               "    extends x(x)\n"
               "    implements x, x, x;\n"
               "  generate\n"
               "  endgenerate\n"
               "endclass : x");
  verifyFormat("function automatic logic [1 : 0] x\n"
               "    (input x);\n"
               "  generate\n"
               "  endgenerate\n"
               "endfunction : x");
  // Type names with '::' should be recognized.
  verifyFormat("function automatic x::x x\n"
               "    (input x);\n"
               "endfunction : x");
  // Names having to do macros should be recognized.
  verifyFormat("function automatic x::x x``x\n"
               "    (input x);\n"
               "endfunction : x");
  verifyFormat("function automatic x::x `x\n"
               "    (input x);\n"
               "endfunction : x");
  verifyNoCrash("x x(x x, x x);");
}

TEST_F(FormatTestVerilog, Identifiers) {
  // Escaped identifiers should not be split.
  verifyFormat("\\busa+index");
  verifyFormat("\\-clock");
  verifyFormat("\\***error-condition***");
  verifyFormat("\\net1\\/net2");
  verifyFormat("\\{a,b}");
  verifyFormat("\\a*(b+c)");
  // Escaped identifiers can't be joined with the next token.  Extra space
  // should be removed.
  verifyFormat("\\busa+index ;", "\\busa+index\n"
                                 ";");
  verifyFormat("\\busa+index ;", "\\busa+index\r\n"
                                 ";");
  verifyFormat("\\busa+index ;", "\\busa+index  ;");
  verifyFormat("\\busa+index ;", "\\busa+index\n"
                                 " ;");
  verifyFormat("\\busa+index ;");
  verifyFormat("(\\busa+index );");
  verifyFormat("\\busa+index \\busa+index ;");
}

TEST_F(FormatTestVerilog, If) {
  verifyFormat("if (x)\n"
               "  x = x;");
  verifyFormat("unique if (x)\n"
               "  x = x;");
  verifyFormat("unique0 if (x)\n"
               "  x = x;");
  verifyFormat("priority 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};");

  // With attributes.
  verifyFormat("(* x *) if (x)\n"
               "  x = x;");
  verifyFormat("(* x = \"x\" *) if (x)\n"
               "  x = x;");
  verifyFormat("(* x, x = \"x\" *) if (x)\n"
               "  x = x;");

  // Assert are treated similar to if.  But the else parts should not be
  // chained.
  verifyFormat("assert (x);");
  verifyFormat("assert (x)\n"
               "  $info();");
  verifyFormat("assert (x)\n"
               "  $info();\n"
               "else\n"
               "  $error();");
  verifyFormat("assert (x)\n"
               "else\n"
               "  $error();");
  verifyFormat("assert (x)\n"
               "else begin\n"
               "end");
  verifyFormat("assert (x)\n"
               "else\n"
               "  if (x)\n"
               "    $error();");
  verifyFormat("assert (x)\n"
               "  $info();\n"
               "else\n"
               "  if (x)\n"
               "    $error();");
  verifyFormat("assert (x)\n"
               "  $info();\n"
               "else\n"
               "  if (x)\n"
               "    $error();\n"
               "  else\n"
               "    $error();");
  verifyFormat("assert (x)\n"
               "  $info();\n"
               "else\n"
               "  if (x)\n"
               "    $error();\n"
               "  else if (x)\n"
               "    $error();\n"
               "  else\n"
               "    $error();");
  // The body is optional for asserts.  The next line should not be indented if
  // the statement already ended with a semicolon.
  verifyFormat("assert (x);\n"
               "x = x;");
  verifyFormat("if (x)\n"
               "  assert (x);\n"
               "else if (x) begin\n"
               "end else begin\n"
               "end");
  verifyFormat("if (x)\n"
               "  assert (x);\n"
               "else begin\n"
               "end");
  verifyFormat("if (x)\n"
               "  assert (x)\n"
               "  else begin\n"
               "  end");
  // Other keywords.
  verifyFormat("assume (x)\n"
               "  $info();");
  verifyFormat("cover (x)\n"
               "  $info();");
  verifyFormat("restrict (x)\n"
               "  $info();");
  verifyFormat("assert #0 (x)\n"
               "  $info();");
  verifyFormat("assert final (x)\n"
               "  $info();");
  verifyFormat("cover #0 (x)\n"
               "  $info();");
  verifyFormat("cover final (x)\n"
               "  $info();");

  // The space around parentheses options should work.
  auto Style = getDefaultStyle();
  verifyFormat("if (x)\n"
               "  x = x;\n"
               "else if (x)\n"
               "  x = x;",
               Style);
  verifyFormat("assert (x);", Style);
  verifyFormat("assert #0 (x);", Style);
  verifyFormat("assert (x)\n"
               "else\n"
               "  if (x)\n"
               "    x = x;",
               Style);
  Style.SpacesInParens = FormatStyle::SIPO_Custom;
  Style.SpacesInParensOptions.InConditionalStatements = true;
  verifyFormat("if ( x )\n"
               "  x = x;\n"
               "else if ( x )\n"
               "  x = x;",
               Style);
  verifyFormat("assert ( x );", Style);
  verifyFormat("assert #0 ( x );", Style);
  verifyFormat("assert ( x )\n"
               "else\n"
               "  if ( x )\n"
               "    x = x;",
               Style);
}

TEST_F(FormatTestVerilog, Instantiation) {
  // Without ports.
  verifyFormat("ffnand ff1;");
  // With named ports.
  verifyFormat("ffnand ff1(.qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2));");
  // With wildcard.
  verifyFormat("ffnand ff1(.qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2),\n"
               "           .*);");
  verifyFormat("ffnand ff1(.*,\n"
               "           .qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2));");
  // With unconnected ports.
  verifyFormat("ffnand ff1(.q(),\n"
               "           .qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2));");
  verifyFormat("ffnand ff1(.q(),\n"
               "           .qbar(),\n"
               "           .clear(),\n"
               "           .preset());");
  verifyFormat("ffnand ff1(,\n"
               "           .qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2));");
  // With positional ports.
  verifyFormat("ffnand ff1(out1,\n"
               "           in1,\n"
               "           in2);");
  verifyFormat("ffnand ff1(,\n"
               "           out1,\n"
               "           in1,\n"
               "           in2);");
  // Multiple instantiations.
  verifyFormat("ffnand ff1(.q(),\n"
               "           .qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2)),\n"
               "       ff1(.q(),\n"
               "           .qbar(out1),\n"
               "           .clear(in1),\n"
               "           .preset(in2));");
  verifyFormat("ffnand //\n"
               "    ff1(.q(),\n"
               "        .qbar(out1),\n"
               "        .clear(in1),\n"
               "        .preset(in2)),\n"
               "    ff1(.q(),\n"
               "        .qbar(out1),\n"
               "        .clear(in1),\n"
               "        .preset(in2));");
  verifyNoCrash(", ff1();");
  // With breaking between instance ports disabled.
  auto Style = getDefaultStyle();
  Style.VerilogBreakBetweenInstancePorts = false;
  verifyFormat("ffnand ff1;", Style);
  verifyFormat("ffnand ff1(.qbar(out1), .clear(in1), .preset(in2), .*);",
               Style);
  verifyFormat("ffnand ff1(out1, in1, in2);", Style);
  verifyFormat("ffnand ff1(.q(), .qbar(out1), .clear(in1), .preset(in2)),\n"
               "       ff1(.q(), .qbar(out1), .clear(in1), .preset(in2));",
               Style);
  verifyFormat("ffnand //\n"
               "    ff1(.q(), .qbar(out1), .clear(in1), .preset(in2)),\n"
               "    ff1(.q(), .qbar(out1), .clear(in1), .preset(in2));",
               Style);
}

TEST_F(FormatTestVerilog, Loop) {
  verifyFormat("foreach (x[x])\n"
               "  x = x;");
  verifyFormat("repeat (x)\n"
               "  x = x;");
  verifyFormat("foreach (x[x]) begin\n"
               "end");
  verifyFormat("repeat (x) begin\n"
               "end");
  auto Style = getDefaultStyle();
  Style.SpacesInParens = FormatStyle::SIPO_Custom;
  Style.SpacesInParensOptions.InConditionalStatements = true;
  verifyFormat("foreach ( x[x] )\n"
               "  x = x;",
               Style);
  verifyFormat("repeat ( x )\n"
               "  x = x;",
               Style);
}

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 `*` and `*>` are binary.
  verifyFormat("x = x * x;");
  verifyFormat("x = (x * x);");
  verifyFormat("(opcode *> o1) = 6.1;");
  verifyFormat("(C, D *> Q) = 18;");
  // The wildcard import is not a binary operator.
  verifyFormat("import p::*;");

  // 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.
  verifyFormat("x = x < -x;", "x=x<-x;");
  verifyFormat("x = x << -x;", "x=x<<-x;");
  verifyFormat("x = x <<< -x;", "x=x<<<-x;");

  // Test that operators that are C++ identifiers get treated as operators.
  verifyFormat("solve s before d;");                       // before
  verifyFormat("binsof(i) intersect {0};");                // intersect
  verifyFormat("req dist {1};");                           // dist
  verifyFormat("a inside {b, c};");                        // inside
  verifyFormat("bus.randomize() with { atype == low; };"); // with
}

TEST_F(FormatTestVerilog, Preprocessor) {
  auto Style = getDefaultStyle();
  Style.ColumnLimit = 20;

  // Macro definitions.
  verifyFormat("`define X          \\\n"
               "  if (x)           \\\n"
               "    x = x;",
               "`define X if(x)x=x;", Style);
  verifyFormat("`define X(x)       \\\n"
               "  if (x)           \\\n"
               "    x = x;",
               "`define X(x) if(x)x=x;", Style);
  verifyFormat("`define X          \\\n"
               "  x = x;           \\\n"
               "  x = x;",
               "`define X x=x;x=x;", Style);
  // Macro definitions with invocations inside.
  verifyFormat("`define LIST       \\\n"
               "  `ENTRY           \\\n"
               "  `ENTRY",
               "`define LIST \\\n"
               "`ENTRY \\\n"
               "`ENTRY",
               Style);
  verifyFormat("`define LIST       \\\n"
               "  `x = `x;         \\\n"
               "  `x = `x;",
               "`define LIST \\\n"
               "`x = `x; \\\n"
               "`x = `x;",
               Style);
  verifyFormat("`define LIST       \\\n"
               "  `x = `x;         \\\n"
               "  `x = `x;",
               "`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) {
    verifyFormat("if (x)\n"
                 "`" +
                     Name +
                     "\n"
                     "  ;",
                 "if (x)\n"
                 "`" +
                     Name +
                     "\n"
                     ";",
                 Style);
  }
  // Lines starting with a regular macro invocation should be indented as a
  // normal line.
  verifyFormat("if (x)\n"
               "  `x = `x;\n"
               "`timescale 1ns / 1ps",
               "if (x)\n"
               "`x = `x;\n"
               "`timescale 1ns / 1ps",
               Style);
  verifyFormat("if (x)\n"
               "`timescale 1ns / 1ps\n"
               "  `x = `x;",
               "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) {
    verifyFormat("if (x)\n"
                 "  `" +
                     Name + ";",
                 "if (x)\n"
                 "`" +
                     Name +
                     "\n"
                     ";",
                 Style);
  }
}

TEST_F(FormatTestVerilog, Primitive) {
  verifyFormat("primitive multiplexer\n"
               "    (mux, control, dataA, dataB);\n"
               "  output mux;\n"
               "  input control, dataA, dataB;\n"
               "  table\n"
               "    0 1 ? : 1;\n"
               "    0 0 ? : 0;\n"
               "    1 ? 1 : 1;\n"
               "    1 ? 0 : 0;\n"
               "    x 0 0 : 0;\n"
               "    x 1 1 : 1;\n"
               "  endtable\n"
               "endprimitive");
  verifyFormat("primitive latch\n"
               "    (q, ena_, data);\n"
               "  output q;\n"
               "  reg q;\n"
               "  input ena_, data;\n"
               "  table\n"
               "    0 1 : ? : 1;\n"
               "    0 0 : ? : 0;\n"
               "    1 ? : ? : -;\n"
               "    ? * : ? : -;\n"
               "  endtable\n"
               "endprimitive");
  verifyFormat("primitive d\n"
               "    (q, clock, data);\n"
               "  output q;\n"
               "  reg q;\n"
               "  input clock, data;\n"
               "  table\n"
               "    (01) 0 : ? : 0;\n"
               "    (01) 1 : ? : 1;\n"
               "    (0?) 1 : 1 : 1;\n"
               "    (0?) 0 : 0 : 0;\n"
               "    (?0) ? : ? : -;\n"
               "    (?\?) ? : ? : -;\n"
               "  endtable\n"
               "endprimitive");
}

TEST_F(FormatTestVerilog, Streaming) {
  verifyFormat("x = {>>{j}};");
  verifyFormat("x = {>>byte{j}};");
  verifyFormat("x = {<<{j}};");
  verifyFormat("x = {<<byte{j}};");
  verifyFormat("x = {<<16{j}};");
  verifyFormat("x = {<<{8'b0011_0101}};");
  verifyFormat("x = {<<4{6'b11_0101}};");
  verifyFormat("x = {>>4{6'b11_0101}};");
  verifyFormat("x = {<<2{{<<{4'b1101}}}};");
  verifyFormat("bit [96 : 1] y = {>>{a, b, c}};");
  verifyFormat("int j = {>>{a, b, c}};");
  verifyFormat("{>>{a, b, c}} = 23'b1;");
  verifyFormat("{>>{a, b, c}} = x;");
  verifyFormat("{>>{j}} = x;");
  verifyFormat("{>>byte{j}} = x;");
  verifyFormat("{<<{j}} = x;");
  verifyFormat("{<<byte{j}} = x;");
}

TEST_F(FormatTestVerilog, StringLiteral) {
  // Long strings should be broken.
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx ",
   "xxxx"});)",
               R"(x({"xxxxxxxxxxxxxxxx xxxx"});)",
               getStyleWithColumns(getDefaultStyle(), 23));
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx",
   " xxxx"});)",
               R"(x({"xxxxxxxxxxxxxxxx xxxx"});)",
               getStyleWithColumns(getDefaultStyle(), 22));
  // Braces should be added when they don't already exist.
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx ",
   "xxxx"});)",
               R"(x("xxxxxxxxxxxxxxxx xxxx");)",
               getStyleWithColumns(getDefaultStyle(), 23));
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx",
   " xxxx"});)",
               R"(x("xxxxxxxxxxxxxxxx xxxx");)",
               getStyleWithColumns(getDefaultStyle(), 22));
  verifyFormat(R"(x({{"xxxxxxxxxxxxxxxx ",
    "xxxx"} == x});)",
               R"(x({"xxxxxxxxxxxxxxxx xxxx" == x});)",
               getStyleWithColumns(getDefaultStyle(), 24));
  verifyFormat(R"(string x = {"xxxxxxxxxxxxxxxx ",
            "xxxxxxxx"};)",
               R"(string x = "xxxxxxxxxxxxxxxx xxxxxxxx";)",
               getStyleWithColumns(getDefaultStyle(), 32));
  // Space around braces should be correct.
  auto Style = getStyleWithColumns(getDefaultStyle(), 24);
  Style.Cpp11BracedListStyle = false;
  verifyFormat(R"(x({ "xxxxxxxxxxxxxxxx ",
    "xxxx" });)",
               R"(x("xxxxxxxxxxxxxxxx xxxx");)", Style);
  // Braces should not be added twice.
  verifyFormat(R"(x({"xxxxxxxx",
   "xxxxxxxx",
   "xxxxxx"});)",
               R"(x("xxxxxxxxxxxxxxxxxxxxxx");)",
               getStyleWithColumns(getDefaultStyle(), 14));
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx ",
   "xxxxxxxxxxxxxxxx ",
   "xxxx"});)",
               R"(x("xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxx");)",
               getStyleWithColumns(getDefaultStyle(), 23));
  verifyFormat(R"(x({"xxxxxxxxxxxxxxxx ",
   "xxxxxxxxxxxxxxxx ",
   "xxxx"});)",
               R"(x({"xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx ", "xxxx"});)",
               getStyleWithColumns(getDefaultStyle(), 23));
  // import/export "DPI"/"DPI-C" cannot be split.
  verifyFormat(R"(import
    "DPI-C" function void foo
    ();)",
               R"(import "DPI-C" function void foo();)",
               getStyleWithColumns(getDefaultStyle(), 23));
  verifyFormat(R"(export "DPI-C" function foo;)",
               R"(export "DPI-C" function foo;)",
               getStyleWithColumns(getDefaultStyle(), 23));
  // These kinds of strings don't exist in Verilog.
  verifyNoCrash(R"(x(@"xxxxxxxxxxxxxxxx xxxx");)",
                getStyleWithColumns(getDefaultStyle(), 23));
  verifyNoCrash(R"(x(u"xxxxxxxxxxxxxxxx xxxx");)",
                getStyleWithColumns(getDefaultStyle(), 23));
  verifyNoCrash(R"(x(u8"xxxxxxxxxxxxxxxx xxxx");)",
                getStyleWithColumns(getDefaultStyle(), 23));
  verifyNoCrash(R"(x(_T("xxxxxxxxxxxxxxxx xxxx"));)",
                getStyleWithColumns(getDefaultStyle(), 23));
}

TEST_F(FormatTestVerilog, StructLiteral) {
  verifyFormat("c = '{0, 0.0};");
  verifyFormat("c = '{'{1, 1.0}, '{2, 2.0}};");
  verifyFormat("c = '{a: 0, b: 0.0};");
  verifyFormat("c = '{a: 0, b: 0.0, default: 0};");
  verifyFormat("d = {int: 1, shortreal: 1.0};");
  verifyFormat("c = '{default: 0};");

  // The identifier before the quote can be either a tag or a type case.  There
  // should be a space between the tag and the quote.
  verifyFormat("c = ab'{a: 0, b: 0.0};");
  verifyFormat("c = ab'{cd: cd'{1, 1.0}, ef: ef'{2, 2.0}};");
  verifyFormat("c = ab'{cd'{1, 1.0}, ef'{2, 2.0}};");
  verifyFormat("d = ab'{int: 1, shortreal: 1.0};");
  verifyFormat("x = tagged Add '{e1, 4, ed};");

  auto Style = getDefaultStyle();
  Style.SpacesInContainerLiterals = true;
  verifyFormat("c = '{a : 0, b : 0.0};", Style);
  verifyFormat("c = '{a : 0, b : 0.0, default : 0};", Style);
  verifyFormat("c = ab'{a : 0, b : 0.0};", Style);
  verifyFormat("c = ab'{cd : cd'{1, 1.0}, ef : ef'{2, 2.0}};", Style);

  // It should be indented correctly when the line has to break.
  verifyFormat("c = //\n"
               "    '{default: 0};");
  Style = getDefaultStyle();
  Style.ContinuationIndentWidth = 2;
  verifyFormat("c = //\n"
               "  '{default: 0};",
               Style);
}

TEST_F(FormatTestVerilog, StructuredProcedure) {
  // Blocks should be indented correctly.
  verifyFormat("initial begin\n"
               "end");
  verifyFormat("initial begin\n"
               "  x <= x;\n"
               "  x <= x;\n"
               "end");
  verifyFormat("initial\n"
               "  x <= x;\n"
               "x <= x;");
  verifyFormat("always @(x) begin\n"
               "end");
  verifyFormat("always @(x) begin\n"
               "  x <= x;\n"
               "  x <= x;\n"
               "end");
  verifyFormat("always @(x)\n"
               "  x <= x;\n"
               "x <= x;");
  // Various keywords.
  verifyFormat("always @(x)\n"
               "  x <= x;");
  verifyFormat("always @(posedge x)\n"
               "  x <= x;");
  verifyFormat("always @(posedge x or posedge y)\n"
               "  x <= x;");
  verifyFormat("always @(posedge x, posedge y)\n"
               "  x <= x;");
  verifyFormat("always @(negedge x, negedge y)\n"
               "  x <= x;");
  verifyFormat("always @(edge x, edge y)\n"
               "  x <= x;");
  verifyFormat("always\n"
               "  x <= x;");
  verifyFormat("always @*\n"
               "  x <= x;");
  verifyFormat("always @(*)\n"
               "  x <= x;");
  verifyFormat("always_comb\n"
               "  x <= x;");
  verifyFormat("always_latch @(x)\n"
               "  x <= x;");
  verifyFormat("always_ff @(posedge x)\n"
               "  x <= x;");
  verifyFormat("initial\n"
               "  x <= x;");
  verifyFormat("final\n"
               "  x <= x;");
  verifyFormat("forever\n"
               "  x <= x;");
}
} // namespace
} // namespace test
} // namespace format
} // namespace clang
