1 // Copyright Brian Schott (Hackerpilot) 2015. 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.incorrect_infinite_range; 7 8 import dscanner.analysis.base; 9 import dscanner.analysis.helpers; 10 import dparse.ast; 11 import dparse.lexer; 12 13 /** 14 * Checks for incorrect infinite range definitions 15 */ 16 class IncorrectInfiniteRangeCheck : BaseAnalyzer 17 { 18 alias visit = BaseAnalyzer.visit; 19 20 /// 21 this(string fileName, bool skipTests = false) 22 { 23 super(fileName, null, skipTests); 24 } 25 26 override void visit(const StructBody structBody) 27 { 28 inStruct++; 29 structBody.accept(this); 30 inStruct--; 31 } 32 33 override void visit(const FunctionDeclaration fd) 34 { 35 if (inStruct > 0 && fd.name.text == "empty") 36 { 37 line = fd.name.line; 38 column = fd.name.column; 39 fd.accept(this); 40 } 41 } 42 43 override void visit(const FunctionBody fb) 44 { 45 if (fb.bodyStatement !is null) 46 visit(fb.bodyStatement.blockStatement); 47 else 48 if (fb.blockStatement !is null) 49 visit(fb.blockStatement); 50 } 51 52 override void visit(const BlockStatement bs) 53 { 54 if (bs.declarationsAndStatements is null) 55 return; 56 if (bs.declarationsAndStatements.declarationsAndStatements is null) 57 return; 58 if (bs.declarationsAndStatements.declarationsAndStatements.length != 1) 59 return; 60 visit(bs.declarationsAndStatements); 61 } 62 63 override void visit(const ReturnStatement rs) 64 { 65 if (rs.expression.items.length != 1) 66 return; 67 UnaryExpression unary = cast(UnaryExpression) rs.expression.items[0]; 68 if (unary is null) 69 return; 70 if (unary.primaryExpression is null) 71 return; 72 if (unary.primaryExpression.primary != tok!"false") 73 return; 74 addErrorMessage(line, column, KEY, MESSAGE); 75 } 76 77 override void visit(const Unittest u) 78 { 79 } 80 81 private: 82 uint inStruct; 83 enum string KEY = "dscanner.suspicious.incorrect_infinite_range"; 84 enum string MESSAGE = "Use `enum bool empty = false;` to define an infinite range."; 85 size_t line; 86 size_t column; 87 } 88 89 unittest 90 { 91 import std.stdio : stderr; 92 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 93 import std.format : format; 94 95 StaticAnalysisConfig sac = disabledConfig(); 96 sac.incorrect_infinite_range_check = Check.enabled; 97 assertAnalyzerWarnings(q{struct InfiniteRange 98 { 99 bool empty() // [warn]: %1$s 100 { 101 return false; 102 } 103 104 bool stuff() 105 { 106 return false; 107 } 108 109 unittest 110 { 111 return false; 112 } 113 114 // https://issues.dlang.org/show_bug.cgi?id=18409 115 struct Foo 116 { 117 ~this() nothrow @nogc; 118 } 119 } 120 121 bool empty() { return false; } 122 class C { bool empty() { return false; } } // [warn]: %1$s 123 124 }c 125 .format(IncorrectInfiniteRangeCheck.MESSAGE), sac); 126 127 stderr.writeln("Unittest for IncorrectInfiniteRangeCheck passed."); 128 }