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