mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
add lint and quick-fixes for Money.amount.toString()
This commit is contained in:
@@ -3,6 +3,8 @@ import "package:analysis_server_plugin/registry.dart";
|
||||
import "package:cw_custom_lints/http_force_proxy/http_force_proxy_rule.dart";
|
||||
import "package:cw_custom_lints/modal_top_bar_semantics/modal_top_bar_semantics_rule.dart";
|
||||
import "package:cw_custom_lints/modern_button_semantics/modern_button_semantics_rule.dart";
|
||||
import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_fix.dart";
|
||||
import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_rule.dart";
|
||||
import "package:cw_custom_lints/print_verbose/print_verbose_fix.dart";
|
||||
import "package:cw_custom_lints/print_verbose/print_verbose_rule.dart";
|
||||
import "package:cw_custom_lints/restricted_imports/restricted_imports_rule.dart";
|
||||
@@ -20,7 +22,13 @@ class CwCustomLintsPlugin extends Plugin {
|
||||
registry.registerWarningRule(HttpForceProxyRule());
|
||||
registry.registerWarningRule(ModernButtonSemanticsRule());
|
||||
registry.registerWarningRule(ModalTopBarSemanticsRule());
|
||||
registry.registerWarningRule(MoneyAmountToStringRule());
|
||||
|
||||
registry.registerFixForRule(PrintVerboseRule.code, ReplaceWithPrintV.new);
|
||||
registry.registerFixForRule(MoneyAmountToStringRule.code, ReplaceWithMoneyToString.new);
|
||||
registry.registerFixForRule(
|
||||
MoneyAmountToStringRule.code,
|
||||
ReplaceWithMoneyToStringInBaseUnit.new,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import "package:analysis_server_plugin/edit/dart/correction_producer.dart";
|
||||
import "package:analysis_server_plugin/edit/dart/dart_fix_kind_priority.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer_plugin/utilities/change_builder/change_builder_core.dart";
|
||||
import "package:analyzer_plugin/utilities/fixes/fixes.dart";
|
||||
import "package:analyzer_plugin/utilities/range_factory.dart";
|
||||
import "package:cw_custom_lints/money_amount_to_string/money_amount_to_string_rule.dart";
|
||||
|
||||
abstract class _ReplaceMoneyAmountToString extends ResolvedCorrectionProducer {
|
||||
_ReplaceMoneyAmountToString({required super.context});
|
||||
|
||||
String get replacement;
|
||||
|
||||
@override
|
||||
CorrectionApplicability get applicability => CorrectionApplicability.singleLocation;
|
||||
|
||||
@override
|
||||
Future<void> compute(ChangeBuilder builder) async {
|
||||
final invocation = node.thisOrAncestorOfType<MethodInvocation>();
|
||||
if (invocation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final amount = moneyAmountReference(invocation.realTarget);
|
||||
if (amount == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await builder.addDartFileEdit(
|
||||
file,
|
||||
(builder) => builder.addSimpleReplacement(range.startEnd(amount, invocation), replacement),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ReplaceWithMoneyToString extends _ReplaceMoneyAmountToString {
|
||||
ReplaceWithMoneyToString({required super.context});
|
||||
|
||||
static const _fixKind = FixKind(
|
||||
"dart.fix.replaceWithMoneyToString",
|
||||
DartFixKindPriority.standard,
|
||||
"Replace with toString() for a decimal amount",
|
||||
);
|
||||
|
||||
@override
|
||||
FixKind get fixKind => _fixKind;
|
||||
|
||||
@override
|
||||
String get replacement => "toString()";
|
||||
}
|
||||
|
||||
class ReplaceWithMoneyToStringInBaseUnit extends _ReplaceMoneyAmountToString {
|
||||
ReplaceWithMoneyToStringInBaseUnit({required super.context});
|
||||
|
||||
static const _fixKind = FixKind(
|
||||
"dart.fix.replaceWithMoneyToStringInBaseUnit",
|
||||
DartFixKindPriority.standard,
|
||||
"Replace with toStringWithPrecision(useBaseUnit: true) for base units",
|
||||
);
|
||||
|
||||
@override
|
||||
FixKind get fixKind => _fixKind;
|
||||
|
||||
@override
|
||||
String get replacement => "toStringWithPrecision(useBaseUnit: true)";
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import "package:analyzer/analysis_rule/analysis_rule.dart";
|
||||
import "package:analyzer/analysis_rule/rule_context.dart";
|
||||
import "package:analyzer/analysis_rule/rule_visitor_registry.dart";
|
||||
import "package:analyzer/dart/ast/ast.dart";
|
||||
import "package:analyzer/dart/ast/visitor.dart";
|
||||
import "package:analyzer/dart/element/element.dart";
|
||||
import "package:analyzer/error/error.dart";
|
||||
|
||||
class MoneyAmountToStringRule extends AnalysisRule {
|
||||
MoneyAmountToStringRule()
|
||||
: super(
|
||||
name: "no_money_amount_to_string",
|
||||
description:
|
||||
"Money.amount is the internal BigInt, so stringifying it drops the decimal point.",
|
||||
);
|
||||
|
||||
static const LintCode code = LintCode(
|
||||
"no_money_amount_to_string",
|
||||
"This stringifies the internal BigInt of Money instead of the Money itself, so the decimal point is dropped and the amount reads far larger than it is.",
|
||||
correctionMessage:
|
||||
"Call toString() on the Money for a decimal amount, or toStringWithPrecision(useBaseUnit: true) for base units.",
|
||||
severity: DiagnosticSeverity.WARNING,
|
||||
);
|
||||
|
||||
@override
|
||||
LintCode get diagnosticCode => code;
|
||||
|
||||
@override
|
||||
void registerNodeProcessors(RuleVisitorRegistry registry, RuleContext context) =>
|
||||
registry.addMethodInvocation(this, _Visitor(this));
|
||||
}
|
||||
|
||||
|
||||
SimpleIdentifier? moneyAmountReference(Expression? expression) {
|
||||
final identifier = switch (expression) {
|
||||
PrefixedIdentifier() => expression.identifier,
|
||||
PropertyAccess() => expression.propertyName,
|
||||
SimpleIdentifier() => expression,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (identifier == null || identifier.name != "amount") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _isDeclaredByMoney(identifier.element) ? identifier : null;
|
||||
}
|
||||
|
||||
bool _isDeclaredByMoney(Element? element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final enclosing = element.enclosingElement;
|
||||
if (enclosing is! InterfaceElement || enclosing.name != "Money") {
|
||||
return false;
|
||||
}
|
||||
|
||||
final libraryUri = element.library?.uri;
|
||||
if (libraryUri == null || libraryUri.scheme != "package") {
|
||||
return false;
|
||||
}
|
||||
|
||||
final segments = libraryUri.pathSegments;
|
||||
return segments.isNotEmpty && segments.first == "cw_core";
|
||||
}
|
||||
|
||||
class _Visitor extends SimpleAstVisitor<void> {
|
||||
_Visitor(this.rule);
|
||||
|
||||
final AnalysisRule rule;
|
||||
|
||||
@override
|
||||
void visitMethodInvocation(MethodInvocation node) {
|
||||
if (node.methodName.name != "toString" || node.argumentList.arguments.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (moneyAmountReference(node.realTarget) == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
rule.reportAtNode(node);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user