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) 24 { 25 super(fileName, null); 26 } 27 28 override void visit(const AssertExpression ae) 29 { 30 import std.conv : to; 31 import std.string : removechars; 32 33 UnaryExpression unary = cast(UnaryExpression) ae.assertion; 34 if (unary is null) 35 return; 36 if (unary.primaryExpression is null) 37 return; 38 immutable token = unary.primaryExpression.primary; 39 immutable skipSwitch = unary.primaryExpression.arrayLiteral !is null 40 || unary.primaryExpression.assocArrayLiteral !is null 41 || unary.primaryExpression.functionLiteralExpression !is null; 42 if (!skipSwitch) switch (token.type) 43 { 44 case tok!"doubleLiteral": 45 if (!token.text.removechars("Ll").to!double) 46 return; 47 break; 48 case tok!"floatLiteral": 49 if (!token.text.removechars("Ff").to!float) 50 return; 51 break; 52 case tok!"idoubleLiteral": 53 case tok!"ifloatLiteral": 54 case tok!"irealLiteral": 55 return; // `to` doesn't support imaginary numbers 56 case tok!"intLiteral": 57 if (!token.text.to!int) 58 return; 59 break; 60 case tok!"longLiteral": 61 if (!token.text.removechars("Ll").to!long) 62 return; 63 break; 64 case tok!"realLiteral": 65 if (!token.text.to!real) 66 return; 67 break; 68 case tok!"uintLiteral": 69 if (!token.text.removechars("Uu").to!uint) 70 return; 71 break; 72 case tok!"ulongLiteral": 73 if (!token.text.removechars("UuLl").to!ulong) 74 return; 75 break; 76 case tok!"characterLiteral": 77 if (token.text == `'\0'`) 78 return; 79 break; 80 case tok!"dstringLiteral": 81 case tok!"stringLiteral": 82 case tok!"wstringLiteral": 83 case tok!"true": 84 break; 85 default: 86 return; 87 } 88 addErrorMessage(ae.line, ae.column, KEY, MESSAGE); 89 } 90 91 private: 92 enum string KEY = "dscanner.suspicious.useless_assert"; 93 enum string MESSAGE = "Assert condition is always true."; 94 } 95 96 unittest 97 { 98 import std.stdio : stderr; 99 import analysis.config : StaticAnalysisConfig; 100 import std.format : format; 101 102 StaticAnalysisConfig sac; 103 sac.useless_assert_check = true; 104 assertAnalyzerWarnings(q{ 105 unittest 106 { 107 assert(true); // [warn]: %1$s 108 assert(1); // [warn]: %1$s 109 assert([10]); // [warn]: %1$s 110 assert(false); 111 assert(0); 112 assert(0.0L); 113 } 114 115 }} 116 .format(UselessAssertCheck.MESSAGE), sac); 117 stderr.writeln("Unittest for UselessAssertCheck passed."); 118 }