Add logical operator precedence check
This commit is contained in:
parent
20dca2a0c7
commit
3f4395e95b
|
@ -65,4 +65,7 @@ struct StaticAnalysisConfig
|
||||||
|
|
||||||
@INI("Checks for confusing code in inline asm statements")
|
@INI("Checks for confusing code in inline asm statements")
|
||||||
bool asm_style_check;
|
bool asm_style_check;
|
||||||
|
|
||||||
|
@INI("Checks for confusing logical operator precedence")
|
||||||
|
bool logical_precedence_check;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// 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 analysis.logic_precedence;
|
||||||
|
|
||||||
|
import std.stdio;
|
||||||
|
import std.d.ast;
|
||||||
|
import std.d.lexer;
|
||||||
|
import analysis.base;
|
||||||
|
import analysis.helpers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for code with confusing && and || operator precedence
|
||||||
|
* ---
|
||||||
|
* if (a && b || c) // bad
|
||||||
|
* if (a && (b || c)) // good
|
||||||
|
* ---
|
||||||
|
*/
|
||||||
|
class LogicPrecedenceCheck : BaseAnalyzer
|
||||||
|
{
|
||||||
|
alias visit = BaseAnalyzer.visit;
|
||||||
|
|
||||||
|
enum string KEY = "dscanner.confusing.logical_precedence";
|
||||||
|
|
||||||
|
this(string fileName)
|
||||||
|
{
|
||||||
|
super(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(const OrOrExpression orOr)
|
||||||
|
{
|
||||||
|
if (orOr.left is null || orOr.right is null) return;
|
||||||
|
const AndAndExpression left = cast(AndAndExpression) orOr.left;
|
||||||
|
const AndAndExpression right = cast(AndAndExpression) orOr.right;
|
||||||
|
if (left is null && right is null) return;
|
||||||
|
if ((left !is null && left.right is null) && (right !is null && right.right is null)) return;
|
||||||
|
addErrorMessage(orOr.line, orOr.column, KEY,
|
||||||
|
"Use parenthesis to clarify this expression.");
|
||||||
|
orOr.accept(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
import analysis.config;
|
||||||
|
StaticAnalysisConfig sac;
|
||||||
|
sac.logic_precedence_check = true;
|
||||||
|
assertAnalyzerWarnings(q{
|
||||||
|
void testFish()
|
||||||
|
{
|
||||||
|
if (a && b || c) {} // [warn]:
|
||||||
|
if ((a && b) || c) {} // Good
|
||||||
|
if (b || c && d) {} // [warn]:
|
||||||
|
if (b || (c && d)) {} // Good
|
||||||
|
}
|
||||||
|
}c, sac);
|
||||||
|
stderr.writeln("Unittest for LogicPrecedenceCheck passed.");
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import analysis.opequals_without_tohash;
|
||||||
import analysis.length_subtraction;
|
import analysis.length_subtraction;
|
||||||
import analysis.builtin_property_names;
|
import analysis.builtin_property_names;
|
||||||
import analysis.asm_style;
|
import analysis.asm_style;
|
||||||
|
import analysis.logic_precedence;
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ MessageSet analyze(string fileName, ubyte[] code, const StaticAnalysisConfig ana
|
||||||
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
|
if (analysisConfig.length_subtraction_check) checks ~= new LengthSubtractionCheck(fileName);
|
||||||
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
|
if (analysisConfig.builtin_property_names_check) checks ~= new BuiltinPropertyNameCheck(fileName);
|
||||||
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName);
|
if (analysisConfig.asm_style_check) checks ~= new AsmStyleCheck(fileName);
|
||||||
|
if (analysisConfig.logical_precedence_check) checks ~= new LogicPrecedenceCheck(fileName);
|
||||||
|
|
||||||
foreach (check; checks)
|
foreach (check; checks)
|
||||||
{
|
{
|
||||||
|
|
16
astprinter.d
16
astprinter.d
|
@ -625,6 +625,21 @@ class XMLPrinter : ASTVisitor
|
||||||
output.writeln("</mulExpression>");
|
output.writeln("</mulExpression>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(const OrOrExpression orOrExpression)
|
||||||
|
{
|
||||||
|
output.writeln("<orOrExpression>");
|
||||||
|
output.writeln("<left>");
|
||||||
|
visit(orOrExpression.left);
|
||||||
|
output.writeln("</left>");
|
||||||
|
if (orOrExpression.right !is null)
|
||||||
|
{
|
||||||
|
output.writeln("<right>");
|
||||||
|
visit(orOrExpression.right);
|
||||||
|
output.writeln("</right>");
|
||||||
|
}
|
||||||
|
output.writeln("</orOrExpression>");
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(const Parameter param)
|
override void visit(const Parameter param)
|
||||||
{
|
{
|
||||||
output.writeln("<parameter>");
|
output.writeln("<parameter>");
|
||||||
|
@ -1037,7 +1052,6 @@ class XMLPrinter : ASTVisitor
|
||||||
override void visit(const NonVoidInitializer nonVoidInitializer) { mixin (tagAndAccept!"nonVoidInitializer"); }
|
override void visit(const NonVoidInitializer nonVoidInitializer) { mixin (tagAndAccept!"nonVoidInitializer"); }
|
||||||
override void visit(const Operands operands) { mixin (tagAndAccept!"operands"); }
|
override void visit(const Operands operands) { mixin (tagAndAccept!"operands"); }
|
||||||
override void visit(const OrExpression orExpression) { mixin (tagAndAccept!"orExpression"); }
|
override void visit(const OrExpression orExpression) { mixin (tagAndAccept!"orExpression"); }
|
||||||
override void visit(const OrOrExpression orOrExpression) { mixin (tagAndAccept!"orOrExpression"); }
|
|
||||||
override void visit(const OutStatement outStatement) { mixin (tagAndAccept!"outStatement"); } override void visit(const MixinDeclaration mixinDeclaration) { mixin (tagAndAccept!"mixinDeclaration"); }
|
override void visit(const OutStatement outStatement) { mixin (tagAndAccept!"outStatement"); } override void visit(const MixinDeclaration mixinDeclaration) { mixin (tagAndAccept!"mixinDeclaration"); }
|
||||||
override void visit(const Parameters parameters) { mixin (tagAndAccept!"parameters"); }
|
override void visit(const Parameters parameters) { mixin (tagAndAccept!"parameters"); }
|
||||||
override void visit(const Postblit postblit) { mixin (tagAndAccept!"postblit"); } override void visit(const NewAnonClassExpression newAnonClassExpression) { mixin (tagAndAccept!"newAnonClassExpression"); }
|
override void visit(const Postblit postblit) { mixin (tagAndAccept!"postblit"); } override void visit(const NewAnonClassExpression newAnonClassExpression) { mixin (tagAndAccept!"newAnonClassExpression"); }
|
||||||
|
|
Loading…
Reference in New Issue