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 analysis.lambda_return_check;
7 
8 import dparse.ast;
9 import dparse.lexer;
10 import 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 unittest
48 {
49 	import analysis.helpers : assertAnalyzerWarnings;
50 	import analysis.config : StaticAnalysisConfig, Check;
51 	import std.stdio : stderr;
52 
53 	StaticAnalysisConfig sac;
54 	sac.lambda_return_check = Check.enabled;
55 
56 	auto code = `
57 		void main()
58 		{
59 			int[] b;
60 			auto a = b.map!(a => { return a * a + 2; }).array(); // [warn]: This lambda returns a lambda. Add parenthesis to clarify.
61 			pragma(msg, typeof(a => { return a; })); // [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({ return a; }));
64 			pragma(msg, typeof(a => () { return a; }));
65 		}`c;
66 	assertAnalyzerWarnings(code, sac);
67 	stderr.writeln("Unittest for LambdaReturnCheck passed.");
68 }