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 final class LengthSubtractionCheck : BaseAnalyzer 20 { 21 alias visit = BaseAnalyzer.visit; 22 23 mixin AnalyzerInfo!"length_subtraction_check"; 24 25 this(string fileName, const(Scope)* sc, bool skipTests = false) 26 { 27 super(fileName, sc, skipTests); 28 } 29 30 override void visit(const AddExpression addExpression) 31 { 32 if (addExpression.operator == tok!"-") 33 { 34 const UnaryExpression l = cast(const UnaryExpression) addExpression.left; 35 const UnaryExpression r = cast(const UnaryExpression) addExpression.right; 36 if (l is null || r is null) 37 { 38 // stderr.writeln(__FILE__, " ", __LINE__); 39 goto end; 40 } 41 if (r.primaryExpression is null || r.primaryExpression.primary.type != tok!"intLiteral") 42 { 43 // stderr.writeln(__FILE__, " ", __LINE__); 44 goto end; 45 } 46 if (l.identifierOrTemplateInstance is null 47 || l.identifierOrTemplateInstance.identifier.text != "length") 48 { 49 // stderr.writeln(__FILE__, " ", __LINE__); 50 goto end; 51 } 52 const(Token) token = l.identifierOrTemplateInstance.identifier; 53 addErrorMessage(token.line, token.column, "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 dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 64 65 StaticAnalysisConfig sac = disabledConfig(); 66 sac.length_subtraction_check = Check.enabled; 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 }