// Copyright Brian Schott (Hackerpilot) 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) module analysis.useless_assert; import analysis.base; import analysis.helpers; import dparse.ast; import dparse.lexer; import std.stdio; /** * Checks for asserts that always succeed */ class UselessAssertCheck : BaseAnalyzer { alias visit = BaseAnalyzer.visit; /// this(string fileName, bool skipTests = false) { super(fileName, null, skipTests); } override void visit(const AssertExpression ae) { import std.conv : to; import std.string : removechars; UnaryExpression unary = cast(UnaryExpression) ae.assertion; if (unary is null) return; if (unary.primaryExpression is null) return; immutable token = unary.primaryExpression.primary; 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.removechars("Ll").to!double) return; break; case tok!"floatLiteral": if (!token.text.removechars("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.removechars("Ll").to!long) return; break; case tok!"realLiteral": if (!token.text.to!real) return; break; case tok!"uintLiteral": if (!token.text.removechars("Uu").to!uint) return; break; case tok!"ulongLiteral": if (!token.text.removechars("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(ae.line, ae.column, KEY, MESSAGE); } private: enum string KEY = "dscanner.suspicious.useless_assert"; enum string MESSAGE = "Assert condition is always true."; } unittest { import std.stdio : stderr; import analysis.config : StaticAnalysisConfig, Check; import std.format : format; StaticAnalysisConfig sac; sac.useless_assert_check = Check.enabled; assertAnalyzerWarnings(q{ unittest { assert(true); // [warn]: %1$s assert(1); // [warn]: %1$s assert([10]); // [warn]: %1$s assert(false); assert(0); assert(0.0L); } }c .format(UselessAssertCheck.MESSAGE), sac); stderr.writeln("Unittest for UselessAssertCheck passed."); }