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