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 final class LogicPrecedenceCheck : BaseAnalyzer 23 { 24 alias visit = BaseAnalyzer.visit; 25 26 enum string KEY = "dscanner.confusing.logical_precedence"; 27 mixin AnalyzerInfo!"logical_precedence_check"; 28 29 this(string fileName, const(Scope)* sc, bool skipTests = false) 30 { 31 super(fileName, sc, skipTests); 32 } 33 34 override void visit(const OrOrExpression orOr) 35 { 36 if (orOr.left is null || orOr.right is null) 37 return; 38 const AndAndExpression left = cast(AndAndExpression) orOr.left; 39 const AndAndExpression right = cast(AndAndExpression) orOr.right; 40 if (left is null && right is null) 41 return; 42 if ((left !is null && left.right is null) && (right !is null && right.right is null)) 43 return; 44 addErrorMessage(orOr.line, orOr.column, KEY, 45 "Use parenthesis to clarify this expression."); 46 orOr.accept(this); 47 } 48 } 49 50 unittest 51 { 52 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 53 54 StaticAnalysisConfig sac = disabledConfig(); 55 sac.logical_precedence_check = Check.enabled; 56 assertAnalyzerWarnings(q{ 57 void testFish() 58 { 59 if (a && b || c) {} // [warn]: Use parenthesis to clarify this expression. 60 if ((a && b) || c) {} // Good 61 if (b || c && d) {} // [warn]: Use parenthesis to clarify this expression. 62 if (b || (c && d)) {} // Good 63 } 64 }}, sac); 65 stderr.writeln("Unittest for LogicPrecedenceCheck passed."); 66 }