protected @Nullable Object getDataInner(@NotNull String dataId, boolean rulesAllowed, boolean ruleValuesAllowed) {
    int keyIndex = getDataKeyIndex(dataId);
    if (keyIndex == -1) return EXPLICIT_NULL; // DataKey not found

    Object answer = null;
    for (ProviderData map : myCachedData) {
      ProgressManager.checkCanceled();
      boolean isComputed = false;
      answer = map.uiSnapshot.get(dataId);
      if (answer == null) {
        answer = map.computedData.get(dataId);
        isComputed = true;
      }
      if (answer == EXPLICIT_NULL) break;
      if (answer != null) {
        if (isComputed) {
          reportValueProvidedByRulesUsage(dataId, !ruleValuesAllowed);
          if (!ruleValuesAllowed) return null;
        }
        answer = DataValidators.validOrNull(answer, dataId, this);
        if (answer != null) break;
        if (!isComputed) return null;
        // allow slow data providers and rules to re-calc the value
        map.computedData.remove(dataId);
      }
      if (!rulesAllowed || map.nullsByRules.get(keyIndex)) continue;

      answer = myDataManager.getDataFromRules(dataId, GetDataRuleType.PROVIDER, id -> {
        if (Objects.equals(id, dataId)) return null;
        Object o = map.uiSnapshot.get(id);
        return o != null ? o : map.computedData.get(id);
      });

      if (answer == null) {
        map.nullsByRules.set(keyIndex);
      }
      else {
        map.computedData.put(dataId, answer);
        reportValueProvidedByRules(dataId);
        break;
      }
    }
    return answer;
  }
protected @Nullable Object getDataInner(@NotNull String dataId, boolean rulesAllowed, boolean ruleValuesAllowed)