-
Notifications
You must be signed in to change notification settings - Fork 212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new lint rule for negative array dimensions #1835
Add new lint rule for negative array dimensions #1835
Conversation
Codecov ReportPatch coverage:
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more Additional details and impacted files@@ Coverage Diff @@
## master #1835 +/- ##
==========================================
+ Coverage 93.08% 93.09% +0.01%
==========================================
Files 353 354 +1
Lines 25656 25723 +67
==========================================
+ Hits 23881 23946 +65
- Misses 1775 1777 +2
... and 8 files with indirect coverage changes Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report in Codecov by Sentry. |
f77f0ca
to
9f96c9f
Compare
9f96c9f
to
2e9e8d3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for contributing this!
if (UnaryPrefixExprMatcher().Matches(symbol, &manager)) { | ||
const auto& node = SymbolCastToNode(symbol); | ||
const auto& children = node.children(); | ||
const auto& leaf_symbol = *children[0].get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend defining a named function for anything that indexes into the list of childre.
e.g. add a GetUnaryPrefixExprOperator
to https://cs.opensource.google/verible/verible/+/master:verilog/CST/expression.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incidentally, what I'm requesting here is aligned with #159
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went ahead and added the suggested functions. Let me know if they're ok or if you think they could use some more work.
if (children.size() <= 1) return; | ||
|
||
int value = -1; | ||
const auto& child_node = children[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar suggestion, maybe call this GetUnaryPrefixExprOperand
in https://cs.opensource.google/verible/verible/+/master:verilog/CST/expression.h
const auto& child_node = children[1]; | ||
const bool is_constant = ConstantIntegerValue(*child_node.get(), &value); | ||
|
||
const verible::TokenInfo token(TK_OTHER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be declared inside the following if
body, because it is only used there.
namespace verilog { | ||
namespace analysis { | ||
|
||
class ForbidNegativeArrayDim : public verible::SyntaxTreeLintRule { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recommend documenting what this class does here, with some simple examples.
@@ -0,0 +1,48 @@ | |||
// Copyright 2017-2020 The Verible Authors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might as well make this 2023 (other files too)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done! Updated also expression.cc and expression.h files
{"logic l [10+(-5):0];"}, | ||
{"logic l [(", {kScalar, "-5"}, "):0];"}, | ||
{"logic l [-(-5):0];"}, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggested cases:
foo_type [a:b] name [c:d]
- declaration inside module ports
- declaration inside module body
- declaration inside class
- local declaration inside function
Add auxiliary functions for kUnaryExpressions Add more test cases Update copyright
Add auxiliary functions for kUnaryExpressions Add more test cases Update copyright for modified files
verilog/CST/expression.cc
Outdated
@@ -98,6 +98,19 @@ const verible::Symbol* GetConditionExpressionFalseCase( | |||
return GetSubtreeAsSymbol(condition_expr, NodeEnum::kConditionExpression, 4); | |||
} | |||
|
|||
const verible::TokenInfo* GetUnaryPrefixOperator( | |||
const verible::Symbol& symbol) { | |||
const auto& children = verible::SymbolCastToNode(symbol).children(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if symbol does not happen to be a node, then this will crash. You probably want to return nullptr
in case symbol.Kind()
is not a node.
Or you could test that it is a kUnaryPrefixExpression
, which is a better, more specific, test.
(Also add a test for it to see that other nodes than kUnaryPrefixExpressions always return nullptr).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the checks in both functions, thanks pointing it out.
verilog/CST/expression.cc
Outdated
const verible::TokenInfo* GetUnaryPrefixOperator( | ||
const verible::Symbol& symbol) { | ||
const auto& children = verible::SymbolCastToNode(symbol).children(); | ||
const auto leaf_symbol = children.front().get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, we try to avoid using auto
unless whatever comes back is a huge templated type which does not add any benefit for the reader. So use the type that is returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks! Used auto because I saw it in use and thought that was the general style, looks much better now.
const verible::Symbol& symbol) { | ||
const auto& children = verible::SymbolCastToNode(symbol).children(); | ||
const auto leaf_symbol = children.front().get(); | ||
return &verible::down_cast<const verible::SyntaxTreeLeaf*>(leaf_symbol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know that leaf_symbol
we get is a SyntaxTreeLeaf
so that we can safely cast ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed every kUnaryPrefixExpression has the following form
Node @0 (tag: kUnaryPrefixExpression) {
Leaf @0 /* ... */
Node @1 /* ... /*
So I guess that if we're sure the current node is a kUnaryPrefixExpression we can assume the cast will work always? Let me know if I'm wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the time of the writing of this comment, we only got verible::Symbol
, so didn't know that yet.
@@ -81,6 +81,12 @@ const verible::Symbol* GetConditionExpressionTrueCase(const verible::Symbol&); | |||
// Returns the false-case expression of a kConditionExpression. | |||
const verible::Symbol* GetConditionExpressionFalseCase(const verible::Symbol&); | |||
|
|||
// Returns the operator of a kUnaryPrefixExpression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add tests for the new functions in expression_test.cc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Let me know if they're thorough enough.
const auto operand = verilog::GetUnaryPrefixOperand(symbol); | ||
|
||
const bool is_constant = verilog::ConstantIntegerValue(*operand, &value); | ||
if (is_constant > 0 && value > 0 && u_operator->text() == "-") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_constant is a bool, so using >
on it is confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sorry about that. Removed "value > 0" check, noticed it was needed and when I added it back I somehow made a mess.
// Extract operand and operator from kUnaryPrefixExpression | ||
const auto u_operator = verilog::GetUnaryPrefixOperator(symbol); | ||
const auto operand = verilog::GetUnaryPrefixOperand(symbol); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're at this point, did the matcher make sure that u_operator and operand are never nullptr ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the matcher ensures that symbol is a kUnaryPrefixExpression, I would expect that they would never be nullptr (if my asumption about the general format for every kUnaryPrefixExpression is correct). If I'm wrong, I would just add an early return if either operand or u_operator are nullptr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is sufficient if you add that as a comment; something like:
// symbol is a UnaryPrefixExpression, so operator and operand are defined
- Change auto for the actual types - Add tests for new functions for unary expressions - Add checks for correct input type for new functions. Return nullptr when appropiate - Remove typo when checking boolean value (redundant > 0)
431b9d1
to
820e8f8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. A few more comments.
const verible::Symbol& symbol) { | ||
const auto& children = verible::SymbolCastToNode(symbol).children(); | ||
const auto leaf_symbol = children.front().get(); | ||
return &verible::down_cast<const verible::SyntaxTreeLeaf*>(leaf_symbol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the time of the writing of this comment, we only got verible::Symbol
, so didn't know that yet.
verilog/CST/expression.cc
Outdated
@@ -98,6 +98,25 @@ const verible::Symbol* GetConditionExpressionFalseCase( | |||
return GetSubtreeAsSymbol(condition_expr, NodeEnum::kConditionExpression, 4); | |||
} | |||
|
|||
const verible::TokenInfo* GetUnaryPrefixOperator( | |||
const verible::Symbol& symbol) { | |||
const SyntaxTreeNode* node = &verible::SymbolCastToNode(symbol); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this will crash if symbol is not a node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check added.
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also add tests where Symbol is not a unary prefix expression. What if symbol is a leaf ?
Having test cases with broken input helps to make sure we handle that gracefully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added calls to the GetUnaryPrefix... functions with wrong input and check they return null pointer
// Extract operand and operator from kUnaryPrefixExpression | ||
const auto u_operator = verilog::GetUnaryPrefixOperator(symbol); | ||
const auto operand = verilog::GetUnaryPrefixOperand(symbol); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is sufficient if you add that as a comment; something like:
// symbol is a UnaryPrefixExpression, so operator and operand are defined
} | ||
|
||
verible::matcher::BoundSymbolManager manager; | ||
if (UnaryPrefixExprMatcher().Matches(symbol, &manager)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is not matching, we can early out here. Saves one level of indentation and reduces the stack-size the reader of this code needs :)
if (!UnaryPrefixExprMatcher().Matches(symbol, &manager)) return;
... everything that follows implies that we have a unary prefix expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks for pointing that out
- Perform check before doing SymbolCastToNode - Call function with broken input (leafs, ...) - Add comments, style cleanup.
/* Can't detect this at the moment */ | ||
{"logic l [+(-5):0];"}, | ||
/* Packed */ | ||
{"logic [", {kScalar, "-10"}, ":-0] l;"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering, should there be a configuration for the packed and unpacked ranges ?
Maybe a particular style allows to set a bitwidth with negative values but not array sizes.
Something to discuss in #382, then a potential implementation that distinguishes the ranges in a follow-up PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, @fangism any additional comments ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, thank you for your hard work!
Thank you both! My pleasure, I'll search for other issues feasible for my with my little knowledge of the codebase. Feel free to point me in any direction that might be of use to you! Thanks again, enjoy the weekend and thanks for the great project you manage! |
Attempt to fix #382. I'm sure the code could use some improvements, so happy to accomodate any feedback!
Edit:
Sorry for the several updates, after making the pull request I realized that there are some corner cases (parenthesis, ...) so I tried to fix some of those. It still won't pick up things like +(-5) but I can't see an easy way to fix that.