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