// Copyright (c) 2016, 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/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart'
    show DartType, InterfaceType, FunctionType;
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart'
    show DartObject, DartObjectImpl;
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/type_system.dart' show Dart2TypeSystem;

class Tuple2<T0, T1> {
  final T0 e0;
  final T1 e1;
  Tuple2(this.e0, this.e1);
}

/// Instantiates [t] with dynamic bounds.
///
/// Note: this should only be used when the resulting type is later replaced,
/// such as a "deferred supertype" (used to break circularity between the
/// supertype's type arguments and the class definition). Otherwise
/// [instantiateElementTypeToBounds] should be used instead.
InterfaceType fillDynamicTypeArgsForClass(InterfaceType t) {
  if (t.typeArguments.isNotEmpty) {
    var rawT = t.element.type;
    var dyn = List.filled(rawT.typeArguments.length, DynamicTypeImpl.instance);
    return rawT.substitute2(dyn, rawT.typeArguments);
  }
  return t;
}

/// Instantiates the [element] type to bounds.
///
/// Conceptually this is similar to [Dart2TypeSystem.instantiateToBounds] on
/// `element.type`, but unfortunately typedef elements do not return a
/// meaningful type, so we need to work around that.
DartType instantiateElementTypeToBounds(
    Dart2TypeSystem rules, TypeDefiningElement element) {
  Element e = element;
  if (e is TypeParameterizedElement) {
    // TODO(jmesserly): we can't use `instantiateToBounds` because typedefs do
    // not include their type parameters, for example:
    //
    //     typedef void void Func<T>(T x);               // Dart 1 syntax.
    //     typedef void GenericFunc<T> = S Func<S>(T x); // Dart 2 syntax.
    //
    // There is no way to get a type that has `<T>` as a type formal from the
    // element (without constructing it ourselves).
    //
    // Futhermore, the second line is represented by a GenericTypeAliasElement,
    // and its type getter does not even include its own type formals `<S>`.
    // That has to be worked around using `.function.type`.
    var type = e is GenericTypeAliasElement ? e.function.type : e.type;
    var bounds = rules.instantiateTypeFormalsToBounds(e.typeParameters);
    if (bounds == null) return type;
    return type.substitute2(
        bounds, TypeParameterTypeImpl.getTypes(e.typeParameters));
  }
  return element.type;
}

/// Given an annotated [node] and a [test] function, returns the first matching
/// constant valued annotation.
///
/// For example if we had the ClassDeclaration node for `FontElement`:
///
///    @js.JS('HTMLFontElement')
///    @deprecated
///    class FontElement { ... }
///
/// We could match `@deprecated` with a test function like:
///
///    (v) => v.type.name == 'Deprecated' && v.type.element.library.isDartCore
///
DartObject findAnnotation(Element element, bool test(DartObjectImpl value)) {
  if (element == null) return null;
  for (var metadata in element.metadata) {
    var value = metadata.computeConstantValue();
    if (value is DartObjectImpl && test(value)) return value;
  }
  return null;
}

/// Searches all supertype, in order of most derived members, to see if any
/// [match] a condition. If so, returns the first match, otherwise returns null.
InterfaceType findSupertype(InterfaceType type, bool match(InterfaceType t)) {
  for (var m in type.mixins.reversed) {
    if (match(m)) return m;
  }
  var s = type.superclass;
  if (s == null) return null;

  if (match(s)) return type;
  return findSupertype(s, match);
}

//TODO(leafp): Is this really necessary?  In theory I think
// the static type should always be filled in for resolved
// ASTs.  This may be a vestigial workaround.
DartType getStaticType(Expression e) =>
    e.staticType ?? DynamicTypeImpl.instance;

// TODO(leafp) Factor this out or use an existing library
/// Similar to [SimpleIdentifier] inGetterContext, inSetterContext, and
/// inDeclarationContext, this method returns true if [node] is used in an
/// invocation context such as a MethodInvocation.
bool inInvocationContext(Expression node) {
  if (node == null) return false;
  var parent = node.parent;
  while (parent is ParenthesizedExpression) {
    node = parent;
    parent = node.parent;
  }
  return parent is InvocationExpression && identical(node, parent.function) ||
      parent is MethodInvocation &&
          parent.methodName.name == 'call' &&
          identical(node, parent.target);
}

bool isInlineJS(Element e) {
  if (e != null && e.name == 'JS' && e is FunctionElement) {
    var uri = e.librarySource.uri;
    return uri.scheme == 'dart' && uri.path == '_foreign_helper';
  }
  return false;
}

bool isLibraryPrefix(Expression node) =>
    node is SimpleIdentifier && node.staticElement is PrefixElement;

ExecutableElement getFunctionBodyElement(FunctionBody body) {
  var f = body.parent;
  if (f is FunctionExpression) {
    return f.declaredElement;
  } else if (f is MethodDeclaration) {
    return f.declaredElement;
  } else {
    return (f as ConstructorDeclaration).declaredElement;
  }
}

/// Returns the value of the `name` field from the [match]ing annotation on
/// [element], or `null` if we didn't find a valid match or it was not a string.
///
/// For example, consider this code:
///
///     class MyAnnotation {
///       final String name;
///       // ...
///       const MyAnnotation(this.name/*, ... other params ... */);
///     }
///
///     @MyAnnotation('FooBar')
///     main() { ... }
///
/// If we match the annotation for the `@MyAnnotation('FooBar')` this will
/// return the string 'FooBar'.
String getAnnotationName(Element element, bool match(DartObjectImpl value)) =>
    findAnnotation(element, match)?.getField('name')?.toStringValue();

List<ClassElement> getSuperclasses(ClassElement cls) {
  var result = <ClassElement>[];
  var visited = HashSet<ClassElement>();
  while (cls != null && visited.add(cls)) {
    for (var mixinType in cls.mixins.reversed) {
      var mixin = mixinType.element;
      if (mixin != null) result.add(mixin);
    }
    var supertype = cls.supertype;
    // Object or mixin declaration.
    if (supertype == null) break;

    cls = supertype.element;
    result.add(cls);
  }
  return result;
}

List<ClassElement> getImmediateSuperclasses(ClassElement c) {
  var result = <ClassElement>[];
  for (var m in c.mixins.reversed) {
    result.add(m.element);
  }
  var s = c.supertype;
  if (s != null) result.add(s.element);
  return result;
}

/// Returns true if the library [l] is dart:_runtime.
// TODO(jmesserly): unlike other methods in this file, this one wouldn't be
// suitable for upstream to Analyzer, as it's DDC specific.
bool isSdkInternalRuntime(LibraryElement l) {
  var uri = l.source.uri;
  return uri.scheme == 'dart' && uri.path == '_runtime';
}

/// Return `true` if the given [classElement] has a noSuchMethod() method
/// distinct from the one declared in class Object, as per the Dart Language
/// Specification (section 10.4).
// TODO(jmesserly): this was taken from error_verifier.dart
bool hasNoSuchMethod(ClassElement classElement) {
  // TODO(jmesserly): this is slow in Analyzer. It's a linear scan through all
  // methods, up through the class hierarchy.
  var method = classElement.lookUpMethod(
      FunctionElement.NO_SUCH_METHOD_METHOD_NAME, classElement.library);
  var definingClass = method?.enclosingElement;
  return definingClass != null && !definingClass.type.isObject;
}

/// Returns true if this class is of the form:
/// `class C = Object with M [implements I1, I2 ...];`
///
/// A mixin alias class is a mixin application, that can also be itself used as
/// a mixin.
bool isMixinAliasClass(ClassElement c) {
  return c.isMixinApplication && c.supertype.isObject && c.mixins.length == 1;
}

bool isCallableClass(ClassElement c) {
  // See if we have a "call" with a statically known function type:
  //
  // - if it's a method, then it does because all methods do,
  // - if it's a getter, check the return type.
  //
  // Other cases like a getter returning dynamic/Object/Function will be
  // handled at runtime by the dynamic call mechanism. So we only
  // concern ourselves with statically known function types.
  //
  // We can ignore `noSuchMethod` because:
  // * `dynamic d; d();` without a declared `call` method is handled by dcall.
  // * for `class C implements Callable { noSuchMethod(i) { ... } }` we find
  //   the `call` method on the `Callable` interface.
  var callMethod = c.type.lookUpInheritedGetterOrMethod('call');
  return callMethod is PropertyAccessorElement
      ? callMethod.returnType is FunctionType
      : callMethod != null;
}

/// Returns true if [x] and [y] are equal, in other words, `x <: y` and `y <: x`
/// and they have equivalent display form when printed.
//
// TODO(jmesserly): this exists to work around broken FunctionTypeImpl.== in
// Analyzer. It has two bugs:
// - typeArguments are considered, even though this has no semantic effect.
//   For example: `int -> int` that resulted from `(<T>(T) -> T)<int>` will not
//   equal another `int -> int`, even though they are the same type.
// - named arguments are incorrectly treated as ordered, see
//   https://github.com/dart-lang/sdk/issues/26126.
bool typesAreEqual(DartType x, DartType y) {
  if (identical(x, y)) return true;
  if (x is FunctionType) {
    if (y is FunctionType) {
      if (x.typeFormals.length != y.typeFormals.length) {
        return false;
      }
      // `<T>T -> T` should be equal to `<U>U -> U`
      // To test this, we instantiate both types with the same (unique) type
      // variables, and see if the result is equal.
      if (x.typeFormals.isNotEmpty) {
        var fresh = FunctionTypeImpl.relateTypeFormals(
            x, y, (t, s, _, __) => typesAreEqual(t, s));
        if (fresh == null) {
          return false;
        }
        return typesAreEqual(x.instantiate(fresh), y.instantiate(fresh));
      }

      return typesAreEqual(x.returnType, y.returnType) &&
          _argumentsAreEqual(x.normalParameterTypes, y.normalParameterTypes) &&
          _argumentsAreEqual(
              x.optionalParameterTypes, y.optionalParameterTypes) &&
          _namedArgumentsAreEqual(x.namedParameterTypes, y.namedParameterTypes);
    } else {
      return false;
    }
  }
  if (x is InterfaceType) {
    return y is InterfaceType &&
        x.element == y.element &&
        _argumentsAreEqual(x.typeArguments, y.typeArguments);
  }
  return x == y;
}

bool _argumentsAreEqual(List<DartType> first, List<DartType> second) {
  if (first.length != second.length) return false;
  for (int i = 0; i < first.length; i++) {
    if (!typesAreEqual(first[i], second[i])) return false;
  }
  return true;
}

bool _namedArgumentsAreEqual(
    Map<String, DartType> xArgs, Map<String, DartType> yArgs) {
  if (yArgs.length != xArgs.length) return false;
  for (var name in xArgs.keys) {
    var x = xArgs[name];
    var y = yArgs[name];
    if (y == null || !typesAreEqual(x, y)) return false;
  }
  return true;
}

/// Returns a valid hashCode for [t] for use with [typesAreEqual].
int typeHashCode(DartType t) {
  // TODO(jmesserly): this is from Analyzer; it's not a great hash function.
  // We should at least fix how this combines hashes.
  if (t is FunctionType) {
    if (t.typeFormals.isNotEmpty) {
      // Instantiate the generic function type, so we hash equivalent
      // generic function types to the same value. For example, `<X>(X) -> X`
      // and `<Y>(Y) -> Y` shouold have the same hash.
      //
      // TODO(jmesserly): it would be better to instantiate these with unique
      // types for each position, so we can distinguish cases like these:
      //
      //     <A, B>(A) -> B
      //     <C, D>(D) -> C      // reversed
      //     <E, F>(E) -> void   // uses `void`
      //
      // Currently all of those will have the same hash code.
      //
      // The choice of `void` is rather arbitrary. Of the types we can easily
      // obtain from Analyzer, it should collide a bit less than something like
      // `dynamic`.
      int code = t.typeFormals.length;
      code = (code << 1) +
          typeHashCode(t.instantiate(
              List.filled(t.typeFormals.length, VoidTypeImpl.instance)));
      return code;
    }
    int code = typeHashCode(t.returnType);
    for (var p in t.normalParameterTypes) {
      code = (code << 1) + typeHashCode(p);
    }
    for (var p in t.optionalParameterTypes) {
      code = (code << 1) + typeHashCode(p);
    }
    for (var p in t.namedParameterTypes.values) {
      code ^= typeHashCode(p); // xor because named parameters are unordered.
    }
    return code;
  }
  return t.hashCode;
}

Uri uriForCompilationUnit(CompilationUnitElement unit) {
  if (unit.source.isInSystemLibrary) {
    return unit.source.uri;
  }
  // TODO(jmesserly): this needs serious cleanup.
  // There does appear to be something strange going on with Analyzer
  // URIs if we try and use them directly on Windows.
  // See also compiler.dart placeSourceMap, which could use cleanup too.
  var sourcePath = unit.source.fullName;
  return sourcePath.startsWith('package:')
      ? Uri.parse(sourcePath)
      // TODO(jmesserly): shouldn't this be path.toUri?
      : Uri.file(sourcePath);
}

/// Returns true iff this factory constructor just throws [UnsupportedError]/
///
/// `dart:html` has many of these.
bool isUnsupportedFactoryConstructor(ConstructorDeclaration node) {
  var ctorBody = node.body;
  var element = node.declaredElement;
  if (element.isPrivate &&
      element.librarySource.isInSystemLibrary &&
      ctorBody is BlockFunctionBody) {
    var statements = ctorBody.block.statements;
    if (statements.length == 1) {
      var statement = statements[0];
      if (statement is ExpressionStatement) {
        var expr = statement.expression;
        if (expr is ThrowExpression &&
            expr.expression is InstanceCreationExpression) {
          if (expr.expression.staticType.name == 'UnsupportedError') {
            // HTML adds a lot of private constructors that are unreachable.
            // Skip these.
            return true;
          }
        }
      }
    }
  }
  return false;
}

bool isBuiltinAnnotation(
    DartObjectImpl value, String libraryName, String annotationName) {
  var e = value?.type?.element;
  if (e?.name != annotationName) return false;
  var uri = e.source.uri;
  var path = uri.pathSegments[0];
  return uri.scheme == 'dart' && path == libraryName;
}

/// Returns the integer value for [node] as a [BigInt].
///
/// `node.value` should not be used directly as it depends on platform integers
/// and may be `null` for some valid integer literals (in either an `int` or a
/// `double` context)
BigInt getLiteralBigIntValue(IntegerLiteral node) {
  // TODO(jmesserly): workaround for #34360: Analyzer tree does not store
  // the BigInt or double value, so we need to re-parse it from the token.
  return BigInt.parse(node.literal.lexeme);
}
