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

fix: correctly track prefixes usage for check-unused-code #1208

Merged
merged 2 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* feat: add static code diagnostic [`prefer-define-hero-tag`](https://dcm.dev/docs/individuals/rules/common/prefer-define-hero-tag).
* chore: restrict `analyzer` version to `>=5.1.0 <5.8.0`.
* feat: add static code diagnostic [`avoid-substring`](https://dcm.dev/docs/individuals/rules/common/avoid-substring).
* fix: correctly track prefixes usage for check-unused-code.

## 5.6.0

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import 'package:analyzer/dart/element/element.dart';

import 'prefix_element_usage.dart';

/// A container with information about used imports prefixes and used imported
/// elements.
class FileElementsUsage {
/// The map of referenced prefix elements and the elements that they prefix.
final Map<PrefixElement, PrefixElementUsage> prefixMap = {};

/// The set of referenced top-level elements.
final Set<Element> elements = {};

Expand All @@ -19,7 +14,6 @@ class FileElementsUsage {
final Map<Set<String>, Set<Element>> conditionalElements = {};

void merge(FileElementsUsage other) {
prefixMap.addAll(other.prefixMap);
elements.addAll(other.elements);
usedExtensions.addAll(other.usedExtensions);
exports.addAll(other.exports);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,7 @@ class UnusedCodeAnalyzer {
!codeUsages.elements
.any((usedElement) => _isUsed(usedElement, element)) &&
!codeUsages.usedExtensions
.any((usedElement) => _isUsed(usedElement, element)) &&
!codeUsages.prefixMap.values.any((usage) =>
usage.paths.contains(path) &&
usage.elements.any(
(usedElement) =>
_isUsed(usedElement, element) ||
(usedElement.name == element.name &&
usedElement.kind == element.kind),
));
.any((usedElement) => _isUsed(usedElement, element));

UnusedCodeIssue _createUnusedCodeIssue(
ElementImpl element,
Expand Down
75 changes: 1 addition & 74 deletions lib/src/analyzers/unused_code_analyzer/used_code_visitor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import 'package:collection/collection.dart';

import '../../utils/flutter_types_utils.dart';
import 'models/file_elements_usage.dart';
import 'models/prefix_element_usage.dart';

// Copied from https://github.com/dart-lang/sdk/blob/main/pkg/analyzer/lib/src/error/imports_verifier.dart#L15

Expand Down Expand Up @@ -124,40 +123,6 @@ class UsedCodeVisitor extends RecursiveAstVisitor<void> {
}
}

/// If the given [identifier] is prefixed with a [PrefixElement], fill the
/// corresponding `UsedImportedElements.prefixMap` entry and return `true`.
bool _recordPrefixMap(SimpleIdentifier identifier, Element element) {
bool recordIfTargetIsPrefixElement(Expression? target) {
if (target is SimpleIdentifier) {
final targetElement = target.staticElement;
if (targetElement is PrefixElement) {
fileElementsUsage.prefixMap
.putIfAbsent(
targetElement,
() => PrefixElementUsage(_getPrefixUsagePaths(target), {}),
)
.add(element);

return true;
}
}

return false;
}

final parent = identifier.parent;

if (parent is MethodInvocation && parent.methodName == identifier) {
return recordIfTargetIsPrefixElement(parent.target);
}

if (parent is PrefixedIdentifier && parent.identifier == identifier) {
return recordIfTargetIsPrefixElement(parent.prefix);
}

return false;
}

bool _recordConditionalElement(Element element) {
// ignore: deprecated_member_use
final elementPath = element.enclosingElement3?.source?.fullName;
Expand Down Expand Up @@ -194,7 +159,7 @@ class UsedCodeVisitor extends RecursiveAstVisitor<void> {
}

void _visitIdentifier(SimpleIdentifier identifier, Element? element) {
if (element == null) {
if (element == null || element is PrefixElement) {
return;
}

Expand All @@ -214,11 +179,6 @@ class UsedCodeVisitor extends RecursiveAstVisitor<void> {
return;
}

// Record `importPrefix.identifier` into 'prefixMap'.
if (_recordPrefixMap(identifier, element)) {
return;
}

// ignore: deprecated_member_use
final enclosingElement = element.enclosingElement3;
if (enclosingElement is CompilationUnitElement) {
Expand All @@ -227,11 +187,6 @@ class UsedCodeVisitor extends RecursiveAstVisitor<void> {
_recordUsedExtension(enclosingElement);

return;
} else if (element is PrefixElement) {
fileElementsUsage.prefixMap.putIfAbsent(
element,
() => PrefixElementUsage(_getPrefixUsagePaths(identifier), {}),
);
} else if (element is MultiplyDefinedElement) {
// If the element is multiply defined then call this method recursively
// for each of the conflicting elements.
Expand All @@ -244,34 +199,6 @@ class UsedCodeVisitor extends RecursiveAstVisitor<void> {
}
}

Iterable<String> _getPrefixUsagePaths(SimpleIdentifier target) {
final root = target.root;

if (root is! CompilationUnit) {
return [];
}

return root.directives.fold<List<String>>([], (previousValue, directive) {
if (directive is ImportDirective &&
directive.prefix?.name == target.name) {
// ignore: deprecated_member_use
final path = directive.element2?.importedLibrary?.source.fullName;
if (path != null) {
previousValue.add(path);
}

for (final config in directive.configurations) {
final uri = config.resolvedUri;
if (uri is DirectiveUriWithSource) {
previousValue.add(uri.source.fullName);
}
}
}

return previousValue;
});
}

bool _isVariableDeclarationInitializer(
AstNode? target,
SimpleIdentifier identifier,
Expand Down