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 }