IsFutureRule class
Warns when a runtime is Future / is Future<T> type check is used to
branch behavior on a value that carries NO static evidence of being
asynchronous — typically a dynamic or Object value.
Since: v14.3.3 | Updated: v14.3.4 | Rule version: v2
A runtime is Future check on an untyped value is fragile: Future<T>
generic erasure makes the test unreliable across generic boundaries, and
the branch usually duplicates logic that await would unify. The fix is
almost always to type the value as FutureOr<T> and await it directly —
await on a non-Future value simply returns that value, so the branch
becomes unnecessary.
FutureOr narrowing is exempt (v2). When the tested expression is
ALREADY statically typed FutureOr<T> and the is clause names the
matching Future<T>, the check is the canonical, analyzer-recommended way
to narrow a FutureOr<T> — and it is the ONLY way to do so in a
synchronous context, where await is not available because the enclosing
function cannot be made async (an overridden synchronous interface
method, a getter, a build() method). Reporting there was a false
positive: the rule's own correction ("type the parameter as FutureOr<T>")
was already satisfied, so the diagnostic was unactionable. v2 therefore
consults node.expression.staticType and stays silent on that idiom.
Fires on both x is Future and the negated x is! Future — the negation
does not change the underlying fragility, only which branch runs first.
It also fires on the nullable form x is Future<T>?, since
isDartAsyncFuture is true for both Future<T> and Future<T>?.
Known gap: this rule only inspects IsExpression nodes, so Dart 3
pattern-matching equivalents such as switch (result) { case Future(): }
or if (result case Future _) are structurally different AST nodes
(object/type patterns, not is checks) and are NOT currently flagged,
even though they express the same fragile runtime check. Left as a
follow-up rather than in scope for v1.
Scope note: this rule only matches the literal Future type written
in the is clause — it does not walk supertypes to catch a custom class
that merely extends/implements Future (e.g. x is MyCustomFuture).
That is a deliberate, narrower scope than _staticTypeIsFuture in
async_rules.dart (which walks allSupertypes to catch such custom
subclasses when checking a value's static type) — matching a
user-written custom-Future type isn't the same fragile pattern this rule
targets, since the author controls that type directly.
BAD:
void handle(dynamic result) {
if (result is Future) {
result.then((value) => print(value));
} else {
print(result);
}
}
GOOD:
Future<void> handle(FutureOr<Object?> result) async {
final value = await result; // FutureOr<T> + await handles both cases.
print(value);
}
GOOD (FutureOr narrowing in a synchronous context):
// Overriding a synchronous interface method — `await` is unavailable
// because the signature forbids making this function async, so the
// `is Future<T>` narrowing of an already-FutureOr<T> value is correct.
int? tryReadSync(FutureOr<int> value) {
if (value is Future<int>) return null;
return value; // Promoted to int by the narrowing above.
}
- Inheritance
-
- Object
- SaropaLintRule
- IsFutureRule
Constructors
Properties
- accuracyTarget → AccuracyTarget?
-
Optional accuracy target for this rule (for documentation and tooling).
Does not enforce; used by reports and rule-audit scripts.
no setterinherited
-
applicableFileTypes
→ Set<
FileType> ? -
The file types this rule applies to.
no setterinherited
- canUseParsedResult → bool
-
Indicates whether this analysis rule can work with just the parsed
information or if it requires a resolved unit.
no setterinherited
-
certIds
→ List<
String> -
CERT coding standard identifiers (e.g. STR02-C). Populate only where
there is a clear mapping; leave empty for most rules initially.
no setterinherited
- code → LintCode
-
The lint code for this rule.
no setterinherited
-
configAliases
→ List<
String> -
Alternate config keys that can be used to reference this rule.
no setterinherited
-
conflictingRules
→ List<
String> -
Curated opposite/competing rule names.
no setterinherited
- cost → RuleCost
-
The estimated execution cost of this rule.
no setteroverride
-
cweIds
→ List<
int> -
CWE identifiers this rule helps prevent or detect.
https://cwe.mitre.org/ — e.g. CWE-798 (Hardcoded Credentials).
no setterinherited
- description → String
-
Short description suitable for display in console output and IDEs.
finalinherited
- diagnosticCode → DiagnosticCode
-
The code to report for a violation.
no setterinherited
-
diagnosticCodes
→ List<
DiagnosticCode> -
The diagnostic codes associated with this analysis rule.
no setterinherited
- documentationUrl → String
-
Returns the documentation URL for this rule.
no setterinherited
- effectiveSeverity → DiagnosticSeverity?
-
Get the effective severity for this rule, considering overrides.
no setterinherited
- exampleBad → String?
-
Short code example that VIOLATES this rule (shown in CLI walkthrough).
no setterinherited
- exampleGood → String?
-
Short code example of COMPLIANT code (shown in CLI walkthrough).
no setterinherited
-
fixGenerators
→ List<
SaropaFixGenerator> -
Fix producer generators for this rule.
no setterinherited
- hashCode → int
-
The hash code for this object.
no setterinherited
- hyphenatedName → String
-
Returns the rule name in hyphenated format for display.
no setterinherited
- impact → LintImpact
-
Code quality issue — a fragile async pattern with a low-effort fix.
Review when count exceeds 100.
no setteroverride
-
incompatibleRules
→ List<
String> -
A list of incompatible rule names.
no setterinherited
- isDisabled → bool
-
Check if this rule is disabled via configuration.
no setterinherited
- maximumLineCount → int
-
Maximum line count for this rule to run.
no setterinherited
- minimumLineCount → int
-
Minimum line count for this rule to run.
no setterinherited
- name → String
-
The rule name.
finalinherited
- owasp → OwaspMapping?
-
OWASP categories this rule helps prevent.
no setterinherited
- pubspecVisitor → PubspecVisitor?
-
A visitor that visits a
Pubspecto perform analysis.no setterinherited -
Curated "see also" rule names for discoverability in docs/IDE tooling.
no setterinherited
- reporter ← DiagnosticReporter
-
Sets the
DiagnosticReporterfor theCompilationUnitcurrently being visited.no getterinherited -
requiredPatterns
→ Set<
String> ? -
String patterns that must be present in the file for this rule to run.
no setteroverride
- requiresAsync → bool
-
Whether this rule only applies to async code.
no setterinherited
- requiresBlocImport → bool
-
Whether this rule only applies to files that import Bloc.
no setterinherited
- requiresClassDeclaration → bool
-
Whether this rule only applies to files with class declarations.
no setterinherited
- requiresFlutterImport → bool
-
Whether this rule only applies to files that import Flutter.
no setterinherited
- requiresImports → bool
-
Whether this rule only applies to files with imports.
no setterinherited
- requiresMainFunction → bool
-
Whether this rule only applies to files with a main() function.
no setterinherited
- requiresProviderImport → bool
-
Whether this rule only applies to files that import Provider.
no setterinherited
- requiresRiverpodImport → bool
-
Whether this rule only applies to files that import Riverpod.
no setterinherited
- requiresWidgets → bool
-
Whether this rule only applies to Flutter widget code.
no setterinherited
- ruleStatus → RuleStatus
-
Lifecycle status. Default RuleStatus.ready. Use RuleStatus.beta for
new or heuristic-heavy rules; RuleStatus.deprecated for sunset.
no setterinherited
- ruleType → RuleType?
-
Semantic type of this rule. Default
null= unspecified (legacy). When set, used for quality gates, accuracy targets, and reporting.no setteroverride - runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- skipExampleFiles → bool
-
Whether to skip example files (example/**).
no setterinherited
- skipFixtureFiles → bool
-
Whether to skip fixture files (fixture/, fixtures/).
no setterinherited
- skipGeneratedCode → bool
-
Whether to skip generated files (*.g.dart, *.freezed.dart, *.gen.dart).
no setterinherited
- skipTestFiles → bool
-
Whether to skip test files (*_test.dart, test/**).
no setterinherited
- state → RuleState
-
The state of this analysis rule.
finalinherited
-
supersedesRules
→ List<
String> -
Rule names this rule supersedes/replaces.
no setterinherited
-
Tags for filtering and discovery (e.g. in docs, IDE, or CI).
Examples: 'performance', 'accessibility', 'suspicious', 'convention'.
no setteroverride
- testRelevance → TestRelevance
-
How this rule relates to test files.
no setterinherited
- usesTypeResolution → bool
-
Whether this rule triggers lazy cross-library type resolution in the
analyzer (e.g.
.staticType,.library,.allSupertypes,.enclosingElement).no setteroverride
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
registerNodeProcessors(
RuleVisitorRegistry registry, RuleContext context) → void -
Registers node processors in the given
registry.inherited -
reportAtNode(
AstNode? node, {List< Object> arguments = const [], List<DiagnosticMessage> ? contextMessages}) → Diagnostic? -
Reports a diagnostic at
nodewith messageargumentsandcontextMessages.inherited -
reportAtOffset(
int offset, int length, {List< Object> arguments = const [], List<DiagnosticMessage> ? contextMessages}) → Diagnostic -
Reports a diagnostic at
offset, withlength, with messageargumentsandcontextMessages.inherited -
reportAtPubNode(
PubspecNode node, {List< Object> arguments = const [], List<DiagnosticMessage> contextMessages = const []}) → Diagnostic -
Reports a diagnostic at Pubspec
node, with messageargumentsandcontextMessages.inherited -
reportAtSourceRange(
SourceRange sourceRange, {List< Object> arguments = const [], List<DiagnosticMessage> ? contextMessages}) → Diagnostic -
Reports a diagnostic at
sourceRange, with messageargumentsandcontextMessages.inherited -
reportAtToken(
Token token, {List< Object> arguments = const [], List<DiagnosticMessage> ? contextMessages}) → Diagnostic? -
Reports a diagnostic at
token, with messageargumentsandcontextMessages.inherited -
runWithReporter(
SaropaDiagnosticReporter reporter, SaropaContext context) → void -
Override this method to implement your lint rule.
override
-
shouldSkipFile(
String path) → bool -
Check if a file path should be skipped based on context settings.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited