auto functions checker, check assert(false) and string literal mixin.

This commit is contained in:
Basile Burg 2016-11-26 06:59:40 +01:00
parent 762dee0482
commit cbeca3ba34
No known key found for this signature in database
GPG Key ID: 1868039F415CB8CF
1 changed files with 76 additions and 10 deletions

View File

@ -29,6 +29,7 @@ private:
enum string MESSAGE = "Auto function without return statement, prefer an explicit void";
bool[] _returns;
size_t _mixinDepth;
public:
@ -40,7 +41,7 @@ public:
super(fileName, null, skipTests);
}
override void visit(const FunctionDeclaration decl)
override void visit(const(FunctionDeclaration) decl)
{
_returns.length += 1;
scope(exit) _returns.length -= 1;
@ -55,12 +56,48 @@ public:
addErrorMessage(decl.name.line, decl.name.column, KEY, MESSAGE);
}
override void visit(const ReturnStatement rst)
override void visit(const(ReturnStatement) rst)
{
if (_returns.length)
_returns[$-1] = true;
rst.accept(this);
}
override void visit(const(AssertExpression) exp)
{
exp.accept(this);
if (_returns.length)
{
const UnaryExpression u = cast(UnaryExpression) exp.assertion;
if (!u)
return;
const PrimaryExpression p = u.primaryExpression;
if (!p)
return;
immutable token = p.primary;
if (token.type == tok!"false")
_returns[$-1] = true;
else if (token.text == "0")
_returns[$-1] = true;
}
}
override void visit(const(MixinExpression) mix)
{
++_mixinDepth;
mix.accept(this);
--_mixinDepth;
}
override void visit(const(PrimaryExpression) exp)
{
exp.accept(this);
import std.algorithm.searching : find;
import std.range : empty;
if (_returns.length && _mixinDepth && !exp.primary.text.find("return").empty)
_returns[$-1] = true;
}
}
unittest
@ -74,14 +111,43 @@ unittest
sac.auto_function_check = Check.enabled;
assertAnalyzerWarnings(q{
auto ref doStuff(){} // [warn]: %s
auto doStuff(){} // [warn]: %s
int doStuff(){auto doStuff(){}} // [warn]: %s
auto doStuff(){return 0;}
int doStuff(){/*error but not the aim*/}
auto doStuff(){} // [warn]: %s
int doStuff(){auto doStuff(){}} // [warn]: %s
auto doStuff(){return 0;}
int doStuff(){/*error but not the aim*/}
}c.format(
AutoFunctionChecker.MESSAGE,
AutoFunctionChecker.MESSAGE,
AutoFunctionChecker.MESSAGE,
), sac);
AutoFunctionChecker.MESSAGE,
AutoFunctionChecker.MESSAGE,
AutoFunctionChecker.MESSAGE,
), sac);
assertAnalyzerWarnings(q{
auto doStuff(){assert(true);} // [warn]: %s
auto doStuff(){assert(false);}
}c.format(
AutoFunctionChecker.MESSAGE,
), sac);
assertAnalyzerWarnings(q{
auto doStuff(){assert(1);} // [warn]: %s
auto doStuff(){assert(0);}
}c.format(
AutoFunctionChecker.MESSAGE,
), sac);
assertAnalyzerWarnings(q{
auto doStuff(){mixin("0+0");} // [warn]: %s
auto doStuff(){mixin("return 0;");}
}c.format(
AutoFunctionChecker.MESSAGE,
), sac);
assertAnalyzerWarnings(q{
auto doStuff(){mixin("0+0");} // [warn]: %s
auto doStuff(){mixin("static if (true)" ~ " return " ~ 0.stringof ~ ";");}
}c.format(
AutoFunctionChecker.MESSAGE,
), sac);
stderr.writeln("Unittest for AutoFunctionChecker passed.");
}