assert_without_msg: Check for std.exception.enforce
This commit is contained in:
parent
5ba4a7bffa
commit
8304e8540c
|
@ -10,6 +10,7 @@ import dparse.lexer;
|
|||
import dparse.ast;
|
||||
|
||||
import std.stdio;
|
||||
import std.algorithm;
|
||||
|
||||
/**
|
||||
* Check that all asserts have an explanatory message.
|
||||
|
@ -31,8 +32,60 @@ class AssertWithoutMessageCheck : BaseAnalyzer
|
|||
addErrorMessage(expr.line, expr.column, KEY, MESSAGE);
|
||||
}
|
||||
|
||||
override void visit(const FunctionCallExpression expr)
|
||||
{
|
||||
if (!isStdExceptionImported)
|
||||
return;
|
||||
|
||||
if (expr.unaryExpression !is null &&
|
||||
expr.unaryExpression.primaryExpression !is null &&
|
||||
expr.unaryExpression.primaryExpression.identifierOrTemplateInstance !is null)
|
||||
{
|
||||
auto ident = expr.unaryExpression.primaryExpression.identifierOrTemplateInstance.identifier;
|
||||
if (ident.text == "enforce" && expr.arguments !is null && expr.arguments.argumentList !is null &&
|
||||
expr.arguments.argumentList.items.length < 2)
|
||||
addErrorMessage(ident.line, ident.column, KEY, MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(const SingleImport sImport)
|
||||
{
|
||||
static immutable stdException = ["std", "exception"];
|
||||
if (sImport.identifierChain.identifiers.map!(a => a.text).equal(stdException))
|
||||
isStdExceptionImported = true;
|
||||
}
|
||||
|
||||
// revert the stack after new scopes
|
||||
override void visit(const Declaration decl)
|
||||
{
|
||||
// be careful - ImportDeclarations don't introduce a new scope
|
||||
if (decl.importDeclaration is null)
|
||||
{
|
||||
bool tmp = isStdExceptionImported;
|
||||
scope(exit) isStdExceptionImported = tmp;
|
||||
decl.accept(this);
|
||||
}
|
||||
else
|
||||
decl.accept(this);
|
||||
}
|
||||
|
||||
mixin ScopedVisit!IfStatement;
|
||||
mixin ScopedVisit!BlockStatement;
|
||||
|
||||
alias visit = BaseAnalyzer.visit;
|
||||
|
||||
private:
|
||||
bool isStdExceptionImported;
|
||||
|
||||
template ScopedVisit(NodeType)
|
||||
{
|
||||
override void visit(const NodeType n)
|
||||
{
|
||||
bool tmp = isStdExceptionImported;
|
||||
scope(exit) isStdExceptionImported = tmp;
|
||||
n.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -63,6 +116,40 @@ unittest
|
|||
AssertWithoutMessageCheck.MESSAGE,
|
||||
), sac);
|
||||
|
||||
// check for std.exception.enforce
|
||||
assertAnalyzerWarnings(q{
|
||||
unittest {
|
||||
enforce(0); // std.exception not imported yet - could be a user-defined symbol
|
||||
import std.exception;
|
||||
enforce(0, "foo bar");
|
||||
enforce(0); // [warn]: %s
|
||||
}
|
||||
}c.format(
|
||||
AssertWithoutMessageCheck.MESSAGE,
|
||||
), sac);
|
||||
|
||||
// check for std.exception.enforce
|
||||
assertAnalyzerWarnings(q{
|
||||
unittest {
|
||||
import exception;
|
||||
class C {
|
||||
import std.exception;
|
||||
}
|
||||
enforce(0); // std.exception not imported yet - could be a user-defined symbol
|
||||
struct S {
|
||||
import std.exception;
|
||||
}
|
||||
enforce(0); // std.exception not imported yet - could be a user-defined symbol
|
||||
if (false) {
|
||||
import std.exception;
|
||||
}
|
||||
enforce(0); // std.exception not imported yet - could be a user-defined symbol
|
||||
{
|
||||
import std.exception;
|
||||
}
|
||||
enforce(0); // std.exception not imported yet - could be a user-defined symbol
|
||||
}
|
||||
}c, sac);
|
||||
|
||||
stderr.writeln("Unittest for AssertWithoutMessageCheck passed.");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue