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