mirror of
https://github.com/dlang-community/D-Scanner.git
synced 2025-04-29 14:50:01 +03:00
replace libparse in incorrect infinite range visitor (#33)
This commit is contained in:
parent
5ddffd8d0e
commit
a3efa880e8
2 changed files with 68 additions and 76 deletions
|
@ -10,90 +10,88 @@ import dscanner.analysis.helpers;
|
||||||
import dparse.ast;
|
import dparse.ast;
|
||||||
import dparse.lexer;
|
import dparse.lexer;
|
||||||
|
|
||||||
import std.typecons : Rebindable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for incorrect infinite range definitions
|
* Checks for incorrect infinite range definitions
|
||||||
*/
|
*/
|
||||||
final class IncorrectInfiniteRangeCheck : BaseAnalyzer
|
extern(C++) class IncorrectInfiniteRangeCheck(AST) : BaseAnalyzerDmd
|
||||||
{
|
{
|
||||||
alias visit = BaseAnalyzer.visit;
|
// alias visit = BaseAnalyzerDmd!AST.visit;
|
||||||
|
alias visit = BaseAnalyzerDmd.visit;
|
||||||
|
|
||||||
mixin AnalyzerInfo!"incorrect_infinite_range_check";
|
mixin AnalyzerInfo!"incorrect_infinite_range_check";
|
||||||
|
|
||||||
///
|
///
|
||||||
this(BaseAnalyzerArguments args)
|
extern(D) this(string fileName)
|
||||||
{
|
{
|
||||||
super(args);
|
super(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const StructBody structBody)
|
override void visit(AST.StructDeclaration sd)
|
||||||
{
|
{
|
||||||
inStruct++;
|
inAggregate++;
|
||||||
structBody.accept(this);
|
super.visit(sd);
|
||||||
inStruct--;
|
inAggregate--;
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const FunctionDeclaration fd)
|
override void visit(AST.ClassDeclaration cd)
|
||||||
{
|
{
|
||||||
if (inStruct > 0 && fd.name.text == "empty")
|
inAggregate++;
|
||||||
{
|
super.visit(cd);
|
||||||
auto old = parentFunc;
|
inAggregate--;
|
||||||
parentFunc = fd;
|
|
||||||
fd.accept(this);
|
|
||||||
parentFunc = old;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const FunctionBody fb)
|
override void visit(AST.FuncDeclaration fd)
|
||||||
{
|
{
|
||||||
if (fb.specifiedFunctionBody && fb.specifiedFunctionBody.blockStatement !is null)
|
import dmd.astenums : Tbool;
|
||||||
visit(fb.specifiedFunctionBody.blockStatement);
|
|
||||||
else if (fb.shortenedFunctionBody && fb.shortenedFunctionBody.expression !is null)
|
if (!inAggregate)
|
||||||
visitReturnExpression(fb.shortenedFunctionBody.expression);
|
return;
|
||||||
|
|
||||||
|
if (!fd.ident || fd.ident.toString() != "empty")
|
||||||
|
return;
|
||||||
|
|
||||||
|
AST.TypeFunction tf = fd.type.isTypeFunction();
|
||||||
|
|
||||||
|
if (!tf || !tf.next || !tf.next.ty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AST.ReturnStatement rs = fd.fbody ? fd.fbody.isReturnStatement() : null;
|
||||||
|
|
||||||
|
if (rs)
|
||||||
|
{
|
||||||
|
AST.IntegerExp ie = cast(AST.IntegerExp) rs.exp;
|
||||||
|
|
||||||
|
if (ie && ie.getInteger() == 0)
|
||||||
|
addErrorMessage(cast(ulong) fd.loc.linnum, cast(ulong) fd.loc.charnum, KEY,
|
||||||
|
"Use `enum bool empty = false;` to define an infinite range.");
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const BlockStatement bs)
|
AST.CompoundStatement cs = fd.fbody ? fd.fbody.isCompoundStatement() : null;
|
||||||
|
|
||||||
|
if (!cs || (*cs.statements).length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto rs1 = (*cs.statements)[0].isReturnStatement())
|
||||||
{
|
{
|
||||||
if (bs.declarationsAndStatements is null)
|
AST.IntegerExp ie = cast(AST.IntegerExp) rs1.exp;
|
||||||
return;
|
|
||||||
if (bs.declarationsAndStatements.declarationsAndStatements is null)
|
if (ie && ie.getInteger() == 0)
|
||||||
return;
|
addErrorMessage(cast(ulong) fd.loc.linnum, cast(ulong) fd.loc.charnum, KEY,
|
||||||
if (bs.declarationsAndStatements.declarationsAndStatements.length != 1)
|
"Use `enum bool empty = false;` to define an infinite range.");
|
||||||
return;
|
|
||||||
visit(bs.declarationsAndStatements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override void visit(const ReturnStatement rs)
|
super.visit(fd);
|
||||||
{
|
|
||||||
if (inStruct == 0 || parentFunc == null) // not within a struct yet
|
|
||||||
return;
|
|
||||||
visitReturnExpression(rs.expression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitReturnExpression(const Expression expression)
|
override void visit(AST.UnitTestDeclaration ud)
|
||||||
{
|
{
|
||||||
if (!expression || expression.items.length != 1)
|
|
||||||
return;
|
|
||||||
UnaryExpression unary = cast(UnaryExpression) expression.items[0];
|
|
||||||
if (unary is null)
|
|
||||||
return;
|
|
||||||
if (unary.primaryExpression is null)
|
|
||||||
return;
|
|
||||||
if (unary.primaryExpression.primary != tok!"false")
|
|
||||||
return;
|
|
||||||
addErrorMessage(parentFunc.get, KEY, MESSAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
override void visit(const Unittest u)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint inStruct;
|
uint inAggregate;
|
||||||
enum string KEY = "dscanner.suspicious.incorrect_infinite_range";
|
enum string KEY = "dscanner.suspicious.incorrect_infinite_range";
|
||||||
enum string MESSAGE = "Use `enum bool empty = false;` to define an infinite range.";
|
enum string MESSAGE = "Use `enum bool empty = false;` to define an infinite range.";
|
||||||
Rebindable!(const FunctionDeclaration) parentFunc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -104,14 +102,12 @@ unittest
|
||||||
|
|
||||||
StaticAnalysisConfig sac = disabledConfig();
|
StaticAnalysisConfig sac = disabledConfig();
|
||||||
sac.incorrect_infinite_range_check = Check.enabled;
|
sac.incorrect_infinite_range_check = Check.enabled;
|
||||||
assertAnalyzerWarnings(q{struct InfiniteRange
|
assertAnalyzerWarningsDMD(q{struct InfiniteRange
|
||||||
{
|
{
|
||||||
bool empty()
|
bool empty() // [warn]: Use `enum bool empty = false;` to define an infinite range.
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
} /+
|
}
|
||||||
^^ [warn]: %1$s+/
|
|
||||||
// TODO: test for multiline issues like this
|
|
||||||
|
|
||||||
bool stuff()
|
bool stuff()
|
||||||
{
|
{
|
||||||
|
@ -132,8 +128,7 @@ unittest
|
||||||
|
|
||||||
struct InfiniteRange
|
struct InfiniteRange
|
||||||
{
|
{
|
||||||
bool empty() => false; /+
|
bool empty() => false; // [warn]: Use `enum bool empty = false;` to define an infinite range.
|
||||||
^^^^^^^^^^^^^^^^^^^^^^ [warn]: %1$s +/
|
|
||||||
bool stuff() => false;
|
bool stuff() => false;
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
|
@ -148,11 +143,9 @@ struct InfiniteRange
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() { return false; }
|
bool empty() { return false; }
|
||||||
class C { bool empty() { return false; } } /+
|
class C { bool empty() { return false; } } // [warn]: Use `enum bool empty = false;` to define an infinite range.
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [warn]: %1$s +/
|
|
||||||
|
|
||||||
}c
|
}c, sac);
|
||||||
.format(IncorrectInfiniteRangeCheck.MESSAGE), sac);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test for https://github.com/dlang-community/D-Scanner/issues/656
|
// test for https://github.com/dlang-community/D-Scanner/issues/656
|
||||||
|
@ -173,7 +166,7 @@ unittest
|
||||||
|
|
||||||
StaticAnalysisConfig sac = disabledConfig();
|
StaticAnalysisConfig sac = disabledConfig();
|
||||||
sac.incorrect_infinite_range_check = Check.enabled;
|
sac.incorrect_infinite_range_check = Check.enabled;
|
||||||
assertAnalyzerWarnings(q{
|
assertAnalyzerWarningsDMD(q{
|
||||||
enum isAllZeroBits = ()
|
enum isAllZeroBits = ()
|
||||||
{
|
{
|
||||||
if (true)
|
if (true)
|
||||||
|
|
|
@ -929,10 +929,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
|
||||||
checks ~= new AutoRefAssignmentCheck(args.setSkipTests(
|
checks ~= new AutoRefAssignmentCheck(args.setSkipTests(
|
||||||
analysisConfig.auto_ref_assignment_check == Check.skipTests && !ut));
|
analysisConfig.auto_ref_assignment_check == Check.skipTests && !ut));
|
||||||
|
|
||||||
if (moduleName.shouldRun!IncorrectInfiniteRangeCheck(analysisConfig))
|
|
||||||
checks ~= new IncorrectInfiniteRangeCheck(args.setSkipTests(
|
|
||||||
analysisConfig.incorrect_infinite_range_check == Check.skipTests && !ut));
|
|
||||||
|
|
||||||
if (moduleName.shouldRun!UselessAssertCheck(analysisConfig))
|
if (moduleName.shouldRun!UselessAssertCheck(analysisConfig))
|
||||||
checks ~= new UselessAssertCheck(args.setSkipTests(
|
checks ~= new UselessAssertCheck(args.setSkipTests(
|
||||||
analysisConfig.useless_assert_check == Check.skipTests && !ut));
|
analysisConfig.useless_assert_check == Check.skipTests && !ut));
|
||||||
|
@ -1330,6 +1326,9 @@ MessageSet analyzeDmd(string fileName, ASTBase.Module m, const char[] moduleName
|
||||||
if (moduleName.shouldRunDmd!(FinalAttributeChecker!ASTBase)(config))
|
if (moduleName.shouldRunDmd!(FinalAttributeChecker!ASTBase)(config))
|
||||||
visitors ~= new FinalAttributeChecker!ASTBase(fileName);
|
visitors ~= new FinalAttributeChecker!ASTBase(fileName);
|
||||||
|
|
||||||
|
if (moduleName.shouldRunDmd!(IncorrectInfiniteRangeCheck!ASTBase)(config))
|
||||||
|
visitors ~= new IncorrectInfiniteRangeCheck!ASTBase(fileName);
|
||||||
|
|
||||||
foreach (visitor; visitors)
|
foreach (visitor; visitors)
|
||||||
{
|
{
|
||||||
m.accept(visitor);
|
m.accept(visitor);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue