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