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