Implement static analysis check for members and properties that shadow built-in properties
This commit is contained in:
parent
7d5dd3bfde
commit
798cdbffbf
|
@ -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.");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue