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