2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.psi.impl;
19 import com.intellij.lang.Language;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.util.TextRange;
22 import com.intellij.psi.*;
23 import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
24 import com.intellij.psi.templateLanguages.OuterLanguageElement;
25 import org.jetbrains.annotations.NotNull;
26 import org.jetbrains.annotations.Nullable;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.List;
33 public class SharedPsiElementImplUtil {
34 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.SharedPsiElementImplUtil");
36 private SharedPsiElementImplUtil() {
40 public static PsiReference findReferenceAt(PsiElement thisElement, int offset, @Nullable Language lang) {
41 if (thisElement == null) return null;
42 PsiElement element = lang != null ? thisElement.getContainingFile().getViewProvider().findElementAt(offset, lang) :
43 thisElement.findElementAt(offset);
44 if (element == null || element instanceof OuterLanguageElement) return null;
45 offset = thisElement.getTextRange().getStartOffset() + offset - element.getTextRange().getStartOffset();
47 List<PsiReference> referencesList = new ArrayList<PsiReference>();
48 while (element != null) {
49 addReferences(offset, element, referencesList);
50 offset = element.getStartOffsetInParent() + offset;
51 if (element instanceof PsiFile) break;
52 element = element.getParent();
55 if (referencesList.isEmpty()) return null;
56 if (referencesList.size() == 1) return referencesList.get(0);
57 return new PsiMultiReference(referencesList.toArray(new PsiReference[referencesList.size()]),
58 referencesList.get(referencesList.size() - 1).getElement());
62 public static PsiReference findReferenceAt(PsiElement thisElement, int offset) {
63 return findReferenceAt(thisElement, offset, null);
66 private static void addReferences(int offset, PsiElement element, final Collection<PsiReference> outReferences) {
67 for (final PsiReference reference : element.getReferences()) {
68 if (reference == null) {
71 for (TextRange range : ReferenceRange.getRanges(reference)) {
72 LOG.assertTrue(range != null, reference);
73 if (range.containsOffset(offset)) {
74 outReferences.add(reference);
81 public static PsiReference[] getReferences(PsiElement thisElement) {
82 PsiReference ref = thisElement.getReference();
83 if (ref == null) return PsiReference.EMPTY_ARRAY;
84 return new PsiReference[]{ref};
88 public static PsiElement getNextSibling(PsiElement element) {
89 if (element instanceof PsiFile) {
90 final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider();
91 element = viewProvider.getPsi(viewProvider.getBaseLanguage());
93 if (element == null) return null;
94 final PsiElement parent = element.getParent();
95 if (parent == null) return null;
97 final PsiElement[] children = parent.getChildren();
98 final int index = getChildIndex(children, element);
99 return 0 <= index && index < children.length - 1 ? children[index + 1] : null;
103 public static PsiElement getPrevSibling(PsiElement element) {
104 if (element instanceof PsiFile) {
105 final FileViewProvider viewProvider = ((PsiFile)element).getViewProvider();
106 element = viewProvider.getPsi(viewProvider.getBaseLanguage());
108 if (element == null) return null;
109 final PsiElement parent = element.getParent();
110 if (parent == null) return null;
112 final PsiElement[] children = parent.getChildren();
113 final int index = getChildIndex(children, element);
114 return index > 0 ? children[index - 1] : null;
117 private static int getChildIndex(final PsiElement[] children, final PsiElement child) {
118 for (int i = 0; i < children.length; i++) {
119 PsiElement candidate = children[i];
120 // do not use equals() since some smart-heads are used to override it (e.g. JspxImportStatementImpl)
121 if (candidate == child) {
125 LOG.error("Cannot find element among its parent' children." +
126 " element: '" + child + "';" +
127 " parent: '" + child.getParent() + "';" +
128 " children: " + Arrays.asList(children) + "; " +
129 " file:" + child.getContainingFile());