@NotNull
  public static Nullness checkNullness(
      @Nullable final PsiVariable variable, @Nullable final PsiElement context) {
    if (variable == null || context == null) return Nullness.UNKNOWN;

    final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context);
    if (codeBlock == null) {
      return Nullness.UNKNOWN;
    }
    final ValuableInstructionVisitor visitor = new ValuableInstructionVisitor(context);
    RunnerResult result = new ValuableDataFlowRunner().analyzeMethod(codeBlock, visitor);
    if (result != RunnerResult.OK) {
      return Nullness.UNKNOWN;
    }
    if (visitor.myNulls.contains(variable) && !visitor.myNotNulls.contains(variable))
      return Nullness.NULLABLE;
    if (visitor.myNotNulls.contains(variable) && !visitor.myNulls.contains(variable))
      return Nullness.NOT_NULL;
    return Nullness.UNKNOWN;
  }
  @Nullable("null means DFA analysis has failed (too complex to analyze)")
  public static Collection<PsiExpression> getCachedVariableValues(
      @Nullable final PsiVariable variable, @Nullable final PsiElement context) {
    if (variable == null || context == null) return Collections.emptyList();

    CachedValue<MultiValuesMap<PsiVariable, PsiExpression>> cachedValue =
        context.getUserData(DFA_VARIABLE_INFO_KEY);
    if (cachedValue == null) {
      final PsiElement codeBlock = DfaPsiUtil.getEnclosingCodeBlock(variable, context);
      cachedValue =
          CachedValuesManager.getManager(context.getProject())
              .createCachedValue(
                  new CachedValueProvider<MultiValuesMap<PsiVariable, PsiExpression>>() {
                    @Override
                    public Result<MultiValuesMap<PsiVariable, PsiExpression>> compute() {
                      final MultiValuesMap<PsiVariable, PsiExpression> result;
                      if (codeBlock == null) {
                        result = null;
                      } else {
                        final ValuableInstructionVisitor visitor =
                            new ValuableInstructionVisitor(context);
                        RunnerResult runnerResult =
                            new ValuableDataFlowRunner().analyzeMethod(codeBlock, visitor);
                        if (runnerResult == RunnerResult.OK) {
                          result = visitor.myValues;
                        } else {
                          result = TOO_COMPLEX;
                        }
                      }
                      return new Result<MultiValuesMap<PsiVariable, PsiExpression>>(
                          result, variable);
                    }
                  },
                  false);
      context.putUserData(DFA_VARIABLE_INFO_KEY, cachedValue);
    }
    final MultiValuesMap<PsiVariable, PsiExpression> value = cachedValue.getValue();
    if (value == TOO_COMPLEX) return null;
    final Collection<PsiExpression> expressions = value == null ? null : value.get(variable);
    return expressions == null ? Collections.<PsiExpression>emptyList() : expressions;
  }