Implement #191
This commit is contained in:
parent
622c5e75cb
commit
7d5dd3bfde
|
@ -56,4 +56,7 @@ struct StaticAnalysisConfig
|
|||
|
||||
@INI("Checks that opEquals and toHash are both defined or neither are defined")
|
||||
bool opequals_tohash_check;
|
||||
|
||||
@INI("Checks for subtraction from .length properties")
|
||||
bool length_subtraction_check;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// 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.length_subtraction;
|
||||
|
||||
import std.stdio;
|
||||
|
||||
import std.d.ast;
|
||||
import std.d.lexer;
|
||||
import analysis.base;
|
||||
import analysis.helpers;
|
||||
|
||||
|
||||
/**
|
||||
* Checks for subtraction from a .length property. This is usually a bug.
|
||||
*/
|
||||
class LengthSubtractionCheck : BaseAnalyzer
|
||||
{
|
||||
alias visit = BaseAnalyzer.visit;
|
||||
|
||||
this(string fileName)
|
||||
{
|
||||
super(fileName);
|
||||
}
|
||||
|
||||
override void visit(const AddExpression addExpression)
|
||||
{
|
||||
if (addExpression.operator == tok!"-")
|
||||
{
|
||||
UnaryExpression l = cast(UnaryExpression) addExpression.left;
|
||||
UnaryExpression r = cast(UnaryExpression) addExpression.right;
|
||||
if (l is null || r is null)
|
||||
{
|
||||
// stderr.writeln(__FILE__, " ", __LINE__);
|
||||
goto end;
|
||||
}
|
||||
if (r.primaryExpression is null || r.primaryExpression.primary.type != tok!"intLiteral")
|
||||
{
|
||||
// stderr.writeln(__FILE__, " ", __LINE__);
|
||||
goto end;
|
||||
}
|
||||
if (l.identifierOrTemplateInstance is null
|
||||
|| l.identifierOrTemplateInstance.identifier.text != "length")
|
||||
{
|
||||
// stderr.writeln(__FILE__, " ", __LINE__);
|
||||
goto end;
|
||||
}
|
||||
const(Token) token = l.identifierOrTemplateInstance.identifier;
|
||||
addErrorMessage(token.line, token.column,
|
||||
"Avoid subtracting from '.length' as it may be unsigned.");
|
||||
}
|
||||
end:
|
||||
addExpression.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import analysis.config;
|
||||
StaticAnalysisConfig sac;
|
||||
sac.if_else_same_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
void testSizeT()
|
||||
{
|
||||
if (i < a.length - 1) // [warn]: Avoid subtracting from '.length' as it may be unsigned.
|
||||
writeln("something");
|
||||
}
|
||||
}c, sac);
|
||||
stderr.writeln("Unittest for IfElseSameCheck passed.");
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import analysis.constructors;
|
|||
import analysis.unused;
|
||||
import analysis.duplicate_attribute;
|
||||
import analysis.opequals_without_tohash;
|
||||
import analysis.length_subtraction;
|
||||
|
||||
void messageFunction(string fileName, size_t line, size_t column, string message,
|
||||
bool isError)
|
||||
|
@ -94,6 +95,7 @@ string[] analyze(string fileName, ubyte[] code, StaticAnalysisConfig analysisCon
|
|||
if (analysisConfig.unused_variable_check) checks ~= new UnusedVariableCheck(fileName);
|
||||
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);
|
||||
|
||||
foreach (check; checks)
|
||||
{
|
||||
|
|
28
astprinter.d
28
astprinter.d
|
@ -61,12 +61,12 @@ class XMLPrinter : ASTVisitor
|
|||
{
|
||||
output.writeln("<andAndExpression>");
|
||||
output.writeln("<left>");
|
||||
andAndExpression.left.accept(this);
|
||||
visit(andAndExpression.left);
|
||||
output.writeln("</left>");
|
||||
if (andAndExpression.right !is null)
|
||||
{
|
||||
output.writeln("<right>");
|
||||
andAndExpression.right.accept(this);
|
||||
visit(andAndExpression.right);
|
||||
output.writeln("</right>");
|
||||
}
|
||||
output.writeln("</andAndExpression>");
|
||||
|
@ -76,12 +76,12 @@ class XMLPrinter : ASTVisitor
|
|||
{
|
||||
output.writeln("<andExpression>");
|
||||
output.writeln("<left>");
|
||||
andExpression.left.accept(this);
|
||||
visit(andExpression.left);
|
||||
output.writeln("</left>");
|
||||
if (andExpression.right !is null)
|
||||
{
|
||||
output.writeln("<right>");
|
||||
andExpression.right.accept(this);
|
||||
visit(andExpression.right);
|
||||
output.writeln("</right>");
|
||||
}
|
||||
output.writeln("</andExpression>");
|
||||
|
@ -441,10 +441,10 @@ class XMLPrinter : ASTVisitor
|
|||
{
|
||||
output.writeln("<equalExpression operator=\"", str(equalExpression.operator), "\">");
|
||||
output.writeln("<left>");
|
||||
equalExpression.left.accept(this);
|
||||
visit(equalExpression.left);
|
||||
output.writeln("</left>");
|
||||
output.writeln("<right>");
|
||||
equalExpression.right.accept(this);
|
||||
visit(equalExpression.right);
|
||||
output.writeln("</right>");
|
||||
output.writeln("</equalExpression>");
|
||||
}
|
||||
|
@ -956,12 +956,12 @@ class XMLPrinter : ASTVisitor
|
|||
{
|
||||
output.writeln("<powExpression>");
|
||||
output.writeln("<left>");
|
||||
powExpression.left.accept(this);
|
||||
visit(powExpression.left);
|
||||
output.writeln("</left>");
|
||||
if (powExpression.right !is null)
|
||||
{
|
||||
output.writeln("<right>");
|
||||
powExpression.right.accept(this);
|
||||
visit(powExpression.right);
|
||||
output.writeln("</right>");
|
||||
}
|
||||
output.writeln("</powExpression>");
|
||||
|
@ -997,10 +997,10 @@ class XMLPrinter : ASTVisitor
|
|||
output.writeln("<relExpression operator=\"",
|
||||
xmlAttributeEscape(str(relExpression.operator)), "\">");
|
||||
output.writeln("<left>");
|
||||
relExpression.left.accept(this);
|
||||
visit(relExpression.left);
|
||||
output.writeln("</left>");
|
||||
output.writeln("<right>");
|
||||
relExpression.right.accept(this);
|
||||
visit(relExpression.right);
|
||||
output.writeln("</right>");
|
||||
output.writeln("</relExpression>");
|
||||
}
|
||||
|
@ -1037,10 +1037,10 @@ class XMLPrinter : ASTVisitor
|
|||
output.writeln("<shiftExpression operator=\"",
|
||||
xmlAttributeEscape(str(shiftExpression.operator)), "\">");
|
||||
output.writeln("<left>");
|
||||
shiftExpression.left.accept(this);
|
||||
visit(shiftExpression.left);
|
||||
output.writeln("</left>");
|
||||
output.writeln("<right>");
|
||||
shiftExpression.right.accept(this);
|
||||
visit(shiftExpression.right);
|
||||
output.writeln("</right>");
|
||||
output.writeln("</shiftExpression>");
|
||||
}
|
||||
|
@ -1496,12 +1496,12 @@ class XMLPrinter : ASTVisitor
|
|||
{
|
||||
output.writeln("<xorExpression>");
|
||||
output.writeln("<left>");
|
||||
xorExpression.left.accept(this);
|
||||
visit(xorExpression.left);
|
||||
output.writeln("</left>");
|
||||
if (xorExpression.right !is null)
|
||||
{
|
||||
output.writeln("<right>");
|
||||
xorExpression.right.accept(this);
|
||||
visit(xorExpression.right);
|
||||
output.writeln("</right>");
|
||||
}
|
||||
output.writeln("</xorExpression>");
|
||||
|
|
Loading…
Reference in New Issue