1 // Copyright Brian Schott (Hackerpilot) 2015. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 module analysis.useless_assert; 7 8 import analysis.base; 9 import analysis.helpers; 10 import dparse.ast; 11 import dparse.lexer; 12 13 import std.stdio; 14 15 /** 16 * Checks for asserts that always succeed 17 */ 18 class UselessAssertCheck : BaseAnalyzer 19 { 20 alias visit = BaseAnalyzer.visit; 21 22 /// 23 this(string fileName, bool skipTests = false) 24 { 25 // assertions likely to be in unittest so never skip 26 super(fileName, null, skipTests); 27 } 28 29 override void visit(const AssertExpression ae) 30 { 31 import std.conv : to; 32 import std.string : removechars; 33 34 UnaryExpression unary = cast(UnaryExpression) ae.assertion; 35 if (unary is null) 36 return; 37 if (unary.primaryExpression is null) 38 return; 39 immutable token = unary.primaryExpression.primary; 40 immutable skipSwitch = unary.primaryExpression.arrayLiteral !is null 41 || unary.primaryExpression.assocArrayLiteral !is null 42 || unary.primaryExpression.functionLiteralExpression !is null; 43 if (!skipSwitch) switch (token.type) 44 { 45 case tok!"doubleLiteral": 46 if (!token.text.removechars("Ll").to!double) 47 return; 48 break; 49 case tok!"floatLiteral": 50 if (!token.text.removechars("Ff").to!float) 51 return; 52 break; 53 case tok!"idoubleLiteral": 54 case tok!"ifloatLiteral": 55 case tok!"irealLiteral": 56 return; // `to` doesn't support imaginary numbers 57 case tok!"intLiteral": 58 if (!token.text.to!int) 59 return; 60 break; 61 case tok!"longLiteral": 62 if (!token.text.removechars("Ll").to!long) 63 return; 64 break; 65 case tok!"realLiteral": 66 if (!token.text.to!real) 67 return; 68 break; 69 case tok!"uintLiteral": 70 if (!token.text.removechars("Uu").to!uint) 71 return; 72 break; 73 case tok!"ulongLiteral": 74 if (!token.text.removechars("UuLl").to!ulong) 75 return; 76 break; 77 case tok!"characterLiteral": 78 if (token.text == `'\0'`) 79 return; 80 break; 81 case tok!"dstringLiteral": 82 case tok!"stringLiteral": 83 case tok!"wstringLiteral": 84 case tok!"true": 85 break; 86 default: 87 return; 88 } 89 addErrorMessage(ae.line, ae.column, KEY, MESSAGE); 90 } 91 92 private: 93 enum string KEY = "dscanner.suspicious.useless_assert"; 94 enum string MESSAGE = "Assert condition is always true."; 95 } 96 97 unittest 98 { 99 import std.stdio : stderr; 100 import analysis.config : StaticAnalysisConfig, Check; 101 import std.format : format; 102 103 StaticAnalysisConfig sac; 104 sac.useless_assert_check = Check.enabled; 105 assertAnalyzerWarnings(q{ 106 unittest 107 { 108 assert(true); // [warn]: %1$s 109 assert(1); // [warn]: %1$s 110 assert([10]); // [warn]: %1$s 111 assert(false); 112 assert(0); 113 assert(0.0L); 114 } 115 116 }} 117 .format(UselessAssertCheck.MESSAGE), sac); 118 stderr.writeln("Unittest for UselessAssertCheck passed."); 119 }