diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2392,6 +2392,17 @@ if (Style.isCSharp() && Tok.is(tok::ampamp)) return TT_BinaryOperator; + if (Style.isVerilog()) { + // In Verilog, `*` can only be a binary operator. `&` can be either unary + // or binary. `*` also includes `*>` in module path declarations in + // specify blocks because merged tokens take the type of the first one by + // default. + if (Tok.is(tok::star)) + return TT_BinaryOperator; + return determineUnaryOperatorByUsage(Tok) ? TT_UnaryOperator + : TT_BinaryOperator; + } + const FormatToken *PrevToken = Tok.getPreviousNonComment(); if (!PrevToken) return TT_UnaryOperator; @@ -3987,7 +3998,12 @@ return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && (Left.isNot(tok::colon) || Left.isNot(TT_ObjCMethodExpr)); } - if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square, + // No space between the variable name and the initializer list. + // A a1{1}; + // Verilog doesn't have such syntax, but it has word operators that are C++ + // identifiers like `a inside {b, c}`. So the rule is not applicable. + if (!Style.isVerilog() && + (Left.isOneOf(tok::identifier, tok::greater, tok::r_square, tok::r_paren) || Left.isSimpleTypeSpecifier()) && Right.is(tok::l_brace) && Right.getNextNonComment() && @@ -4373,12 +4389,24 @@ Keywords.isWordLike(Left))) { return false; } + // Don't add spaces in imports like `import foo::*;`. + if ((Right.is(tok::star) && Left.is(tok::coloncolon)) || + (Left.is(tok::star) && Right.is(tok::semi))) { + return false; + } // Add space in attribute like `(* ASYNC_REG = "TRUE" *)`. if (Left.endsSequence(tok::star, tok::l_paren) && Right.is(tok::identifier)) return true; // Add space before drive strength like in `wire (strong1, pull0)`. if (Right.is(tok::l_paren) && Right.is(TT_VerilogStrength)) return true; + // Don't add space in a streaming concatenation like `{>>{j}}`. + if ((Left.is(tok::l_brace) && + Right.isOneOf(tok::lessless, tok::greatergreater)) || + (Left.endsSequence(tok::lessless, tok::l_brace) || + Left.endsSequence(tok::greatergreater, tok::l_brace))) { + return false; + } } if (Left.is(TT_ImplicitStringLiteral)) return Right.hasWhitespaceBefore(); diff --git a/clang/unittests/Format/FormatTestVerilog.cpp b/clang/unittests/Format/FormatTestVerilog.cpp --- a/clang/unittests/Format/FormatTestVerilog.cpp +++ b/clang/unittests/Format/FormatTestVerilog.cpp @@ -657,6 +657,14 @@ 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--;"); @@ -697,6 +705,13 @@ 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 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) { @@ -849,6 +864,26 @@ "endprimitive"); } +TEST_F(FormatTestVerilog, Streaming) { + verifyFormat("x = {>>{j}};"); + verifyFormat("x = {>>byte{j}};"); + verifyFormat("x = {<<{j}};"); + 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("{<