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.ifelsesame;
7 
8 import std.stdio;
9 
10 import std.d.ast;
11 import std.d.lexer;
12 import analysis.base;
13 import analysis.helpers;
14 
15 
16 /**
17  * Checks for duplicated code in conditional and logical expressions.
18  * $(UL
19  * $(LI If statements whose "then" block is the same as the "else" block)
20  * $(LI || and && expressions where the left and right are the same)
21  * $(LI == expressions where the left and right are the same)
22  * )
23  */
24 class IfElseSameCheck : BaseAnalyzer
25 {
26 	alias visit = BaseAnalyzer.visit;
27 
28 	this(string fileName)
29 	{
30 		super(fileName);
31 	}
32 
33 	override void visit(const IfStatement ifStatement)
34 	{
35 		if (ifStatement.thenStatement == ifStatement.elseStatement)
36 			addErrorMessage(ifStatement.line, ifStatement.column,
37 				"dscanner.bugs.if_else_same",
38 				"'Else' branch is identical to 'Then' branch.");
39 		ifStatement.accept(this);
40 	}
41 
42 	override void visit(const AssignExpression assignExpression)
43 	{
44 		const AssignExpression e = cast(const AssignExpression) assignExpression.assignExpression;
45 		if (e !is null && assignExpression.operator == tok!"="
46 			&& e.ternaryExpression == assignExpression.ternaryExpression)
47 		{
48 			addErrorMessage(assignExpression.line, assignExpression.column,
49 				"dscanner.bugs.self_assignment",
50 				"Left side of assignment operatior is identical to the right side.");
51 		}
52 		assignExpression.accept(this);
53 	}
54 
55 	override void visit(const AndAndExpression andAndExpression)
56 	{
57 		if (andAndExpression.left !is null && andAndExpression.right !is null
58 			&& andAndExpression.left == andAndExpression.right)
59 		{
60 			addErrorMessage(andAndExpression.line, andAndExpression.column,
61 				"dscanner.bugs.logic_operator_operands",
62 				"Left side of logical and is identical to right side.");
63 		}
64 		andAndExpression.accept(this);
65 	}
66 
67 	override void visit(const OrOrExpression orOrExpression)
68 	{
69 		if (orOrExpression.left !is null && orOrExpression.right !is null
70 			&& orOrExpression.left == orOrExpression.right)
71 		{
72 			addErrorMessage(orOrExpression.line, orOrExpression.column,
73 				"dscanner.bugs.logic_operator_operands",
74 				"Left side of logical or is identical to right side.");
75 		}
76 		orOrExpression.accept(this);
77 	}
78 }
79 
80 unittest
81 {
82 	import analysis.config : StaticAnalysisConfig;
83 
84 	StaticAnalysisConfig sac;
85 	sac.if_else_same_check = true;
86 	assertAnalyzerWarnings(q{
87 		void testSizeT()
88 		{
89 			string person = "unknown";
90 			if (person == "unknown") // [warn]: 'Else' branch is identical to 'Then' branch.
91 				person = "bobrick"; // same
92 			else
93 				person = "bobrick"; // same
94 
95 			if (person == "unknown") // ok
96 				person = "ricky"; // not same
97 			else
98 				person = "bobby"; // not same
99 		}
100 	}}, sac);
101 	stderr.writeln("Unittest for IfElseSameCheck passed.");
102 }
103