Skip to content

refactor: migrate avoid_using_api#304

Merged
solid-illiaaihistov merged 12 commits into
solid-software:analysis_server_migrationfrom
solid-illiaaihistov:249-migrate-avoid_using_api
Jul 8, 2026
Merged

refactor: migrate avoid_using_api#304
solid-illiaaihistov merged 12 commits into
solid-software:analysis_server_migrationfrom
solid-illiaaihistov:249-migrate-avoid_using_api

Conversation

@solid-illiaaihistov

Copy link
Copy Markdown
Collaborator

Closes #249

@solid-illiaaihistov solid-illiaaihistov linked an issue Jun 30, 2026 that may be closed by this pull request

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the avoid_using_api lint rule to utilize the analyzer-based RuleContext and RuleVisitorRegistry instead of custom_lint APIs. It replaces AvoidUsingApiLinter with AvoidUsingApiVisitor (extending SimpleAstVisitor), introduces several AST node helper extensions in node_utils.dart, refactors path matching in path_utils.dart, and replaces old integration tests with a comprehensive unit test suite. The review feedback suggests making the rootPath parameter in _getActiveEntries nullable to align with shouldSkipFile and passing context.package?.root.path directly instead of coalescing it to an empty string.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart
Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
@solid-illiaaihistov

Copy link
Copy Markdown
Collaborator Author

I found a bug related to the use of severity in this rule, and I'm working on a fix.

Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
Comment on lines +330 to +345
if (actualClassName != className) {
return;
}

if (node.constructorName.name?.name != expectedConstructorName) {
return;
}

if (!node.argumentList.containsNamed(namedParameter)) {
return;
}

if (matchesSource(
node.constructorName.type.element?.libraryUri,
source,
)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (actualClassName != className) {
return;
}
if (node.constructorName.name?.name != expectedConstructorName) {
return;
}
if (!node.argumentList.containsNamed(namedParameter)) {
return;
}
if (matchesSource(
node.constructorName.type.element?.libraryUri,
source,
)) {
if (actualClassName == className &&
node.constructorName.name?.name == expectedConstructorName &&
node.argumentList.containsNamed(namedParameter) &&
matchesSource(
node.constructorName.type.element?.libraryUri,
source,
)) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are probably more similar refactors possible in this file that I missed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I implemented similar improvements in other parts of this class as well.

Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
}
}

bool _isMemberOrClass(Element? element, String className, String source) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like it can be extracted to util?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread lib/src/lints/avoid_using_api/visitors/avoid_using_api_visitor.dart Outdated
return;
}

reporter.atNode(node, _getLintCode(entry));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repeated 8 times, why don't we wrap reporter into a function when we return it from _resolveContext so it looks more like:

Suggested change
reporter.atNode(node, _getLintCode(entry));
report(node);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

…ied traversal method and moving member checks to extensions

@solid-danylosafonov solid-danylosafonov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it kinda starts looking like we could extract _checkX methods to be polymorphic extensions on node types so e.g. instead of _checkIdFromSource(node, entry), we'd have node.checkIdFromSource(entry). But I also think that checkX might not be the best name here

Comment on lines +116 to +118
final resolved = _resolveContext();
if (resolved == null) return;
final (:activeEntries, :reporter) = resolved;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably can inline it now

Suggested change
final resolved = _resolveContext();
if (resolved == null) return;
final (:activeEntries, :reporter) = resolved;
final currentUnit = context.currentUnit;
if (currentUnit == null) return;
final activeEntries = _cachedActiveEntries ??= _getActiveEntries(
currentUnit.file.path,
context.package?.root.path,
);
final reporter = currentUnit.diagnosticReporter;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines +121 to +127
visitEntry(node, entry, (target) {
if (target is AstNode) {
reporter.atNode(target, _getLintCode(entry));
} else if (target is Token) {
reporter.atToken(target, _getLintCode(entry));
}
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we can inline _getLintCode here

Suggested change
visitEntry(node, entry, (target) {
if (target is AstNode) {
reporter.atNode(target, _getLintCode(entry));
} else if (target is Token) {
reporter.atToken(target, _getLintCode(entry));
}
});
visitEntry(node, entry, (target) {
final severity =
entry.severity ?? parameters.severity ?? DiagnosticSeverity.INFO;
final code = LintCode(
AvoidUsingApiRule.lintName,
entry.reason ?? AvoidUsingApiRule.defaultMessage,
severity: severity,
uniqueName: AvoidUsingApiRule.getUniqueName(severity),
);
visitEntry(
node,
entry,
(target) => switch (target) {
AstNode() => reporter.atNode(target, code),
Token() => reporter.atToken(target, code),
_ => (),
},
);
});

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

void Function(
T,
AvoidUsingApiEntryParameters,
void Function(SyntacticEntity),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually can avoid passing it in alltogether

Suggested change
void Function(SyntacticEntity),
  void _visit<T>(
    T node,
    void Function(T) visitSuper,
    SyntacticEntity? Function(
      T,
      AvoidUsingApiEntryParameters,
    )
    visitEntry,
  ) {
    visitSuper(node);

    final currentUnit = context.currentUnit;
    if (currentUnit == null) return;

    final activeEntries = _cachedActiveEntries ??= _getActiveEntries(
      currentUnit.file.path,
      context.package?.root.path,
    );

    final reporter = currentUnit.diagnosticReporter;

    for (final entry in activeEntries) {
      final severity =
          entry.severity ?? parameters.severity ?? DiagnosticSeverity.INFO;

      final code = LintCode(
        AvoidUsingApiRule.lintName,
        entry.reason ?? AvoidUsingApiRule.defaultMessage,
        severity: severity,
        uniqueName: AvoidUsingApiRule.getUniqueName(severity),
      );

      final target = visitEntry(node, entry);
      (() => switch (target) {
        AstNode() => reporter.atNode(target, code),
        Token() => reporter.atToken(target, code),
        _ => (),
      })();
    }
  }

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment on lines +287 to +292
final source = entry.source;
if (source == null) return;

final className = entry.className;
final identifier = entry.identifier;
final namedParameter = entry.namedParameter;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final source = entry.source;
if (source == null) return;
final className = entry.className;
final identifier = entry.identifier;
final namedParameter = entry.namedParameter;
final AvoidUsingApiEntryParameters(
:className,
:identifier,
:namedParameter,
:source,
) = entry;
if (source == null) return null;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

final identifier = entry.identifier;
final namedParameter = entry.namedParameter;

switch ((className, identifier, namedParameter)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we can short circuit here

Suggested change
switch ((className, identifier, namedParameter)) {
if (className == null) return;
switch ((identifier, namedParameter)) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@solid-danylosafonov solid-danylosafonov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@solid-illiaaihistov solid-illiaaihistov merged commit b38c6d9 into solid-software:analysis_server_migration Jul 8, 2026
1 check failed
@solid-illiaaihistov solid-illiaaihistov deleted the 249-migrate-avoid_using_api branch July 8, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate avoid_using_api

2 participants