summaryrefslogtreecommitdiff
path: root/java/java-tests/testSrc/com/intellij/psi/search/FindUsagesTest.java
blob: 7e9bb8425a10a26f5dca7fe04bc683e182780455 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/*
 * Copyright 2000-2012 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.search;

import com.intellij.JavaTestUtil;
import com.intellij.find.findUsages.JavaFindUsagesHandler;
import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PsiTestCase;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
import com.intellij.testFramework.fixtures.TempDirTestFixture;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.Processor;
import com.intellij.util.containers.IntArrayList;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class FindUsagesTest extends PsiTestCase{

  @Override
  protected void setUp() throws Exception {
    super.setUp();

    String root = JavaTestUtil.getJavaTestDataPath() + "/psi/search/findUsages/" + getTestName(true);
    PsiTestUtil.removeAllRoots(myModule, IdeaTestUtil.getMockJdk17());
    PsiTestUtil.createTestProjectStructure(myProject, myModule, root, myFilesToDelete);
  }

  public void testOverloadConstructors() throws Exception {
    PsiClass aClass = myJavaFacade.findClass("B", GlobalSearchScope.allScope(myProject));
    PsiMethod constructor;
//    constructor = myJavaFacade.getElementFactory().createConstructor();
//    constructor = aClass.findMethodBySignature(constructor, false);
    constructor = aClass.findMethodsByName("B", false)[0];
    PsiMethodCallExpression superCall = (PsiMethodCallExpression) constructor.getBody().getStatements()[0].getFirstChild();
    PsiReferenceExpression superExpr = superCall.getMethodExpression();
    String[] fileNames = new String[]{"B.java", "A.java", "A.java", "B.java"};
    int[] starts = new int[]{};
    int[] ends = new int[]{};
    final ArrayList<PsiFile> filesList = new ArrayList<PsiFile>();
    final IntArrayList startsList = new IntArrayList();
    final IntArrayList endsList = new IntArrayList();
    PsiReference[] refs =
      MethodReferencesSearch.search((PsiMethod)superExpr.resolve(), GlobalSearchScope.projectScope(myProject), false).toArray(PsiReference.EMPTY_ARRAY);
    for (PsiReference ref : refs) {
      addReference(ref, filesList, startsList, endsList);
    }
    checkResult(fileNames, filesList, starts, startsList, ends, endsList);
  }

  public void testSiblingImplement() throws Exception {
    PsiClass anInterface = myJavaFacade.findClass("A.I", GlobalSearchScope.allScope(myProject));
    PsiMethod method = anInterface.getMethods()[0];
    final Collection<PsiMethod> overriders = OverridingMethodsSearch.search(method).findAll();
    assertEquals(1, overriders.size());
  }

  public void testProtectedMethodInPackageLocalClass() throws Throwable {
    PsiMethod method = myJavaFacade.findClass("foo.PackageLocal", GlobalSearchScope.allScope(myProject)).getMethods()[0];
    assertEquals(1, OverridingMethodsSearch.search(method).findAll().size());
    assertEquals(1, ReferencesSearch.search(method).findAll().size());
  }

  public void testLibraryClassUsageFromDecompiledSource() {
    PsiElement decompiled =
      ((PsiCompiledElement)myJavaFacade.findClass("javax.swing.JLabel", GlobalSearchScope.allScope(myProject))).getMirror();
    assertEquals(2, ReferencesSearch.search(decompiled).findAll().size());
  }

  public void testImplicitConstructorUsage() throws Throwable {
    PsiMethod[] ctrs = myJavaFacade.findClass("Foo", GlobalSearchScope.allScope(myProject)).getConstructors();
    PsiMethod method = ctrs[0];
    assertEquals(0, method.getParameterList().getParametersCount());
    assertEquals(0, ReferencesSearch.search(method).findAll().size());

    PsiMethod usedMethod = ctrs[1];
    assertEquals(1, usedMethod.getParameterList().getParametersCount());
    assertEquals(1, ReferencesSearch.search(usedMethod).findAll().size());
  }

  private static void addReference(PsiReference ref, ArrayList<PsiFile> filesList, IntArrayList startsList, IntArrayList endsList) {
    PsiElement element = ref.getElement();
    filesList.add(element.getContainingFile());
    TextRange range = element.getTextRange();
    TextRange rangeInElement = ref.getRangeInElement();
    startsList.add(range.getStartOffset() + rangeInElement.getStartOffset());
    endsList.add(range.getStartOffset() + rangeInElement.getEndOffset());
  }

  public void testFieldInJavadoc() throws Exception{
    PsiClass aClass = myJavaFacade.findClass("A", GlobalSearchScope.allScope(myProject));
    PsiField field = aClass.findFieldByName("FIELD", false);
    doTest(field, new String[]{"A.java"}, new int[]{}, new int[]{});
  }

  public void testXml() throws Exception{
    PsiClass aClass = myJavaFacade.findClass("com.Foo", GlobalSearchScope.allScope(myProject));
    doTest(aClass, new String[]{"Test.xml"}, new int[]{32}, new int[]{35});

    final PsiFile nonCodeUsage = PsiFileFactory.getInstance(myProject).createFileFromText("a.xml", StdFileTypes.XML, "<root action='com.Foo'/>", 0, true);
    assertTrue(new UsageInfo(nonCodeUsage, 14, 21, true).getNavigationOffset() > 0);
  }

  public void testNonCodeClassUsages() throws Exception {
    final TempDirTestFixture tdf = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture();
    tdf.setUp();

    try {
      new WriteCommandAction(getProject()) {
        @Override
        protected void run(Result result) throws Throwable {
          final ModifiableModuleModel moduleModel = ModuleManager.getInstance(getProject()).getModifiableModel();
          moduleModel.newModule("independent/independent.iml", StdModuleTypes.JAVA.getId());
          moduleModel.commit();

          tdf.createFile("plugin.xml", "<document>\n" +
                                       "  <action class=\"com.Foo\" />\n" +
                                       "  <action class=\"com.Foo.Bar\" />\n" +
                                       "  <action class=\"com.Foo$Bar\" />\n" +
                                       "</document>");

          PsiTestUtil.addContentRoot(ModuleManager.getInstance(getProject()).findModuleByName("independent"), tdf.getFile(""));
        }
      }.execute();

      GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
      PsiClass foo = myJavaFacade.findClass("com.Foo", scope);
      PsiClass bar = myJavaFacade.findClass("com.Foo.Bar", scope);

      final int[] count = {0};
      Processor<UsageInfo> processor = new Processor<UsageInfo>() {
        @Override
        public boolean process(UsageInfo usageInfo) {
          int navigationOffset = usageInfo.getNavigationOffset();
          assertTrue(navigationOffset > 0);
          String textAfter = usageInfo.getFile().getText().substring(navigationOffset);
          assertTrue(textAfter, textAfter.startsWith("Foo") || textAfter.startsWith("Bar") ||
                                textAfter.startsWith("com.Foo.Bar") // sorry, can't get references with dollar-dot mismatch to work now
          );
          count[0]++;
          return true;
        }
      };
      JavaFindUsagesHandler handler = new JavaFindUsagesHandler(bar, JavaFindUsagesHandlerFactory.getInstance(getProject()));

      count[0] = 0;
      handler.processUsagesInText(foo, processor, scope);
      assertEquals(3, count[0]);

      count[0] = 0;
      handler.processUsagesInText(bar, processor, scope);
      assertEquals(2, count[0]);
    }
    finally {
      tdf.tearDown();
    }
  }

  public static void doTest(PsiElement element, String[] fileNames, int[] starts, int[] ends) throws Exception {
    final ArrayList<PsiFile> filesList = new ArrayList<PsiFile>();
    final IntArrayList startsList = new IntArrayList();
    final IntArrayList endsList = new IntArrayList();
    ReferencesSearch.search(element, GlobalSearchScope.projectScope(element.getProject()), false).forEach(new PsiReferenceProcessorAdapter(new PsiReferenceProcessor() {
        @Override
        public boolean execute(PsiReference ref) {
          addReference(ref, filesList, startsList, endsList);
          return true;
        }
      }));

    checkResult(fileNames, filesList, starts, startsList, ends, endsList);

  }

  private static class SearchResult implements Comparable<SearchResult> {
    String fileName;
    int startOffset;
    int endOffset;

    private SearchResult(final String fileName, final int startOffset, final int endOffset) {
      this.fileName = fileName;
      this.startOffset = startOffset;
      this.endOffset = endOffset;
    }

    @Override
    public int compareTo(final SearchResult o) {
      int rc = fileName.compareTo(o.fileName);
      if (rc != 0) return rc;

      rc = startOffset - o.startOffset;
      if (rc != 0) return rc;

      return endOffset - o.endOffset;
    }

    public String toString() {
      return fileName + "[" + startOffset + ":" + endOffset + "]";
    }

    public boolean equals(final Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      final SearchResult that = (SearchResult)o;

      if (endOffset != that.endOffset) return false;
      if (startOffset != that.startOffset) return false;
      if (fileName != null ? !fileName.equals(that.fileName) : that.fileName != null) return false;

      return true;
    }
  }

  private static void checkResult(String[] fileNames, final ArrayList<PsiFile> filesList, int[] starts, final IntArrayList startsList, int[] ends, final IntArrayList endsList) {
    List<SearchResult> expected = new ArrayList<SearchResult>();
    for (int i = 0; i < fileNames.length; i++) {
      String fileName = fileNames[i];
      expected.add(new SearchResult(fileName, i < starts.length ? starts[i] : -1, i < ends.length ? ends[i] : -1));
    }

    List<SearchResult> actual = new ArrayList<SearchResult>();
    for (int i = 0; i < filesList.size(); i++) {
      PsiFile psiFile = filesList.get(i);
      actual.add(
        new SearchResult(psiFile.getName(), i < starts.length ? startsList.get(i) : -1, i < ends.length ? endsList.get(i) : -1));
    }

    Collections.sort(expected);
    Collections.sort(actual);

    assertEquals("Usages don't match", expected, actual);
  }
}