private OffsetRange getReferenceSpan(
      TokenSequence<?> ts, TokenHierarchy<Document> th, int lexOffset) {
    Token<?> token = ts.token();
    TokenId id = token.id();

    //        if (id == PythonTokenId.IDENTIFIER) {
    //            if (token.length() == 1 && id == PythonTokenId.IDENTIFIER &&
    // token.text().toString().equals(",")) {
    //                return OffsetRange.NONE;
    //            }
    //        }

    // TODO: Tokens.SUPER, Tokens.THIS, Tokens.SELF ...
    if (id == PythonTokenId.IDENTIFIER) {
      return new OffsetRange(ts.offset(), ts.offset() + token.length());
    }

    // Look for embedded RDoc comments:
    TokenSequence<?> embedded = ts.embedded();

    if (embedded != null) {
      ts = embedded;
      embedded.move(lexOffset);

      if (embedded.moveNext()) {
        Token<?> embeddedToken = embedded.token();

        if (embeddedToken.id() == PythonStringTokenId.URL) {
          return new OffsetRange(embedded.offset(), embedded.offset() + embeddedToken.length());
        }
        // Recurse into the range - perhaps there is Ruby code (identifiers

        // etc.) to follow there
        OffsetRange range = getReferenceSpan(embedded, th, lexOffset);

        if (range != OffsetRange.NONE) {
          return range;
        }
      }
    }

    return OffsetRange.NONE;
  }
  private void validateChangePoints(Collection<Token> changePoints, int... origs) {
    Set<Pair> awaited = new HashSet<Pair>();

    for (int cntr = 0; cntr < origs.length; cntr += 2) {
      awaited.add(new Pair(origs[cntr], origs[cntr + 1]));
    }

    Set<Pair> got = new HashSet<Pair>();

    for (Token<JavaTokenId> h : changePoints) {
      got.add(new Pair(h.offset(null), h.offset(null) + h.length()));
    }

    assertEquals(awaited, got);
  }