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 final class StaticIfElse : BaseAnalyzer
26 {
27 	alias visit = BaseAnalyzer.visit;
28 
29 	mixin AnalyzerInfo!"static_if_else_check";
30 
31 	this(string fileName, bool skipTests = false)
32 	{
33 		super(fileName, null, skipTests);
34 	}
35 
36 	override void visit(const ConditionalStatement cc)
37 	{
38 		cc.accept(this);
39 		if (cc.falseStatement is null)
40 		{
41 			return;
42 		}
43 		const(IfStatement) ifStmt = getIfStatement(cc);
44 		if (!ifStmt)
45 		{
46 			return;
47 		}
48 		addErrorMessage(ifStmt.line, ifStmt.column, KEY, "Mismatched static if. Use 'else static if' here.");
49 	}
50 
51 	const(IfStatement) getIfStatement(const ConditionalStatement cc)
52 	{
53 		return safeAccess(cc).falseStatement.statement.statementNoCaseNoDefault.ifStatement;
54 	}
55 
56 	enum KEY = "dscanner.suspicious.static_if_else";
57 }
58 
59 unittest
60 {
61 	import dscanner.analysis.helpers : assertAnalyzerWarnings;
62 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
63 	import std.stdio : stderr;
64 
65 	StaticAnalysisConfig sac = disabledConfig();
66 	sac.static_if_else_check = Check.enabled;
67 	assertAnalyzerWarnings(q{
68 		void foo() {
69 			static if (false)
70 				auto a = 0;
71 			else if (true) // [warn]: Mismatched static if. Use 'else static if' here.
72 				auto b = 1;
73 		}
74 	}}, sac);
75 	// Explicit braces, so no warning.
76 	assertAnalyzerWarnings(q{
77 		void foo() {
78 			static if (false)
79 				auto a = 0;
80 			else {
81 				if (true)
82 					auto b = 1;
83 			}
84 		}
85 	}}, sac);
86 
87 	stderr.writeln("Unittest for StaticIfElse passed.");
88 }