Skip to content

Commit 1fdc9f9

Browse files
committed
1 parent c860d66 commit 1fdc9f9

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

lib/src/rules.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ import 'package:linter/src/rules/empty_statements.dart';
2828
import 'package:linter/src/rules/hash_and_equals.dart';
2929
import 'package:linter/src/rules/implementation_imports.dart';
3030
import 'package:linter/src/rules/iterable_contains_unrelated_type.dart';
31-
import 'package:linter/src/rules/list_remove_unrelated_type.dart';
3231
import 'package:linter/src/rules/library_names.dart';
3332
import 'package:linter/src/rules/library_prefixes.dart';
33+
import 'package:linter/src/rules/list_remove_unrelated_type.dart';
3434
import 'package:linter/src/rules/non_constant_identifier_names.dart';
3535
import 'package:linter/src/rules/one_member_abstracts.dart';
3636
import 'package:linter/src/rules/only_throw_errors.dart';
@@ -52,6 +52,7 @@ import 'package:linter/src/rules/unawaited_futures.dart';
5252
import 'package:linter/src/rules/unnecessary_brace_in_string_interp.dart';
5353
import 'package:linter/src/rules/unnecessary_getters_setters.dart';
5454
import 'package:linter/src/rules/unrelated_type_equality_checks.dart';
55+
import 'package:linter/src/rules/whitespace_around_ops.dart';
5556

5657
final Registry ruleRegistry = new Registry()
5758
..register(new AlwaysDeclareReturnTypes())
@@ -99,8 +100,8 @@ final Registry ruleRegistry = new Registry()
99100
// Disabled pending fix: https://github.com/dart-lang/linter/issues/35
100101
//..register(new UnnecessaryGetters())
101102
..register(new UnnecessaryGettersSetters())
102-
..register(new UnrelatedTypeEqualityChecks());
103-
103+
..register(new UnrelatedTypeEqualityChecks())
104+
..register(new WhitespaceAroundOps());
104105

105106
/// Registry of contributed lint rules.
106107
class Registry extends Object with IterableMixin<LintRule> {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
library linter.src.rules.whitespace_around_ops;
6+
7+
import 'package:analyzer/dart/ast/ast.dart';
8+
import 'package:analyzer/dart/ast/token.dart';
9+
import 'package:analyzer/dart/ast/visitor.dart';
10+
import 'package:linter/src/linter.dart';
11+
12+
const desc = r'Use proper whitespace around operators.';
13+
14+
const details = r'''
15+
**DO** ensure that there are spaces around binary operators and before any
16+
unary ones.
17+
18+
Improper whitespace can create confusion, especially when applied to operators
19+
where it's possible to get a binary operator when you mean a unary one. For
20+
example, the mistyping of `5 /~ 10` when you mean `5 ~/ 10` is hidden by the
21+
improper spacing. (Properly spaced, the mistake is more clear: `5 / ~10`.)
22+
Whenever possible, use the formatter to cleanup whitespace. Otherwise, take
23+
care to ensure that there are spaces around binary operators and before any
24+
unary ones.
25+
26+
27+
**BAD:**
28+
```
29+
print(5 /~ 10); //whoops
30+
```
31+
32+
**GOOD:**
33+
```
34+
print(5 / ~10); //aha!
35+
```
36+
''';
37+
38+
class Visitor extends SimpleAstVisitor {
39+
final LintRule rule;
40+
Visitor(this.rule);
41+
42+
@override
43+
visitBinaryExpression(BinaryExpression node) {
44+
if (!spaced(node.leftOperand.endToken, node.operator) ||
45+
!spaced(node.operator, node.rightOperand.beginToken)) {
46+
rule.reportLintForToken(node.operator);
47+
}
48+
}
49+
50+
@override
51+
visitPrefixExpression(PrefixExpression node) {
52+
if (spaced(node.operator, node.operand.beginToken)) {
53+
rule.reportLintForToken(node.operator);
54+
}
55+
}
56+
57+
static bool spaced(Token first, Token second) =>
58+
first != null && second != null && first.end != second.offset;
59+
}
60+
61+
class WhitespaceAroundOps extends LintRule {
62+
WhitespaceAroundOps()
63+
: super(
64+
name: 'whitespace_around_ops',
65+
description: desc,
66+
details: details,
67+
group: Group.style);
68+
69+
@override
70+
AstVisitor getVisitor() => new Visitor(this);
71+
}

test/rules/whitespace_around_ops.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// test w/ `dart test/util/solo_test.dart whitespace_around_ops`
6+
7+
8+
// Define our own int so we don't need `int` in our mock SDK.
9+
class MyInt {
10+
MyInt operator -() => this;
11+
MyInt operator ~() => this;
12+
MyInt operator ~/(MyInt other) => this;
13+
MyInt operator /(MyInt other) => this;
14+
}
15+
16+
void main() {
17+
MyInt f, g;
18+
print(f ~/ g);
19+
print(f~/ g); //LINT
20+
print(f ~/g); //LINT
21+
print(f~/g); //LINT
22+
print(f/ ~g); //LINT
23+
print(f /~g); //LINT
24+
print(f / ~g); //OK
25+
f =- g; //LINT
26+
f = -g; //OK
27+
}

0 commit comments

Comments
 (0)