| Index: lib/src/rules/prefer_is_not_empty.dart
|
| diff --git a/lib/src/rules/prefer_is_not_empty.dart b/lib/src/rules/prefer_is_not_empty.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..da7791f12d461a4147ee7af42391826204e234d2
|
| --- /dev/null
|
| +++ b/lib/src/rules/prefer_is_not_empty.dart
|
| @@ -0,0 +1,102 @@
|
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library linter.src.rules.prefer_is_not_empty;
|
| +
|
| +import 'package:analyzer/src/generated/ast.dart'
|
| + show
|
| + AstNode,
|
| + AstVisitor,
|
| + PrefixExpression,
|
| + PrefixedIdentifier,
|
| + PropertyAccess,
|
| + SimpleAstVisitor,
|
| + SimpleIdentifier;
|
| +import 'package:analyzer/src/generated/element.dart' show Element;
|
| +import 'package:analyzer/src/generated/scanner.dart' show TokenType;
|
| +import 'package:linter/src/ast.dart';
|
| +import 'package:linter/src/linter.dart';
|
| +
|
| +const desc = 'Use isNotEmpty for Iterables and Maps.';
|
| +
|
| +const details = '''
|
| +**PREFER** `x.isNotEmpty` to `!x.isEmpty` for Iterables and Maps.
|
| +
|
| +When testing whether an iterable or map is empty, prefer `isNotEmpty` over
|
| +`!isEmpty`.
|
| +
|
| +**GOOD:**
|
| +```
|
| +if (todo.isNotEmpty) {
|
| + sendResults(request, todo.isEmpty);
|
| +}
|
| +```
|
| +
|
| +**BAD:**
|
| +```
|
| +if (!sources.isEmpty) {
|
| + process(sources);
|
| +}
|
| +```
|
| +''';
|
| +
|
| +class PreferIsNotEmpty extends LintRule {
|
| + PreferIsNotEmpty()
|
| + : super(
|
| + name: 'prefer_is_not_empty',
|
| + description: desc,
|
| + details: details,
|
| + group: Group.style);
|
| +
|
| + @override
|
| + AstVisitor getVisitor() => new Visitor(this);
|
| +}
|
| +
|
| +class Visitor extends SimpleAstVisitor {
|
| + final LintRule rule;
|
| + Visitor(this.rule);
|
| +
|
| + @override
|
| + visitSimpleIdentifier(SimpleIdentifier identifier) {
|
| + AstNode isEmptyAccess = null;
|
| + SimpleIdentifier isEmptyIdentifier = null;
|
| +
|
| + AstNode parent = identifier.parent;
|
| + if (parent is PropertyAccess) {
|
| + isEmptyIdentifier = parent.propertyName;
|
| + isEmptyAccess = parent;
|
| + } else if (parent is PrefixedIdentifier) {
|
| + isEmptyIdentifier = parent.identifier;
|
| + isEmptyAccess = parent;
|
| + }
|
| +
|
| + if (isEmptyIdentifier == null) {
|
| + return;
|
| + }
|
| +
|
| + // Should be "isEmpty".
|
| + Element propertyElement = isEmptyIdentifier.bestElement;
|
| + if (propertyElement == null || 'isEmpty' != propertyElement.name) {
|
| + return;
|
| + }
|
| + // Should have "isNotEmpty".
|
| + Element propertyTarget = propertyElement.enclosingElement;
|
| + if (propertyTarget == null ||
|
| + getChildren(propertyTarget, 'isNotEmpty').isEmpty) {
|
| + return;
|
| + }
|
| + // Should be in PrefixExpression.
|
| + if (isEmptyAccess.parent is! PrefixExpression) {
|
| + return;
|
| + }
|
| + PrefixExpression prefixExpression =
|
| + isEmptyAccess.parent as PrefixExpression;
|
| + // Should be !
|
| + if (prefixExpression.operator.type != TokenType.BANG) {
|
| + return;
|
| + }
|
| +
|
| + rule.reportLint(prefixExpression);
|
| + }
|
| +}
|
|
|