/**
  * Removes all expected elements that refer to the same terminal. Attention: This method assumes
  * that the given list of expected terminals contains only elements that start at the same
  * position.
  */
 protected void removeDuplicateEntriesFromBucket(
     List<org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal>
         expectedElements) {
   int size = expectedElements.size();
   for (int i = 0; i < size - 1; i++) {
     org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal elementAtIndex =
         expectedElements.get(i);
     org.emftext.language.xpath3.resource.xpath3.IXpath3ExpectedElement terminal =
         elementAtIndex.getTerminal();
     for (int j = i + 1; j < size; ) {
       org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal elementAtNext =
           expectedElements.get(j);
       EClass metaClass = elementAtIndex.getContainmentTrace().getStartClass();
       EClass nextMetaClass = elementAtNext.getContainmentTrace().getStartClass();
       org.emftext.language.xpath3.resource.xpath3.IXpath3ExpectedElement nextTerminal =
           elementAtNext.getTerminal();
       // Terminals that have a different root meta class in the containment trace must
       // be kept because they can the decision whether an expected terminals is valid or
       // not depends on the root of the containment trace.
       boolean differentMetaclass = metaClass != nextMetaClass;
       if (terminal.equals(nextTerminal) && !differentMetaclass) {
         expectedElements.remove(j);
         size--;
       } else {
         j++;
       }
     }
   }
 }
  protected void removeInvalidEntriesAtEnd(
      List<org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal>
          expectedElements) {
    org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3FollowSetGroupList followSetGroupList =
        new org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3FollowSetGroupList(
            expectedElements);
    List<org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3FollowSetGroup> followSetGroups =
        followSetGroupList.getFollowSetGroups();
    int lastStartExcludingHiddenTokens = -1;
    for (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3FollowSetGroup followSetGroup :
        followSetGroups) {
      boolean sameStartExcludingHiddenTokens =
          followSetGroup.hasSameStartExcludingHiddenTokens(lastStartExcludingHiddenTokens);
      lastStartExcludingHiddenTokens = followSetGroup.getStartExcludingHiddenTokens();
      EObject container = followSetGroup.getContainer();
      EClass currentRule = null;
      if (container != null) {
        currentRule = container.eClass();
      }
      List<org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal>
          expectedTerminals = followSetGroup.getExpectedTerminals();
      for (org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal
          expectedTerminal : expectedTerminals) {
        org.emftext.language.xpath3.resource.xpath3.IXpath3ExpectedElement terminalAtIndex =
            expectedTerminal.getTerminal();
        EClass ruleMetaclass = terminalAtIndex.getRuleMetaclass();
        boolean differentRule = currentRule != ruleMetaclass;
        // If the two expected elements have a different parent in the syntax definition,
        // we must not discard the second element, because it probably stems from a parent
        // rule.
        org.emftext.language.xpath3.resource.xpath3.grammar.Xpath3ContainmentTrace
            containmentTrace = expectedTerminal.getContainmentTrace();
        boolean fitsAtCurrentPosition = fitsAtCurrentPosition(container, containmentTrace);
        boolean inContainmentTrace =
            pathToRootContains(container, expectedTerminal.getTerminal().getRuleMetaclass());
        boolean keepElement = true;
        if (differentRule && !inContainmentTrace) {
          if (!fitsAtCurrentPosition) {
            keepElement = false;
          }
        }
        if (sameStartExcludingHiddenTokens) {
          keepElement = false;
        }

        if (keepElement) {
        } else {
          // We must not call expectedElements.remove(expectedTerminal) because the
          // hashCode() method of ExpectedTerminal does not consider the start positions and
          // remove the wrong elements.
          for (int i = 0; i < expectedElements.size(); i++) {
            org.emftext.language.xpath3.resource.xpath3.mopp.Xpath3ExpectedTerminal next =
                expectedElements.get(i);
            if (next == expectedTerminal) {
              expectedElements.remove(i);
              break;
            }
          }
        }
      }
    }
  }