// Copyright (c) 2015, 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/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
import 'package:analyzer/dart/ast/visitor.dart' show RecursiveAstVisitor;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'element_helpers.dart' show getStaticType, isInlineJS, findAnnotation;
import 'js_interop.dart' show isNotNullAnnotation, isNullCheckAnnotation;
import 'js_typerep.dart';
import 'property_model.dart';

/// An inference engine for nullable types.
///
/// This can answer questions about whether expressions are nullable
/// (see [isNullable]). Given a set of compilation units in a library, it will
/// determine if locals can be null using flow-insensitive analysis.
///
/// The analysis for null expressions is conservative and incomplete, but it can
/// optimize some patterns.
// TODO(vsm): Revisit whether we really need this when we get
// better non-nullability in the type system.
abstract class NullableTypeInference {
  LibraryElement get coreLibrary;
  VirtualFieldModel get virtualFields;

  JSTypeRep get jsTypeRep;
  bool isObjectMember(String name);

  /// Known non-null local variables.
  HashSet<LocalVariableElement> _notNullLocals;

  void inferNullableTypes(AstNode node) {
    var visitor = _NullableLocalInference(this);
    node.accept(visitor);
    _notNullLocals = visitor.computeNotNullLocals();
  }

  /// Adds a new variable, typically a compiler generated temporary, and record
  /// whether its type is nullable.
  void addTemporaryVariable(LocalVariableElement local,
      {bool nullable = true}) {
    if (!nullable) _notNullLocals.add(local);
  }

  /// Returns true if [expr] can be null.
  bool isNullable(Expression expr) => _isNullable(expr);

  bool _isNonNullMethodInvocation(MethodInvocation expr) {
    // TODO(vsm): This logic overlaps with the resolver.
    // Where is the best place to put this?
    var e = resolutionMap.staticElementForIdentifier(expr.methodName);
    if (e == null) return false;
    if (isInlineJS(e)) {
      // Fix types for JS builtin calls.
      //
      // This code was taken from analyzer. It's not super sophisticated:
      // only looks for the type name in dart:core, so we just copy it here.
      //
      // TODO(jmesserly): we'll likely need something that can handle a wider
      // variety of types, especially when we get to JS interop.
      var args = expr.argumentList.arguments;
      var first = args.isNotEmpty ? args.first : null;
      if (first is SimpleStringLiteral) {
        var types = first.stringValue;
        if (types != '' &&
            types != 'var' &&
            !types.split('|').contains('Null')) {
          return true;
        }
      }
    }

    if (e.name == 'identical' && identical(e.library, coreLibrary)) {
      return true;
    }
    // If this is a method call, check to see whether it is to a final
    // type for which we have a known implementation type (i.e. int, bool,
    // double, and String), and if so use the element for the implementation
    // type instead.
    if (e is MethodElement) {
      Element container = e.enclosingElement;
      if (container is ClassElement) {
        DartType targetType = container.type;
        InterfaceType implType = jsTypeRep.getImplementationType(targetType);
        if (implType != null) {
          MethodElement method = implType.lookUpMethod(e.name, coreLibrary);
          if (method != null) e = method;
        }
      }
    }
    // If the method or function is annotated as returning a non-null value
    // then the result of the call is non-null.
    return (e is MethodElement || e is FunctionElement) && _assertedNotNull(e);
  }

  bool _isNonNullProperty(Element element, String name) {
    if (element is! PropertyInducingElement &&
        element is! PropertyAccessorElement) {
      return false;
    }
    // If this is a reference to an element of a type for which
    // we have a known implementation type (i.e. int, double,
    // bool, String), then use the element for the implementation
    // type.
    Element container = element.enclosingElement;
    if (container is ClassElement) {
      var targetType = container.type;
      var implType = jsTypeRep.getImplementationType(targetType);
      if (implType != null) {
        var getter = implType.lookUpGetter(name, coreLibrary);
        if (getter != null) element = getter;
      }
    }
    // If the getter is a synthetic element, then any annotations will
    // be on the variable, so use those instead.
    if (element is PropertyAccessorElement && element.isSynthetic) {
      return _assertedNotNull(element.variable);
    }
    // Return true if the element is annotated as returning a non-null value.
    return _assertedNotNull(element);
  }

  /// Returns true if [expr] can be null, optionally using [localIsNullable]
  /// for locals.
  ///
  /// If [localIsNullable] is not supplied, this will use the known list of
  /// [_notNullLocals].
  bool _isNullable(Expression expr,
      [bool localIsNullable(LocalVariableElement e)]) {
    // TODO(jmesserly): we do recursive calls in a few places. This could
    // leads to O(depth) cost for calling this function. We could store the
    // resulting value if that becomes an issue, so we maintain the invariant
    // that each node is visited once.
    Element element = null;
    String name = null;
    if (expr is PropertyAccess &&
        expr.operator?.type != TokenType.QUESTION_PERIOD) {
      element = expr.propertyName.staticElement;
      name = expr.propertyName.name;
    } else if (expr is PrefixedIdentifier) {
      element = expr.staticElement;
      name = expr.identifier.name;
    } else if (expr is Identifier) {
      element = expr.staticElement;
      name = expr.name;
    }
    if (element != null) {
      if (_isNonNullProperty(element, name)) return false;

      // Type literals are not null.
      if (element is ClassElement || element is FunctionTypeAliasElement) {
        return false;
      }

      if (element is LocalVariableElement) {
        if (localIsNullable != null) {
          return localIsNullable(element);
        }
        return !_notNullLocals.contains(element);
      }

      if (element is ParameterElement && _assertedNotNull(element)) {
        return false;
      }

      if (element is FunctionElement || element is MethodElement) {
        // A function or method. This can't be null.
        return false;
      }

      if (element is PropertyAccessorElement && element.isGetter) {
        PropertyInducingElement variable = element.variable;
        if (variable is FieldElement && virtualFields.isVirtual(variable)) {
          return true;
        }
        var value = variable.computeConstantValue();
        return value == null || value.isNull || !value.hasKnownValue;
      }

      // Other types of identifiers are nullable (parameters, fields).
      return true;
    }

    if (expr is Literal) return expr is NullLiteral;
    if (expr is IsExpression) return false;
    if (expr is FunctionExpression) return false;
    if (expr is ThisExpression) return false;
    if (expr is SuperExpression) return false;
    if (expr is CascadeExpression) {
      // Cascades normally can't return `null`, because if the target is null,
      // they will throw noSuchMethod.
      // The only properties/methods on `null` are those on Object itself.
      for (var section in expr.cascadeSections) {
        Element e = null;
        if (section is PropertyAccess) {
          e = section.propertyName.staticElement;
        } else if (section is MethodInvocation) {
          e = section.methodName.staticElement;
        } else if (section is IndexExpression) {
          // Object does not have operator []=.
          return false;
        }
        // We encountered a non-Object method/property.
        if (e != null && !isObjectMember(e.name)) {
          return false;
        }
      }
      return _isNullable(expr.target, localIsNullable);
    }
    if (expr is ConditionalExpression) {
      return _isNullable(expr.thenExpression, localIsNullable) ||
          _isNullable(expr.elseExpression, localIsNullable);
    }
    if (expr is ParenthesizedExpression) {
      return _isNullable(expr.expression, localIsNullable);
    }
    if (expr is InstanceCreationExpression) {
      var e = resolutionMap.staticElementForConstructorReference(expr);
      if (e == null) return true;

      // Follow redirects.
      while (e.redirectedConstructor != null) {
        e = e.redirectedConstructor;
      }

      // Generative constructors are not nullable.
      if (!e.isFactory) return false;

      // Factory constructors are nullable. However it is a bad pattern and
      // our own SDK will never do this.
      // TODO(jmesserly): we could enforce this for user-defined constructors.
      if (e.library.source.isInSystemLibrary) return false;

      return true;
    }
    if (expr is MethodInvocation &&
        (expr.operator?.lexeme != '?.' ||
            !_isNullable(expr.target, localIsNullable)) &&
        _isNonNullMethodInvocation(expr)) {
      return false;
    }

    Expression operand, rightOperand;
    String op;
    if (expr is AssignmentExpression) {
      op = expr.operator.lexeme;
      assert(op.endsWith('='));
      if (op == '=') {
        return _isNullable(expr.rightHandSide, localIsNullable);
      }
      // op assignment like +=, remove trailing '='
      op = op.substring(0, op.length - 1);
      operand = expr.leftHandSide;
      rightOperand = expr.rightHandSide;
    } else if (expr is BinaryExpression) {
      operand = expr.leftOperand;
      rightOperand = expr.rightOperand;
      op = expr.operator.lexeme;
    } else if (expr is PrefixExpression) {
      operand = expr.operand;
      op = expr.operator.lexeme;
    } else if (expr is PostfixExpression) {
      operand = expr.operand;
      op = expr.operator.lexeme;
    }
    switch (op) {
      case '==':
      case '!=':
      case '&&':
      case '||':
      case '!':
        return false;
      case '??':
        return _isNullable(operand, localIsNullable) &&
            _isNullable(rightOperand, localIsNullable);
    }
    if (operand != null && jsTypeRep.isPrimitive(getStaticType(operand))) {
      return false;
    }

    // TODO(ochafik,jmesserly): handle other cases such as: refs to top-level
    // finals that have been assigned non-nullable values.

    // Failed to recognize a non-nullable case: assume it can be null.
    return true;
  }
}

/// A visitor that determines which local variables are non-nullable.
///
/// This will consider all assignments to local variables using
/// flow-insensitive inference. That information is used to determine which
/// variables are nullable in the given scope.
// TODO(ochafik): Introduce flow analysis (a variable may be nullable in
// some places and not in others).
class _NullableLocalInference extends RecursiveAstVisitor {
  final NullableTypeInference _nullInference;

  /// Known local variables.
  final _locals = HashSet<LocalVariableElement>.identity();

  /// Variables that are known to be nullable.
  final _nullableLocals = HashSet<LocalVariableElement>.identity();

  /// Given a variable, tracks all other variables that it is assigned to.
  final _assignments =
      HashMap<LocalVariableElement, Set<LocalVariableElement>>.identity();

  _NullableLocalInference(this._nullInference);

  /// After visiting nodes, this can be called to compute the set of not-null
  /// locals.
  ///
  /// This method must only be called once. After it is called, the visitor
  /// should be discarded.
  HashSet<LocalVariableElement> computeNotNullLocals() {
    // Given a set of variables that are nullable, remove them from our list of
    // local variables. The end result of this process is a list of variables
    // known to be not null.
    visitNullableLocal(LocalVariableElement e) {
      _locals.remove(e);

      // Visit all other locals that this one is assigned to, and record that
      // they are nullable too.
      _assignments.remove(e)?.forEach(visitNullableLocal);
    }

    _nullableLocals.forEach(visitNullableLocal);

    // Any remaining locals are non-null.
    return _locals;
  }

  @override
  visitVariableDeclaration(VariableDeclaration node) {
    var element = node.declaredElement;
    var initializer = node.initializer;
    if (element is LocalVariableElement) {
      _locals.add(element);
      if (initializer != null) {
        _visitAssignment(node.name, initializer);
      } else if (!_assertedNotNull(element)) {
        _nullableLocals.add(element);
      }
    }
    super.visitVariableDeclaration(node);
  }

  @override
  visitForStatement(ForStatement node) {
    var forLoopParts = node.forLoopParts;
    if (forLoopParts is ForEachParts) {
      if (forLoopParts is ForEachPartsWithIdentifier &&
          forLoopParts.identifier != null) {
        var element = forLoopParts.identifier.staticElement;
        if (element is LocalVariableElement && !_assertedNotNull(element)) {
          _nullableLocals.add(element);
        }
      } else if (forLoopParts is ForEachPartsWithDeclaration) {
        var declaration = forLoopParts.loopVariable;
        var element = declaration.declaredElement;
        _locals.add(element);
        if (!_assertedNotNull(element)) {
          _nullableLocals.add(element);
        }
      } else {
        throw new StateError('Unrecognized for loop parts');
      }
    }
    super.visitForStatement(node);
  }

  @override
  visitCatchClause(CatchClause node) {
    var e = node.exceptionParameter?.staticElement;
    if (e is LocalVariableElement) {
      _locals.add(e);
      // TODO(jmesserly): we allow throwing of `null`, for better or worse.
      _nullableLocals.add(e);
    }

    e = node.stackTraceParameter?.staticElement;
    if (e is LocalVariableElement) _locals.add(e);

    super.visitCatchClause(node);
  }

  @override
  visitAssignmentExpression(AssignmentExpression node) {
    if (node.operator.lexeme == '=') {
      _visitAssignment(node.leftHandSide, node.rightHandSide);
    } else {
      _visitAssignment(node.leftHandSide, node);
    }
    super.visitAssignmentExpression(node);
  }

  @override
  visitPostfixExpression(PostfixExpression node) {
    var op = node.operator.type;
    if (op.isIncrementOperator) {
      _visitAssignment(node.operand, node);
    }
    super.visitPostfixExpression(node);
  }

  @override
  visitPrefixExpression(PrefixExpression node) {
    var op = node.operator.type;
    if (op.isIncrementOperator) {
      _visitAssignment(node.operand, node);
    }
    super.visitPrefixExpression(node);
  }

  void _visitAssignment(Expression left, Expression right) {
    if (left is SimpleIdentifier) {
      var element = left.staticElement;
      if (element is LocalVariableElement && !_assertedNotNull(element)) {
        bool visitLocal(LocalVariableElement otherLocal) {
          // Record the assignment.
          _assignments
              .putIfAbsent(otherLocal, () => HashSet.identity())
              .add(element);
          // Optimistically assume this local is not null.
          // We will validate this assumption later.
          return false;
        }

        if (_nullInference._isNullable(right, visitLocal)) {
          _nullableLocals.add(element);
        }
      }
    }
  }
}

bool _assertedNotNull(Element e) =>
    findAnnotation(e, isNotNullAnnotation) != null ||
    findAnnotation(e, isNullCheckAnnotation) != null;
