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 }c, sac); 72 stderr.writeln("Unittest for IfElseSameCheck passed."); 73 }