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