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 dscanner.analysis.builtin_property_names;
7 
8 import std.stdio;
9 import std.regex;
10 import dparse.ast;
11 import dparse.lexer;
12 import dscanner.analysis.base;
13 import dscanner.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 dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
106 
107 	StaticAnalysisConfig sac = disabledConfig();
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 	}c, sac);
117 
118 	stderr.writeln("Unittest for NumberStyleCheck passed.");
119 }