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 analysis.length_subtraction;
7 
8 import std.stdio;
9 
10 import std.d.ast;
11 import std.d.lexer;
12 import analysis.base;
13 import analysis.helpers;
14 
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)
24 	{
25 		super(fileName);
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,
52 				"dscanner.suspicious.length_subtraction",
53 				"Avoid subtracting from '.length' as it may be unsigned.");
54 		}
55 	end:
56 		addExpression.accept(this);
57 	}
58 }
59 
60 unittest
61 {
62 	import analysis.config : StaticAnalysisConfig;
63 
64 	StaticAnalysisConfig sac;
65 	sac.length_subtraction_check = true;
66 	assertAnalyzerWarnings(q{
67 		void testSizeT()
68 		{
69 			if (i < a.length - 1) // [warn]: Avoid subtracting from '.length' as it may be unsigned.
70 				writeln("something");
71 		}
72 	}}, sac);
73 	stderr.writeln("Unittest for IfElseSameCheck passed.");
74 }
75