PsiElement (int start, int end, int index, @NotNull PsiElement element, @Nullable StringBuilder processingInfoStorage) { TextRange range = element.getTextRange(); if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Starting processing from element '%s'. It's range is %s%n", element, range)); } while (range != null && range.getStartOffset() == start && range.getEndOffset() < end) { element = element.getParent(); if (element == null) { if (processingInfoStorage != null) { processingInfoStorage.append("Reached top of PSI tree"); } return null; } range = element.getTextRange(); if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Expanding element to '%s' and range to '%s'%n", element, range)); } } if (range == null || range.getStartOffset() != start || range.getEndOffset() != end) { if (processingInfoStorage != null) { processingInfoStorage.append(String.format( "Stopping %s because target element's range differs from the target one. Element: '%s', it's range: %s%n", getClass(), element, range)); } return null; } // There is a possible case that we have a hierarchy of PSI elements that target the same document range. We need to find // out the right one then. int indexFromRoot = getElementHierarchyIndex(element); if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Target element index is %d. Current index from root is %d%n", index, indexFromRoot)); } if (index > indexFromRoot) { int steps = index - indexFromRoot; PsiElement result = element; for (PsiElement e = result.getFirstChild(); steps > 0 && e != null && range.equals(e.getTextRange()); steps--, e = e.getFirstChild()) { if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Clarifying target element to '%s', its range is %s%n", result, result.getTextRange())); } result = e; } return result; } int steps = indexFromRoot - index; PsiElement result = element; while (--steps >= 0) { result = result.getParent(); if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Reducing target element to '%s', its range is %s%n", result, result.getTextRange())); } } if (processingInfoStorage != null) { processingInfoStorage.append(String.format("Returning element '%s', its range is %s%n", result, result.getTextRange())); } return result; }