1 //          Copyright Brian Schott (Hackerpilot) 2014.
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.length_subtraction;
7 
8 import std.stdio;
9 
10 import dparse.ast;
11 import dparse.lexer;
12 import dscanner.analysis.base;
13 import dscanner.analysis.helpers;
14 import dsymbol.scope_;
15 
16 /**
17  * Checks for subtraction from a .length property. This is usually a bug.
18  */
19 class LengthSubtractionCheck : BaseAnalyzer
20 {
21 	alias visit = BaseAnalyzer.visit;
22 
23 	this(string fileName, const(Scope)* sc, bool skipTests = false)
24 	{
25 		super(fileName, sc, skipTests);
26 	}
27 
28 	override void visit(const AddExpression addExpression)
29 	{
30 		if (addExpression.operator == tok!"-")
31 		{
32 			const UnaryExpression l = cast(const UnaryExpression) addExpression.left;
33 			const UnaryExpression r = cast(const UnaryExpression) addExpression.right;
34 			if (l is null || r is null)
35 			{
36 				//				stderr.writeln(__FILE__, " ", __LINE__);
37 				goto end;
38 			}
39 			if (r.primaryExpression is null || r.primaryExpression.primary.type != tok!"intLiteral")
40 			{
41 				//				stderr.writeln(__FILE__, " ", __LINE__);
42 				goto end;
43 			}
44 			if (l.identifierOrTemplateInstance is null
45 					|| l.identifierOrTemplateInstance.identifier.text != "length")
46 			{
47 				//				stderr.writeln(__FILE__, " ", __LINE__);
48 				goto end;
49 			}
50 			const(Token) token = l.identifierOrTemplateInstance.identifier;
51 			addErrorMessage(token.line, token.column, "dscanner.suspicious.length_subtraction",
52 					"Avoid subtracting from '.length' as it may be unsigned.");
53 		}
54 	end:
55 		addExpression.accept(this);
56 	}
57 }
58 
59 unittest
60 {
61 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
62 
63 	StaticAnalysisConfig sac = disabledConfig();
64 	sac.length_subtraction_check = Check.enabled;
65 	assertAnalyzerWarnings(q{
66 		void testSizeT()
67 		{
68 			if (i < a.length - 1) // [warn]: Avoid subtracting from '.length' as it may be unsigned.
69 				writeln("something");
70 		}
71 	}}, sac);
72 	stderr.writeln("Unittest for IfElseSameCheck passed.");
73 }