Implement static analysis check for members and properties that shadow built-in properties

This commit is contained in:
Hackerpilot 2014-07-24 18:12:31 -07:00
parent 7d5dd3bfde
commit 798cdbffbf
5 changed files with 112 additions and 2 deletions

View File

@ -0,0 +1,105 @@
// Copyright Brian Schott (Sir Alaran) 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 analysis.builtin_property_names;
import std.stdio;
import std.regex;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
/**
* The following code should be killed with fire:
* ---
* class SomeClass
* {
* void init();
* int init;
* string mangleof = "LOL";
* auto init = 10;
* enum sizeof = 10;
* }
* ---
*/
class BuiltinPropertyNameCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
{
super(fileName);
}
override void visit(const FunctionDeclaration fd)
{
if (depth > 0 && isBuiltinProperty(fd.name.text))
{
addErrorMessage(fd.name.line, fd.name.column, generateErrorMessage(fd.name.text));
}
fd.accept(this);
}
override void visit(const AutoDeclaration ad)
{
if (depth > 0) foreach (i; ad.identifiers)
{
if (isBuiltinProperty(i.text))
addErrorMessage(i.line, i.column, generateErrorMessage(i.text));
}
}
override void visit(const Declarator d)
{
if (depth > 0 && isBuiltinProperty(d.name.text))
addErrorMessage(d.name.line, d.name.column, generateErrorMessage(d.name.text));
}
override void visit(const StructBody sb)
{
depth++;
sb.accept(this);
depth--;
}
private:
string generateErrorMessage(string name)
{
import std.string;
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;
return builtinProperties.canFind(name);
}
enum string[] builtinProperties = [
"init", "sizeof", "mangleof", "alignof", "stringof"
];
int depth;
}
unittest
{
import analysis.config;
StaticAnalysisConfig sac;
sac.builtin_property_name_check = true;
assertAnalyzerWarnings(q{
class SomeClass
{
void init(); //
int init;
auto init = 10;
}
}c, sac);
stderr.writeln("Unittest for NumberStyleCheck passed.");
}

View File

@ -59,4 +59,7 @@ struct StaticAnalysisConfig
@INI("Checks for subtraction from .length properties")
bool length_subtraction_check;
@INI("Checks for methods or properties whose names conflict with built-in properties")
bool builtin_property_names_check;
}

View File

@ -26,6 +26,7 @@ import analysis.unused;
import analysis.duplicate_attribute;
import analysis.opequals_without_tohash;
import analysis.length_subtraction;
import analysis.builtin_property_names;
void messageFunction(string fileName, size_t line, size_t column, string message,
bool isError)
@ -96,6 +97,7 @@ string[] analyze(string fileName, ubyte[] code, StaticAnalysisConfig analysisCon
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
foreach (check; checks)
{

View File

@ -307,7 +307,7 @@ class UnusedVariableCheck : BaseAnalyzer
if (!uu.isRef)
addErrorMessage(uu.line, uu.column,
(uu.isParameter ? "Parameter " : "Variable ")
~ uu.name ~ " is never used");
~ uu.name ~ " is never used.");
}
tree = tree[0 .. $ - 1];
}

@ -1 +1 @@
Subproject commit 98ab5c704d336da3af507563c676d9c022f21e70
Subproject commit 04241f78cda7d9a784893d287ec0bb1304cbd6db