Fix #272
This commit is contained in:
parent
8494e6a601
commit
fab67f9abd
|
@ -0,0 +1,128 @@
|
|||
// Copyright Brian Schott (Hackerpilot) 2015.
|
||||
// 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.auto_ref_assignment;
|
||||
|
||||
import dparse.lexer;
|
||||
import dparse.ast;
|
||||
import analysis.base;
|
||||
|
||||
/**
|
||||
* Checks for assignment to auto-ref function parameters.
|
||||
*/
|
||||
class AutoRefAssignmentCheck : BaseAnalyzer
|
||||
{
|
||||
///
|
||||
this(string fileName)
|
||||
{
|
||||
super(fileName, null);
|
||||
}
|
||||
|
||||
override void visit(const FunctionDeclaration func)
|
||||
{
|
||||
if (func.parameters is null || func.parameters.parameters.length == 0)
|
||||
return;
|
||||
pushScope();
|
||||
scope (exit)
|
||||
popScope();
|
||||
func.accept(this);
|
||||
}
|
||||
|
||||
override void visit(const Parameter param)
|
||||
{
|
||||
import std.algorithm.searching : canFind;
|
||||
|
||||
immutable bool isAuto = param.parameterAttributes.canFind(cast(ubyte) tok!"auto");
|
||||
immutable bool isRef = param.parameterAttributes.canFind(cast(ubyte) tok!"ref");
|
||||
if (!isAuto || !isRef)
|
||||
return;
|
||||
addSymbol(param.name.text);
|
||||
}
|
||||
|
||||
override void visit(const AssignExpression assign)
|
||||
{
|
||||
if (assign.operator == tok!"" || scopes.length == 0)
|
||||
return;
|
||||
interest++;
|
||||
assign.ternaryExpression.accept(this);
|
||||
interest--;
|
||||
}
|
||||
|
||||
override void visit(const IdentifierOrTemplateInstance ioti)
|
||||
{
|
||||
import std.algorithm.searching : canFind;
|
||||
|
||||
if (ioti.identifier == tok!"" || interest <= 0)
|
||||
return;
|
||||
if (scopes[$ - 1].canFind(ioti.identifier.text))
|
||||
addErrorMessage(ioti.identifier.line, ioti.identifier.column, KEY,
|
||||
"Assignment to auto-ref function parameter");
|
||||
}
|
||||
|
||||
override void visit(const IdentifierChain ic)
|
||||
{
|
||||
import std.algorithm.searching : canFind;
|
||||
|
||||
if (ic.identifiers.length == 0 || interest <= 0)
|
||||
return;
|
||||
if (scopes[$ - 1].canFind(ic.identifiers[0].text))
|
||||
addErrorMessage(ic.identifiers[0].line, ic.identifiers[0].column, KEY,
|
||||
MESSAGE);
|
||||
}
|
||||
|
||||
alias visit = BaseAnalyzer.visit;
|
||||
|
||||
private:
|
||||
|
||||
enum string MESSAGE = "Assignment to auto-ref function parameter";
|
||||
enum string KEY = "dscanner.suspicious.auto_ref_assignment";
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(interest >= 0);
|
||||
}
|
||||
|
||||
int interest;
|
||||
|
||||
void addSymbol(string symbolName)
|
||||
{
|
||||
scopes[$ - 1] ~= symbolName;
|
||||
}
|
||||
|
||||
void pushScope()
|
||||
{
|
||||
scopes.length++;
|
||||
}
|
||||
|
||||
void popScope()
|
||||
{
|
||||
scopes = scopes[0 .. $ - 1];
|
||||
}
|
||||
|
||||
string[][] scopes;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
import std.stdio : stderr;
|
||||
import std.format : format;
|
||||
import analysis.config : StaticAnalysisConfig;
|
||||
import analysis.helpers : assertAnalyzerWarnings;
|
||||
|
||||
StaticAnalysisConfig sac;
|
||||
sac.auto_ref_assignment_check = true;
|
||||
assertAnalyzerWarnings(q{
|
||||
int doStuff(T)(auto ref int a)
|
||||
{
|
||||
a = 10; // [warn]: %s
|
||||
}
|
||||
|
||||
int doStuff(T)(ref int a)
|
||||
{
|
||||
a = 10;
|
||||
}
|
||||
}c.format(AutoRefAssignmentCheck.MESSAGE), sac);
|
||||
stderr.writeln("Unittest for AutoRefAssignmentCheck passed.");
|
||||
}
|
|
@ -101,4 +101,7 @@ struct StaticAnalysisConfig
|
|||
|
||||
@INI("Checks for lines longer than 120 characters")
|
||||
bool long_line_check;
|
||||
|
||||
@INI("Checks for assignment to auto-ref function parameters")
|
||||
bool auto_ref_assignment_check;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import analysis.redundant_parens;
|
|||
import analysis.mismatched_args;
|
||||
import analysis.label_var_same_name_check;
|
||||
import analysis.line_length;
|
||||
import analysis.auto_ref_assignment;
|
||||
|
||||
import dsymbol.string_interning : internString;
|
||||
import dsymbol.scope_;
|
||||
|
@ -260,6 +261,8 @@ MessageSet analyze(string fileName, const Module m,
|
|||
checks ~= new UnusedVariableCheck(fileName, moduleScope);
|
||||
if (analysisConfig.long_line_check)
|
||||
checks ~= new LineLengthCheck(fileName, tokens);
|
||||
if (analysisConfig.auto_ref_assignment_check)
|
||||
checks ~= new AutoRefAssignmentCheck(fileName);
|
||||
version (none)
|
||||
if (analysisConfig.redundant_if_check)
|
||||
checks ~= new IfStatementCheck(fileName, moduleScope);
|
||||
|
|
Loading…
Reference in New Issue