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 dscanner.analysis.ifelsesame;
7 
8 import std.stdio;
9 import dparse.ast;
10 import dparse.lexer;
11 import dscanner.analysis.base;
12 import dscanner.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, bool skipTests = false)
28 	{
29 		super(fileName, sc, skipTests);
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) assignExpression.expression;
43 		if (e !is null && assignExpression.operator == tok!"="
44 				&& e.ternaryExpression == assignExpression.ternaryExpression)
45 		{
46 			addErrorMessage(assignExpression.line, assignExpression.column, "dscanner.bugs.self_assignment",
47 					"Left side of assignment operatior is identical to the right side.");
48 		}
49 		assignExpression.accept(this);
50 	}
51 
52 	override void visit(const AndAndExpression andAndExpression)
53 	{
54 		if (andAndExpression.left !is null && andAndExpression.right !is null
55 				&& andAndExpression.left == andAndExpression.right)
56 		{
57 			addErrorMessage(andAndExpression.line, andAndExpression.column,
58 					"dscanner.bugs.logic_operator_operands",
59 					"Left side of logical and is identical to right side.");
60 		}
61 		andAndExpression.accept(this);
62 	}
63 
64 	override void visit(const OrOrExpression orOrExpression)
65 	{
66 		if (orOrExpression.left !is null && orOrExpression.right !is null
67 				&& orOrExpression.left == orOrExpression.right)
68 		{
69 			addErrorMessage(orOrExpression.line, orOrExpression.column,
70 					"dscanner.bugs.logic_operator_operands",
71 					"Left side of logical or is identical to right side.");
72 		}
73 		orOrExpression.accept(this);
74 	}
75 }
76 
77 unittest
78 {
79 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
80 
81 	StaticAnalysisConfig sac = disabledConfig();
82 	sac.if_else_same_check = Check.enabled;
83 	assertAnalyzerWarnings(q{
84 		void testSizeT()
85 		{
86 			string person = "unknown";
87 			if (person == "unknown") // [warn]: 'Else' branch is identical to 'Then' branch.
88 				person = "bobrick"; // same
89 			else
90 				person = "bobrick"; // same
91 
92 			if (person == "unknown") // ok
93 				person = "ricky"; // not same
94 			else
95 				person = "bobby"; // not same
96 		}
97 	}c, sac);
98 	stderr.writeln("Unittest for IfElseSameCheck passed.");
99 }