Merge pull request #249 from WalterWaldron/fix242

Fix #242 - Warn about unused labels
This commit is contained in:
Brian Schott 2015-05-11 13:41:24 -07:00
commit 1ea4f53a38
3 changed files with 177 additions and 0 deletions

View File

@ -51,6 +51,9 @@ struct StaticAnalysisConfig
@INI("Checks for unused variables and function parameters")
bool unused_variable_check;
@INI("Checks for unused labels")
bool unused_label_check;
@INI("Checks for duplicate attributes")
bool duplicate_attribute;

View File

@ -28,6 +28,7 @@ import analysis.range;
import analysis.ifelsesame;
import analysis.constructors;
import analysis.unused;
import analysis.unused_label;
import analysis.duplicate_attribute;
import analysis.opequals_without_tohash;
import analysis.length_subtraction;
@ -176,6 +177,7 @@ MessageSet analyze(string fileName, const Module m,
if (analysisConfig.backwards_range_check) checks ~= new BackwardsRangeCheck(fileName);
if (analysisConfig.if_else_same_check) checks ~= new IfElseSameCheck(fileName);
if (analysisConfig.constructor_check) checks ~= new ConstructorCheck(fileName);
if (analysisConfig.unused_label_check) checks ~= new UnusedLabelCheck(fileName);
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);

172
src/analysis/unused_label.d Normal file
View File

@ -0,0 +1,172 @@
// 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.unused_label;
import std.stdio;
import std.d.ast;
import std.d.lexer;
import analysis.base;
import analysis.helpers;
class UnusedLabelCheck : BaseAnalyzer
{
alias visit = BaseAnalyzer.visit;
this(string fileName)
{
super(fileName);
}
static struct Label
{
string name;
size_t line;
size_t column;
bool used;
}
Label[string][] stack;
auto ref current() @property
{
return stack[$-1];
}
void pushScope()
{
stack.length++;
}
void popScope()
{
foreach (label; current.byValue())
{
assert(label.line != size_t.max && label.column != size_t.max);
if (!label.used)
{
addErrorMessage(label.line, label.column,
"dscanner.suspicious.unused_label",
"Label \"" ~ label.name ~ "\" is not used.");
}
}
stack.length--;
}
override void visit(const FunctionBody functionBody)
{
if (functionBody.blockStatement !is null)
{
pushScope();
functionBody.blockStatement.accept(this);
popScope();
}
if (functionBody.bodyStatement !is null)
{
pushScope();
functionBody.bodyStatement.accept(this);
popScope();
}
if (functionBody.outStatement !is null)
{
pushScope();
functionBody.outStatement.accept(this);
popScope();
}
if (functionBody.inStatement !is null)
{
pushScope();
functionBody.inStatement.accept(this);
popScope();
}
}
override void visit(const LabeledStatement labeledStatement)
{
auto token = &labeledStatement.identifier;
Label* label = token.text in current;
if (label is null)
{
current[token.text] = Label(token.text, token.line, token.column, false);
}
else
{
label.line = token.line;
label.column = token.column;
}
labeledStatement.declarationOrStatement.accept(this);
}
void labelUsed(string name)
{
Label* entry = name in current;
if (entry is null)
current[name] = Label(name, size_t.max, size_t.max, true);
else
entry.used = true;
}
override void visit(const ContinueStatement contStatement)
{
if (contStatement.label.text.length)
labelUsed(contStatement.label.text);
}
override void visit(const BreakStatement breakStatement)
{
if (breakStatement.label.text.length)
labelUsed(breakStatement.label.text);
}
override void visit(const GotoStatement gotoStatement)
{
if (gotoStatement.label.text.length)
labelUsed(gotoStatement.label.text);
}
}
unittest
{
import analysis.config : StaticAnalysisConfig;
StaticAnalysisConfig sac;
sac.unused_label_check = true;
assertAnalyzerWarnings(q{
int testUnusedLabel()
{
int x = 0;
A: // [warn]: Label "A" is not used.
if (x) goto B;
x++;
B:
goto C;
void foo()
{
C: // [warn]: Label "C" is not used.
return;
}
C:
void bar()
{
goto D;
D:
return;
}
D: // [warn]: Label "D" is not used.
goto E;
() {
E: // [warn]: Label "E" is not used.
return;
}();
E:
() {
goto F;
F:
return;
}();
F: // [warn]: Label "F" is not used.
return x;
}
}c, sac);
stderr.writeln("Unittest for UnusedLabelCheck passed.");
}