Skip to content
This repository was archived by the owner on Jul 16, 2023. It is now read-only.

Commit 7d393d9

Browse files
authored
feat: improve check unused l10n (#563)
* feat: improve check unused l10n * chore: update changelog * chore: fix linter
1 parent 7078881 commit 7d393d9

File tree

5 files changed

+130
-25
lines changed

5 files changed

+130
-25
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* chore: activate self implemented rules: `avoid-unnecessary-type-assertions`, `avoid-unnecessary-type-casts`, `prefer-first`, `prefer-last`, `prefer-match-file-name`
99
* refactor: cleanup anti-patterns, metrics and rules documentation
1010
* fix: `no-magic-number` not working in array of widgets
11+
* feat: improve check unused l10n
1112

1213
## 4.6.0
1314

lib/src/analyzers/unused_l10n_analyzer/unused_l10n_visitor.dart

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@ class UnusedL10nVisitor extends RecursiveAstVisitor<void> {
1818
super.visitMethodInvocation(node);
1919

2020
final target = node.target;
21+
final name = node.methodName.name;
2122

22-
if (target is SimpleIdentifier && _classPattern.hasMatch(target.name)) {
23-
final staticElement = target.staticElement;
24-
final name = node.methodName.name;
23+
if (_matchIdentifier(target)) {
24+
_addMemberInvocation(target as SimpleIdentifier, name);
25+
} else if (_matchConstructorOf(target)) {
26+
_addMemberInvocationOnConstructor(
27+
target as InstanceCreationExpression,
28+
name,
29+
);
30+
} else if (_matchMethodOf(target)) {
31+
final classTarget = (target as MethodInvocation).target;
2532

26-
if (staticElement is ClassElement) {
27-
_invocations.update(
28-
staticElement,
29-
(value) => value..add(name),
30-
ifAbsent: () => {name},
31-
);
33+
if (_matchIdentifier(classTarget)) {
34+
_addMemberInvocation(classTarget as SimpleIdentifier, name);
3235
}
3336
}
3437
}
@@ -52,4 +55,66 @@ class UnusedL10nVisitor extends RecursiveAstVisitor<void> {
5255
}
5356
}
5457
}
58+
59+
@override
60+
void visitPropertyAccess(PropertyAccess node) {
61+
super.visitPropertyAccess(node);
62+
63+
final target = node.target;
64+
final name = node.propertyName.name;
65+
66+
if (_matchConstructorOf(target)) {
67+
_addMemberInvocationOnConstructor(
68+
target as InstanceCreationExpression,
69+
name,
70+
);
71+
} else if (_matchMethodOf(target)) {
72+
final classTarget = (target as MethodInvocation).target;
73+
74+
if (_matchIdentifier(classTarget)) {
75+
_addMemberInvocation(classTarget as SimpleIdentifier, name);
76+
}
77+
}
78+
}
79+
80+
bool _matchIdentifier(Expression? target) =>
81+
target is SimpleIdentifier && _classPattern.hasMatch(target.name);
82+
83+
bool _matchConstructorOf(Expression? target) =>
84+
target is InstanceCreationExpression &&
85+
_classPattern.hasMatch(
86+
target.staticType?.getDisplayString(withNullability: false) ?? '',
87+
) &&
88+
target.constructorName.name?.name == 'of';
89+
90+
bool _matchMethodOf(Expression? target) =>
91+
target is MethodInvocation && target.methodName.name == 'of';
92+
93+
void _addMemberInvocation(SimpleIdentifier target, String name) {
94+
final staticElement = target.staticElement;
95+
96+
if (staticElement is ClassElement) {
97+
_invocations.update(
98+
staticElement,
99+
(value) => value..add(name),
100+
ifAbsent: () => {name},
101+
);
102+
}
103+
}
104+
105+
void _addMemberInvocationOnConstructor(
106+
InstanceCreationExpression target,
107+
String name,
108+
) {
109+
final staticElement =
110+
target.constructorName.staticElement?.enclosingElement;
111+
112+
if (staticElement is ClassElement) {
113+
_invocations.update(
114+
staticElement,
115+
(value) => value..add(name),
116+
ifAbsent: () => {name},
117+
);
118+
}
119+
}
55120
}

test/resources/unused_l10n_analyzer/test_i18n.dart

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ class TestI18n {
77

88
static String secondMethod(String value, num number) =>
99
value + number.toString();
10+
11+
String regularMethod(String value) => value;
12+
13+
String get regularGetter => 'regular getter'; // LINT
14+
15+
final String regularField = 'regular field';
16+
17+
TestI18n.of(String value) {
18+
print(value);
19+
}
1020
}
1121

1222
class S {
@@ -18,4 +28,17 @@ class S {
1828

1929
static String secondMethod(String value, num number) => // LINT
2030
value + number.toString();
31+
32+
String regularMethod(String value) => value;
33+
34+
String get regularGetter => 'regular getter';
35+
36+
final String regularField = 'regular field'; // LINT
37+
38+
// ignore: prefer_constructors_over_static_methods
39+
static S of(String value) {
40+
print(value);
41+
42+
return S();
43+
}
2144
}

test/resources/unused_l10n_analyzer/unused_l10n_analyzer_example.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ void main() {
44
final _ = TestI18n.method('value');
55

66
S.getter;
7+
8+
TestI18n.of('').regularMethod('some-string');
9+
10+
TestI18n.of('').regularField.trim();
711
}
812

913
class SomeClass {
1014
final field = TestI18n.field;
15+
16+
void method() {
17+
S.of('').regularMethod('');
18+
S.of('').regularGetter;
19+
}
1120
}

test/src/analyzers/unused_l10n_analyzer/unused_l10n_analyzer_test.dart

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,18 @@ void main() {
4141
expect(firstIssue.location.line, 4);
4242
expect(firstIssue.location.column, 3);
4343

44-
final secondIssues = report.issues.last;
44+
final secondIssue = report.issues.elementAt(1);
45+
expect(secondIssue.memberName, 'regularGetter');
46+
expect(secondIssue.location.line, 13);
47+
expect(secondIssue.location.column, 3);
48+
49+
final thirdIssue = report.issues.elementAt(2);
4550
expect(
46-
secondIssues.memberName,
51+
thirdIssue.memberName,
4752
'secondMethod(String value, num number)',
4853
);
49-
expect(secondIssues.location.line, 8);
50-
expect(secondIssues.location.column, 3);
54+
expect(thirdIssue.location.line, 8);
55+
expect(thirdIssue.location.column, 3);
5156
});
5257

5358
test('should analyze files with custom class pattern', () async {
@@ -67,24 +72,26 @@ void main() {
6772

6873
final firstIssue = report.issues.first;
6974
expect(firstIssue.memberName, 'field');
70-
expect(firstIssue.location.line, 13);
75+
expect(firstIssue.location.line, 23);
7176
expect(firstIssue.location.column, 3);
7277

73-
final secondIssues = report.issues.elementAt(1);
74-
expect(
75-
secondIssues.memberName,
76-
'method(String value)',
77-
);
78-
expect(secondIssues.location.line, 17);
79-
expect(secondIssues.location.column, 3);
78+
final secondIssue = report.issues.elementAt(1);
79+
expect(secondIssue.memberName, 'regularField');
80+
expect(secondIssue.location.line, 36);
81+
expect(secondIssue.location.column, 3);
82+
83+
final thirdIssue = report.issues.elementAt(2);
84+
expect(thirdIssue.memberName, 'method(String value)');
85+
expect(thirdIssue.location.line, 27);
86+
expect(thirdIssue.location.column, 3);
8087

81-
final thirdIssues = report.issues.elementAt(2);
88+
final forthIssue = report.issues.elementAt(3);
8289
expect(
83-
thirdIssues.memberName,
90+
forthIssue.memberName,
8491
'secondMethod(String value, num number)',
8592
);
86-
expect(thirdIssues.location.line, 19);
87-
expect(thirdIssues.location.column, 3);
93+
expect(forthIssue.location.line, 29);
94+
expect(forthIssue.location.column, 3);
8895
});
8996

9097
test('should report no issues for a custom class name pattern', () async {

0 commit comments

Comments
 (0)