private static IRegion getPathRegion(
      PathNameCS pathNameCS, IRegion selection, int[] selectedPos) {
    int[] positions = getPathPos(pathNameCS);
    if (positions == null) {
      return HyperlinkUtil.createRegion(pathNameCS);
    }

    int nameOffset = pathNameCS.getStartOffset();
    int i = 0;
    for (SimpleNameCS name : pathNameCS.getSimpleNames()) {
      int offset = selection.getOffset();
      if (nameOffset <= offset && offset <= nameOffset + name.getValue().length()) {
        selectedPos[0] = i;
        return new Region(nameOffset, name.getValue().length());
      }

      if (i == positions.length) {
        break;
      }

      nameOffset = positions[i++];
    }

    return HyperlinkUtil.createRegion(pathNameCS);
  }
  private static int[] getPathPos(PathNameCS pathNameCS) {
    EList<SimpleNameCS> sequenceOfNames = pathNameCS.getSimpleNames();
    if (sequenceOfNames.size() == 1) {
      return null;
    }

    int size = sequenceOfNames.size() - 1;
    int[] positions = new int[size];
    Arrays.fill(positions, -1);

    IToken startToken = pathNameCS.getStartToken();
    IToken endToken = pathNameCS.getEndToken();

    IPrsStream prsStream = startToken.getIPrsStream();
    IToken nextToken = startToken;

    int tokenIndex = 1;
    int i = 0;
    while (nextToken != endToken) {
      nextToken = prsStream.getIToken(startToken.getTokenIndex() + tokenIndex++);
      if (nextToken.getKind() == QVTOParsersym.TK_IDENTIFIER) {
        positions[i++] = nextToken.getStartOffset();
        if (i == positions.length) {
          // safety exit in case we have inconsistent start end token
          break;
        }
      }
    }

    return positions;
  }
  private static EModelElementRef findReferencedMetamodelElement(
      CSTNode syntaxElement, IRegion region) {
    Object astObj = syntaxElement.getAst();

    if (astObj instanceof EClassifier) {
      if (syntaxElement instanceof SimpleNameCS) {
        if (astObj instanceof EModelElement) {
          return new EModelElementRef(
              (EModelElement) astObj, HyperlinkUtil.createRegion(syntaxElement));
        }
      } else if (syntaxElement instanceof PathNameCS && !isConstructorCS(syntaxElement)) {
        if (astObj instanceof ENamedElement) {
          PathNameCS pathNameCS = (PathNameCS) syntaxElement;

          int[] selectedNamePos = new int[1];
          // IRegion resultRegion = refineRegion(pathNameCS, region, selectedNamePos);
          IRegion resultRegion = getPathRegion(pathNameCS, region, selectedNamePos);
          if (resultRegion != null) {
            ENamedElement ast = (ENamedElement) pathNameCS.getAst();
            int pos = selectedNamePos[0];
            final EList<SimpleNameCS> csNames = pathNameCS.getSimpleNames();

            if (pos >= 0 && pos < csNames.size() - 1) {
              QvtOperationalEnv env = getEnv(pathNameCS);

              List<SimpleNameCS> selectedNames = csNames.subList(0, pos + 1);
              List<String> stringNames = new ArrayList<String>(selectedNames.size());
              for (SimpleNameCS nameCS : selectedNames) {
                stringNames.add(nameCS.getValue());
              }

              ast = env.lookupClassifier(stringNames);
              if (ast == null) {
                ast = env.lookupPackage(stringNames);
              }
            }

            if (ast != null) {
              return new EModelElementRef(ast, resultRegion);
            }
          }
        }
      }
    } else if (astObj instanceof EEnumLiteral) {
      return new EModelElementRef((EEnumLiteral) astObj, HyperlinkUtil.createRegion(syntaxElement));
    }

    return null;
  }