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")
|
@INI("Checks for subtraction from .length properties")
|
||||||
bool length_subtraction_check;
|
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.duplicate_attribute;
|
||||||
import analysis.opequals_without_tohash;
|
import analysis.opequals_without_tohash;
|
||||||
import analysis.length_subtraction;
|
import analysis.length_subtraction;
|
||||||
|
import analysis.builtin_property_names;
|
||||||
|
|
||||||
void messageFunction(string fileName, size_t line, size_t column, string message,
|
void messageFunction(string fileName, size_t line, size_t column, string message,
|
||||||
bool isError)
|
bool isError)
|
||||||
|
@ -96,6 +97,7 @@ string[] analyze(string fileName, ubyte[] code, StaticAnalysisConfig analysisCon
|
||||||
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
|
if (analysisConfig.duplicate_attribute) checks ~= new DuplicateAttributeCheck(fileName);
|
||||||
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
|
if (analysisConfig.opequals_tohash_check) checks ~= new OpEqualsWithoutToHashCheck(fileName);
|
||||||
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
|
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
|
||||||
|
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
|
||||||
|
|
||||||
foreach (check; checks)
|
foreach (check; checks)
|
||||||
{
|
{
|
||||||
|
|
|
@ -307,7 +307,7 @@ class UnusedVariableCheck : BaseAnalyzer
|
||||||
if (!uu.isRef)
|
if (!uu.isRef)
|
||||||
addErrorMessage(uu.line, uu.column,
|
addErrorMessage(uu.line, uu.column,
|
||||||
(uu.isParameter ? "Parameter " : "Variable ")
|
(uu.isParameter ? "Parameter " : "Variable ")
|
||||||
~ uu.name ~ " is never used");
|
~ uu.name ~ " is never used.");
|
||||||
}
|
}
|
||||||
tree = tree[0 .. $ - 1];
|
tree = tree[0 .. $ - 1];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 98ab5c704d336da3af507563c676d9c022f21e70
|
Subproject commit 04241f78cda7d9a784893d287ec0bb1304cbd6db
|
Loading…
Reference in New Issue