Add check for asserts without an explanatory message#495
Add check for asserts without an explanatory message#495dlang-bot merged 2 commits intodlang-community:masterfrom
Conversation
|
Awesome! |
ghost
left a comment
There was a problem hiding this comment.
Asking to put a message in assert(0), assert(false), etc, is not reasonable, e.g in default cases of switches and other similar uses.
Also it's very easy to cheat on the check: assert(0, " ")`.
|
I agree with @bbasile that |
|
But in general, when reasonable people may disagree, it's better to leave it to the end-user to decide. So I guess the solution should be to add Hopefully there should be an easy way to reuse the same analyzer for all of them. I wonder if something along the lines of this would work: enum AssertCheck
{
normalAssert,
unreachableAssert,
normalEnforce,
unreachableEnforce
}
class AssertWithoutMessageCheck : AssertWithoutMessageCheckImpl!(AssertCheck.normalAssert) { }
class Assert0WithoutMessageCheck : AssertWithoutMessageCheckImpl!(AssertCheck.unreachableAssert) { }
class EnforceWithoutMessageCheck : AssertWithoutMessageCheckImpl!(AssertCheck.normalEnforce) { }
class Enforce0WithoutMessageCheck : AssertWithoutMessageCheckImpl!(AssertCheck.unreachableEnforce) { }
class AssertWithoutMessageCheckImpl(AssertCheck config) : BaseAnalyzer
{
static if (config == AssertCheck.normalAssert)
{
enum string KEY = "dscanner.style.assert_without_msg";
enum string MESSAGE = "An assert(cond) should have an explanatory message";
}
else static if (config == AssertCheck.unreachableAssert)
{
enum string KEY = "dscanner.style.assert0_without_msg";
enum string MESSAGE = "An assert(false) should have an explanatory message";
}
else static if (config == AssertCheck.normalEnforce)
{
enum string KEY = "dscanner.style.enforce_without_msg";
enum string MESSAGE = "An enforce(cond) should have an explanatory message";
}
else static if (config == AssertCheck.unreachableEnforce)
{
enum string KEY = "dscanner.style.enforce0_without_msg";
enum string MESSAGE = "An enforce(false) should have an explanatory message";
}
else
static assert(0, "Invalid AssertCheck template argument: " ~ config.stringof);
// ...
}Sounds good? Edit: For some reason, I expected some fancy metaprogramming that would automatically instantiate decedents of |
|
@wilzbach, did you try the new check with phobos ? Maybe the results, the false positive and how much solvable they look can help to convince you but it's only two cases to skip, 0 and false and empty string literals too. |
src/analysis/config.d
Outdated
|
|
||
| @INI("Check for asserts without an explanatory message") | ||
| string assert_without_msg = Check.disabled; | ||
| string assert_without_msg = Check.skipTests; |
There was a problem hiding this comment.
I don't agree with this change. Wasn't the check designed for phobos in first place ?
87e8ba1 to
b6b3825
Compare
Done.
Good idea. Full list is here: http://sprunge.us/MaGf A couple of examples (abbreviated):
|
I think there's no usecase to prevent
DScanner isn't used as an API, but through the command-line and thus the enum Check: string
{
/// Check is disabled.
disabled = "disabled",
/// Check is enabled.
enabled = "enabled",
/// Check is enabled but not operated in the unittests.
skipTests = "skip-unittest"
}But we could create a new type for this check - sth. like this would work fine: enum AssertWithoutMsgCheck: string
{
/// Check is disabled.
disabled = "disabled",
/// Check is enabled.
enabled = "enabled",
/// Check is enabled but not operated in the unittests.
skipTests = "skip-unittest",
/// Check is enabled, but not for assert(0) or assert(false)
skipAssert0 = "skip-assert0",
/// Check is enabled, but not for assert(0) or assert(false) and unittest
skipTestsAssert0 = "skip-unittest-assert0",
} |
src/analysis/assert_without_msg.d
Outdated
| } | ||
| } | ||
|
|
||
| void preventCheating(const ExpressionNode exprNode) |
There was a problem hiding this comment.
IMHO this is a waste of code.
There was a problem hiding this comment.
I agree, but it wasn't hard and it helps to get this through the review.
There was a problem hiding this comment.
The cheating complaint is nonsensical, someone inclined to "cheat" can just as well do it with assert(cond, "fgsfds");. But the entire idea of "cheat prevention" in such tools is completely meaningless. There is no need to waste any time on it.
There was a problem hiding this comment.
which you would also detect while reviewing Phobos, if this assert thing was really an issue (caugh caugh).
There was a problem hiding this comment.
It's easy to write an assertion or enforce without a message by accident, negligence, or simple unawareness of best practices; however, cheating the tool would take malevolent intent. We pretty much only care about the first three.
There was a problem hiding this comment.
I agree with @CyberShadow, we should protect against accidents, not malice.
|
I still dont see the code that test for |
It seems like we don't need that for Phobos. If you'd like it for general use of DScanner, perhaps you could implement that after this PR is merged? |
| assertAnalyzerWarnings(q{ | ||
| unittest { | ||
| assert(0, "foo bar"); | ||
| assert(0); // [warn]: %s |
There was a problem hiding this comment.
@bbasile FWIW I test for assert(0) - just not in the way you would like it to be.
|
I opt out from this review. The only thing that's important to my eyes is that it's disabled by default. |
|
Sorry, hit the wrong button. |
|
So nobody merges this ? Was it supposed to be finished or WIP ? |
I never had time to remove the "cheating check", but AFAICT nothing else is blocking this. |
|
So removes it and let's get the merge. |
b6b3825 to
8304e85
Compare
Finally removed! |
From the NG: http://forum.dlang.org/post/uagjlugnczfegbuxdjzr@forum.dlang.org