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