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