Skip to content

Commit afd77da

Browse files
committed
feat: add named parameter
1 parent 268c098 commit afd77da

File tree

7 files changed

+184
-7
lines changed

7 files changed

+184
-7
lines changed

lib/src/lints/avoid_using_api/avoid_using_api_linter.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,4 +309,70 @@ class AvoidUsingApiLinter {
309309
reporter.atNode(node, entryCode);
310310
});
311311
}
312+
313+
/// Lints usages of a named parameter from a given source
314+
void banUsageWithSpecificNamedParameter(
315+
LintCode entryCode,
316+
String identifier,
317+
String namedParameter,
318+
String className,
319+
String source,
320+
) {
321+
context.registry.addMethodInvocation((node) {
322+
final methodName = node.methodName.name;
323+
if (methodName != identifier) return;
324+
325+
final enclosingElement = node.methodName.element?.enclosingElement2;
326+
if (enclosingElement == null || enclosingElement.name3 != className) {
327+
return;
328+
}
329+
330+
if (!_hasNamedParameter(node.argumentList, namedParameter)) {
331+
return;
332+
}
333+
334+
final sourcePath = enclosingElement.library2?.uri.toString() ?? '';
335+
if (!_matchesSource(sourcePath, source)) {
336+
return;
337+
}
338+
339+
reporter.atNode(node.methodName, entryCode);
340+
});
341+
342+
context.registry.addInstanceCreationExpression((node) {
343+
final String? expectedConstructorName;
344+
if (identifier == defaultConstructorIdentifier) {
345+
expectedConstructorName = null;
346+
} else {
347+
expectedConstructorName = identifier;
348+
}
349+
350+
final actualClassName = node.constructorName.type.name2.lexeme;
351+
if (actualClassName != className) {
352+
return;
353+
}
354+
355+
if (node.constructorName.name?.name != expectedConstructorName) {
356+
return;
357+
}
358+
359+
if (!_hasNamedParameter(node.argumentList, namedParameter)) {
360+
return;
361+
}
362+
363+
final sourcePath =
364+
node.constructorName.type.element2?.library2?.uri.toString();
365+
if (sourcePath == null || !_matchesSource(sourcePath, source)) {
366+
return;
367+
}
368+
369+
reporter.atNode(node, entryCode);
370+
});
371+
}
372+
373+
bool _hasNamedParameter(ArgumentList argumentList, String namedParameter) =>
374+
argumentList.arguments.any(
375+
(arg) =>
376+
arg is NamedExpression && arg.name.label.name == namedParameter,
377+
);
312378
}

lib/src/lints/avoid_using_api/avoid_using_api_rule.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,19 @@ class AvoidUsingApiRule extends SolidLintRule<AvoidUsingApiParameters> {
126126
switch (entry) {
127127
case AvoidUsingApiEntryParameters(:final source) when source == null:
128128
break;
129+
case AvoidUsingApiEntryParameters(
130+
:final identifier?,
131+
:final namedParameter?,
132+
:final className?,
133+
:final source?
134+
):
135+
linter.banUsageWithSpecificNamedParameter(
136+
entryCode,
137+
identifier,
138+
namedParameter,
139+
className,
140+
source,
141+
);
129142
case AvoidUsingApiEntryParameters(
130143
:final identifier?,
131144
:final className?,

lib/src/lints/avoid_using_api/models/avoid_using_api_entry_parameters.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:solid_lints/src/utils/parameter_utils.dart';
77
///
88
/// Parameters:
99
/// * identifier: Variable/method name
10+
/// * named_parameter: Named parameter of the constructor/method
1011
/// * class_name: Name of the class containing the variable/method
1112
/// * source: Package (e.g., dart:async or package:example)
1213
/// * severity: The default severity of the lint for each entry.
@@ -35,6 +36,9 @@ class AvoidUsingApiEntryParameters {
3536
/// Variable/method name
3637
final String? identifier;
3738

39+
/// Named parameter of the constrcutor/method
40+
final String? namedParameter;
41+
3842
/// Name of the class containing the variable/method
3943
final String? className;
4044

@@ -56,6 +60,7 @@ class AvoidUsingApiEntryParameters {
5660
/// Constructor for [AvoidUsingApiEntryParameters] model
5761
const AvoidUsingApiEntryParameters({
5862
this.identifier,
63+
this.namedParameter,
5964
this.className,
6065
this.source,
6166
this.severity,
@@ -70,6 +75,7 @@ class AvoidUsingApiEntryParameters {
7075
) =>
7176
AvoidUsingApiEntryParameters(
7277
identifier: json['identifier'] as String?,
78+
namedParameter: json['named_parameter'] as String?,
7379
className: json['class_name'] as String?,
7480
source: json['source'] as String?,
7581
severity: decodeErrorSeverity(json['severity'] as String?),

lint_test/avoid_using_api/external_source/lib/external_source.dart

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,35 @@
44
class BannedCodeUsage {
55
final String test4 = 'Hello World';
66

7-
BannedCodeUsage();
7+
BannedCodeUsage({this.parameter1, this.parameter2});
88

9-
factory BannedCodeUsage.test3() {
10-
return BannedCodeUsage();
9+
String? parameter1;
10+
String? parameter2;
11+
12+
factory BannedCodeUsage.test3({String? parameter1, String? parameter2}) {
13+
return BannedCodeUsage(
14+
parameter1: parameter1,
15+
parameter2: parameter2,
16+
);
1117
}
1218

13-
void test() {}
19+
BannedCodeUsage.test5({String? parameter1, String? parameter2});
20+
21+
void test({String? parameter1, String? parameter2}) {}
1422

15-
static String test2() {
23+
static String test2({String? parameter1, String? parameter2}) {
1624
return 'Hello World';
1725
}
1826
}
1927

2028
const test2 = 'Hello World';
2129

22-
void test() {}
30+
void test({String? parameter1}) {}
2331

2432
int banned = 5;
2533

2634
extension BannedExtension on int {
27-
int banned() => this + 10;
35+
int banned({String? parameter1, String? parameter2}) => this + 10;
2836

2937
int get bannedGetter => 10;
3038
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
analyzer:
2+
plugins:
3+
- ../../custom_lint
4+
5+
custom_lint:
6+
rules:
7+
- avoid_using_api:
8+
severity: warning
9+
entries:
10+
- identifier: ()
11+
named_parameter: parameter1
12+
class_name: BannedCodeUsage
13+
source: package:external_source
14+
reason: "Use parameter2 instead"
15+
- identifier: test3
16+
named_parameter: parameter1
17+
class_name: BannedCodeUsage
18+
source: package:external_source
19+
reason: "Use parameter2 instead"
20+
- identifier: test5
21+
named_parameter: parameter1
22+
class_name: BannedCodeUsage
23+
source: package:external_source
24+
reason: "Use parameter2 instead"
25+
- identifier: test2
26+
named_parameter: parameter1
27+
class_name: BannedCodeUsage
28+
source: package:external_source
29+
reason: "Use parameter2 instead"
30+
- identifier: test
31+
named_parameter: parameter1
32+
class_name: BannedCodeUsage
33+
source: package:external_source
34+
reason: "Use parameter2 instead"
35+
- identifier: banned
36+
named_parameter: parameter1
37+
class_name: BannedExtension
38+
source: package:external_source
39+
reason: "Use parameter2 instead"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// ignore_for_file: unused_local_variable
2+
3+
import 'package:external_source/external_source.dart';
4+
5+
void testingBannedCodeLint() async {
6+
// expect_lint: avoid_using_api
7+
final bannedCodeUsage = BannedCodeUsage(parameter1: '');
8+
9+
// expect_lint: avoid_using_api
10+
final test3 = BannedCodeUsage.test3(parameter1: '');
11+
12+
// expect_lint: avoid_using_api
13+
final test5 = BannedCodeUsage.test5(parameter1: '');
14+
15+
// expect_lint: avoid_using_api
16+
BannedCodeUsage.test2(
17+
parameter1: 'test',
18+
);
19+
20+
final obj = BannedCodeUsage();
21+
// expect_lint: avoid_using_api
22+
obj.test(parameter1: '');
23+
24+
test(parameter1: '');
25+
26+
// expect_lint: avoid_using_api
27+
2.banned(parameter1: '');
28+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: identifier_class_source_ban
2+
description: A sample command-line application.
3+
version: 1.0.0
4+
publish_to: none
5+
6+
environment:
7+
sdk: ^3.1.3
8+
9+
dependencies:
10+
external_source:
11+
path: ../external_source
12+
13+
dev_dependencies:
14+
lints: ^3.0.0
15+
test: ^1.21.0
16+
solid_lints:
17+
path: ../../../

0 commit comments

Comments
 (0)