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 final class IfElseSameCheck : BaseAnalyzer 24 { 25 alias visit = BaseAnalyzer.visit; 26 27 mixin AnalyzerInfo!"if_else_same_check"; 28 29 this(string fileName, const(Scope)* sc, bool skipTests = false) 30 { 31 super(fileName, sc, skipTests); 32 } 33 34 override void visit(const IfStatement ifStatement) 35 { 36 if (ifStatement.thenStatement && (ifStatement.thenStatement == ifStatement.elseStatement)) 37 addErrorMessage(ifStatement.line, ifStatement.column, 38 "dscanner.bugs.if_else_same", "'Else' branch is identical to 'Then' branch."); 39 ifStatement.accept(this); 40 } 41 42 override void visit(const AssignExpression assignExpression) 43 { 44 auto e = cast(const AssignExpression) assignExpression.expression; 45 if (e !is null && assignExpression.operator == tok!"=" 46 && e.ternaryExpression == assignExpression.ternaryExpression) 47 { 48 addErrorMessage(assignExpression.line, assignExpression.column, "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 dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 82 83 StaticAnalysisConfig sac = disabledConfig(); 84 sac.if_else_same_check = Check.enabled; 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 101 assertAnalyzerWarnings(q{ 102 void foo() 103 { 104 if (auto stuff = call()) 105 } 106 }}, sac); 107 108 stderr.writeln("Unittest for IfElseSameCheck passed."); 109 }