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