anchor.diff:    void registerNodeProcessors(
         NodeLintRegistry registry, LinterContext context) {
       var visitor = _Visitor(this, context);
  -    registry.addCompilationUnit(this, visitor);
       registry.addConstructorFieldInitializer(this, visitor);
  +    registry.addThisExpression(this, visitor);
     }
   }
   
  -// todo (pq): refactor to not use scoped visitor
  -class _UnnecessaryThisVisitor extends ScopedVisitor {
  +class _Visitor extends SimpleAstVisitor<void> {
     final LintRule rule;
   
  -  _UnnecessaryThisVisitor(
  -      this.rule, LinterContext context, CompilationUnit node)
  -      : super(
  -          node.declaredElement.library,
  -          rule.reporter.source,
  -          context.typeProvider as TypeProviderImpl,
  -          AnalysisErrorListener.NULL_LISTENER,
  -        );
  +  final LinterContext context;
  +
  +  _Visitor(this.rule, this.context);
   
     @override
     void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
  
positive.code: import 'package:analyzer/dart/ast/ast.dart';
  import 'package:analyzer/dart/ast/visitor.dart';
  import 'package:analyzer/dart/element/element.dart';
  import 'package:analyzer/error/listener.dart';
  import 'package:analyzer/src/generated/resolver.dart'; // ignore: implementation_imports
  
  import '../analyzer.dart';
  import '../util/dart_type_utilities.dart';
  
  const _desc = r"Don't access members with `this` unless avoiding shadowing.";
  
  
negative.code:   @override
    void visitThisExpression(ThisExpression node) {
      final parent = node.parent;
  
      Element element;
      if (parent is PropertyAccess) {
        element = parent.propertyName.staticElement;
      } else if (parent is MethodInvocation) {
        element = parent.methodName.staticElement;
      } else {
        return;
      }
  
      if (_canReferenceElementWithoutThisPrefix(element, node)) {
        rule.reportLint(parent);
      }
    }
  
    bool _canReferenceElementWithoutThisPrefix(Element element, AstNode node) {
      if (element == null) {
        return false;
      }
  
      var id = element.displayName;
      var isSetter = element is PropertyAccessorElement && element.isSetter;
      var result = context.resolveNameInScope(id, isSetter, node);
  
      // No result, definitely no shadowing.
      // The requested element is inherited, or from an extension.
      if (result.isNone) {
        return true;
      }
  
      // The result has the matching name, might be shadowing.
      // Check that the element is the same.
      if (result.isRequestedName) {
        return result.element == element;
      }
  
      // The result has the same basename, but not the same name.
      // Must be an instance member, so that:
      //  - not shadowed by a local declaration;
      //  - prevents us from going up to the library scope;
      //  - the requested element must be inherited, or from an extension.
      if (result.isDifferentName) {
        var enclosing = result.element.enclosingElement;
        return enclosing is ClassElement;
      }
  
      // Should not happen.
      return false;
    }
  }
  