Skip to content

Instantly share code, notes, and snippets.

@pedromassango
Created April 4, 2021 19:50
Show Gist options
  • Save pedromassango/3ce08b936e39920a2e584ac2a94f8701 to your computer and use it in GitHub Desktop.
Save pedromassango/3ce08b936e39920a2e584ac2a94f8701 to your computer and use it in GitHub Desktop.
Lint rule: explicit_return for nullable types
// Copyright (c) 2021, 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.
import 'dart:async';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:linter/src/rules/always_declare_return_types.dart';
import 'package:linter/src/rules/avoid_returning_this.dart';
import '../analyzer.dart';
import '../util/dart_type_utilities.dart';
const _desc = r'Explicitly return null when a null would be inferred';
const _details = r'''
**DO** Explicitly return null when a null would be inferred.
When declaring a method that returns a nullable type,
declare that it returns null explicitly.
**BAD:**
```
String? f() {}
Future<String?> f2() async {}
```
**GOOD:**
```dart
String? f() {
return null;
}
Future<String?> f2() async {
return null;
}
```
''';
class ExplicitReturn extends LintRule implements NodeLintRule {
ExplicitReturn()
: super(
name: 'explicit_return',
description: _desc,
details: _details,
group: Group.style);
@override
void registerNodeProcessors(NodeLintRegistry registry, LinterContext context) {
var visitor = _Visitor(context, this);
registry.addMethodDeclaration(this, visitor);
//registry.addFunctionDeclaration(this, visitor);
}
}
class _Visitor extends SimpleAstVisitor {
final LintRule rule;
final LinterContext linterContext;
_Visitor(this.linterContext, this.rule);
@override
void visitMethodDeclaration(MethodDeclaration node) {
if (node.returnType == null) return;
if (_hasVoidReturnType(node.returnType!)) return;
var returnType = node.returnType!;
if(_isNullableReturnStatement(returnType)) {
var returnStatements = DartTypeUtilities.traverseNodesInDFS(node.body)
.whereType<ReturnStatement>();
var hasReturnStatement = returnStatements.any((element) => element.expression != null);
if (!hasReturnStatement) {
rule.reportLint(node);
}
}
}
bool _hasVoidReturnType(TypeAnnotation returnType) => returnType.type is VoidType;
bool _isNullableReturnStatement(TypeAnnotation returnType) {
if (_isAsync(returnType) && returnType.type is InterfaceType) {
var futureArgumentType = (returnType.type! as InterfaceType).typeArguments.first;
return !DartTypeUtilities.isNonNullable(linterContext, futureArgumentType);
}
return !DartTypeUtilities.isNonNullable(linterContext, returnType.type);
}
bool _isAsync(TypeAnnotation returnType) =>
returnType.type!.isDartAsyncFuture || returnType.type!.isDartAsyncFutureOr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment