Skip to content

Commit 6db0c18

Browse files
committed
[clang-format] Handle Verilog modules
Now things inside hierarchies like modules and interfaces are indented. When the module header spans multiple lines, all except the first line are indented as continuations. We added the property `IsContinuation` to mark lines that should be indented this way. In order that the colons inside square brackets don't get labeled as `TT_ObjCMethodExpr`, we added a check to only use this type when the language is not Verilog. Differential Revision: https://reviews.llvm.org/D128712
1 parent 67480b3 commit 6db0c18

File tree

8 files changed

+297
-17
lines changed

8 files changed

+297
-17
lines changed

clang/lib/Format/FormatToken.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ namespace format {
137137
TYPE(UntouchableMacroFunc) \
138138
/* like in begin : block */ \
139139
TYPE(VerilogBlockLabelColon) \
140+
/* The square bracket for the dimension part of the type name. \
141+
* In 'logic [1:0] x[1:0]', only the first '['. This way we can have space \
142+
* before the first bracket but not the second. */ \
143+
TYPE(VerilogDimensionedTypeName) \
140144
/* for the base in a number literal, not including the quote */ \
141145
TYPE(VerilogNumberBase) \
142146
TYPE(Unknown)
@@ -1743,6 +1747,22 @@ struct AdditionalKeywords {
17431747
kw_join_any, kw_join_none);
17441748
}
17451749

1750+
/// Returns whether \p Tok is a Verilog keyword that opens a module, etc.
1751+
bool isVerilogHierarchy(const FormatToken &Tok) const {
1752+
if (Tok.endsSequence(kw_function, kw_with))
1753+
return false;
1754+
if (Tok.is(kw_property)) {
1755+
const FormatToken *Prev = Tok.getPreviousNonComment();
1756+
return !(Prev &&
1757+
Prev->isOneOf(tok::kw_restrict, kw_assert, kw_assume, kw_cover));
1758+
}
1759+
return Tok.isOneOf(tok::kw_case, tok::kw_class, kw_function, kw_module,
1760+
kw_interface, kw_package, kw_casex, kw_casez, kw_checker,
1761+
kw_clocking, kw_covergroup, kw_macromodule, kw_primitive,
1762+
kw_program, kw_property, kw_randcase, kw_randsequence,
1763+
kw_task);
1764+
}
1765+
17461766
/// Whether the token begins a block.
17471767
bool isBlockBegin(const FormatToken &Tok, const FormatStyle &Style) const {
17481768
return Tok.is(TT_MacroBlockBegin) ||

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,13 @@ class AnnotatingParser {
238238
}
239239

240240
bool StartsObjCMethodExpr = false;
241-
if (FormatToken *MaybeSel = OpeningParen.Previous) {
242-
// @selector( starts a selector.
243-
if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
244-
MaybeSel->Previous->is(tok::at)) {
245-
StartsObjCMethodExpr = true;
241+
if (!Style.isVerilog()) {
242+
if (FormatToken *MaybeSel = OpeningParen.Previous) {
243+
// @selector( starts a selector.
244+
if (MaybeSel->isObjCAtKeyword(tok::objc_selector) &&
245+
MaybeSel->Previous && MaybeSel->Previous->is(tok::at)) {
246+
StartsObjCMethodExpr = true;
247+
}
246248
}
247249
}
248250

@@ -761,7 +763,8 @@ class AnnotatingParser {
761763
// Remember that this is a [[using ns: foo]] C++ attribute, so we
762764
// don't add a space before the colon (unlike other colons).
763765
CurrentToken->setType(TT_AttributeColon);
764-
} else if (Left->isOneOf(TT_ArraySubscriptLSquare,
766+
} else if (!Style.isVerilog() &&
767+
Left->isOneOf(TT_ArraySubscriptLSquare,
765768
TT_DesignatedInitializerLSquare)) {
766769
Left->setType(TT_ObjCMethodExpr);
767770
StartsObjCMethodExpr = true;
@@ -951,6 +954,8 @@ class AnnotatingParser {
951954
if (Keywords.isVerilogEnd(*Tok->Previous) ||
952955
Keywords.isVerilogBegin(*Tok->Previous)) {
953956
Tok->setType(TT_VerilogBlockLabelColon);
957+
} else if (Contexts.back().ContextKind == tok::l_square) {
958+
Tok->setType(TT_BitFieldColon);
954959
}
955960
break;
956961
}
@@ -1230,6 +1235,8 @@ class AnnotatingParser {
12301235
Tok->Next->isNot(tok::l_paren)) {
12311236
Tok->setType(TT_CSharpGenericTypeConstraint);
12321237
parseCSharpGenericTypeConstraint();
1238+
if (Tok->getPreviousNonComment() == nullptr)
1239+
Line.IsContinuation = true;
12331240
}
12341241
break;
12351242
case tok::arrow:
@@ -1411,8 +1418,8 @@ class AnnotatingParser {
14111418
IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
14121419
if ((Style.Language == FormatStyle::LK_Java &&
14131420
CurrentToken->is(Keywords.kw_package)) ||
1414-
(Info && Info->getPPKeywordID() == tok::pp_import &&
1415-
CurrentToken->Next &&
1421+
(!Style.isVerilog() && Info &&
1422+
Info->getPPKeywordID() == tok::pp_import && CurrentToken->Next &&
14161423
CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier,
14171424
tok::kw_static))) {
14181425
next();
@@ -4009,6 +4016,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
40094016
(Left.is(TT_VerilogNumberBase) && Right.is(tok::numeric_constant))) {
40104017
return false;
40114018
}
4019+
// Add space between the type name and dimension like `logic [1:0]`.
4020+
if (Right.is(tok::l_square) &&
4021+
Left.isOneOf(TT_VerilogDimensionedTypeName, Keywords.kw_function)) {
4022+
return true;
4023+
}
40124024
// Don't add spaces between a casting type and the quote or repetition count
40134025
// and the brace.
40144026
if ((Right.is(Keywords.kw_apostrophe) ||
@@ -4990,7 +5002,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
49905002
}
49915003

49925004
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const {
4993-
llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n";
5005+
llvm::errs() << "AnnotatedTokens(L=" << Line.Level << ", T=" << Line.Type
5006+
<< ", C=" << Line.IsContinuation << "):\n";
49945007
const FormatToken *Tok = Line.First;
49955008
while (Tok) {
49965009
llvm::errs() << " M=" << Tok->MustBreakBefore

clang/lib/Format/TokenAnnotator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class AnnotatedLine {
4343
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
4444
IsMultiVariableDeclStmt(false), Affected(false),
4545
LeadingEmptyLinesAffected(false), ChildrenAffected(false),
46+
IsContinuation(Line.IsContinuation),
4647
FirstStartColumn(Line.FirstStartColumn) {
4748
assert(!Line.Tokens.empty());
4849

@@ -143,6 +144,10 @@ class AnnotatedLine {
143144
/// \c True if one of this line's children intersects with an input range.
144145
bool ChildrenAffected;
145146

147+
/// \c True if this line should be indented by ContinuationIndent in addition
148+
/// to the normal indention level.
149+
bool IsContinuation;
150+
146151
unsigned FirstStartColumn;
147152

148153
private:

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class LevelIndentTracker {
6969
}
7070
if (static_cast<int>(Indent) + Offset >= 0)
7171
Indent += Offset;
72-
if (Line.First->is(TT_CSharpGenericTypeConstraint))
72+
if (Line.IsContinuation)
7373
Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
7474
}
7575

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 164 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -839,8 +839,13 @@ FormatToken *UnwrappedLineParser::parseBlock(
839839
}
840840
};
841841

842+
// Whether this is a Verilog-specific block that has a special header like a
843+
// module.
844+
const bool VerilogHierarchy =
845+
Style.isVerilog() && Keywords.isVerilogHierarchy(*FormatTok);
842846
assert((FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) ||
843-
(Style.isVerilog() && Keywords.isVerilogBegin(*FormatTok))) &&
847+
(Style.isVerilog() &&
848+
(Keywords.isVerilogBegin(*FormatTok) || VerilogHierarchy))) &&
844849
"'{' or macro block token expected");
845850
FormatToken *Tok = FormatTok;
846851
const bool FollowedByComment = Tokens->peekNextToken()->is(tok::comment);
@@ -850,14 +855,20 @@ FormatToken *UnwrappedLineParser::parseBlock(
850855

851856
// For Whitesmiths mode, jump to the next level prior to skipping over the
852857
// braces.
853-
if (AddLevels > 0 && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths)
858+
if (!VerilogHierarchy && AddLevels > 0 &&
859+
Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) {
854860
++Line->Level;
861+
}
855862

856863
size_t PPStartHash = computePPHash();
857864

858865
const unsigned InitialLevel = Line->Level;
859-
nextToken(/*LevelDifference=*/AddLevels);
860-
HandleVerilogBlockLabel();
866+
if (VerilogHierarchy) {
867+
AddLevels += parseVerilogHierarchyHeader();
868+
} else {
869+
nextToken(/*LevelDifference=*/AddLevels);
870+
HandleVerilogBlockLabel();
871+
}
861872

862873
// Bail out if there are too many levels. Otherwise, the stack might overflow.
863874
if (Line->Level > 300)
@@ -1552,7 +1563,14 @@ void UnwrappedLineParser::parseStructuralElement(
15521563
return;
15531564
case tok::kw_extern:
15541565
nextToken();
1555-
if (FormatTok->is(tok::string_literal)) {
1566+
if (Style.isVerilog()) {
1567+
// In Verilog and extern module declaration looks like a start of module.
1568+
// But there is no body and endmodule. So we handle it separately.
1569+
if (Keywords.isVerilogHierarchy(*FormatTok)) {
1570+
parseVerilogHierarchyHeader();
1571+
return;
1572+
}
1573+
} else if (FormatTok->is(tok::string_literal)) {
15561574
nextToken();
15571575
if (FormatTok->is(tok::l_brace)) {
15581576
if (Style.BraceWrapping.AfterExternBlock)
@@ -1751,9 +1769,15 @@ void UnwrappedLineParser::parseStructuralElement(
17511769
parseEnum();
17521770
}
17531771
break;
1772+
case tok::kw_class:
1773+
if (Style.isVerilog()) {
1774+
parseBlock();
1775+
addUnwrappedLine();
1776+
return;
1777+
}
1778+
LLVM_FALLTHROUGH;
17541779
case tok::kw_struct:
17551780
case tok::kw_union:
1756-
case tok::kw_class:
17571781
if (parseStructLike())
17581782
return;
17591783
break;
@@ -1889,7 +1913,8 @@ void UnwrappedLineParser::parseStructuralElement(
18891913
}
18901914

18911915
if (Style.isVerilog()) {
1892-
if (Keywords.isVerilogBegin(*FormatTok)) {
1916+
if (Keywords.isVerilogBegin(*FormatTok) ||
1917+
Keywords.isVerilogHierarchy(*FormatTok)) {
18931918
parseBlock();
18941919
addUnwrappedLine();
18951920
return;
@@ -3998,6 +4023,137 @@ void UnwrappedLineParser::parseStatementMacro() {
39984023
addUnwrappedLine();
39994024
}
40004025

4026+
void UnwrappedLineParser::parseVerilogHierarchyIdentifier() {
4027+
// consume things like a::`b.c[d:e] or a::*
4028+
while (true) {
4029+
if (FormatTok->isOneOf(tok::star, tok::period, tok::periodstar,
4030+
tok::coloncolon, tok::hash) ||
4031+
Keywords.isVerilogIdentifier(*FormatTok)) {
4032+
nextToken();
4033+
} else if (FormatTok->is(tok::l_square)) {
4034+
parseSquare();
4035+
} else {
4036+
break;
4037+
}
4038+
}
4039+
}
4040+
4041+
void UnwrappedLineParser::parseVerilogSensitivityList() {
4042+
assert(FormatTok->is(tok::at));
4043+
nextToken();
4044+
// A block event expression has 2 at signs.
4045+
if (FormatTok->is(tok::at))
4046+
nextToken();
4047+
switch (FormatTok->Tok.getKind()) {
4048+
case tok::star:
4049+
nextToken();
4050+
break;
4051+
case tok::l_paren:
4052+
parseParens();
4053+
break;
4054+
default:
4055+
parseVerilogHierarchyIdentifier();
4056+
break;
4057+
}
4058+
}
4059+
4060+
unsigned UnwrappedLineParser::parseVerilogHierarchyHeader() {
4061+
unsigned AddLevels = 0;
4062+
4063+
if (FormatTok->is(Keywords.kw_clocking)) {
4064+
nextToken();
4065+
if (Keywords.isVerilogIdentifier(*FormatTok))
4066+
nextToken();
4067+
if (FormatTok->is(tok::at))
4068+
parseVerilogSensitivityList();
4069+
if (FormatTok->is(tok::semi))
4070+
nextToken();
4071+
} else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex,
4072+
Keywords.kw_casez, Keywords.kw_randcase,
4073+
Keywords.kw_randsequence)) {
4074+
if (Style.IndentCaseLabels)
4075+
++AddLevels;
4076+
nextToken();
4077+
if (FormatTok->is(tok::l_paren))
4078+
parseParens();
4079+
if (FormatTok->isOneOf(Keywords.kw_inside, Keywords.kw_matches))
4080+
nextToken();
4081+
// The case header has no semicolon.
4082+
} else {
4083+
// "module" etc.
4084+
nextToken();
4085+
// all the words like the name of the module and specifiers like
4086+
// "automatic" and the width of function return type
4087+
while (true) {
4088+
if (FormatTok->is(tok::l_square)) {
4089+
auto Prev = FormatTok->getPreviousNonComment();
4090+
if (Prev && Keywords.isVerilogIdentifier(*Prev))
4091+
Prev->setFinalizedType(TT_VerilogDimensionedTypeName);
4092+
parseSquare();
4093+
} else if (Keywords.isVerilogIdentifier(*FormatTok) ||
4094+
FormatTok->isOneOf(Keywords.kw_automatic, tok::kw_static)) {
4095+
nextToken();
4096+
} else {
4097+
break;
4098+
}
4099+
}
4100+
4101+
auto NewLine = [this]() {
4102+
addUnwrappedLine();
4103+
Line->IsContinuation = true;
4104+
};
4105+
4106+
// package imports
4107+
while (FormatTok->is(Keywords.kw_import)) {
4108+
NewLine();
4109+
nextToken();
4110+
parseVerilogHierarchyIdentifier();
4111+
if (FormatTok->is(tok::semi))
4112+
nextToken();
4113+
}
4114+
4115+
// parameters and ports
4116+
if (FormatTok->is(Keywords.kw_verilogHash)) {
4117+
NewLine();
4118+
nextToken();
4119+
if (FormatTok->is(tok::l_paren))
4120+
parseParens();
4121+
}
4122+
if (FormatTok->is(tok::l_paren)) {
4123+
NewLine();
4124+
parseParens();
4125+
}
4126+
4127+
// extends and implements
4128+
if (FormatTok->is(Keywords.kw_extends)) {
4129+
NewLine();
4130+
nextToken();
4131+
parseVerilogHierarchyIdentifier();
4132+
if (FormatTok->is(tok::l_paren))
4133+
parseParens();
4134+
}
4135+
if (FormatTok->is(Keywords.kw_implements)) {
4136+
NewLine();
4137+
do {
4138+
nextToken();
4139+
parseVerilogHierarchyIdentifier();
4140+
} while (FormatTok->is(tok::comma));
4141+
}
4142+
4143+
// Coverage event for cover groups.
4144+
if (FormatTok->is(tok::at)) {
4145+
NewLine();
4146+
parseVerilogSensitivityList();
4147+
}
4148+
4149+
if (FormatTok->is(tok::semi))
4150+
nextToken(/*LevelDifference=*/1);
4151+
addUnwrappedLine();
4152+
}
4153+
4154+
return AddLevels;
4155+
}
4156+
40014157
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
40024158
StringRef Prefix = "") {
40034159
llvm::dbgs() << Prefix << "Line(" << Line.Level
@@ -4035,6 +4191,7 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) {
40354191
Line->Tokens.clear();
40364192
Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
40374193
Line->FirstStartColumn = 0;
4194+
Line->IsContinuation = false;
40384195

40394196
if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove)
40404197
--Line->Level;

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ struct UnwrappedLine {
4949

5050
bool MustBeDeclaration;
5151

52+
/// \c True if this line should be indented by ContinuationIndent in
53+
/// addition to the normal indention level.
54+
bool IsContinuation = false;
55+
5256
/// If this \c UnwrappedLine closes a block in a sequence of lines,
5357
/// \c MatchingOpeningBlockLineIndex stores the index of the corresponding
5458
/// opening line. Otherwise, \c MatchingOpeningBlockLineIndex must be
@@ -174,6 +178,11 @@ class UnwrappedLineParser {
174178
bool tryToParsePropertyAccessor();
175179
void tryToParseJSFunction();
176180
bool tryToParseSimpleAttribute();
181+
void parseVerilogHierarchyIdentifier();
182+
void parseVerilogSensitivityList();
183+
// Returns the number of levels of indentation in addition to the normal 1
184+
// level for a block, used for indenting case labels.
185+
unsigned parseVerilogHierarchyHeader();
177186

178187
// Used by addUnwrappedLine to denote whether to keep or remove a level
179188
// when resetting the line state.

0 commit comments

Comments
 (0)