1 // Copyright Brian Schott (Hackerpilot) 2014. 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.numbers; 7 8 import std.stdio; 9 import std.regex; 10 import dparse.ast; 11 import dparse.lexer; 12 import dscanner.analysis.base; 13 import dscanner.analysis.helpers; 14 import dsymbol.scope_ : Scope; 15 16 /** 17 * Checks for long and hard-to-read number literals 18 */ 19 class NumberStyleCheck : BaseAnalyzer 20 { 21 public: 22 alias visit = BaseAnalyzer.visit; 23 24 /** 25 * Constructs the style checker with the given file name. 26 */ 27 this(string fileName, const(Scope)* sc, bool skipTests = false) 28 { 29 super(fileName, sc, skipTests); 30 } 31 32 override void visit(const Token t) 33 { 34 import std.algorithm : startsWith; 35 36 if (isNumberLiteral(t.type) && !t.text.startsWith("0x") 37 && ((t.text.startsWith("0b") && !t.text.matchFirst(badBinaryRegex) 38 .empty) || !t.text.matchFirst(badDecimalRegex).empty)) 39 { 40 addErrorMessage(t.line, t.column, "dscanner.style.number_literals", 41 "Use underscores to improve number constant readability."); 42 } 43 } 44 45 private: 46 auto badBinaryRegex = ctRegex!(`^0b[01]{9,}`); 47 auto badDecimalRegex = ctRegex!(`^\d{5,}`); 48 } 49 50 unittest 51 { 52 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 53 54 StaticAnalysisConfig sac = disabledConfig(); 55 sac.number_style_check = Check.enabled; 56 assertAnalyzerWarnings(q{ 57 void testNumbers() 58 { 59 int a; 60 a = 1; // ok 61 a = 10; // ok 62 a = 100; // ok 63 a = 1000; // FIXME: boom 64 a = 10000; // [warn]: Use underscores to improve number constant readability. 65 a = 100000; // [warn]: Use underscores to improve number constant readability. 66 a = 1000000; // [warn]: Use underscores to improve number constant readability. 67 } 68 }c, sac); 69 70 stderr.writeln("Unittest for NumberStyleCheck passed."); 71 }