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