// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';

import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/type.dart';
// ignore: implementation_imports
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:collection/collection.dart';
import 'package:pub_semver/pub_semver.dart';

import '../analyzer.dart';
import '../extensions.dart';

const _desc = 'Unreachable top-level members in executable libraries.';

class UnreachableFromMain extends LintRule {
  UnreachableFromMain()
    : super(
        name: LintNames.unreachable_from_main,
        description: _desc,
        state: State.stable(since: Version(3, 1, 0)),
      );

  @override
  LintCode get lintCode => LinterLintCode.unreachable_from_main;

  @override
  void registerNodeProcessors(
    NodeLintRegistry registry,
    LinterContext context,
  ) {
    var visitor = _Visitor(this, context);
    registry.addCompilationUnit(this, visitor);
  }
}

/// This gathers all declarations which we may wish to report on.
class _DeclarationGatherer {
  final LinterContext linterContext;

  /// All declarations which we may wish to report on.
  final Set<Declaration> declarations = {};

  _DeclarationGatherer({required this.linterContext});

  void addDeclarations(CompilationUnit node) {
    for (var declaration in node.declarations) {
      if (declaration is TopLevelVariableDeclaration) {
        declarations.addAll(declaration.variables.variables);
      } else {
        declarations.add(declaration);
        var declaredElement = declaration.declaredFragment?.element;
        if (declaredElement == null || declaredElement.isPrivate) {
          continue;
        }
        if (declaration is ClassDeclaration) {
          _addMembers(
            containerElement: declaration.declaredFragment?.element,
            members: declaration.members,
          );
        } else if (declaration is EnumDeclaration) {
          _addMembers(
            containerElement: declaration.declaredFragment?.element,
            members: declaration.members,
          );
        } else if (declaration is ExtensionDeclaration) {
          _addMembers(containerElement: null, members: declaration.members);
        } else if (declaration is ExtensionTypeDeclaration) {
          _addMembers(containerElement: null, members: declaration.members);
        } else if (declaration is MixinDeclaration) {
          _addMembers(
            containerElement: declaration.declaredFragment?.element,
            members: declaration.members,
          );
        }
      }
    }
  }

  void _addMembers({
    required Element2? containerElement,
    required List<ClassMember> members,
  }) {
    bool isOverride(ExecutableElement2? element) {
      if (containerElement is! InterfaceElement2) {
        return false;
      }

      if (element == null) {
        return false;
      }

      var nameObj = Name.forElement(element);
      if (nameObj == null) {
        return false;
      }

      var inheritance = linterContext.inheritanceManager;
      return inheritance.getOverridden(containerElement, nameObj) != null;
    }

    for (var member in members) {
      switch (member) {
        case ConstructorDeclaration():
          var e = member.declaredFragment?.element;
          if (e != null && e.isPublic && member.parent is! EnumDeclaration) {
            declarations.add(member);
          }
        case FieldDeclaration():
          for (var field in member.fields.variables) {
            var element = field.declaredFragment?.element;
            if (element is FieldElement2 && element.isPublic) {
              if (!isOverride(element.getter2)) {
                declarations.add(field);
              }
            }
          }
        case MethodDeclaration():
          var element = member.declaredFragment?.element;
          if (element != null && element.isPublic) {
            var rawName = member.name.lexeme;
            var isTestMethod =
                rawName.startsWith('test_') ||
                rawName.startsWith('solo_test_') ||
                rawName == 'setUp' ||
                rawName == 'tearDown';
            if (!isOverride(element) && !isTestMethod) {
              declarations.add(member);
            }
          }
      }
    }
  }
}

/// A visitor which gathers the declarations of the "references" it visits.
///
/// "References" are most often [SimpleIdentifier]s, but can also be other
/// nodes which refer to a declaration.
class _ReferenceVisitor extends RecursiveAstVisitor<void> {
  Map<Element2, Declaration> declarationMap;

  Set<Declaration> declarations = {};

  /// References from patterns should not be counted.
  int _patternLevel = 0;

  _ReferenceVisitor(this.declarationMap);

  @override
  void visitAnnotation(Annotation node) {
    var e = node.element2;
    if (e != null) {
      _addDeclaration(e);
    }
    super.visitAnnotation(node);
  }

  @override
  void visitAssignmentExpression(AssignmentExpression node) {
    _visitCompoundAssignmentExpression(node);
    super.visitAssignmentExpression(node);
  }

  @override
  void visitClassDeclaration(ClassDeclaration node) {
    _addNamedType(node.extendsClause?.superclass);
    _addNamedTypes(node.withClause?.mixinTypes);
    _addNamedTypes(node.implementsClause?.interfaces);

    var element = node.declaredFragment?.element;

    if (element != null) {
      var hasConstructors = node.members.any(
        (e) => e is ConstructorDeclaration,
      );
      if (!hasConstructors) {
        // The default constructor will have an implicit super-initializer to
        // the super-type's unnamed constructor.
        _addDefaultSuperConstructorDeclaration(node);
      }

      var metadata = element.metadata2;
      // This for-loop style is copied from analyzer's `hasX` getters on
      // [Element].
      for (var i = 0; i < metadata.annotations.length; i++) {
        if (metadata.annotations[i].isReflectiveTest) {
          // The class is instantiated through the use of mirrors in
          // 'test_reflective_loader'.
          var unnamedConstructor = element.constructors2.firstWhereOrNull(
            (constructor) => constructor.name3 == 'new',
          );
          if (unnamedConstructor != null) {
            _addDeclaration(unnamedConstructor);
          }
        }
      }
    }
    super.visitClassDeclaration(node);
  }

  @override
  visitConstantPattern(ConstantPattern node) {
    _patternLevel++;
    try {
      return super.visitConstantPattern(node);
    } finally {
      _patternLevel--;
    }
  }

  @override
  void visitConstructorDeclaration(ConstructorDeclaration node) {
    // If a constructor in a class declaration does not have an explicit
    // super-initializer (or redirection?) then it has an implicit
    // super-initializer to the super-type's unnamed constructor.
    var hasSuperInitializer = node.initializers.any(
      (e) => e is SuperConstructorInvocation,
    );
    if (!hasSuperInitializer) {
      var enclosingClass = node.parent;
      if (enclosingClass is ClassDeclaration) {
        _addDefaultSuperConstructorDeclaration(enclosingClass);
      }
    }
    super.visitConstructorDeclaration(node);
  }

  @override
  void visitConstructorName(ConstructorName node) {
    var e = node.element;
    if (e != null && _patternLevel == 0) {
      _addDeclaration(e);
      var type = node.type.element2;
      if (type != null) {
        _addDeclaration(type);
      }
    }
    super.visitConstructorName(node);
  }

  @override
  void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) {
    _addNamedTypes(node.implementsClause?.interfaces);

    super.visitExtensionTypeDeclaration(node);
  }

  @override
  void visitMethodDeclaration(MethodDeclaration node) {
    if (node.name.lexeme == 'toJson' && !node.isStatic) {
      // The 'dart:convert' library uses dynamic invocation to call `toJson` on
      // arbitrary objects. Any declaration of `toJson` is automatically
      // reachable.
      var element = node.declaredFragment?.element;
      if (element != null) {
        _addDeclaration(element);
      }
    }
    super.visitMethodDeclaration(node);
  }

  @override
  void visitNamedType(NamedType node) {
    var element = node.element2;
    if (element == null) {
      return;
    }

    var nodeIsInTypeArgument =
        node.thisOrAncestorOfType<TypeArgumentList>() != null;

    if (
    // Any reference to a typedef marks it as reachable, since structural
    // typing is used to match against objects.
    node.type?.alias != null ||
        // Any reference to an extension type marks it as reachable, since
        // casting can be used to instantiate the type.
        node.type?.element3 is ExtensionTypeElement2 ||
        nodeIsInTypeArgument ||
        // A reference to any type in an external variable declaration marks
        // that type as reachable, since the external implementation can
        // instantiate it.
        node.isInExternalVariableTypeOrFunctionReturnType) {
      _addDeclaration(element);
    }

    // Intentionally do not add the declaration of non-alias named types, as a
    // reference to such a type in a [TypeAnnotation] is not good enough to
    // count as "reachable". Marking a type as reachable only because it was
    // seen in a type annotation would be a miscategorization if the type is
    // never instantiated or subtyped.

    var typeArguments = node.typeArguments;
    if (typeArguments != null) {
      for (var typeArgument in typeArguments.arguments) {
        typeArgument.accept(this);
      }
    }
  }

  @override
  void visitPatternField(PatternField node) {
    var e = node.element2;
    if (e != null) {
      _addDeclaration(e);
    }
    super.visitPatternField(node);
  }

  @override
  void visitPostfixExpression(PostfixExpression node) {
    _visitCompoundAssignmentExpression(node);
    super.visitPostfixExpression(node);
  }

  @override
  void visitPrefixExpression(PrefixExpression node) {
    _visitCompoundAssignmentExpression(node);
    super.visitPrefixExpression(node);
  }

  @override
  void visitRedirectingConstructorInvocation(
    RedirectingConstructorInvocation node,
  ) {
    var element = node.element;
    if (element != null) {
      _addDeclaration(element);
    }
    super.visitRedirectingConstructorInvocation(node);
  }

  @override
  void visitSimpleIdentifier(SimpleIdentifier node) {
    if (!node.inDeclarationContext()) {
      var e = node.element;
      if (e != null) {
        _addDeclaration(e);
      }
    }
    super.visitSimpleIdentifier(node);
  }

  @override
  void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
    var e = node.element;
    if (e != null) {
      _addDeclaration(e);
    }
    super.visitSuperConstructorInvocation(node);
  }

  @override
  void visitVariableDeclaration(VariableDeclaration node) {
    var parent = node.parent;
    if (parent is VariableDeclarationList) {
      var type = parent.type;
      if (type != null) {
        type.accept(this);
      }
    }
    super.visitVariableDeclaration(node);
  }

  /// Adds the declaration of the top-level element which contains [element] to
  /// [declarations], if it is found in [declarationMap].
  ///
  /// Also adds the declaration of [element] if it is a public static accessor
  /// or static method on a public top-level element.
  void _addDeclaration(Element2 element) {
    // First add the enclosing top-level declaration.
    var enclosingTopLevelElement = element.thisOrAncestorMatching2(
      (a) =>
          a.enclosingElement2 == null || a.enclosingElement2 is LibraryElement2,
    );
    var enclosingTopLevelDeclaration = declarationMap[enclosingTopLevelElement];
    if (enclosingTopLevelDeclaration != null) {
      declarations.add(enclosingTopLevelDeclaration);
    }

    // Also add [element]'s declaration if it is a constructor, static accessor,
    // or static method.
    if (element.isPrivate) {
      return;
    }
    var enclosingElement = element.enclosingElement2;
    if (enclosingElement == null || enclosingElement.isPrivate) {
      return;
    }
    if (enclosingElement is InterfaceElement2 ||
        enclosingElement is ExtensionElement2 ||
        enclosingElement is ExtensionTypeElement2) {
      var declarationElement = element.baseElement;
      var declaration = declarationMap[declarationElement];
      if (declaration != null) {
        declarations.add(declaration);
      }
    }
  }

  void _addDefaultSuperConstructorDeclaration(ClassDeclaration class_) {
    var classElement = class_.declaredFragment?.element;
    var supertype = classElement?.supertype;
    if (supertype != null) {
      var unnamedConstructor = supertype.constructors2.firstWhereOrNull(
        (e) => e.name3 == 'new',
      );
      if (unnamedConstructor != null) {
        _addDeclaration(unnamedConstructor);
      }
    }
  }

  void _addNamedType(NamedType? node) {
    if (node == null) {
      return;
    }

    var element = node.element2;
    if (element == null) {
      return;
    }

    var declaration = declarationMap[element];
    if (declaration == null) {
      return;
    }

    declarations.add(declaration);
  }

  void _addNamedTypes(List<NamedType>? nodes) {
    nodes?.forEach(_addNamedType);
  }

  void _visitCompoundAssignmentExpression(CompoundAssignmentExpression node) {
    var readElement = node.readElement2;
    if (readElement != null) {
      _addDeclaration(readElement);
    }
    var writeElement = node.writeElement2;
    if (writeElement != null) {
      _addDeclaration(writeElement);
    }
  }
}

class _Visitor extends SimpleAstVisitor<void> {
  final LintRule rule;
  final LinterContext context;

  _Visitor(this.rule, this.context);

  @override
  void visitCompilationUnit(CompilationUnit node) {
    var declarationGatherer = _DeclarationGatherer(linterContext: context);
    for (var unit in context.allUnits) {
      declarationGatherer.addDeclarations(unit.unit);
    }
    var declarations = declarationGatherer.declarations;
    var entryPoints = declarations.where(_isEntryPoint);
    if (entryPoints.isEmpty) return;

    // Map each top-level and static element to its declaration.
    var declarationByElement = <Element2, Declaration>{};
    for (var declaration in declarations) {
      var element = declaration.declaredFragment?.element;
      if (element != null) {
        declarationByElement[element] = declaration;
        if (element is TopLevelVariableElement2) {
          var getter = element.getter2;
          if (getter != null) declarationByElement[getter] = declaration;
          var setter = element.setter2;
          if (setter != null) declarationByElement[setter] = declaration;
        } else if (element is FieldElement2) {
          var getter = element.getter2;
          if (getter != null) declarationByElement[getter] = declaration;
          var setter = element.setter2;
          if (setter != null) declarationByElement[setter] = declaration;
        }
      }
    }

    // The set of the declarations which each top-level and static declaration
    // references.
    var dependencies = <Declaration, Set<Declaration>>{};

    // Map each declaration to the collection of declarations which are
    // referenced within its body.
    for (var declaration in declarations) {
      var visitor = _ReferenceVisitor(declarationByElement);
      declaration.accept(visitor);
      dependencies[declaration] = visitor.declarations;
    }

    var usedMembers = entryPoints.toSet();
    var declarationsToCheck = Queue.of(usedMembers);

    // Loop through declarations which are reachable from the set of
    // entry-points. We mark each such declaration as "used", and add its
    // dependencies to the queue to loop through. Once the queue is empty,
    // `usedMembers` contains every declaration reachable from an entry-point.
    while (declarationsToCheck.isNotEmpty) {
      var declaration = declarationsToCheck.removeLast();
      for (var dep in dependencies[declaration]!) {
        if (usedMembers.add(dep)) {
          declarationsToCheck.add(dep);
        }
      }
    }

    var unitDeclarationGatherer = _DeclarationGatherer(linterContext: context);
    unitDeclarationGatherer.addDeclarations(node);
    var unitDeclarations = unitDeclarationGatherer.declarations;
    var unusedDeclarations = unitDeclarations.difference(usedMembers);
    var unusedMembers =
        unusedDeclarations.where((declaration) {
          var element = declaration.declaredFragment?.element;
          return element != null &&
              element.isPublic &&
              !element.hasVisibleForTesting &&
              !element.hasWidgetPreview;
        }).toList();

    for (var member in unusedMembers) {
      if (member is ConstructorDeclaration) {
        if (member.name == null) {
          rule.reportLint(member.returnType, arguments: [member.nameForError]);
        } else {
          rule.reportLintForToken(
            member.name,
            arguments: [member.nameForError],
          );
        }
      } else if (member is NamedCompilationUnitMember) {
        rule.reportLintForToken(member.name, arguments: [member.nameForError]);
      } else if (member is MethodDeclaration) {
        rule.reportLintForToken(member.name, arguments: [member.name.lexeme]);
      } else if (member is VariableDeclaration) {
        rule.reportLintForToken(member.name, arguments: [member.nameForError]);
      } else if (member is ExtensionDeclaration) {
        var name = member.name;
        rule.reportLintForToken(
          name ?? member.extensionKeyword,
          arguments: [name?.lexeme ?? '<unnamed>'],
        );
      } else {
        throw UnimplementedError('(${member.runtimeType}) $member');
      }
    }
  }

  bool _isEntryPoint(Declaration e) =>
      e is FunctionDeclaration &&
      (e.name.lexeme == 'main' || e.metadata.any(_isExemptingAnnotation));

  bool _isExemptingAnnotation(Annotation annotation) {
    if (annotation.isPragma) {
      return _isValidVmEntryPoint(annotation);
    } else if (annotation.isWidgetPreview) {
      return true;
    }
    return false;
  }

  bool _isValidVmEntryPoint(Annotation annotation) {
    var value = annotation.elementAnnotation?.computeConstantValue();
    if (value == null) return false;
    var name = value.getField('name');
    return name != null &&
        name.hasKnownValue &&
        name.toStringValue() == 'vm:entry-point';
  }
}

extension on Metadata {
  bool get hasWidgetPreview {
    var annotations = this.annotations;
    for (var i = 0; i < annotations.length; i++) {
      var annotation = annotations[i];
      if (annotation.isWidgetPreview) {
        return true;
      }
    }
    return false;
  }
}

extension on ElementAnnotation {
  /// The URI of the Flutter widget previews library.
  static final Uri _flutterWidgetPreviewLibraryUri = Uri.parse(
    'package:flutter/src/widget_previews/widget_previews.dart',
  );

  bool get isWidgetPreview {
    var element2 = this.element2;
    return element2 is ConstructorElement2 &&
        element2.enclosingElement2.name3 == 'Preview' &&
        element2.library2.uri == _flutterWidgetPreviewLibraryUri;
  }
}

extension on LibraryElement2 {
  bool get isWidgetPreviews =>
      uri ==
      Uri.parse('package:flutter/src/widget_previews/widget_previews.dart');
}

extension on Element2 {
  bool get hasVisibleForTesting => switch (this) {
    Annotatable(:var metadata2) => metadata2.hasVisibleForTesting,
    _ => false,
  };
  bool get hasWidgetPreview => switch (this) {
    Annotatable(:var metadata2) =>
      // Widget previews can be applied to public:
      //   - Constructors (generative and factory)
      //   - Top-level functions
      //   - Static member functions
      (this is ConstructorElement2 ||
              this is TopLevelFunctionElement ||
              (this is ExecutableElement2 &&
                  (this as ExecutableElement2).isStatic)) &&
          !isPrivate &&
          metadata2.hasWidgetPreview,
    _ => false,
  };
  bool get isPragma => (library2?.isDartCore ?? false) && name3 == 'pragma';
  bool get isWidgetPreview =>
      (library2?.isWidgetPreviews ?? false) && name3 == 'Preview';
}

extension on Annotation {
  bool get isPragma {
    DartType? type = _elementType;
    if (type == null) {
      // Dunno what this is.
      return false;
    }
    return type is InterfaceType && type.element3.isPragma;
  }

  bool get isWidgetPreview {
    DartType? type = _elementType;
    if (type == null) {
      // Dunno what this is.
      return false;
    }
    return type is InterfaceType && type.element3.isWidgetPreview;
  }

  DartType? get _elementType {
    var element = elementAnnotation?.element2;
    DartType? type;
    if (element is ConstructorElement2) {
      type = element.returnType;
    } else if (element is GetterElement) {
      type = element.returnType;
    }
    return type;
  }
}

extension on Declaration {
  String get nameForError {
    // TODO(srawlins): Move this to analyzer when other uses are found.
    var self = this;
    if (self is ConstructorDeclaration) {
      var name = self.name?.lexeme ?? 'new';
      return '${self.returnType.name}.$name';
    } else if (self is EnumConstantDeclaration) {
      return self.name.lexeme;
    } else if (self is ExtensionDeclaration) {
      var name = self.name;
      return name?.lexeme ?? 'the unnamed extension';
    } else if (self is MethodDeclaration) {
      return self.name.lexeme;
    } else if (self is NamedCompilationUnitMember) {
      return self.name.lexeme;
    } else if (self is VariableDeclaration) {
      return self.name.lexeme;
    }

    assert(false, 'Uncovered Declaration subtype: ${self.runtimeType}');
    return '';
  }
}

extension on NamedType {
  bool get isInExternalVariableTypeOrFunctionReturnType {
    var topTypeAnnotation = topmostTypeAnnotation;

    switch (topTypeAnnotation.parent) {
      case MethodDeclaration(:var externalKeyword, :var returnType):
        return externalKeyword != null && returnType == topTypeAnnotation;
      case VariableDeclarationList(
        parent: FieldDeclaration(:var externalKeyword),
      ):
      case VariableDeclarationList(
        parent: TopLevelVariableDeclaration(:var externalKeyword),
      ):
        return externalKeyword != null;
    }
    return false;
  }

  TypeAnnotation get topmostTypeAnnotation {
    TypeAnnotation topTypeAnnotation = this;
    var parent = this.parent;
    while (parent is TypeAnnotation) {
      topTypeAnnotation = parent;
      parent = topTypeAnnotation.parent;
    }
    return topTypeAnnotation;
  }
}
