D-Scanner/src/dscanner/analysis/logic_precedence.d

83 lines
2.0 KiB
D

// Copyright Brian Schott (Hackerpilot) 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 dscanner.analysis.logic_precedence;
import dscanner.analysis.base;
import dscanner.analysis.helpers;
/**
* Checks for code with confusing && and || operator precedence
* ---
* if (a && b || c) // bad
* if (a && (b || c)) // good
* ---
*/
extern(C++) class LogicPrecedenceCheck(AST) : BaseAnalyzerDmd
{
enum string KEY = "dscanner.confusing.logical_precedence";
mixin AnalyzerInfo!"logical_precedence_check";
alias visit = BaseAnalyzerDmd.visit;
extern(D) this(string fileName, bool skipTests = false)
{
super(fileName, skipTests);
}
override void visit(AST.LogicalExp le)
{
import dmd.tokens : EXP;
auto left = le.e1.isLogicalExp();
auto right = le.e2.isLogicalExp();
if (left)
left = left.op == EXP.andAnd ? left : null;
if (right)
right = right.op == EXP.andAnd ? right : null;
if (le.op != EXP.orOr)
goto END;
if (!left && !right)
goto END;
// TODO: fix
//if ((left && left.parens) || (right && right.parens))
//goto END;
if ((left !is null && left.e2 is null) && (right !is null && right.e2 is null))
goto END;
addErrorMessage(cast(ulong) le.loc.linnum, cast(ulong) le.loc.charnum, KEY,
"Use parenthesis to clarify this expression.");
END:
super.visit(le);
}
}
/*
TODO: fixme
unittest
{
import dscanner.analysis.config : StaticAnalysisConfig, Check, disabledConfig;
import std.stdio : stderr;
StaticAnalysisConfig sac = disabledConfig();
sac.logical_precedence_check = Check.enabled;
assertAnalyzerWarningsDMD(q{
void testFish()
{
if (a && b || c) {} // [warn]: Use parenthesis to clarify this expression.
if ((a && b) || c) {} // Good
if (b || c && d) {} // [warn]: Use parenthesis to clarify this expression.
if (b || (c && d)) {} // Good
}
}c, sac);
stderr.writeln("Unittest for LogicPrecedenceCheck passed.");
}
*/