[analyzer] Combine ElementUsageFrontierDetectors
Originally attempted to stab away at the cost of https://dart-review.googlesource.com/c/sdk/+/478701 - and while it did get better it was still much more expensive than before. With https://dart-review.googlesource.com/c/sdk/+/478701 having been reverted I've rebased and this is the new numbers: Parent CL: 42,517,120,185 instructions:u 42,517,237,423 instructions:u 42,514,559,436 instructions:u This CL: 41,687,688,230 instructions:u 41,687,684,807 instructions:u 41,687,673,825 instructions:u Saves ~827 mio instructions Change-Id: I752163a27dd779f27fafecce219cdc15e0f73d29 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/482241 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Paul Berry <paulberry@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
committed by
Commit Queue
parent
be0a084a73
commit
951471ebf2
@@ -26,6 +26,7 @@ import 'package:analyzer/src/error/deprecated_functionality_verifier.dart';
|
||||
import 'package:analyzer/src/error/deprecated_member_use_verifier.dart';
|
||||
import 'package:analyzer/src/error/do_not_submit_member_use_verifier.dart';
|
||||
import 'package:analyzer/src/error/doc_comment_verifier.dart';
|
||||
import 'package:analyzer/src/error/element_usage_detector.dart';
|
||||
import 'package:analyzer/src/error/element_usage_frontier_detector.dart';
|
||||
import 'package:analyzer/src/error/error_handler_verifier.dart';
|
||||
import 'package:analyzer/src/error/experimental_member_use_verifier.dart';
|
||||
@@ -66,7 +67,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
final DeprecatedFunctionalityVerifier _deprecatedFunctionalityVerifier;
|
||||
|
||||
final List<ElementUsageFrontierDetector> _elementUsageFrontierDetectors;
|
||||
final ElementUsageFrontierDetector _elementUsageFrontierDetector;
|
||||
|
||||
final ErrorHandlerVerifier _errorHandlerVerifier;
|
||||
|
||||
@@ -117,29 +118,29 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
_diagnosticReporter,
|
||||
_currentLibrary,
|
||||
),
|
||||
_elementUsageFrontierDetectors = [
|
||||
ElementUsageFrontierDetector(
|
||||
workspacePackage: workspacePackage,
|
||||
elementUsageSet: const DeprecatedElementUsageSet(),
|
||||
elementUsageReporter: DeprecatedElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
_elementUsageFrontierDetector = ElementUsageFrontierDetector(
|
||||
workspacePackage: workspacePackage,
|
||||
usagesAndReporters: [
|
||||
UsageSetAndReporter(
|
||||
const DeprecatedElementUsageSet(),
|
||||
DeprecatedElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
),
|
||||
),
|
||||
),
|
||||
ElementUsageFrontierDetector(
|
||||
workspacePackage: workspacePackage,
|
||||
elementUsageSet: const ExperimentalElementUsageSet(),
|
||||
elementUsageReporter: ExperimentalElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
UsageSetAndReporter(
|
||||
const ExperimentalElementUsageSet(),
|
||||
ExperimentalElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
),
|
||||
),
|
||||
),
|
||||
ElementUsageFrontierDetector(
|
||||
workspacePackage: workspacePackage,
|
||||
elementUsageSet: const DoNotSubmitElementUsageSet(),
|
||||
elementUsageReporter: DoNotSubmitElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
UsageSetAndReporter(
|
||||
const DoNotSubmitElementUsageSet(),
|
||||
DoNotSubmitElementUsageReporter(
|
||||
diagnosticReporter: _diagnosticReporter,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
_errorHandlerVerifier = ErrorHandlerVerifier(
|
||||
_diagnosticReporter,
|
||||
typeProvider,
|
||||
@@ -159,9 +160,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
),
|
||||
_widgetPreviewVerifier = WidgetPreviewVerifier(_diagnosticReporter),
|
||||
_workspacePackage = workspacePackage {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(_currentLibrary);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(_currentLibrary);
|
||||
_inDoNotStoreMember = _currentLibrary.metadata.hasDoNotStore;
|
||||
}
|
||||
|
||||
@@ -188,17 +187,13 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitAssignmentExpression(AssignmentExpression node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.assignmentExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.assignmentExpression(node);
|
||||
super.visitAssignmentExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitBinaryExpression(BinaryExpression node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.binaryExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.binaryExpression(node);
|
||||
_checkForInvariantNanComparison(node);
|
||||
_checkForInvariantNullComparison(node);
|
||||
_invalidAccessVerifier.verifyBinary(node);
|
||||
@@ -233,9 +228,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
bool wasInDoNotStoreMember = _inDoNotStoreMember;
|
||||
_deprecatedFunctionalityVerifier.classDeclaration(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
if (element.metadata.hasDoNotStore) {
|
||||
_inDoNotStoreMember = true;
|
||||
}
|
||||
@@ -250,9 +243,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
} finally {
|
||||
_enclosingClass = null;
|
||||
_invalidAccessVerifier._enclosingClass = null;
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
_inDoNotStoreMember = wasInDoNotStoreMember;
|
||||
}
|
||||
}
|
||||
@@ -262,16 +253,12 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
_immutableVerifier.checkDeclaration(node, nameToken: node.name);
|
||||
_checkForInvalidSealedSuperclass(node);
|
||||
_deprecatedFunctionalityVerifier.classTypeAlias(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
|
||||
try {
|
||||
super.visitClassTypeAlias(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,29 +301,21 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
initializers: node.initializers,
|
||||
);
|
||||
var element = node.declaredFragment!.element;
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.constructorDeclaration(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
_elementUsageFrontierDetector.constructorDeclaration(node);
|
||||
|
||||
_deprecatedFunctionalityVerifier.constructorDeclaration(node);
|
||||
|
||||
try {
|
||||
super.visitConstructorDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstructorName(ConstructorName node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.constructorName(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.constructorName(node);
|
||||
_deprecatedFunctionalityVerifier.constructorName(node);
|
||||
super.visitConstructorName(node);
|
||||
}
|
||||
@@ -359,20 +338,13 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
);
|
||||
}
|
||||
}
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.formalParameter(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
_elementUsageFrontierDetector.formalParameter(node);
|
||||
|
||||
try {
|
||||
super.visitDefaultFormalParameter(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,9 +353,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
DotShorthandConstructorInvocation node,
|
||||
) {
|
||||
_deprecatedFunctionalityVerifier.dotShorthandConstructorInvocation(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.dotShorthandConstructorInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.dotShorthandConstructorInvocation(node);
|
||||
_checkForLiteralConstructorUseInDotShorthand(node);
|
||||
super.visitDotShorthandConstructorInvocation(node);
|
||||
}
|
||||
@@ -391,41 +361,31 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
@override
|
||||
void visitDotShorthandInvocation(DotShorthandInvocation node) {
|
||||
_deprecatedFunctionalityVerifier.dotShorthandInvocation(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.dotShorthandInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.dotShorthandInvocation(node);
|
||||
super.visitDotShorthandInvocation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.dotShorthandPropertyAccess(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.dotShorthandPropertyAccess(node);
|
||||
super.visitDotShorthandPropertyAccess(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitEnumDeclaration(EnumDeclaration node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
_deprecatedFunctionalityVerifier.enumDeclaration(node);
|
||||
|
||||
try {
|
||||
super.visitEnumDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExportDirective(covariant ExportDirectiveImpl node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.exportDirective(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.exportDirective(node);
|
||||
_checkForInternalExport(node);
|
||||
super.visitExportDirective(node);
|
||||
}
|
||||
@@ -440,47 +400,35 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitExtensionDeclaration(ExtensionDeclaration node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
|
||||
try {
|
||||
super.visitExtensionDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtensionOverride(ExtensionOverride node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.extensionOverride(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.extensionOverride(node);
|
||||
super.visitExtensionOverride(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
|
||||
try {
|
||||
super.visitExtensionTypeDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitFieldDeclaration(FieldDeclaration node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.firstVariableElement);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.firstVariableElement);
|
||||
|
||||
try {
|
||||
super.visitFieldDeclaration(node);
|
||||
@@ -522,9 +470,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,9 +484,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
void visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
bool wasInDoNotStoreMember = _inDoNotStoreMember;
|
||||
var element = node.declaredFragment!.element;
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
if (element.metadata.hasDoNotStore) {
|
||||
_inDoNotStoreMember = true;
|
||||
}
|
||||
@@ -559,9 +503,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
);
|
||||
super.visitFunctionDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
_inDoNotStoreMember = wasInDoNotStoreMember;
|
||||
}
|
||||
}
|
||||
@@ -585,9 +527,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.functionExpressionInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.functionExpressionInvocation(node);
|
||||
super.visitFunctionExpressionInvocation(node);
|
||||
}
|
||||
|
||||
@@ -595,16 +535,12 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
void visitFunctionTypeAlias(FunctionTypeAlias node) {
|
||||
_checkStrictInferenceReturnType(node.returnType, node, node.name.lexeme);
|
||||
_checkStrictInferenceInParameters(node.parameters);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
|
||||
try {
|
||||
super.visitFunctionTypeAlias(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,24 +570,18 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
node.name.lexeme,
|
||||
);
|
||||
}
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
|
||||
try {
|
||||
super.visitGenericTypeAlias(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitImportDirective(ImportDirective node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.importDirective(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.importDirective(node);
|
||||
var import = node.libraryImport;
|
||||
if (import != null && import.prefix?.isDeferred == true) {
|
||||
_checkForLoadLibraryFunction(node, import);
|
||||
@@ -662,9 +592,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitIndexExpression(IndexExpression node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.indexExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.indexExpression(node);
|
||||
super.visitIndexExpression(node);
|
||||
}
|
||||
|
||||
@@ -672,9 +600,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
void visitInstanceCreationExpression(
|
||||
covariant InstanceCreationExpressionImpl node,
|
||||
) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.instanceCreationExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.instanceCreationExpression(node);
|
||||
_deprecatedFunctionalityVerifier.instanceCreationExpression(node);
|
||||
_nullSafeApiVerifier.instanceCreation(node);
|
||||
_checkForLiteralConstructorUse(node);
|
||||
@@ -694,9 +620,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
var element = node.declaredFragment!.element;
|
||||
var enclosingElement = element.enclosingElement;
|
||||
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
if (element.metadata.hasDoNotStore) {
|
||||
_inDoNotStoreMember = true;
|
||||
}
|
||||
@@ -776,18 +700,14 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
super.visitMethodDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
_inDoNotStoreMember = wasInDoNotStoreMember;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitMethodInvocation(covariant MethodInvocationImpl node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.methodInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.methodInvocation(node);
|
||||
_deprecatedFunctionalityVerifier.methodInvocation(node);
|
||||
_errorHandlerVerifier.verifyMethodInvocation(node);
|
||||
_nullSafeApiVerifier.methodInvocation(node);
|
||||
@@ -802,9 +722,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
_invalidAccessVerifier._enclosingClass = _enclosingClass;
|
||||
|
||||
_deprecatedFunctionalityVerifier.mixinDeclaration(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
|
||||
try {
|
||||
_immutableVerifier.checkDeclaration(node, nameToken: node.name);
|
||||
@@ -813,17 +731,13 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
} finally {
|
||||
_enclosingClass = null;
|
||||
_invalidAccessVerifier._enclosingClass = null;
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitNamedType(NamedType node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.namedType(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.namedType(node);
|
||||
_invalidAccessVerifier.verifyNamedType(node);
|
||||
var question = node.question;
|
||||
if (question != null) {
|
||||
@@ -845,18 +759,14 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitPatternField(PatternField node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.patternField(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.patternField(node);
|
||||
_invalidAccessVerifier.verifyPatternField(node as PatternFieldImpl);
|
||||
super.visitPatternField(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitPostfixExpression(PostfixExpression node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.postfixExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.postfixExpression(node);
|
||||
if (node.operator.type == TokenType.BANG &&
|
||||
node.operand.typeOrThrow.isDartCoreNull) {
|
||||
_diagnosticReporter.report(diag.nullCheckAlwaysFails.at(node));
|
||||
@@ -866,23 +776,17 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitPrefixExpression(PrefixExpression node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.prefixExpression(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.prefixExpression(node);
|
||||
super.visitPrefixExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitPrimaryConstructorBody(PrimaryConstructorBody node) {
|
||||
var element = node.declaration?.declaredFragment!.element;
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(element);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(element);
|
||||
// TODO(srawlins): Account for @doNotStore, as in `visitFunctionDeclaration`.
|
||||
super.visitPrimaryConstructorBody(node);
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -896,9 +800,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
void visitRedirectingConstructorInvocation(
|
||||
RedirectingConstructorInvocation node,
|
||||
) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.redirectingConstructorInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.redirectingConstructorInvocation(node);
|
||||
super.visitRedirectingConstructorInvocation(node);
|
||||
}
|
||||
|
||||
@@ -918,55 +820,40 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
|
||||
@override
|
||||
void visitSimpleFormalParameter(SimpleFormalParameter node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.declaredFragment!.element);
|
||||
}
|
||||
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.formalParameter(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.declaredFragment!.element);
|
||||
_elementUsageFrontierDetector.formalParameter(node);
|
||||
|
||||
try {
|
||||
super.visitSimpleFormalParameter(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSimpleIdentifier(SimpleIdentifier node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.simpleIdentifier(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.simpleIdentifier(node);
|
||||
_invalidAccessVerifier.verify(node);
|
||||
super.visitSimpleIdentifier(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.superConstructorInvocation(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.superConstructorInvocation(node);
|
||||
_invalidAccessVerifier.verifySuperConstructorInvocation(node);
|
||||
super.visitSuperConstructorInvocation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSuperFormalParameter(SuperFormalParameter node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.superFormalParameter(node);
|
||||
}
|
||||
_elementUsageFrontierDetector.superFormalParameter(node);
|
||||
_checkFinalParameter(node, node.keyword);
|
||||
super.visitSuperFormalParameter(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.pushElement(node.firstVariableElement);
|
||||
}
|
||||
_elementUsageFrontierDetector.pushElement(node.firstVariableElement);
|
||||
|
||||
if (!_invalidAccessVerifier._inTestDirectory) {
|
||||
for (var decl in node.variables.variables) {
|
||||
@@ -977,9 +864,7 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
|
||||
try {
|
||||
super.visitTopLevelVariableDeclaration(node);
|
||||
} finally {
|
||||
for (var v in _elementUsageFrontierDetectors) {
|
||||
v.popElement();
|
||||
}
|
||||
_elementUsageFrontierDetector.popElement();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,12 +63,15 @@ class DeprecatedElementUsageReporter implements ElementUsageReporter<String> {
|
||||
class DeprecatedElementUsageSet implements ElementUsageSet<String> {
|
||||
const DeprecatedElementUsageSet();
|
||||
|
||||
/// The message in the deprecated annotation on the given [element], or
|
||||
@override
|
||||
bool get reliesOnlyOnElementMetadata => true;
|
||||
|
||||
/// The message in the deprecated annotation in [elementMetadata], or
|
||||
/// the empty string if the annotation does not have a message, or `null` if
|
||||
/// the element doesn't have a deprecated annotation.
|
||||
@override
|
||||
String? getTagInfo(Element element) {
|
||||
for (var annotation in element.metadata.annotations) {
|
||||
String? getTagInfo(Element _, Metadata elementMetadata) {
|
||||
for (var annotation in elementMetadata.annotations) {
|
||||
if (!annotation.isDeprecated) continue;
|
||||
var value = annotation.computeConstantValue();
|
||||
if (value == null) continue;
|
||||
|
||||
@@ -37,6 +37,9 @@ class DoNotSubmitElementUsageSet implements ElementUsageSet<()> {
|
||||
const DoNotSubmitElementUsageSet();
|
||||
|
||||
@override
|
||||
()? getTagInfo(Element element) =>
|
||||
element.metadata.hasDoNotSubmit ? () : null;
|
||||
bool get reliesOnlyOnElementMetadata => true;
|
||||
|
||||
@override
|
||||
()? getTagInfo(Element _, Metadata elementMetadata) =>
|
||||
elementMetadata.hasDoNotSubmit ? () : null;
|
||||
}
|
||||
|
||||
@@ -24,17 +24,21 @@ class ElementUsageDetector<TagInfo extends Object> {
|
||||
/// parameter of [ElementUsageReporter.report].
|
||||
final WorkspacePackage? _workspacePackage;
|
||||
|
||||
/// The set of elements to detect usages of.
|
||||
final ElementUsageSet<TagInfo> elementUsageSet;
|
||||
|
||||
/// What to do when a usage of an element in [elementUsageSet] is detected.
|
||||
final ElementUsageReporter<TagInfo> elementUsageReporter;
|
||||
final List<UsageSetAndReporter> usagesArbitrary = [];
|
||||
final List<UsageSetAndReporter> usagesMetadataOnly = [];
|
||||
|
||||
ElementUsageDetector({
|
||||
required WorkspacePackage? workspacePackage,
|
||||
required this.elementUsageSet,
|
||||
required this.elementUsageReporter,
|
||||
}) : _workspacePackage = workspacePackage;
|
||||
required List<UsageSetAndReporter> usagesAndReporters,
|
||||
}) : _workspacePackage = workspacePackage {
|
||||
for (var usageSetAndReporter in usagesAndReporters) {
|
||||
if (usageSetAndReporter.elementUsageSet.reliesOnlyOnElementMetadata) {
|
||||
usagesMetadataOnly.add(usageSetAndReporter);
|
||||
} else {
|
||||
usagesArbitrary.add(usageSetAndReporter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assignmentExpression(AssignmentExpression node) {
|
||||
checkUsage(node.readElement, node.leftHandSide);
|
||||
@@ -47,7 +51,7 @@ class ElementUsageDetector<TagInfo extends Object> {
|
||||
}
|
||||
|
||||
/// Reports the usage of [element] at [node] if [element] is in
|
||||
/// [elementUsageSet].
|
||||
/// any of [usagesMetadataOnly] or [usagesArbitrary].
|
||||
void checkUsage(Element? element, AstNode node) {
|
||||
if (element == null) {
|
||||
return;
|
||||
@@ -61,8 +65,33 @@ class ElementUsageDetector<TagInfo extends Object> {
|
||||
return;
|
||||
}
|
||||
|
||||
var tagInfo = elementUsageSet.getTagInfo(element);
|
||||
if (tagInfo == null) return;
|
||||
List<UsageSetAndReporter>? givesNonNullResults;
|
||||
var elementMetadata = element.metadata;
|
||||
if (elementMetadata.annotations.isNotEmpty) {
|
||||
for (int i = 0; i < usagesMetadataOnly.length; i++) {
|
||||
if (!shouldCheckMetadataOnlyForIndex(i)) continue;
|
||||
var usagesAndReporter = usagesMetadataOnly[i];
|
||||
var tagInfo = usagesAndReporter.elementUsageSet.getTagInfo(
|
||||
element,
|
||||
elementMetadata,
|
||||
);
|
||||
if (tagInfo != null) {
|
||||
(givesNonNullResults ??= []).add(usagesAndReporter);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < usagesArbitrary.length; i++) {
|
||||
if (!shouldCheckArbitraryForIndex(i)) continue;
|
||||
var usagesAndReporter = usagesArbitrary[i];
|
||||
var tagInfo = usagesAndReporter.elementUsageSet.getTagInfo(
|
||||
element,
|
||||
elementMetadata,
|
||||
);
|
||||
if (tagInfo != null) {
|
||||
(givesNonNullResults ??= []).add(usagesAndReporter);
|
||||
}
|
||||
}
|
||||
if (givesNonNullResults == null) return;
|
||||
|
||||
if (_isLocalParameter(element, node)) {
|
||||
return;
|
||||
@@ -120,12 +149,15 @@ class ElementUsageDetector<TagInfo extends Object> {
|
||||
// `ConstructorDeclaration.errorRange` here. This would stray from the API
|
||||
// of passing a SyntacticEntity here.
|
||||
|
||||
elementUsageReporter.report(
|
||||
errorEntity,
|
||||
displayName,
|
||||
tagInfo,
|
||||
isInSamePackage: _isLibraryInWorkspacePackage(element.library),
|
||||
);
|
||||
for (var reportThis in givesNonNullResults) {
|
||||
reportThis.elementUsageReporter.report(
|
||||
errorEntity,
|
||||
displayName,
|
||||
// Getting it again might not be ideal...
|
||||
reportThis.elementUsageSet.getTagInfo(element, elementMetadata)!,
|
||||
isInSamePackage: _isLibraryInWorkspacePackage(element.library),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void constructorDeclaration(ConstructorDeclaration node) {
|
||||
@@ -266,6 +298,18 @@ class ElementUsageDetector<TagInfo extends Object> {
|
||||
_invocationArguments(node.element, node.argumentList);
|
||||
}
|
||||
|
||||
/// If false [checkUsage] may skip the call to `getTagInfo` on the [i]th
|
||||
/// entry of [usagesArbitrary].
|
||||
bool shouldCheckArbitraryForIndex(int i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// If false [checkUsage] may skip the call to `getTagInfo` on the [i]th
|
||||
/// entry of [usagesMetadataOnly].
|
||||
bool shouldCheckMetadataOnlyForIndex(int i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void simpleIdentifier(SimpleIdentifier node) {
|
||||
// Don't report declared identifiers.
|
||||
if (node.inDeclarationContext()) {
|
||||
@@ -426,12 +470,28 @@ abstract class ElementUsageReporter<TagInfo extends Object> {
|
||||
/// string). If there is no auxiliary information, supply `()` for this type
|
||||
/// parameter.
|
||||
abstract class ElementUsageSet<TagInfo extends Object> {
|
||||
/// If [getTagInfo] only relies on the element metadata and can only return
|
||||
/// non-null if the metadata is not empty.
|
||||
///
|
||||
/// Used to skip calls to [getTagInfo] is there is no metadata.
|
||||
bool get reliesOnlyOnElementMetadata;
|
||||
|
||||
/// If [element] is in the set of elements that [ElementUsageDetector] should
|
||||
/// detect usages of, returns auxiliary information associated with [element].
|
||||
///
|
||||
/// [elementMetadata] is the result of [element].metadata, but should be used
|
||||
/// to avoid the overhead of asking again.
|
||||
///
|
||||
/// Otherwise returns `null`.
|
||||
///
|
||||
/// For example, [DeprecatedElementUsageSet]'s implementation of this method
|
||||
/// returns the deprecation message if [element] is deprecated.
|
||||
TagInfo? getTagInfo(Element element);
|
||||
TagInfo? getTagInfo(Element element, Metadata elementMetadata);
|
||||
}
|
||||
|
||||
class UsageSetAndReporter<TagInfo extends Object> {
|
||||
final ElementUsageSet<TagInfo> elementUsageSet;
|
||||
final ElementUsageReporter<TagInfo> elementUsageReporter;
|
||||
|
||||
UsageSetAndReporter(this.elementUsageSet, this.elementUsageReporter);
|
||||
}
|
||||
|
||||
@@ -13,35 +13,96 @@ import 'package:analyzer/src/error/element_usage_detector.dart';
|
||||
/// that _are_ in the set.
|
||||
class ElementUsageFrontierDetector<TagInfo extends Object>
|
||||
extends ElementUsageDetector<TagInfo> {
|
||||
/// Stack corresponding to elements being visited that might be in
|
||||
/// [elementUsageSet].
|
||||
/// Stack corresponding to elements being visited that might be in ith
|
||||
/// [usagesArbitrary], i.e. the first index corresponds to [usagesArbitrary]
|
||||
/// and the second index to the stack depth.
|
||||
///
|
||||
/// Each element indicates whether the corresponding element is in
|
||||
/// [elementUsageSet] or not.
|
||||
final List<bool> _inElementStack = [false];
|
||||
/// Each element indicates whether the corresponding element is in ith
|
||||
/// [usagesArbitrary] or not.
|
||||
final List<List<bool>> _inElementStacksArbitrary = [];
|
||||
|
||||
/// Stack corresponding to elements being visited that might be in ith
|
||||
/// [usagesMetadataOnly], i.e. the first index corresponds to
|
||||
/// [usagesMetadataOnly] and the second index to the stack depth.
|
||||
///
|
||||
/// Each element indicates whether the corresponding element is in ith
|
||||
/// [usagesMetadataOnly] or not.
|
||||
final List<List<bool>> _inElementStacksMetadataOnly = [];
|
||||
|
||||
ElementUsageFrontierDetector({
|
||||
required super.workspacePackage,
|
||||
required super.elementUsageSet,
|
||||
required super.elementUsageReporter,
|
||||
});
|
||||
required super.usagesAndReporters,
|
||||
}) {
|
||||
for (int i = 0; i < usagesArbitrary.length; i++) {
|
||||
_inElementStacksArbitrary.add([false]);
|
||||
}
|
||||
for (int i = 0; i < usagesMetadataOnly.length; i++) {
|
||||
_inElementStacksMetadataOnly.add([false]);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void checkUsage(Element? element, AstNode node) {
|
||||
if (_inElementStack.last) {
|
||||
return;
|
||||
bool allTrue = true;
|
||||
for (var inElementStack in _inElementStacksArbitrary) {
|
||||
if (!inElementStack.last) {
|
||||
allTrue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allTrue) {
|
||||
for (var inElementStack in _inElementStacksMetadataOnly) {
|
||||
if (!inElementStack.last) {
|
||||
allTrue = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allTrue) return;
|
||||
|
||||
super.checkUsage(element, node);
|
||||
}
|
||||
|
||||
void popElement() {
|
||||
_inElementStack.removeLast();
|
||||
for (var inElementStack in _inElementStacksArbitrary) {
|
||||
inElementStack.removeLast();
|
||||
}
|
||||
for (var inElementStack in _inElementStacksMetadataOnly) {
|
||||
inElementStack.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
void pushElement(Element? element) {
|
||||
var value = element != null && elementUsageSet.getTagInfo(element) != null;
|
||||
var newValue = _inElementStack.last || value;
|
||||
_inElementStack.add(newValue);
|
||||
var elementMetadata = element?.metadata;
|
||||
for (int i = 0; i < _inElementStacksArbitrary.length; i++) {
|
||||
var inElementStack = _inElementStacksArbitrary[i];
|
||||
var newValue = inElementStack.last;
|
||||
if (!newValue && element != null) {
|
||||
var elementUsageSet = usagesArbitrary[i].elementUsageSet;
|
||||
newValue =
|
||||
elementUsageSet.getTagInfo(element, elementMetadata!) != null;
|
||||
}
|
||||
inElementStack.add(newValue);
|
||||
}
|
||||
for (int i = 0; i < _inElementStacksMetadataOnly.length; i++) {
|
||||
var inElementStack = _inElementStacksMetadataOnly[i];
|
||||
var newValue = inElementStack.last;
|
||||
if (!newValue && element != null) {
|
||||
var elementUsageSet = usagesMetadataOnly[i].elementUsageSet;
|
||||
newValue =
|
||||
elementUsageSet.getTagInfo(element, elementMetadata!) != null;
|
||||
}
|
||||
inElementStack.add(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldCheckArbitraryForIndex(int i) {
|
||||
return !_inElementStacksArbitrary[i].last;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldCheckMetadataOnlyForIndex(int i) {
|
||||
return !_inElementStacksMetadataOnly[i].last;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,9 @@ class ExperimentalElementUsageSet implements ElementUsageSet<()> {
|
||||
const ExperimentalElementUsageSet();
|
||||
|
||||
@override
|
||||
()? getTagInfo(Element element) =>
|
||||
element.metadata.annotations.any((e) => e.isExperimental) ? () : null;
|
||||
bool get reliesOnlyOnElementMetadata => true;
|
||||
|
||||
@override
|
||||
()? getTagInfo(Element _, Metadata elementMetadata) =>
|
||||
elementMetadata.annotations.any((e) => e.isExperimental) ? () : null;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/src/error/deprecated_member_use_verifier.dart' // ignore: implementation_imports
|
||||
show DeprecatedElementUsageSet, normalizeDeprecationMessage;
|
||||
import 'package:analyzer/src/error/element_usage_detector.dart' // ignore: implementation_imports
|
||||
show ElementUsageReporter;
|
||||
show ElementUsageReporter, UsageSetAndReporter;
|
||||
import 'package:analyzer/src/error/element_usage_frontier_detector.dart' // ignore: implementation_imports
|
||||
show ElementUsageFrontierDetector;
|
||||
import 'package:analyzer/src/utilities/extensions/ast.dart'; // ignore: implementation_imports
|
||||
@@ -95,8 +95,12 @@ class _RecursiveVisitor extends RecursiveAstVisitor<void> {
|
||||
_RecursiveVisitor(MultiAnalysisRule rule, WorkspacePackage package)
|
||||
: _deprecatedVerifier = ElementUsageFrontierDetector(
|
||||
workspacePackage: package,
|
||||
elementUsageSet: const DeprecatedElementUsageSet(),
|
||||
elementUsageReporter: _DeprecatedElementUsageReporter(rule: rule),
|
||||
usagesAndReporters: [
|
||||
UsageSetAndReporter(
|
||||
const DeprecatedElementUsageSet(),
|
||||
_DeprecatedElementUsageReporter(rule: rule),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
Reference in New Issue
Block a user