replace libdparse in useless assert (#63)

This commit is contained in:
lucica28 2023-05-24 14:58:09 +03:00 committed by Vladiwostok
parent 60fd082eb1
commit 6a832f4411
2 changed files with 26 additions and 86 deletions

View file

@ -906,10 +906,6 @@ private BaseAnalyzer[] getAnalyzersForModuleAndConfig(string fileName,
analysisConfig.long_line_check == Check.skipTests && !ut), analysisConfig.long_line_check == Check.skipTests && !ut),
analysisConfig.max_line_length); analysisConfig.max_line_length);
if (moduleName.shouldRun!UselessAssertCheck(analysisConfig))
checks ~= new UselessAssertCheck(args.setSkipTests(
analysisConfig.useless_assert_check == Check.skipTests && !ut));
if (moduleName.shouldRun!LambdaReturnCheck(analysisConfig)) if (moduleName.shouldRun!LambdaReturnCheck(analysisConfig))
checks ~= new LambdaReturnCheck(args.setSkipTests( checks ~= new LambdaReturnCheck(args.setSkipTests(
analysisConfig.lambda_return_check == Check.skipTests && !ut)); analysisConfig.lambda_return_check == Check.skipTests && !ut));
@ -1346,6 +1342,12 @@ MessageSet analyzeDmd(string fileName, ASTCodegen.Module m, const char[] moduleN
fileName, fileName,
config.static_if_else_check == Check.skipTests && !ut config.static_if_else_check == Check.skipTests && !ut
); );
if (moduleName.shouldRunDmd!(UselessAssertCheck!ASTCodegen)(config))
visitors ~= new UselessAssertCheck!ASTCodegen(
fileName,
config.useless_assert_check == Check.skipTests && !ut
);
foreach (visitor; visitors) foreach (visitor; visitors)
{ {

View file

@ -7,94 +7,35 @@ module dscanner.analysis.useless_assert;
import dscanner.analysis.base; import dscanner.analysis.base;
import dscanner.analysis.helpers; import dscanner.analysis.helpers;
import dparse.ast;
import dparse.lexer;
import std.stdio; import std.stdio;
auto filterChars(string chars, S)(S str)
{
import std.algorithm.comparison : among;
import std.algorithm.iteration : filter;
import std.meta : aliasSeqOf;
return str.filter!(c => !c.among(aliasSeqOf!chars));
}
/** /**
* Checks for asserts that always succeed * Checks for asserts that always succeed
*/ */
final class UselessAssertCheck : BaseAnalyzer extern(C++) class UselessAssertCheck(AST) : BaseAnalyzerDmd
{ {
alias visit = BaseAnalyzer.visit; alias visit = BaseAnalyzerDmd.visit;
mixin AnalyzerInfo!"useless_assert_check"; mixin AnalyzerInfo!"useless_assert_check";
/// ///
this(BaseAnalyzerArguments args) extern(D) this(string fileName, bool skipTests = false)
{ {
super(args); super(fileName, skipTests);
} }
override void visit(const AssertExpression ae) override void visit(AST.AssertExp ae)
{ {
import std.conv : to; auto ie = ae.e1.isIntegerExp();
if (ie && ie.getInteger() != 0)
addErrorMessage(cast(ulong) ae.loc.linnum, cast(ulong) ae.loc.charnum, KEY, MESSAGE);
UnaryExpression unary = cast(UnaryExpression) ae.assertArguments.assertion; auto re = ae.e1.isRealExp();
if (unary is null) if (re && re.value != 0)
return; addErrorMessage(cast(ulong) ae.loc.linnum, cast(ulong) ae.loc.charnum, KEY, MESSAGE);
if (unary.primaryExpression is null)
return; if (ae.e1.isStringExp() || ae.e1.isArrayLiteralExp() || ae.e1.isAssocArrayLiteralExp())
immutable token = unary.primaryExpression.primary; addErrorMessage(cast(ulong) ae.loc.linnum, cast(ulong) ae.loc.charnum, KEY, MESSAGE);
immutable skipSwitch = unary.primaryExpression.arrayLiteral !is null
|| unary.primaryExpression.assocArrayLiteral !is null
|| unary.primaryExpression.functionLiteralExpression !is null;
if (!skipSwitch) switch (token.type)
{
case tok!"doubleLiteral":
if (!token.text.filterChars!"Ll".to!double)
return;
break;
case tok!"floatLiteral":
if (!token.text.filterChars!"Ff".to!float)
return;
break;
case tok!"idoubleLiteral":
case tok!"ifloatLiteral":
case tok!"irealLiteral":
return; // `to` doesn't support imaginary numbers
case tok!"intLiteral":
if (!token.text.to!int)
return;
break;
case tok!"longLiteral":
if (!token.text.filterChars!"Ll".to!long)
return;
break;
case tok!"realLiteral":
if (!token.text.to!real)
return;
break;
case tok!"uintLiteral":
if (!token.text.filterChars!"Uu".to!uint)
return;
break;
case tok!"ulongLiteral":
if (!token.text.filterChars!"UuLl".to!ulong)
return;
break;
case tok!"characterLiteral":
if (token.text == `'\0'`)
return;
break;
case tok!"dstringLiteral":
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"true":
break;
default:
return;
}
addErrorMessage(unary, KEY, MESSAGE);
} }
private: private:
@ -108,23 +49,20 @@ unittest
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import std.format : format; import std.format : format;
alias assertAnalyzerWarnings = assertAnalyzerWarningsDMD;
StaticAnalysisConfig sac = disabledConfig(); StaticAnalysisConfig sac = disabledConfig();
sac.useless_assert_check = Check.enabled; sac.useless_assert_check = Check.enabled;
assertAnalyzerWarnings(q{ assertAnalyzerWarnings(q{
unittest unittest
{ {
assert(true); /+ assert(true); // [warn]: Assert condition is always true.
^^^^ [warn]: %1$s +/ assert(1); // [warn]: Assert condition is always true.
assert(1); /+ assert([10]); // [warn]: Assert condition is always true.
^ [warn]: %1$s +/
assert([10]); /+
^^^^ [warn]: %1$s +/
assert(false); assert(false);
assert(0); assert(0);
assert(0.0L); assert(0.0L);
} }
}c, sac);
}c
.format(UselessAssertCheck.MESSAGE), sac);
stderr.writeln("Unittest for UselessAssertCheck passed."); stderr.writeln("Unittest for UselessAssertCheck passed.");
} }