private Map collectMembersInner()

in src/org/intellij/grammar/generator/RuleGraphHelper.java [351:475]


  private Map<PsiElement, Cardinality> collectMembersInner(BnfRule rule, BnfExpression tree, Set<Object> visited) {
    boolean firstNonTrivial = tree == Rule.firstNotTrivial(rule);
    boolean outerLeft = (firstNonTrivial || rule.getExpression() == tree) &&
                        Rule.isLeft(rule) && !isPrivateOrNoType(rule) && !Rule.isInner(rule);
    boolean tryCollapse = firstNonTrivial && !outerLeft && !isPrivateOrNoType(rule) && !Rule.isFake(rule);

    Map<PsiElement, Cardinality> result;
    if (tree instanceof BnfReferenceOrToken) {
      BnfRule targetRule = ((BnfReferenceOrToken)tree).resolveRule();
      if (targetRule != null) {
        if (Rule.isExternal(targetRule)) {
          result = psiMap(newExternalPsi(targetRule.getName()), REQUIRED);
        }
        else if (Rule.isLeft(targetRule)) {
          if (!Rule.isInner(targetRule) && !isPrivateOrNoType(targetRule)) {
            result = psiMap();
            result.put(getSynonymTargetOrSelf(targetRule), REQUIRED);
            result.put(LEFT_MARKER, REQUIRED);
          }
          else {
            result = Collections.emptyMap();
          }
        }
        else if (isPrivateOrNoType(targetRule)) {
          result = collectMembers(targetRule, visited);
        }
        else if (Rule.isUpper(targetRule)) {
          result = Collections.emptyMap();
        }
        else {
          result = psiMap(getSynonymTargetOrSelf(targetRule), REQUIRED);
        }
      }
      else {
        result = psiMap(tree, REQUIRED);
      }
      if (tryCollapse && willCollapse(rule, result)) {
        result = Collections.emptyMap();
      }
    }
    else if (tree instanceof BnfExternalExpression) {
      BnfExternalExpression expression = (BnfExternalExpression)tree;
      List<BnfExpression> arguments = expression.getArguments();
      if (arguments.isEmpty() && Rule.isMeta(rule)) {
        result = psiMap(newExternalPsi(tree.getText()), REQUIRED);
      }
      else {
        BnfExpression ruleRef = expression.getRefElement();
        BnfRule metaRule = ((BnfReferenceOrToken)ruleRef).resolveRule();
        if (metaRule == null) {
          result = psiMap(newExternalPsi("#" + ruleRef.getText()), REQUIRED);
        }
        else if (isPrivateOrNoType(metaRule)) {
          result = psiMap();
          Map<PsiElement, Cardinality> metaResults = collectMembers(metaRule, visited);
          List<String> params = null;
          for (PsiElement member : metaResults.keySet()) {
            Cardinality cardinality = metaResults.get(member);
            if (!isExternalPsi(member)) {
              result.put(member, cardinality);
            }
            else {
              if (params == null) {
                params = collectMetaParameters(metaRule, metaRule.getExpression());
              }
              int idx = params.indexOf(member.getText());
              if (idx > -1 && idx < arguments.size()) {
                Map<PsiElement, Cardinality> argMap = collectMembers(rule, arguments.get(idx), visited);
                for (PsiElement element : argMap.keySet()) {
                  Cardinality existing = ObjectUtils.notNull(result.get(element), NONE);
                  result.put(element, existing.or(cardinality.and(argMap.get(element))));
                }
              }
            }
          }
        }
        else {
          result = psiMap(metaRule, REQUIRED);
        }
      }
      if (tryCollapse && willCollapse(rule, result)) {
        result = Collections.emptyMap();
      }
    }
    else {
      List<BnfExpression> pinned = new ArrayList<>();
      GrammarUtil.processPinnedExpressions(rule, new CommonProcessors.CollectProcessor<>(pinned));
      boolean pinApplied = false;

      IElementType type = getEffectiveType(tree);

      List<Map<PsiElement, Cardinality>> list = new ArrayList<>();
      List<BnfExpression> childExpressions = getChildExpressions(tree);
      for (BnfExpression child : childExpressions) {
        Map<PsiElement, Cardinality> nextMap = collectMembers(rule, child, visited);
        if (pinApplied) {
          nextMap = joinMaps(rule, false, BnfTypes.BNF_OP_OPT, Collections.singletonList(nextMap));
        }
        list.add(nextMap);
        if (!pinApplied && pinned.contains(child)) {
          pinApplied = true;
        }
      }
      result = joinMaps(rule, tryCollapse, type, list);
      result = type == BnfTypes.BNF_SEQUENCE && visited.contains(RECURSION_MARKER) && result.remove(rule.getExpression()) != null ?
               joinMaps(rule, false, type, Arrays.asList(result, result)) : result;
    }
    if (outerLeft && rule.getExpression() == tree) {
      List<Map<PsiElement, Cardinality>> list = new ArrayList<>();
      Map<BnfRule, Cardinality> rulesToTheLeft = getRulesToTheLeft(rule);
      for (BnfRule r : rulesToTheLeft.keySet()) {
        Cardinality cardinality = rulesToTheLeft.get(r);
        Map<PsiElement, Cardinality> leftMap = psiMap(r, REQUIRED);
        if (cardinality.many()) {
          list.add(joinMaps(rule, false, BnfTypes.BNF_CHOICE, Arrays.asList(leftMap, psiMap(rule, REQUIRED))));
        }
        else {
          list.add(leftMap);
        }
      }
      Map<PsiElement, Cardinality> combinedLeftMap = joinMaps(rule, false, BnfTypes.BNF_CHOICE, list);
      result = joinMaps(rule, true, BnfTypes.BNF_SEQUENCE, Arrays.asList(result, combinedLeftMap));
    }
    return result;
  }