1 // Copyright Basile Burg 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.auto_function; 7 8 import analysis.base; 9 import analysis.helpers; 10 import dparse.ast; 11 import dparse.lexer; 12 13 import std.stdio; 14 import std.algorithm.searching : any; 15 16 /** 17 * Checks for auto functions without return statement. 18 * 19 * Auto function without return statement can be an omission and are not 20 * detected by the compiler. However sometimes they can be used as a trick 21 * to infer attributes. 22 */ 23 final class AutoFunctionChecker : BaseAnalyzer 24 { 25 26 private: 27 28 enum string KEY = "dscanner.suspicious.missing_return"; 29 enum string MESSAGE = "Auto function without return statement, prefer an explicit void"; 30 31 bool[] _returns; 32 33 public: 34 35 alias visit = BaseAnalyzer.visit; 36 37 /// 38 this(string fileName, bool skipTests = false) 39 { 40 super(fileName, null, skipTests); 41 } 42 43 override void visit(const FunctionDeclaration decl) 44 { 45 _returns.length += 1; 46 scope(exit) _returns.length -= 1; 47 _returns[$-1] = false; 48 49 const bool autoFun = decl.storageClasses 50 .any!(a => a.token.type == tok!"auto"); 51 52 decl.accept(this); 53 54 if (autoFun && !_returns[$-1]) 55 addErrorMessage(decl.name.line, decl.name.column, KEY, MESSAGE); 56 } 57 58 override void visit(const ReturnStatement rst) 59 { 60 if (_returns.length) 61 _returns[$-1] = true; 62 rst.accept(this); 63 } 64 } 65 66 unittest 67 { 68 import std.stdio : stderr; 69 import std.format : format; 70 import analysis.config : StaticAnalysisConfig, Check; 71 import analysis.helpers : assertAnalyzerWarnings; 72 73 StaticAnalysisConfig sac; 74 sac.auto_function_check = Check.enabled; 75 assertAnalyzerWarnings(q{ 76 auto ref doStuff(){} // [warn]: %s 77 auto doStuff(){} // [warn]: %s 78 int doStuff(){auto doStuff(){}} // [warn]: %s 79 auto doStuff(){return 0;} 80 int doStuff(){/*error but not the aim*/} 81 }}.format( 82 AutoFunctionChecker.MESSAGE, 83 AutoFunctionChecker.MESSAGE, 84 AutoFunctionChecker.MESSAGE, 85 ), sac); 86 stderr.writeln("Unittest for AutoFunctionChecker passed."); 87 }