@Override
  public PsiType[] guessContainerElementType(PsiExpression containerExpr, TextRange rangeToIgnore) {
    HashSet<PsiType> typesSet = new HashSet<>();

    PsiType type = containerExpr.getType();
    PsiType elemType;
    if ((elemType = getGenericElementType(type)) != null) return new PsiType[] {elemType};

    if (containerExpr instanceof PsiReferenceExpression) {
      PsiElement refElement = ((PsiReferenceExpression) containerExpr).resolve();
      if (refElement instanceof PsiVariable) {

        PsiFile file = refElement.getContainingFile();
        if (file == null) {
          file = containerExpr.getContainingFile(); // implicit variable in jsp
        }
        HashSet<PsiVariable> checkedVariables = new HashSet<>();
        addTypesByVariable(
            typesSet,
            (PsiVariable) refElement,
            file,
            checkedVariables,
            CHECK_USAGE | CHECK_DOWN,
            rangeToIgnore);
        checkedVariables.clear();
        addTypesByVariable(
            typesSet, (PsiVariable) refElement, file, checkedVariables, CHECK_UP, rangeToIgnore);
      }
    }

    return typesSet.toArray(PsiType.createArray(typesSet.size()));
  }
  @Override
  public PsiType[] guessTypeToCast(
      PsiExpression expr) { // TODO : make better guess based on control flow
    LinkedHashSet<PsiType> types = new LinkedHashSet<>();

    ContainerUtil.addIfNotNull(types, getControlFlowExpressionType(expr));
    addExprTypesWhenContainerElement(types, expr);
    addExprTypesByDerivedClasses(types, expr);

    return types.toArray(PsiType.createArray(types.size()));
  }