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 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 }