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", "'Else' branch is identical to 'Then' branch.");
37 		ifStatement.accept(this);
38 	}
39 
40 	override void visit(const AssignExpression assignExpression)
41 	{
42 		auto e = cast(const AssignExpression)(cast(const Expression) assignExpression.expression)
43 			.items[$ - 1];
44 		if (e !is null && assignExpression.operator == tok!"="
45 				&& e.ternaryExpression == assignExpression.ternaryExpression)
46 		{
47 			addErrorMessage(assignExpression.line, assignExpression.column, "dscanner.bugs.self_assignment",
48 					"Left side of assignment operatior is identical to the right side.");
49 		}
50 		assignExpression.accept(this);
51 	}
52 
53 	override void visit(const AndAndExpression andAndExpression)
54 	{
55 		if (andAndExpression.left !is null && andAndExpression.right !is null
56 				&& andAndExpression.left == andAndExpression.right)
57 		{
58 			addErrorMessage(andAndExpression.line, andAndExpression.column,
59 					"dscanner.bugs.logic_operator_operands",
60 					"Left side of logical and is identical to right side.");
61 		}
62 		andAndExpression.accept(this);
63 	}
64 
65 	override void visit(const OrOrExpression orOrExpression)
66 	{
67 		if (orOrExpression.left !is null && orOrExpression.right !is null
68 				&& orOrExpression.left == orOrExpression.right)
69 		{
70 			addErrorMessage(orOrExpression.line, orOrExpression.column,
71 					"dscanner.bugs.logic_operator_operands",
72 					"Left side of logical or is identical to right side.");
73 		}
74 		orOrExpression.accept(this);
75 	}
76 }
77 
78 unittest
79 {
80 	import analysis.config : StaticAnalysisConfig;
81 
82 	StaticAnalysisConfig sac;
83 	sac.if_else_same_check = true;
84 	assertAnalyzerWarnings(q{
85 		void testSizeT()
86 		{
87 			string person = "unknown";
88 			if (person == "unknown") // [warn]: 'Else' branch is identical to 'Then' branch.
89 				person = "bobrick"; // same
90 			else
91 				person = "bobrick"; // same
92 
93 			if (person == "unknown") // ok
94 				person = "ricky"; // not same
95 			else
96 				person = "bobby"; // not same
97 		}
98 	}}, sac);
99 	stderr.writeln("Unittest for IfElseSameCheck passed.");
100 }