blob: d1a6b81e1a9aec1698723ac380996a96d6f59061 [file] [log] [blame]
/*
* 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;
}
}