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) depth = d; 51 depth = 0; 52 functionBody.accept(this); 53 } 54 55 override void visit(const AutoDeclaration ad) 56 { 57 if (depth > 0) foreach (i; ad.identifiers) 58 { 59 if (isBuiltinProperty(i.text)) 60 addErrorMessage(i.line, i.column, KEY, generateErrorMessage(i.text)); 61 } 62 } 63 64 override void visit(const Declarator d) 65 { 66 if (depth > 0 && isBuiltinProperty(d.name.text)) 67 addErrorMessage(d.name.line, d.name.column, KEY, generateErrorMessage(d.name.text)); 68 } 69 70 override void visit(const StructBody sb) 71 { 72 depth++; 73 sb.accept(this); 74 depth--; 75 } 76 77 private: 78 79 enum string KEY = "dscanner.confusing.builtin_property_names"; 80 81 string generateErrorMessage(string name) 82 { 83 import std.string : format; 84 return format("Avoid naming members '%s'. This can" 85 ~ " confuse code that depends on the '.%s' property of a type.", name, name); 86 } 87 88 bool isBuiltinProperty(string name) 89 { 90 import std.algorithm : canFind; 91 return builtinProperties.canFind(name); 92 } 93 94 enum string[] builtinProperties = [ 95 "init", "sizeof", "mangleof", "alignof", "stringof" 96 ]; 97 int depth; 98 } 99 100 unittest 101 { 102 import analysis.config : StaticAnalysisConfig; 103 StaticAnalysisConfig sac; 104 sac.builtin_property_names_check = true; 105 assertAnalyzerWarnings(q{ 106 class SomeClass 107 { 108 void init(); // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 109 int init; // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 110 auto init = 10; // [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. 111 } 112 }}, sac); 113 114 stderr.writeln("Unittest for NumberStyleCheck passed."); 115 } 116