From 619f1f05c82f57fc1bcab971531620507614dffd Mon Sep 17 00:00:00 2001 From: Hackerpilot Date: Mon, 17 Feb 2014 21:10:23 -0800 Subject: [PATCH] Fix #111 --- analysis/del.d | 2 +- analysis/range.d | 104 +++++++++++++++++++++++++++++++++++++++++++++++ analysis/run.d | 6 ++- 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 analysis/range.d diff --git a/analysis/del.d b/analysis/del.d index 8cd3646..04aa33f 100644 --- a/analysis/del.d +++ b/analysis/del.d @@ -23,7 +23,7 @@ class DeleteCheck : BaseAnalyzer override void visit(DeleteExpression d) { - addErrorMessage(d.line, d.column, "Avoid using the deprecated delete keyword"); + addErrorMessage(d.line, d.column, "Avoid using the delete keyword"); d.accept(this); } } diff --git a/analysis/range.d b/analysis/range.d new file mode 100644 index 0000000..556acf8 --- /dev/null +++ b/analysis/range.d @@ -0,0 +1,104 @@ +// 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.range; + +import stdx.d.ast; +import stdx.d.lexer; +import analysis.base; + +/** + * Checks for .. expressions where the left side is larger than the right. This + * is almost always a mistake. + */ +class BackwardsRangeCheck : BaseAnalyzer +{ + alias visit = BaseAnalyzer.visit; + + bool hasLeft; + bool hasRight; + long left; + long right; + size_t column; + size_t line; + enum State { ignore, left, right } + State state = State.ignore; + + this(string fileName) + { + super(fileName); + } + + override void visit(ForeachStatement foreachStatement) + { + if (foreachStatement.low !is null && foreachStatement.high !is null) + { + import std.string; + state = State.left; + foreachStatement.low.accept(this); + state = State.right; + foreachStatement.high.accept(this); + state = State.ignore; + if (hasLeft && hasRight && left > right) + { + string message = format( + "%d is larger than %d. Did you mean to use 'foreach_reverse( ... ; %d .. %d)'?", + left, right, right, left); + addErrorMessage(line, this.column, message); + } + hasLeft = false; + hasRight = false; + foreachStatement.accept(this); + } + } + + override void visit(UnaryExpression unary) + { + if (state != State.ignore && unary.primaryExpression is null) + return; + else + unary.accept(this); + } + + override void visit(PrimaryExpression primary) + { + import std.conv; + if (state == State.ignore || !isNumberLiteral(primary.primary.type)) + return; + if (state == State.left) + { + line = primary.primary.line; + column = primary.primary.column; + left = to!long(primary.primary.text); + hasLeft = true; + } + else + { + right = to!long(primary.primary.text); + hasRight = true; + } + } + + override void visit(SliceExpression sliceExpression) + { + import std.stdio; + state = State.left; + sliceExpression.lower.accept(this); + state = State.right; + sliceExpression.upper.accept(this); + state = State.ignore; + if (hasLeft && hasRight && left > right) + { + import std.string; + string message = format( + "%d is larger than %d. This slice is likely incorrect.", + left, right); + addErrorMessage(line, this.column, message); + } + hasLeft = false; + hasRight = false; + sliceExpression.accept(this); + } +} diff --git a/analysis/run.d b/analysis/run.d index 12d935f..3b5bad6 100644 --- a/analysis/run.d +++ b/analysis/run.d @@ -19,6 +19,7 @@ import analysis.del; import analysis.fish; import analysis.numbers; import analysis.objectconst; +import analysis.range; void messageFunction(string fileName, size_t line, size_t column, string message, bool isError) @@ -79,9 +80,12 @@ void analyze(File output, string[] fileNames, bool staticAnalyze = true) auto objConst = new ObjectConstCheck(fileName); objConst.visit(m); + auto backwardsRange = new BackwardsRangeCheck(fileName); + backwardsRange.visit(m); + foreach (message; sort(chain(enums.messages, style.messages, pokemon.messages, del.messages, fish.messages, numbers.messages, - objConst.messages).array)) + objConst.messages, backwardsRange.messages).array)) { writeln(message); }