Skip to content

Commit d47f947

Browse files
authored
Merge pull request #303 from RealyUniqueName/require-no-spaces
Spacing checks: require no spaces
2 parents c307d13 + 484da59 commit d47f947

File tree

10 files changed

+176
-38
lines changed

10 files changed

+176
-38
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ target/
1818
check-style-report.json
1919
check-style-report.xml
2020
coverage.json
21+
22+
display.hxml

checkstyle.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,9 @@
517517
"checkstyle.Main",
518518
"checkstyle.Checker",
519519
"checkstyle.ChecksInfo",
520+
"checkstyle.checks.Check",
521+
"checkstyle.checks.Directive",
522+
"checkstyle.checks.whitespace.SpacingCheck",
520523
"checkstyle.checks.imports.UnusedImportCheck",
521524
"TestMain",
522525
"misc.ExtensionsTest",

resources/default-config.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,13 +442,13 @@
442442
},
443443
{
444444
"props": {
445-
"spaceIfCondition": true,
445+
"spaceIfCondition": 0,
446446
"spaceAroundBinop": true,
447-
"spaceForLoop": true,
447+
"spaceForLoop": 0,
448448
"ignoreRangeOperator": true,
449-
"spaceWhileLoop": true,
450-
"spaceCatch": true,
451-
"spaceSwitchCase": true,
449+
"spaceWhileLoop": 0,
450+
"spaceCatch": 0,
451+
"spaceSwitchCase": 0,
452452
"noSpaceAroundUnop": true
453453
},
454454
"type": "Spacing"

src/checkstyle/Main.hx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import checkstyle.reporter.TextReporter;
1111
import checkstyle.reporter.XMLReporter;
1212
import checkstyle.reporter.CodeClimateReporter;
1313
import checkstyle.reporter.ExitCodeReporter;
14+
import checkstyle.errors.Error;
1415
import haxe.CallStack;
1516
import haxe.Json;
1617
import hxargs.Args;
@@ -181,7 +182,14 @@ class Main {
181182
if (!checkFields.contains(prop)) {
182183
failWith('Check ${check.getModuleName()} has no property named \'$prop\'');
183184
}
184-
Reflect.setField(check, prop, val);
185+
try {
186+
check.configureProperty(prop, val);
187+
}
188+
catch (e:Dynamic) {
189+
var message = 'Failed to configure $prop setting for ${check.getModuleName()}: ';
190+
message += (Std.is(e, Error) ? (e:Error).message : Std.string(e));
191+
failWith(message);
192+
}
185193
}
186194
if (defaultSeverity != null && !props.contains("severity")) check.severity = defaultSeverity;
187195
}

src/checkstyle/checks/Check.hx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ class Check {
3131
desc = haxe.rtti.Meta.getType(Type.getClass(this)).desc[0];
3232
}
3333

34+
public function configureProperty(name:String, value:Dynamic) {
35+
Reflect.setField(this, name, value);
36+
}
37+
3438
public function run(checker:Checker):Array<CheckMessage> {
3539
this.checker = checker;
3640
messages = [];

src/checkstyle/checks/Directive.hx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package checkstyle.checks;
2+
3+
import Type.ValueType;
4+
import checkstyle.errors.InvalidDirectiveError;
5+
6+
enum Directive {
7+
SHOULD;
8+
SHOULD_NOT;
9+
ANY;
10+
}
11+
12+
class DirectiveTools {
13+
static var MAPPING:Map<String, Directive> = [
14+
"should" => SHOULD,
15+
"shouldNot" => SHOULD_NOT,
16+
"any" => ANY
17+
];
18+
19+
public static function fromDynamic(value:Dynamic):Directive {
20+
return switch (Type.typeof(value)) {
21+
case ValueType.TClass(String): getValidated(value);
22+
//support for legacy configs when such settings were boolean
23+
case ValueType.TBool: (value ? SHOULD : ANY);
24+
case _: ANY;
25+
}
26+
}
27+
28+
static function getValidated(value:String):Directive {
29+
var directive = MAPPING.get(value);
30+
if (directive != null) return directive;
31+
throw new InvalidDirectiveError('Invalid directive: $value');
32+
}
33+
}

src/checkstyle/checks/whitespace/SpacingCheck.hx

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,50 @@
11
package checkstyle.checks.whitespace;
22

3+
import Type.ValueType;
34
import checkstyle.utils.ExprUtils;
45
import haxe.macro.Expr;
56
import haxe.macro.Printer;
67
import haxe.macro.Expr.Binop;
78
import haxe.macro.Expr.Unop;
9+
import checkstyle.checks.Directive;
810

911
@name("Spacing")
1012
@desc("Spacing check on if, for, while, switch, try statements and around operators.")
1113
class SpacingCheck extends Check {
1214

1315
public var spaceAroundBinop:Bool;
1416
public var noSpaceAroundUnop:Bool;
15-
public var spaceIfCondition:Bool;
16-
public var spaceForLoop:Bool;
17-
public var spaceWhileLoop:Bool;
18-
public var spaceSwitchCase:Bool;
19-
public var spaceCatch:Bool;
17+
public var spaceIfCondition:Directive;
18+
public var spaceForLoop:Directive;
19+
public var spaceWhileLoop:Directive;
20+
public var spaceSwitchCase:Directive;
21+
public var spaceCatch:Directive;
2022
public var ignoreRangeOperator:Bool;
2123

2224
public function new() {
2325
super(AST);
2426
spaceAroundBinop = true;
2527
noSpaceAroundUnop = true;
26-
spaceIfCondition = true;
27-
spaceForLoop = true;
28-
spaceWhileLoop = true;
29-
spaceSwitchCase = true;
30-
spaceCatch = true;
28+
spaceIfCondition = SHOULD;
29+
spaceForLoop = SHOULD;
30+
spaceWhileLoop = SHOULD;
31+
spaceSwitchCase = SHOULD;
32+
spaceCatch = SHOULD;
3133
ignoreRangeOperator = true;
3234
categories = [Category.STYLE, Category.CLARITY];
3335
}
3436

37+
override public function configureProperty(name:String, value:Dynamic) {
38+
var currentValue = Reflect.field(this, name);
39+
40+
switch (Type.typeof(currentValue)) {
41+
case ValueType.TEnum(Directive):
42+
Reflect.setField(this, name, DirectiveTools.fromDynamic(value));
43+
case _:
44+
super.configureProperty(name, value);
45+
}
46+
}
47+
3548
override function actualRun() {
3649
var lastExpr = null;
3750

@@ -50,18 +63,18 @@ class SpacingCheck extends Check {
5063
if (post) dist = e.pos.max - e2.pos.max;
5164
else dist = e2.pos.min - e.pos.min;
5265
if (dist > unopSize(uo)) logPos('Space around "${unopString(uo)}"', e.pos);
53-
case EIf(econd, _, _) if (spaceIfCondition):
54-
checkSpaceBetweenExpressions("if", e, econd);
55-
case EFor(it, _) if (spaceForLoop):
56-
checkSpaceBetweenExpressions("for", e, it);
57-
case EWhile(econd, _, true) if (spaceWhileLoop):
58-
checkSpaceBetweenExpressions("while", e, econd);
59-
case ESwitch(eswitch, _, _) if (spaceSwitchCase):
60-
checkSpaceBetweenManually("switch", lastExpr, eswitch);
61-
case ETry(etry, catches) if (spaceCatch):
66+
case EIf(econd, _, _):
67+
checkSpaceBetweenExpressions("if", e, econd, spaceIfCondition);
68+
case EFor(it, _):
69+
checkSpaceBetweenExpressions("for", e, it, spaceForLoop);
70+
case EWhile(econd, _, true):
71+
checkSpaceBetweenExpressions("while", e, econd, spaceWhileLoop);
72+
case ESwitch(eswitch, _, _):
73+
checkSpaceBetweenManually("switch", lastExpr, eswitch, spaceSwitchCase);
74+
case ETry(etry, catches):
6275
var exprBeforeCatch = lastExpr;
6376
for (ctch in catches) {
64-
checkSpaceBetweenManually("catch", exprBeforeCatch, ctch.expr);
77+
checkSpaceBetweenManually("catch", exprBeforeCatch, ctch.expr, spaceCatch);
6578
exprBeforeCatch = ctch.expr;
6679
}
6780
default:
@@ -87,18 +100,35 @@ class SpacingCheck extends Check {
87100
return (new Printer()).printUnop(uo);
88101
}
89102

90-
function checkSpaceBetweenExpressions(name:String, e1:Expr, e2:Expr) {
91-
if (e2.pos.min - e1.pos.min < '$name ('.length) {
92-
logRange('No space between "$name" and "("', e1.pos.max, e2.pos.min);
103+
function checkSpaceBetweenExpressions(name:String, e1:Expr, e2:Expr, directive:Directive) {
104+
switch (directive) {
105+
case ANY:
106+
case SHOULD_NOT:
107+
if (e2.pos.min - e1.pos.min > '$name('.length) {
108+
logRange('Space between "$name" and "("', e2.pos.max, e2.pos.min);
109+
}
110+
case SHOULD:
111+
if (e2.pos.min - e1.pos.min < '$name ('.length) {
112+
logRange('No space between "$name" and "("', e1.pos.max, e2.pos.min);
113+
}
93114
}
94115
}
95116

96-
function checkSpaceBetweenManually(name:String, before:Expr, check:Expr) {
117+
function checkSpaceBetweenManually(name:String, before:Expr, check:Expr, directive:Directive) {
97118
var prevExprUntilChecked = checker.file.content.substring(before.pos.min, check.pos.min + 1);
98119
var checkPos = prevExprUntilChecked.lastIndexOf('$name(');
99-
if (checkPos > -1) {
100-
var fileCheckPos = before.pos.min + checkPos;
101-
logRange('No space between "$name" and "("', fileCheckPos, fileCheckPos + '$name('.length);
120+
var fileCheckPos = before.pos.min + checkPos;
121+
122+
switch (directive) {
123+
case ANY:
124+
case SHOULD_NOT:
125+
if (checkPos < 0) {
126+
logRange('Space between "$name" and "("', check.pos.min, check.pos.max);
127+
}
128+
case SHOULD:
129+
if (checkPos > -1) {
130+
logRange('No space between "$name" and "("', fileCheckPos, fileCheckPos + '$name('.length);
131+
}
102132
}
103133
}
104134
}

src/checkstyle/errors/Error.hx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package checkstyle.errors;
2+
3+
class Error {
4+
public var message (default, null):String;
5+
6+
public function new(message:String) {
7+
this.message = message;
8+
}
9+
10+
public function toString():String {
11+
return message;
12+
}
13+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package checkstyle.errors;
2+
3+
class InvalidDirectiveError extends Error {}

test/checks/whitespace/SpacingCheckTest.hx

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
package checks.whitespace;
22

33
import checkstyle.checks.whitespace.SpacingCheck;
4+
import checkstyle.checks.Directive;
45

56
class SpacingCheckTest extends CheckTestCase<SpacingCheckTests> {
67

7-
public function testIf() {
8+
public function testIfShouldContainSpace() {
89
assertMsg(new SpacingCheck(), TEST1A, 'No space between "if" and "("');
910
assertNoMsg(new SpacingCheck(), TEST1B);
1011
}
1112

13+
public function testIfShouldNotContainSpace() {
14+
var check = new SpacingCheck();
15+
check.spaceIfCondition = Directive.SHOULD_NOT;
16+
17+
assertMsg(check, TEST1B, 'Space between "if" and "("');
18+
assertNoMsg(check, TEST1A);
19+
}
20+
1221
public function testBinaryOperator() {
1322
assertMsg(new SpacingCheck(), TEST2, 'No space around "+"');
1423
}
@@ -17,25 +26,57 @@ class SpacingCheckTest extends CheckTestCase<SpacingCheckTests> {
1726
assertMsg(new SpacingCheck(), TEST3, 'Space around "++"');
1827
}
1928

20-
public function testFor() {
29+
public function testForShouldContainSpace() {
2130
assertMsg(new SpacingCheck(), TEST4A, 'No space between "for" and "("');
2231
assertNoMsg(new SpacingCheck(), TEST4B);
2332
}
2433

25-
public function testWhile() {
34+
public function testForShouldNotContainSpace() {
35+
var check = new SpacingCheck();
36+
check.spaceForLoop = Directive.SHOULD_NOT;
37+
38+
assertMsg(check, TEST4B, 'Space between "for" and "("');
39+
assertNoMsg(check, TEST4A);
40+
}
41+
42+
public function testWhileShouldContainSpace() {
2643
assertMsg(new SpacingCheck(), TEST5A, 'No space between "while" and "("');
2744
assertNoMsg(new SpacingCheck(), TEST5B);
2845
}
2946

30-
public function testSwitch() {
47+
public function testWhileShouldNotContainSpace() {
48+
var check = new SpacingCheck();
49+
check.spaceWhileLoop = Directive.SHOULD_NOT;
50+
51+
assertMsg(check, TEST5B, 'Space between "while" and "("');
52+
assertNoMsg(check, TEST5A);
53+
}
54+
55+
public function testSwitchShouldContainSpace() {
3156
assertMsg(new SpacingCheck(), TEST6A, 'No space between "switch" and "("');
3257
assertNoMsg(new SpacingCheck(), TEST6B);
3358
}
3459

35-
public function testCatch() {
60+
public function testSwitchShouldNotContainSpace() {
61+
var check = new SpacingCheck();
62+
check.spaceSwitchCase = Directive.SHOULD_NOT;
63+
64+
assertMsg(check, TEST6B, 'Space between "switch" and "("');
65+
assertNoMsg(check, TEST6A);
66+
}
67+
68+
public function testCatchShouldContainSpace() {
3669
assertMsg(new SpacingCheck(), TEST7A, 'No space between "catch" and "("');
3770
assertNoMsg(new SpacingCheck(), TEST7B);
3871
}
72+
73+
public function testCatchShouldNotContainSpace() {
74+
var check = new SpacingCheck();
75+
check.spaceCatch = Directive.SHOULD_NOT;
76+
77+
assertMsg(check, TEST7B, 'Space between "catch" and "("');
78+
assertNoMsg(check, TEST7A);
79+
}
3980
}
4081

4182
@:enum
@@ -54,6 +95,7 @@ abstract SpacingCheckTests(String) to String {
5495
}
5596
}";
5697

98+
5799
var TEST2 =
58100
"class Test {
59101
public function test() {

0 commit comments

Comments
 (0)