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.logic_precedence; 7 8 import std.stdio; 9 import dparse.ast; 10 import dparse.lexer; 11 import dscanner.analysis.base; 12 import dscanner.analysis.helpers; 13 import dsymbol.scope_; 14 15 /** 16 * Checks for code with confusing && and || operator precedence 17 * --- 18 * if (a && b || c) // bad 19 * if (a && (b || c)) // good 20 * --- 21 */ 22 class LogicPrecedenceCheck : BaseAnalyzer 23 { 24 alias visit = BaseAnalyzer.visit; 25 26 enum string KEY = "dscanner.confusing.logical_precedence"; 27 28 this(string fileName, const(Scope)* sc, bool skipTests = false) 29 { 30 super(fileName, sc, skipTests); 31 } 32 33 override void visit(const OrOrExpression orOr) 34 { 35 if (orOr.left is null || orOr.right is null) 36 return; 37 const AndAndExpression left = cast(AndAndExpression) orOr.left; 38 const AndAndExpression right = cast(AndAndExpression) orOr.right; 39 if (left is null && right is null) 40 return; 41 if ((left !is null && left.right is null) && (right !is null && right.right is null)) 42 return; 43 addErrorMessage(orOr.line, orOr.column, KEY, 44 "Use parenthesis to clarify this expression."); 45 orOr.accept(this); 46 } 47 } 48 49 unittest 50 { 51 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 52 53 StaticAnalysisConfig sac = disabledConfig(); 54 sac.logical_precedence_check = Check.enabled; 55 assertAnalyzerWarnings(q{ 56 void testFish() 57 { 58 if (a && b || c) {} // [warn]: Use parenthesis to clarify this expression. 59 if ((a && b) || c) {} // Good 60 if (b || c && d) {} // [warn]: Use parenthesis to clarify this expression. 61 if (b || (c && d)) {} // Good 62 } 63 }}, sac); 64 stderr.writeln("Unittest for LogicPrecedenceCheck passed."); 65 }