D-Scanner/src/dscanner/analysis/builtin_property_names.d

125 lines
2.9 KiB
D

// Copyright Brian Schott (Hackerpilot) 2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
module dscanner.analysis.builtin_property_names;
import std.stdio;
import std.regex;
import dparse.ast;
import dparse.lexer;
import dscanner.analysis.base;
import dscanner.analysis.helpers;
import dsymbol.scope_;
import std.algorithm : map;
/**
* The following code should be killed with fire:
* ---
* class SomeClass
* {
* void init();
* int init;
* string mangleof = "LOL";
* auto init = 10;
* enum sizeof = 10;
* }
* ---
*/
final class BuiltinPropertyNameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
mixin AnalyzerInfo!"builtin_property_names_check";
this(string fileName, const(Scope)* sc, bool skipTests = false)
{
super(fileName, sc, skipTests);
}
override void visit(const FunctionDeclaration fd)
{
if (depth > 0 && isBuiltinProperty(fd.name.text))
{
addErrorMessage(fd.name, KEY, generateErrorMessage(fd.name.text));
}
fd.accept(this);
}
override void visit(const FunctionBody functionBody)
{
immutable int d = depth;
scope (exit)
depth = d;
depth = 0;
functionBody.accept(this);
}
override void visit(const AutoDeclaration ad)
{
if (depth > 0)
foreach (i; ad.parts.map!(a => a.identifier))
{
if (isBuiltinProperty(i.text))
addErrorMessage(i, KEY, generateErrorMessage(i.text));
}
}
override void visit(const Declarator d)
{
if (depth > 0 && isBuiltinProperty(d.name.text))
addErrorMessage(d.name, KEY, generateErrorMessage(d.name.text));
}
override void visit(const StructBody sb)
{
depth++;
sb.accept(this);
depth--;
}
private:
enum string KEY = "dscanner.confusing.builtin_property_names";
string generateErrorMessage(string name)
{
import std.string : format;
return format("Avoid naming members '%s'. This can"
~ " confuse code that depends on the '.%s' property of a type.", name, name);
}
bool isBuiltinProperty(string name)
{
import std.algorithm : canFind;
return BuiltinProperties.canFind(name);
}
enum string[] BuiltinProperties = ["init", "sizeof", "mangleof", "alignof", "stringof"];
int depth;
}
unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
StaticAnalysisConfig sac = disabledConfig();
sac.builtin_property_names_check = Check.enabled;
assertAnalyzerWarnings(q{
class SomeClass
{
void init(); /+
^^^^ [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. +/
int init; /+
^^^^ [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. +/
auto init = 10; /+
^^^^ [warn]: Avoid naming members 'init'. This can confuse code that depends on the '.init' property of a type. +/
}
}c, sac);
stderr.writeln("Unittest for NumberStyleCheck passed.");
}