replace libparse in incorrect infinite range visitor (#33)

This commit is contained in:
lucica28 2022-11-01 16:44:49 +02:00 committed by Vladiwostok
parent 5ddffd8d0e
commit a3efa880e8
2 changed files with 68 additions and 76 deletions

View file

@ -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)

View file

@ -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);