-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved
avoid_late_keyword
to support ignoring the subtype of the …
…node type (#157) (#158) * Improved `avoid_late_keyword` to support ignoring the subtype of the node type (#157) * Improved `avoid_late_keyword` to support matching the subtype of the node type (support for nested types for dynamic, Object?, Object) #157 * Update lint_test/avoid_late_keyword_test.dart Co-authored-by: Yurii Prykhodko <[email protected]> * Update lib/src/utils/types_utils.dart Co-authored-by: Yurii Prykhodko <[email protected]> * Refactored code for `ignored_types` type matching using AST analyzer (#157) * Divided code into logical parts using the NamedType nodes tree to analyze and compare type names * Refactored code and reorganized files --------- Co-authored-by: Yarl745 <[email protected]> Co-authored-by: Yurii Prykhodko <[email protected]>
- Loading branch information
1 parent
7f08163
commit 979131a
Showing
10 changed files
with
211 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import 'package:analyzer/dart/analysis/utilities.dart'; | ||
import 'package:analyzer/dart/ast/ast.dart'; | ||
import 'package:analyzer/dart/ast/visitor.dart'; | ||
|
||
/// Parses the provided type string to extract a [NamedType]. | ||
NamedType parseNamedTypeFromString(String typeString) { | ||
try { | ||
final namedTypeFinder = _NamedTypeFinder(); | ||
|
||
final parseResult = parseString(content: "$typeString _;"); | ||
parseResult.unit.visitChildren(namedTypeFinder); | ||
|
||
return namedTypeFinder.foundNamedType!; | ||
} catch (_) { | ||
throw Exception("No NamedType could be parsed from the input " | ||
"typeString: '$typeString'. Ensure it's a valid Dart " | ||
"type declaration."); | ||
} | ||
} | ||
|
||
class _NamedTypeFinder extends GeneralizingAstVisitor<void> { | ||
NamedType? _foundNamedType; | ||
|
||
NamedType? get foundNamedType => _foundNamedType; | ||
|
||
@override | ||
void visitNamedType(NamedType namedType) { | ||
_foundNamedType ??= namedType; | ||
} | ||
} | ||
|
||
/// | ||
extension ChildNamedTypes on NamedType { | ||
/// Retrieves child [NamedType] instances from type arguments. | ||
List<NamedType> get childNamedTypes => | ||
typeArguments?.arguments.whereType<NamedType>().toList() ?? []; | ||
|
||
/// Gets the token name of this type instance. | ||
String get tokenName => name2.toString(); | ||
|
||
/// Checks if the current token name is 'dynamic'. | ||
bool get isDynamic => tokenName == "dynamic"; | ||
|
||
/// Checks if the current token name is 'Object'. | ||
bool get isObject => tokenName == "Object"; | ||
|
||
/// Checks if this node is a subtype of the specified node | ||
/// based on their structures. | ||
bool isSubtypeOf({required NamedType node}) { | ||
if (isDynamic || isObject) return true; | ||
|
||
if (tokenName != node.tokenName) return false; | ||
|
||
if (childNamedTypes.isEmpty) return true; | ||
|
||
if (childNamedTypes.length != node.childNamedTypes.length) return false; | ||
|
||
for (int i = 0; i < childNamedTypes.length; i++) { | ||
if (!childNamedTypes[i].isSubtypeOf(node: node.childNamedTypes[i])) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions
10
lint_test/avoid_late_keyword/no_generics/analysis_options.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
analyzer: | ||
plugins: | ||
- ../custom_lint | ||
|
||
custom_lint: | ||
rules: | ||
- avoid_late_keyword: | ||
allow_initialized: false | ||
ignored_types: | ||
- Subscription |
42 changes: 42 additions & 0 deletions
42
lint_test/avoid_late_keyword/no_generics/avoid_late_keyword_no_generics_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// ignore_for_file: prefer_const_declarations, unused_local_variable, prefer_match_file_name | ||
// ignore_for_file: avoid_global_state | ||
|
||
class Subscription<T> {} | ||
|
||
class ConcreteTypeWithNoGenerics {} | ||
|
||
class NotAllowed {} | ||
|
||
/// Check "late" keyword fail | ||
/// | ||
/// `avoid_late_keyword` | ||
/// allow_initialized option disabled | ||
class AvoidLateKeyword { | ||
/// expect_lint: avoid_late_keyword | ||
late final NotAllowed na1; | ||
|
||
late final Subscription subscription1; | ||
|
||
late final Subscription<ConcreteTypeWithNoGenerics> subscription2; | ||
|
||
late final Subscription<List<int>> subscription3; | ||
|
||
late final Subscription<List<List<int>>> subscription4; | ||
|
||
late final Subscription<Map<dynamic, String>> subscription5; | ||
|
||
void test() { | ||
/// expect_lint: avoid_late_keyword | ||
late final NotAllowed na1; | ||
|
||
late final Subscription subscription1; | ||
|
||
late final Subscription<ConcreteTypeWithNoGenerics> subscription2; | ||
|
||
late final Subscription<List<int>> subscription3; | ||
|
||
late final Subscription<List<List<int>>> subscription4; | ||
|
||
late final Subscription<Map<dynamic, String>> subscription5; | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
lint_test/avoid_late_keyword/with_generics/analysis_options.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
analyzer: | ||
plugins: | ||
- ../custom_lint | ||
|
||
custom_lint: | ||
rules: | ||
- avoid_late_keyword: | ||
allow_initialized: true | ||
ignored_types: | ||
- ColorTween | ||
- AnimationController | ||
- Subscription<List<Object?>> | ||
- Subscription<Map<dynamic, String>> | ||
- Subscription<ConcreteTypeWithNoGenerics> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters