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 @@ -1647,6 +1647,7 @@ bool CaretFound = false; bool InCpp11AttributeSpecifier = false; bool InCSharpAttributeSpecifier = false; + bool VerilogAssignmentFound = false; enum { Unknown, // Like the part after `:` in a constructor. @@ -1944,6 +1945,17 @@ (!Current.Previous || Current.Previous->isNot(tok::l_square)) && (!Current.is(tok::greater) && Style.Language != FormatStyle::LK_TextProto)) { + if (Style.isVerilog()) { + if (Current.is(tok::lessequal) && Contexts.size() == 1 && + !Contexts.back().VerilogAssignmentFound) { + // In Verilog `<=` is assignment if in its own statement. It is a + // statement instead of an expression, that is it can not be chained. + Current.ForcedPrecedence = prec::Assignment; + Current.setFinalizedType(TT_BinaryOperator); + } + if (Current.getPrecedence() == prec::Assignment) + Contexts.back().VerilogAssignmentFound = true; + } Current.setType(TT_BinaryOperator); } else if (Current.is(tok::comment)) { if (Current.TokenText.startswith("/*")) { diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -838,7 +838,12 @@ return Style.AlignConsecutiveAssignments.AlignCompound ? C.Tok->getPrecedence() == prec::Assignment - : C.Tok->is(tok::equal); + : (C.Tok->is(tok::equal) || + // In Verilog the '<=' is not a compound assignment, thus + // it is aligned even when the AlignCompound option is not + // set. + (Style.isVerilog() && C.Tok->is(tok::lessequal) && + C.Tok->getPrecedence() == prec::Assignment)); }, Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments, /*RightJustify=*/true); 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 @@ -45,6 +45,58 @@ } }; +TEST_F(FormatTestVerilog, Align) { + FormatStyle Style = getLLVMStyle(FormatStyle::LK_Verilog); + 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, BasedLiteral) { verifyFormat("x = '0;"); verifyFormat("x = '1;"); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1314,6 +1314,21 @@ EXPECT_TOKEN(Tokens[5], tok::question, TT_ConditionalExpr); EXPECT_TOKEN(Tokens[7], tok::colon, TT_ConditionalExpr); EXPECT_TOKEN(Tokens[9], tok::colon, TT_GotoLabelColon); + // Non-blocking assignments. + Tokens = Annotate("a <= b;"); + ASSERT_EQ(Tokens.size(), 5u); + EXPECT_TOKEN(Tokens[1], tok::lessequal, TT_BinaryOperator); + EXPECT_TOKEN_PRECEDENCE(Tokens[1], prec::Assignment); + Tokens = Annotate("if (a <= b) break;"); + ASSERT_EQ(Tokens.size(), 9u); + EXPECT_TOKEN(Tokens[3], tok::lessequal, TT_BinaryOperator); + EXPECT_TOKEN_PRECEDENCE(Tokens[3], prec::Relational); + Tokens = Annotate("a <= b <= a;"); + ASSERT_EQ(Tokens.size(), 7u); + EXPECT_TOKEN(Tokens[1], tok::lessequal, TT_BinaryOperator); + EXPECT_TOKEN_PRECEDENCE(Tokens[1], prec::Assignment); + EXPECT_TOKEN(Tokens[3], tok::lessequal, TT_BinaryOperator); + EXPECT_TOKEN_PRECEDENCE(Tokens[3], prec::Relational); } TEST_F(TokenAnnotatorTest, UnderstandConstructors) {