This commit is contained in:
Hackerpilot 2014-07-23 15:06:07 -07:00
parent 622c5e75cb
commit 7d5dd3bfde
4 changed files with 92 additions and 14 deletions

View File

@ -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;
}

View File

@ -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.");
}

View File

@ -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)
{

View File

@ -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>");