1 //          Copyright Brian Schott (Hackerpilot) 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.lambda_return_check;
7 
8 import dparse.ast;
9 import dparse.lexer;
10 import dscanner.analysis.base;
11 
12 final class LambdaReturnCheck : BaseAnalyzer
13 {
14 	alias visit = BaseAnalyzer.visit;
15 
16 	this(string fileName, bool skipTests = false)
17 	{
18 		super(fileName, null, skipTests);
19 	}
20 
21 	override void visit(const FunctionLiteralExpression fLit)
22 	{
23 		if (fLit.assignExpression is null)
24 			return;
25 		const UnaryExpression unary = cast(const UnaryExpression) fLit.assignExpression;
26 		if (unary is null)
27 			return;
28 		if (unary.primaryExpression is null)
29 			return;
30 		if (unary.primaryExpression.functionLiteralExpression is null)
31 			return;
32 		if (unary.primaryExpression.functionLiteralExpression.parameters !is null)
33 			return;
34 		if (unary.primaryExpression.functionLiteralExpression.identifier != tok!"")
35 			return;
36 		if (unary.primaryExpression.functionLiteralExpression.functionBody is null)
37 			return;
38 		if (unary.primaryExpression.functionLiteralExpression.functionBody.blockStatement is null)
39 			return;
40 		addErrorMessage(fLit.line, fLit.column, KEY, "This lambda returns a lambda. Add parenthesis to clarify.");
41 	}
42 
43 private:
44 	enum KEY = "dscanner.confusing.lambda_returns_lambda";
45 }
46 
47 version(Windows) {/*because of newline in code*/} else
48 unittest
49 {
50 	import dscanner.analysis.helpers : assertAnalyzerWarnings;
51 	import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
52 	import std.stdio : stderr;
53 
54 	StaticAnalysisConfig sac = disabledConfig();
55 	sac.lambda_return_check = Check.enabled;
56 
57 	auto code = `
58 		void main()
59 		{
60 			int[] b;
61 			auto a = b.map!(a => { return a * a + 2; }).array(); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
62 			pragma(msg, typeof(a => { return a; })); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
63 			pragma(msg, typeof((a) => { return a; })); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
64 			pragma(msg, typeof({ return a; }));
65 			pragma(msg, typeof(a => () { return a; }));
66 		}`c;
67 	assertAnalyzerWarnings(code, sac);
68 	stderr.writeln("Unittest for LambdaReturnCheck passed.");
69 }