1 // Copyright Chris Wright (dhasenan) 2016.
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.static_if_else;
7 
8 import dparse.ast;
9 import dparse.lexer;
10 import analysis.base;
11 
12 /**
13  * Checks for potentially mistaken static if / else if.
14  *
15  * It's potentially valid to write:
16  * ---
17  * static if (foo) {
18  * } else if (bar) {
19  * }
20  * ---
21  * 
22  * However, it's more likely that this is a mistake.
23  */
24 class StaticIfElse : BaseAnalyzer
25 {
26 	alias visit = BaseAnalyzer.visit;
27 
28 	this(string fileName, bool skipTests = false)
29 	{
30 		super(fileName, null, skipTests);
31 	}
32 
33 	override void visit(const ConditionalStatement cc)
34 	{
35 		cc.accept(this);
36 		if (cc.falseStatement is null)
37 		{
38 			return;
39 		}
40 		const(IfStatement) ifStmt = getIfStatement(cc);
41 		if (!ifStmt)
42 		{
43 			return;
44 		}
45 		addErrorMessage(ifStmt.line, ifStmt.column, KEY, "Mismatched static if. Use 'else static if' here.");
46 	}
47 
48 	const(IfStatement) getIfStatement(const ConditionalStatement cc)
49 	{
50 		if (cc.falseStatement.statement)
51 		{
52 			if (cc.falseStatement.statement.statementNoCaseNoDefault)
53 			{
54 				if (cc.falseStatement.statement.statementNoCaseNoDefault.ifStatement)
55 				{
56 					return cc.falseStatement.statement.statementNoCaseNoDefault.ifStatement;
57 				}
58 			}
59 		}
60 		return null;
61 	}
62 
63 	enum KEY = "dscanner.suspicious.static_if_else";
64 }
65 
66 unittest
67 {
68 	import analysis.helpers : assertAnalyzerWarnings;
69 	import analysis.config : StaticAnalysisConfig, Check;
70 	import std.stdio : stderr;
71 
72 	StaticAnalysisConfig sac;
73 	sac.static_if_else_check = Check.enabled;
74 	assertAnalyzerWarnings(q{
75 		void foo() {
76 			static if (false)
77 				auto a = 0;
78 			else if (true) // [warn]: Mismatched static if. Use 'else static if' here.
79 				auto b = 1;
80 		}
81 	}}, sac);
82 	// Explicit braces, so no warning.
83 	assertAnalyzerWarnings(q{
84 		void foo() {
85 			static if (false)
86 				auto a = 0;
87 			else {
88 				if (true)
89 					auto b = 1;
90 			}
91 		}
92 	}}, sac);
93 
94 	stderr.writeln("Unittest for StaticIfElse passed.");
95 }