OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 library linter.src.rules.only_throw_error; | 6 library linter.src.rules.only_throw_error; |
7 | 7 |
8 import 'dart:collection'; | 8 import 'dart:collection'; |
| 9 |
9 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/visitor.dart'; | 11 import 'package:analyzer/dart/ast/visitor.dart'; |
11 import 'package:analyzer/dart/element/type.dart'; | 12 import 'package:analyzer/dart/element/type.dart'; |
12 import 'package:linter/src/linter.dart'; | 13 import 'package:linter/src/linter.dart'; |
13 import 'package:linter/src/util/dart_type_utilities.dart'; | 14 import 'package:linter/src/util/dart_type_utilities.dart'; |
14 | 15 |
15 const _desc = r'Only throw instaces of classes extending either Exception or Err
or'; | 16 const _desc = |
| 17 r'Only throw instances of classes extending either Exception or Error'; |
16 | 18 |
17 const _details = r''' | 19 const _details = r''' |
18 | 20 |
19 **DO** throw only instances of classes that extend dart.core.Error or | 21 **DO** throw only instances of classes that extend `dart.core.Error` or |
20 dart.core.Exception. | 22 `dart.core.Exception`. |
21 | 23 |
22 **BAD:** | 24 **BAD:** |
23 ``` | 25 ``` |
24 void throwString() { | 26 void throwString() { |
25 throw 'hello world!'; // LINT | 27 throw 'hello world!'; // LINT |
26 } | 28 } |
27 ``` | 29 ``` |
28 | 30 |
29 **GOOD:** | 31 **GOOD:** |
30 ``` | 32 ``` |
31 void throwArgumentError() { | 33 void throwArgumentError() { |
32 Error error = new ArgumentError('oh!'); | 34 Error error = new ArgumentError('oh!'); |
33 throw error; // OK | 35 throw error; // OK |
34 } | 36 } |
35 ``` | 37 ``` |
36 '''; | 38 '''; |
37 | 39 |
38 class OnlyThrowError extends LintRule { | 40 const _errorClassName = 'Error'; |
| 41 |
| 42 const _exceptionClassName = 'Exception'; |
| 43 |
| 44 const _library = 'dart.core'; |
| 45 final LinkedHashSet<InterfaceTypeDefinition> _interfaceDefinitions = |
| 46 new LinkedHashSet<InterfaceTypeDefinition>.from([ |
| 47 new InterfaceTypeDefinition(_exceptionClassName, _library), |
| 48 new InterfaceTypeDefinition(_errorClassName, _library) |
| 49 ]); |
| 50 bool _isThrowable(DartType type) { |
| 51 return type.isDynamic || |
| 52 DartTypeUtilities.implementsAnyInterface(type, _interfaceDefinitions); |
| 53 } |
| 54 class OnlyThrowErrors extends LintRule { |
39 _Visitor _visitor; | 55 _Visitor _visitor; |
40 | 56 |
41 OnlyThrowError() : super( | 57 OnlyThrowErrors() |
42 name: 'only_throw_error', | 58 : super( |
43 description: _desc, | 59 name: 'only_throw_errors', |
44 details: _details, | 60 description: _desc, |
45 group: Group.style, | 61 details: _details, |
46 maturity: Maturity.experimental) { | 62 group: Group.style, |
| 63 maturity: Maturity.experimental) { |
47 _visitor = new _Visitor(this); | 64 _visitor = new _Visitor(this); |
48 } | 65 } |
49 | 66 |
50 @override | 67 @override |
51 AstVisitor getVisitor() => _visitor; | 68 AstVisitor getVisitor() => _visitor; |
52 } | 69 } |
53 | 70 |
54 class _Visitor extends SimpleAstVisitor { | 71 class _Visitor extends SimpleAstVisitor { |
55 final LintRule rule; | 72 final LintRule rule; |
56 | 73 |
57 _Visitor(this.rule); | 74 _Visitor(this.rule); |
58 | 75 |
59 @override | 76 @override |
60 void visitThrowExpression(ThrowExpression node) { | 77 void visitThrowExpression(ThrowExpression node) { |
61 if (node.expression is Literal) { | 78 if (node.expression is Literal) { |
62 rule.reportLint(node); | 79 rule.reportLint(node); |
63 return; | 80 return; |
64 } | 81 } |
65 | 82 |
66 if (!_isThrowable(node.expression.bestType)) { | 83 if (!_isThrowable(node.expression.bestType)) { |
67 rule.reportLint(node); | 84 rule.reportLint(node); |
68 } | 85 } |
69 } | 86 } |
70 } | 87 } |
71 | |
72 const _library = 'dart.core'; | |
73 const _errorClassName = 'Error'; | |
74 const _exceptionClassName = 'Exception'; | |
75 final LinkedHashSet<InterfaceTypeDefinition> _interfaceDefinitions = | |
76 new LinkedHashSet<InterfaceTypeDefinition>.from([ | |
77 new InterfaceTypeDefinition(_exceptionClassName, _library), | |
78 new InterfaceTypeDefinition(_errorClassName, _library) | |
79 ]); | |
80 | |
81 bool _isThrowable(DartType type) { | |
82 return type.isDynamic || | |
83 DartTypeUtilities.implementsAnyInterface(type, _interfaceDefinitions); | |
84 } | |
OLD | NEW |