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

118 lines
3.3 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 dscanner.analysis.base;
/**
* The following code should be killed with fire:
* ---
* class SomeClass
* {
* void init();
* int init;
* string mangleof = "LOL";
* auto init = 10;
* enum sizeof = 10;
* }
* ---
*/
extern(C++) class BuiltinPropertyNameCheck(AST) : BaseAnalyzerDmd
{
alias visit = BaseAnalyzerDmd.visit;
mixin AnalyzerInfo!"builtin_property_names_check";
extern(D) this(string fileName)
{
super(fileName);
}
mixin AggregateVisit!(AST.StructDeclaration);
mixin AggregateVisit!(AST.ClassDeclaration);
mixin AggregateVisit!(AST.InterfaceDeclaration);
mixin AggregateVisit!(AST.UnionDeclaration);
override void visit(AST.VarDeclaration vd)
{
if (inAggregate && isBuiltinProperty(vd.ident.toString()))
addErrorMessage(cast(ulong) vd.loc.linnum, cast(ulong) vd.loc.charnum,
KEY, generateErrorMessage(vd.ident.toString()));
}
override void visit(AST.FuncDeclaration fd)
{
if (inAggregate && isBuiltinProperty(fd.ident.toString()))
addErrorMessage(cast(ulong) fd.loc.linnum, cast(ulong) fd.loc.charnum,
KEY, generateErrorMessage(fd.ident.toString()));
}
override void visit(AST.AliasDeclaration ad)
{
if (inAggregate && isBuiltinProperty(ad.ident.toString()))
addErrorMessage(cast(ulong) ad.loc.linnum, cast(ulong) ad.loc.charnum,
KEY, generateErrorMessage(ad.ident.toString()));
}
override void visit(AST.TemplateDeclaration td)
{
if (inAggregate && isBuiltinProperty(td.ident.toString()))
addErrorMessage(cast(ulong) td.loc.linnum, cast(ulong) td.loc.charnum,
KEY, generateErrorMessage(td.ident.toString()));
}
private:
enum string KEY = "dscanner.confusing.builtin_property_names";
template AggregateVisit(NodeType)
{
override void visit(NodeType n)
{
inAggregate++;
super.visit(n);
inAggregate--;
}
}
extern(D) string generateErrorMessage(const(char)[] 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);
}
extern(D) bool isBuiltinProperty(const(char)[] name)
{
import std.algorithm : canFind;
return BuiltinProperties.canFind(name);
}
enum string[] BuiltinProperties = ["init", "sizeof", "mangleof", "alignof", "stringof"];
int inAggregate;
}
unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import dscanner.analysis.helpers : assertAnalyzerWarnings = assertAnalyzerWarningsDMD;
import std.stdio : stderr;
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 BuiltinPropertyNamesCheck passed.");
}