Make ElementResolver an ordinary class (not a visitor).

This change eliminates virtual dispatch when invoking the
ElementResolver, which should improve performance.  Also, it makes it
easier to navigate through the code (since we can now jump directly
between an ElementResolver method and its caller).

In addition, this refactor naturally exposed several instances where
we were unnecessarily invoking an ElementResolver method that did
nothing.  Removing these invocations should improve performance as
well.

Change-Id: Ic2e1625f231218e0ba3b57070eb79db230ef61a4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/229440
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
index 1b23467..625037b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/instance_creation_expression_resolver.dart
@@ -120,7 +120,7 @@
     _inferArgumentTypes(node);
     _resolver.visitArgumentList(node.argumentList,
         whyNotPromotedList: whyNotPromotedList);
-    node.accept(_resolver.elementResolver);
+    _resolver.elementResolver.visitInstanceCreationExpression(node);
     _resolver.typeAnalyzer.visitInstanceCreationExpression(node);
     _resolver.checkForArgumentTypesNotAssignableInList(
         node.argumentList, whyNotPromotedList);
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 2dc6017..b32cea7 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
@@ -74,7 +73,7 @@
 /// undeclared variables (which is an error) and names in hide and show
 /// combinators that are not defined in the imported library (which is not an
 /// error).
-class ElementResolver extends SimpleAstVisitor<void> {
+class ElementResolver {
   /// The resolver driving this participant.
   final ResolverVisitor _resolver;
 
@@ -112,24 +111,19 @@
 
   TypeProviderImpl get _typeProvider => _resolver.typeProvider;
 
-  @override
   void visitClassDeclaration(ClassDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitClassTypeAlias(ClassTypeAlias node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitCommentReference(CommentReference node) {
     _commentReferenceResolver.resolve(node);
   }
 
-  @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
-    super.visitConstructorDeclaration(node);
     ConstructorElement element = node.declaredElement!;
     if (element is ConstructorElementImpl) {
       var redirectedNode = node.redirectedConstructor;
@@ -150,7 +144,6 @@
     }
   }
 
-  @override
   void visitConstructorFieldInitializer(
       covariant ConstructorFieldInitializerImpl node) {
     var fieldName = node.fieldName;
@@ -159,7 +152,6 @@
     fieldName.staticElement = fieldElement;
   }
 
-  @override
   void visitConstructorName(covariant ConstructorNameImpl node) {
     var type = node.type2.type;
     if (type == null) {
@@ -183,22 +175,18 @@
     }
   }
 
-  @override
   void visitDeclaredIdentifier(DeclaredIdentifier node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitEnumDeclaration(EnumDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitExportDirective(ExportDirective node) {
     var exportElement = node.element;
     if (exportElement != null) {
@@ -210,43 +198,34 @@
     }
   }
 
-  @override
   void visitExtensionDeclaration(ExtensionDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitFieldDeclaration(FieldDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitFieldFormalParameter(FieldFormalParameter node) {
     _resolveMetadataForParameter(node);
-    super.visitFieldFormalParameter(node);
   }
 
-  @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitFunctionTypeAlias(FunctionTypeAlias node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
     _resolveMetadataForParameter(node);
   }
 
-  @override
   void visitGenericTypeAlias(GenericTypeAlias node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitImportDirective(covariant ImportDirectiveImpl node) {
     var prefixNode = node.prefix;
     if (prefixNode != null) {
@@ -272,7 +251,6 @@
     }
   }
 
-  @override
   void visitInstanceCreationExpression(
       covariant InstanceCreationExpressionImpl node) {
     var invokedConstructor = node.constructorName.staticElement;
@@ -284,17 +262,14 @@
     }
   }
 
-  @override
   void visitLibraryDirective(LibraryDirective node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitMethodDeclaration(MethodDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitMethodInvocation(MethodInvocation node,
       {List<WhyNotPromotedGetter>? whyNotPromotedList}) {
     whyNotPromotedList ??= [];
@@ -302,22 +277,18 @@
         node as MethodInvocationImpl, whyNotPromotedList);
   }
 
-  @override
   void visitMixinDeclaration(MixinDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitPartDirective(PartDirective node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitPartOfDirective(PartOfDirective node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitRedirectingConstructorInvocation(
       covariant RedirectingConstructorInvocationImpl node) {
     var enclosingClass = _resolver.enclosingClass;
@@ -348,12 +319,10 @@
     }
   }
 
-  @override
   void visitSimpleFormalParameter(SimpleFormalParameter node) {
     _resolveMetadataForParameter(node);
   }
 
-  @override
   void visitSuperConstructorInvocation(
       covariant SuperConstructorInvocationImpl node) {
     var enclosingClass = _resolver.enclosingClass;
@@ -416,7 +385,6 @@
     }
   }
 
-  @override
   void visitSuperExpression(SuperExpression node) {
     var context = SuperContext.of(node);
     if (context == SuperContext.annotation || context == SuperContext.static) {
@@ -426,20 +394,16 @@
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.SUPER_IN_EXTENSION, node);
     }
-    super.visitSuperExpression(node);
   }
 
-  @override
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitTypeParameter(TypeParameter node) {
     _resolveAnnotations(node.metadata);
   }
 
-  @override
   void visitVariableDeclarationList(VariableDeclarationList node) {
     _resolveAnnotations(node.metadata);
   }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ad205a7..ad8e1da 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1062,7 +1062,6 @@
   void visitAdjacentStrings(AdjacentStrings node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitAdjacentStrings(node as AdjacentStringsImpl);
   }
 
@@ -1152,14 +1151,12 @@
       flow?.equalityOp_end(
           node.parent as Expression, secondArg, secondArg.typeOrThrow);
     }
-    node.accept(elementResolver);
   }
 
   @override
   void visitAsExpression(AsExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitAsExpression(node as AsExpressionImpl);
     flowAnalysis.asExpression(node);
     insertGenericFunctionInstantiation(node);
@@ -1210,7 +1207,6 @@
     }
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitAwaitExpression(node as AwaitExpressionImpl);
     insertGenericFunctionInstantiation(node);
   }
@@ -1230,7 +1226,6 @@
   void visitBlock(Block node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1240,7 +1235,6 @@
       _thisAccessTracker.enterFunctionBody(node);
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
     } finally {
       _thisAccessTracker.exitFunctionBody(node);
       inferenceContext.popFunctionBodyContext(node);
@@ -1252,7 +1246,6 @@
     flowAnalysis.flow?.booleanLiteral(node, node.value);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitBooleanLiteral(node as BooleanLiteralImpl);
   }
 
@@ -1263,7 +1256,6 @@
     // of the statement.
     //
     checkUnreachableNode(node);
-    node.accept(elementResolver);
     flowAnalysis.breakStatement(node);
   }
 
@@ -1280,7 +1272,6 @@
 
     node.cascadeSections.accept(this);
 
-    node.accept(elementResolver);
     typeAnalyzer.visitCascadeExpression(node);
 
     nullShortingTermination(node);
@@ -1290,7 +1281,6 @@
   void visitCatchClause(CatchClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1303,7 +1293,7 @@
       enclosingClass = node.declaredElement;
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitClassDeclaration(node);
     } finally {
       enclosingClass = outerType;
     }
@@ -1313,14 +1303,13 @@
   void visitClassTypeAlias(ClassTypeAlias node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitClassTypeAlias(node);
   }
 
   @override
   void visitComment(Comment node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1329,7 +1318,7 @@
     // We do not visit the expression because it needs to be visited in the
     // context of the reference.
     //
-    node.accept(elementResolver);
+    elementResolver.visitCommentReference(node);
   }
 
   @override
@@ -1344,7 +1333,6 @@
     for (int i = 0; i < declarationCount; i++) {
       declarations[i].accept(this);
     }
-    node.accept(elementResolver);
   }
 
   @override
@@ -1383,7 +1371,6 @@
     }
     elseExpression = node.elseExpression;
 
-    node.accept(elementResolver);
     typeAnalyzer.visitConditionalExpression(node as ConditionalExpressionImpl);
   }
 
@@ -1408,7 +1395,7 @@
       _setupThisType();
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitConstructorDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
       _thisType = null;
@@ -1438,7 +1425,8 @@
     expression.accept(this);
     expression = node.expression;
     var whyNotPromoted = flowAnalysis.flow?.whyNotPromoted(expression);
-    node.accept(elementResolver);
+    elementResolver.visitConstructorFieldInitializer(
+        node as ConstructorFieldInitializerImpl);
     if (fieldElement != null) {
       if (fieldType != null && expression.staticType != null) {
         var callReference = insertImplicitCallReference(expression);
@@ -1457,7 +1445,7 @@
   @override
   void visitConstructorName(ConstructorName node) {
     node.type2.accept(this);
-    node.accept(elementResolver);
+    elementResolver.visitConstructorName(node as ConstructorNameImpl);
   }
 
   @override
@@ -1469,7 +1457,6 @@
   void visitConstructorSelector(ConstructorSelector node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1479,7 +1466,6 @@
     // of the statement.
     //
     checkUnreachableNode(node);
-    node.accept(elementResolver);
     flowAnalysis.continueStatement(node);
   }
 
@@ -1487,7 +1473,7 @@
   void visitDeclaredIdentifier(DeclaredIdentifier node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitDeclaredIdentifier(node);
   }
 
   @override
@@ -1495,7 +1481,6 @@
     InferenceContext.setType(node.defaultValue, node.declaredElement?.type);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     ParameterElement element = node.declaredElement!;
 
     if (element is DefaultParameterElementImpl && node.isOfLocalFunction) {
@@ -1527,7 +1512,6 @@
   void visitDoubleLiteral(DoubleLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitDoubleLiteral(node as DoubleLiteralImpl);
   }
 
@@ -1538,21 +1522,18 @@
     }
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitEmptyStatement(EmptyStatement node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitEnumConstantArguments(EnumConstantArguments node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1560,7 +1541,7 @@
     node.metadata.accept(this);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitEnumConstantDeclaration(node);
   }
 
   @override
@@ -1573,7 +1554,7 @@
       enclosingClass = node.declaredElement;
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitEnumDeclaration(node);
     } finally {
       enclosingClass = outerType;
     }
@@ -1583,7 +1564,7 @@
   void visitExportDirective(ExportDirective node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitExportDirective(node);
   }
 
   @override
@@ -1602,7 +1583,6 @@
 
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
       insertImplicitCallReference(node.expression);
 
       flowAnalysis.flow?.handleExit();
@@ -1618,14 +1598,12 @@
   void visitExpressionStatement(ExpressionStatement node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitExtendsClause(ExtendsClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1635,7 +1613,7 @@
       enclosingExtension = node.declaredElement!;
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitExtensionDeclaration(node);
     } finally {
       enclosingExtension = outerExtension;
     }
@@ -1651,7 +1629,6 @@
     visitArgumentList(node.argumentList,
         whyNotPromotedList: whyNotPromotedList);
 
-    node.accept(elementResolver);
     extensionResolver.resolveOverride(node, whyNotPromotedList);
   }
 
@@ -1663,7 +1640,7 @@
       _setupThisType();
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitFieldDeclaration(node);
     } finally {
       _thisAccessTracker.exitFieldDeclaration(node);
       _thisType = null;
@@ -1674,7 +1651,7 @@
   void visitFieldFormalParameter(FieldFormalParameter node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitFieldFormalParameter(node);
   }
 
   @override
@@ -1686,7 +1663,6 @@
   void visitFormalParameterList(FormalParameterList node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1719,7 +1695,7 @@
       _enclosingFunction = node.declaredElement;
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitFunctionDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
     }
@@ -1746,7 +1722,6 @@
   void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -1781,28 +1756,27 @@
   void visitFunctionTypeAlias(FunctionTypeAlias node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitFunctionTypeAlias(node);
   }
 
   @override
   void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitFunctionTypedFormalParameter(node);
   }
 
   @override
   void visitGenericFunctionType(GenericFunctionType node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitGenericTypeAlias(GenericTypeAlias node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitGenericTypeAlias(node);
   }
 
   @override
@@ -1832,8 +1806,6 @@
     }
 
     flowAnalysis.flow?.ifStatement_end(elseElement != null);
-
-    node.accept(elementResolver);
   }
 
   @override
@@ -1863,29 +1835,25 @@
     }
 
     flowAnalysis.flow?.ifStatement_end(elseStatement != null);
-
-    node.accept(elementResolver);
   }
 
   @override
   void visitImplementsClause(ImplementsClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitImplicitCallReference(ImplicitCallReference node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitImportDirective(ImportDirective node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitImportDirective(node as ImportDirectiveImpl);
   }
 
   @override
@@ -1936,7 +1904,6 @@
   void visitIntegerLiteral(IntegerLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitIntegerLiteral(node);
   }
 
@@ -1944,21 +1911,18 @@
   void visitInterpolationExpression(InterpolationExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitInterpolationString(InterpolationString node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitIsExpression(IsExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitIsExpression(node as IsExpressionImpl);
     flowAnalysis.isExpression(node);
   }
@@ -1971,7 +1935,6 @@
     flowAnalysis.labeledStatement_enter(node);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     flowAnalysis.labeledStatement_exit(node);
   }
 
@@ -1979,7 +1942,7 @@
   void visitLibraryDirective(LibraryDirective node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitLibraryDirective(node);
   }
 
   @override
@@ -1995,7 +1958,6 @@
   void visitMapLiteralEntry(MapLiteralEntry node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2013,7 +1975,7 @@
       _setupThisType();
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitMethodDeclaration(node);
     } finally {
       _enclosingFunction = outerFunction;
       _thisType = null;
@@ -2078,7 +2040,7 @@
       enclosingClass = node.declaredElement!;
       checkUnreachableNode(node);
       node.visitChildren(this);
-      node.accept(elementResolver);
+      elementResolver.visitMixinDeclaration(node);
     } finally {
       enclosingClass = outerType;
     }
@@ -2089,7 +2051,6 @@
     InferenceContext.setTypeFromNode(node.expression, node);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitNamedExpression(node as NamedExpressionImpl);
     // Any "why not promoted" information that flow analysis had associated with
     // `node.expression` now needs to be forwarded to `node`, so that when
@@ -2110,14 +2071,12 @@
   void visitNativeClause(NativeClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitNativeFunctionBody(NativeFunctionBody node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2125,7 +2084,6 @@
     flowAnalysis.flow?.nullLiteral(node);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitNullLiteral(node as NullLiteralImpl);
   }
 
@@ -2133,7 +2091,6 @@
   void visitOnClause(OnClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2141,7 +2098,6 @@
     InferenceContext.setTypeFromNode(node.expression, node);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer
         .visitParenthesizedExpression(node as ParenthesizedExpressionImpl);
     flowAnalysis.flow?.parenthesizedExpression(node, node.expression);
@@ -2151,14 +2107,14 @@
   void visitPartDirective(PartDirective node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitPartDirective(node);
   }
 
   @override
   void visitPartOfDirective(PartOfDirective node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitPartOfDirective(node);
   }
 
   @override
@@ -2232,7 +2188,8 @@
     // invocation.
     //
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
-    node.accept(elementResolver);
+    elementResolver.visitRedirectingConstructorInvocation(
+        node as RedirectingConstructorInvocationImpl);
     InferenceContext.setType(node.argumentList, node.staticElement?.type);
     visitArgumentList(node.argumentList,
         whyNotPromotedList: whyNotPromotedList);
@@ -2244,7 +2201,6 @@
   void visitRethrowExpression(RethrowExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitRethrowExpression(node as RethrowExpressionImpl);
     flowAnalysis.flow?.handleExit();
   }
@@ -2258,7 +2214,6 @@
 
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
 
     inferenceContext.bodyContext?.addReturnExpression(node.expression);
     flowAnalysis.flow?.handleExit();
@@ -2282,7 +2237,7 @@
   void visitSimpleFormalParameter(SimpleFormalParameter node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitSimpleFormalParameter(node);
   }
 
   @override
@@ -2295,7 +2250,6 @@
   void visitSimpleStringLiteral(SimpleStringLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitSimpleStringLiteral(node as SimpleStringLiteralImpl);
   }
 
@@ -2303,7 +2257,6 @@
   void visitSpreadElement(SpreadElement node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
 
     if (!node.isNullAware) {
       nullableDereferenceVerifier.expression(
@@ -2317,7 +2270,6 @@
   void visitStringInterpolation(StringInterpolation node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitStringInterpolation(node as StringInterpolationImpl);
   }
 
@@ -2329,7 +2281,8 @@
     // invocation.
     //
     var whyNotPromotedList = <Map<DartType, NonPromotionReason> Function()>[];
-    node.accept(elementResolver);
+    elementResolver.visitSuperConstructorInvocation(
+        node as SuperConstructorInvocationImpl);
     InferenceContext.setType(node.argumentList, node.staticElement?.type);
     visitArgumentList(node.argumentList,
         whyNotPromotedList: whyNotPromotedList);
@@ -2341,7 +2294,7 @@
   void visitSuperExpression(SuperExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitSuperExpression(node);
     typeAnalyzer.visitSuperExpression(node as SuperExpressionImpl);
   }
 
@@ -2349,7 +2302,6 @@
   void visitSuperFormalParameter(SuperFormalParameter node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2360,7 +2312,6 @@
         node.expression, _enclosingSwitchStatementExpressionType);
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
 
     var flow = flowAnalysis.flow;
     if (flow != null && flow.isReachable && _isNonNullableByDefault) {
@@ -2380,7 +2331,6 @@
   void visitSwitchDefault(SwitchDefault node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     nullSafetyDeadCodeVerifier.flowEnd(node);
   }
 
@@ -2422,7 +2372,6 @@
   void visitSymbolLiteral(SymbolLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitSymbolLiteral(node as SymbolLiteralImpl);
   }
 
@@ -2430,7 +2379,6 @@
   void visitThisExpression(ThisExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitThisExpression(node as ThisExpressionImpl);
   }
 
@@ -2438,7 +2386,6 @@
   void visitThrowExpression(ThrowExpression node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
     typeAnalyzer.visitThrowExpression(node as ThrowExpressionImpl);
     flowAnalysis.flow?.handleExit();
   }
@@ -2447,7 +2394,7 @@
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitTopLevelVariableDeclaration(node);
   }
 
   @override
@@ -2501,28 +2448,25 @@
   void visitTypeArgumentList(TypeArgumentList node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitTypeLiteral(TypeLiteral node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
   void visitTypeParameter(TypeParameter node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitTypeParameter(node);
   }
 
   @override
   void visitTypeParameterList(TypeParameterList node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2553,14 +2497,13 @@
     }
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
+    elementResolver.visitVariableDeclarationList(node);
   }
 
   @override
   void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override
@@ -2584,14 +2527,12 @@
     nullSafetyDeadCodeVerifier.flowEnd(node.body);
     // TODO(brianwilkerson) If the loop can only be exited because the condition
     // is false, then propagateFalseState(condition);
-    node.accept(elementResolver);
   }
 
   @override
   void visitWithClause(WithClause node) {
     checkUnreachableNode(node);
     node.visitChildren(this);
-    node.accept(elementResolver);
   }
 
   @override