change assumptions about events after renaming root directory: now "roots changed...
[idea/community.git] / platform / lang-api / src / com / intellij / psi / util / ReferenceSetBase.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.psi.util;
18
19 import com.intellij.openapi.util.NotNullLazyValue;
20 import com.intellij.openapi.util.TextRange;
21 import com.intellij.psi.ElementManipulators;
22 import com.intellij.psi.PsiElement;
23 import com.intellij.psi.PsiReference;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30
31 /**
32  * @author Dmitry Avdeev
33  */
34 public abstract class ReferenceSetBase<T extends PsiReference> {
35
36   public static final char DOT_SEPARATOR = '.';
37
38   private final NotNullLazyValue<List<T>> myReferences;
39   private final PsiElement myElement;
40   private final char mySeparator;
41
42   public ReferenceSetBase(@NotNull PsiElement element) {
43     this(element, ElementManipulators.getOffsetInElement(element));
44   }
45   
46   public ReferenceSetBase(@NotNull PsiElement element, int offset) {
47     this(ElementManipulators.getValueText(element), element, offset, DOT_SEPARATOR);
48   }
49
50   public ReferenceSetBase(final String text, @NotNull PsiElement element, int offset, final char separator) {
51     myElement = element;
52     mySeparator = separator;
53     myReferences = new NotNullLazyValue<List<T>>() {
54       @NotNull
55       @Override
56       protected List<T> compute() {
57         return parse(text, offset);
58       }
59     };
60   }
61
62   public boolean isSoft() {
63     return true;
64   }
65   
66   @NotNull
67   protected List<T> parse(String str, int offset) {
68
69     final List<T> references = new ArrayList<>();
70     int current = -1;
71     int index = 0;
72     int next;
73     do {
74       next = findNextSeparator(str, current);
75       final TextRange range = new TextRange(offset + current + 1, offset + (next >= 0 ? next : str.length()));
76       if (!range.isEmpty() || !Character.isWhitespace(mySeparator)) {
77         references.addAll(createReferences(range, index ++));
78       }
79     } while ((current = next) >= 0);
80
81     return references;
82   }
83
84   protected int findNextSeparator(final String str, final int current) {
85     final int next;
86     next = str.indexOf(mySeparator, current + 1);
87     return next;
88   }
89
90   @Nullable
91   protected T createReference(final TextRange range, final int index) {
92     return null;
93   }
94
95   protected List<T> createReferences(final TextRange range, final int index) {
96     T reference = createReference(range, index);
97
98     return reference == null ? Collections.emptyList() : Collections.singletonList(reference);
99   }
100
101   public PsiElement getElement() {
102     return myElement;
103   }
104
105   public List<T> getReferences() {
106     return myReferences.getValue();
107   }
108
109   public PsiReference @NotNull [] getPsiReferences() {
110     return getReferences().toArray(PsiReference.EMPTY_ARRAY);
111   }
112
113   public T getReference(int index) {
114     return getReferences().get(index);
115   }
116
117   @Nullable
118   public T getLastReference() {
119     return getReferences().isEmpty() ? null : getReference(getReferences().size() - 1);
120   }
121 }