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