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.builtin_property_names; 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_; 15 import std.algorithm : map; 16 17 /** 18 * The following code should be killed with fire: 19 * --- 20 * class SomeClass 21 * { 22 * void init(); 23 * int init; 24 * string mangleof = "LOL"; 25 * auto init = 10; 26 * enum sizeof = 10; 27 * } 28 * --- 29 */ 30 final class BuiltinPropertyNameCheck : BaseAnalyzer 31 { 32 alias visit = BaseAnalyzer.visit; 33 34 mixin AnalyzerInfo!"builtin_property_names_check"; 35 36 this(string fileName, const(Scope)* sc, bool skipTests = false) 37 { 38 super(fileName, sc, skipTests); 39 } 40 41 override void visit(const FunctionDeclaration fd) 42 { 43 if (depth > 0 && isBuiltinProperty(fd.name.text)) 44 { 45 addErrorMessage(fd.name.line, fd.name.column, KEY, generateErrorMessage(fd.name.text)); 46 } 47 fd.accept(this); 48 } 49 50 override void visit(const FunctionBody functionBody) 51 { 52 immutable int d = depth; 53 scope (exit) 54 depth = d; 55 depth = 0; 56 functionBody.accept(this); 57 } 58 59 override void visit(const AutoDeclaration ad) 60 { 61 if (depth > 0) 62 foreach (i; ad.parts.map!(a => a.identifier)) 63 { 64 if (isBuiltinProperty(i.text)) 65 addErrorMessage(i.line, i.column, KEY, generateErrorMessage(i.text)); 66 } 67 } 68 69 override void visit(const Declarator d) 70 { 71 if (depth > 0 && isBuiltinProperty(d.name.text)) 72 addErrorMessage(d.name.line, d.name.column, KEY, generateErrorMessage(d.name.text)); 73 } 74 75 override void visit(const StructBody sb) 76 { 77 depth++; 78 sb.accept(this); 79 depth--; 80 } 81 82 private: 83 84 enum string KEY = "dscanner.confusing.builtin_property_names"; 85 86 string generateErrorMessage(string name) 87 { 88 import std.string : format; 89 90 return format("Avoid naming members '%s'. This can" 91 ~ " confuse code that depends on the '.%s' property of a type.", name, name); 92 } 93 94 bool isBuiltinProperty(string name) 95 { 96 import std.algorithm : canFind; 97 98 return BuiltinProperties.canFind(name); 99 } 100 101 enum string[] BuiltinProperties = ["init", "sizeof", "mangleof", "alignof", "stringof"]; 102 int depth; 103 } 104 105 unittest 106 { 107 import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig; 108 109 StaticAnalysisConfig sac = disabledConfig(); 110 sac.builtin_property_names_check = Check.enabled; 111 assertAnalyzerWarnings(q{ 112 class SomeClass 113 { 114 void init(); // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 115 int init; // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 116 auto init = 10; // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 117 } 118 }}, sac); 119 120 stderr.writeln("Unittest for NumberStyleCheck passed."); 121 }