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