/* * Copyright 2000-2009 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.psi.impl; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference; import com.intellij.psi.templateLanguages.OuterLanguageElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; public class SharedPsiElementImplUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.SharedPsiElementImplUtil"); private SharedPsiElementImplUtil() { } @Nullable public static PsiReference findReferenceAt(PsiElement thisElement, int offset, @Nullable Language lang) { if (thisElement == null) return null; PsiElement element = lang != null ? thisElement.getContainingFile().getViewProvider().findElementAt(offset, lang) : thisElement.findElementAt(offset); if (element == null || element instanceof OuterLanguageElement) return null; offset = thisElement.getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset(); List<PsiReference> referencesList = new ArrayList<PsiReference>(); while (element != null) { addReferences(offset, element, referencesList); offset = element.getStartOffsetInParent() + offset; if (element instanceof PsiFile) break; element = element.getParent(); } if (referencesList.isEmpty()) return null; if (referencesList.size() == 1) return referencesList.get(0); return new PsiMultiReference(referencesList.toArray(new PsiReference[referencesList.size()]), referencesList.get(referencesList.size() - 1).getElement()); } @Nullable public static PsiReference findReferenceAt(PsiElement thisElement, int offset) { return findReferenceAt(thisElement, offset, null); } private static void addReferences(int offset, PsiElement element, final Collection<PsiReference> outReferences) { for (final PsiReference reference : element.getReferences()) { if (reference == null) { LOG.error(element); } for (TextRange range : ReferenceRange.getRanges(reference)) { LOG.assertTrue(range != null, reference); if (range.containsOffset(offset)) { outReferences.add(reference); } } } } @NotNull public static PsiReference[] getReferences(PsiElement thisElement) { PsiReference ref = thisElement.getReference(); if (ref == null) return PsiReference.EMPTY_ARRAY; return new PsiReference[]{ref}; } @Nullable public static PsiElement getNextSibling(PsiElement element) { if (element instanceof PsiFile) { final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider(); element = viewProvider.getPsi(viewProvider.getBaseLanguage()); } if (element == null) return null; final PsiElement parent = element.getParent(); if (parent == null) return null; final PsiElement[] children = parent.getChildren(); final int index = getChildIndex(children, element); return 0 <= index && index < children.length - 1 ? children[index + 1] : null; } @Nullable public static PsiElement getPrevSibling(PsiElement element) { if (element instanceof PsiFile) { final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider(); element = viewProvider.getPsi(viewProvider.getBaseLanguage()); } if (element == null) return null; final PsiElement parent = element.getParent(); if (parent == null) return null; final PsiElement[] children = parent.getChildren(); final int index = getChildIndex(children, element); return index > 0 ? children[index - 1] : null; } private static int getChildIndex(final PsiElement[] children, final PsiElement child) { for (int i = 0; i < children.length; i++) { PsiElement candidate = children[i]; // do not use equals() since some smart-heads are used to override it (e.g. JspxImportStatementImpl) if (candidate == child) { return i; } } LOG.error("Cannot find element among its parent' children." + " element: '" + child + "';" + " parent: '" + child.getParent() + "';" + " children: " + Arrays.asList(children) + "; " + " file:" + child.getContainingFile()); return -1; } }