1 /* 2 * Copyright 2015, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.smalidea.findUsages; 33 34 import com.google.common.collect.Lists; 35 import com.intellij.codeInsight.TargetElementUtilBase; 36 import com.intellij.find.FindManager; 37 import com.intellij.find.findUsages.FindUsagesHandler; 38 import com.intellij.find.findUsages.FindUsagesManager; 39 import com.intellij.find.findUsages.FindUsagesOptions; 40 import com.intellij.find.impl.FindManagerImpl; 41 import com.intellij.psi.PsiElement; 42 import com.intellij.psi.PsiFile; 43 import com.intellij.psi.PsiReference; 44 import com.intellij.testFramework.PsiTestCase; 45 import com.intellij.usageView.UsageInfo; 46 import com.intellij.usages.PsiElementUsageTarget; 47 import com.intellij.usages.UsageTarget; 48 import com.intellij.usages.UsageTargetUtil; 49 import com.intellij.util.CommonProcessors; 50 import org.jetbrains.annotations.NotNull; 51 import org.junit.Assert; 52 53 import java.util.Collection; 54 import java.util.List; 55 import java.util.regex.Matcher; 56 import java.util.regex.Pattern; 57 58 public abstract class FindUsagesTest extends PsiTestCase { 59 public static final String USAGE_TAG = "<usage>"; 60 public static final String REF_TAG = "<ref>"; 61 62 private class TestFile { 63 @NotNull public final String fileName; 64 @NotNull public final String fileText; 65 @NotNull public final PsiFile psiFile; 66 TestFile(@otNull String fileName, @NotNull String fileText)67 public TestFile(@NotNull String fileName, @NotNull String fileText) throws Exception { 68 this.fileName = fileName; 69 this.fileText = fileText; 70 this.psiFile = createFile(fileName, getText()); 71 } 72 73 @NotNull getText()74 public String getText() { 75 return fileText.replace(REF_TAG, "").replace(USAGE_TAG, ""); 76 } 77 getRefIndex()78 public int getRefIndex() { 79 return fileText.replace(USAGE_TAG, "").indexOf(REF_TAG); 80 } 81 getUsageIndices()82 public List<Integer> getUsageIndices() { 83 Matcher matcher = Pattern.compile(USAGE_TAG).matcher(fileText.replace(REF_TAG, "")); 84 List<Integer> matches = Lists.newArrayList(); 85 86 int adjustment = 0; 87 while (matcher.find()) { 88 matches.add(matcher.start() - adjustment); 89 adjustment += USAGE_TAG.length(); 90 } 91 return matches; 92 } 93 } 94 95 private List<TestFile> testFiles; 96 97 @Override setUp()98 public void setUp() throws Exception { 99 testFiles = Lists.newArrayList(); 100 super.setUp(); 101 } 102 addFile(String fileName, String fileText)103 protected void addFile(String fileName, String fileText) throws Exception { 104 testFiles.add(new TestFile(fileName, fileText)); 105 } 106 doTest()107 protected void doTest() { 108 109 PsiReference reference = null; 110 PsiElement targetElement = null; 111 112 for (TestFile testFile: testFiles) { 113 int refIndex = testFile.getRefIndex(); 114 if (refIndex != -1) { 115 PsiElement element = testFile.psiFile.findElementAt(refIndex); 116 117 UsageTarget[] targets = UsageTargetUtil.findUsageTargets(element); 118 if (targets != null) { 119 for (UsageTarget target : targets) { 120 if (target instanceof PsiElementUsageTarget) { 121 targetElement = ((PsiElementUsageTarget)target).getElement(); 122 break; 123 } 124 } 125 } 126 127 if (targetElement == null) { 128 reference = testFile.psiFile.findReferenceAt(refIndex); 129 if (reference != null) { 130 targetElement = reference.resolve(); 131 } else { 132 targetElement = TargetElementUtilBase.getInstance().getNamedElement( 133 testFile.psiFile.findElementAt(refIndex), 0); 134 } 135 } 136 break; 137 } 138 } 139 140 Assert.assertNotNull(targetElement); 141 142 Collection<UsageInfo> usages = findUsages(targetElement); 143 for (TestFile testFile: testFiles) { 144 assertUsages(testFile, usages); 145 } 146 } 147 assertUsages(@otNull TestFile testFile, @NotNull Collection<UsageInfo> usages)148 private void assertUsages(@NotNull TestFile testFile, @NotNull Collection<UsageInfo> usages) { 149 List<UsageInfo> fileUsages = Lists.newArrayList(); 150 for (UsageInfo usage: usages) { 151 if (usage.getFile().getName().equals(testFile.fileName)) { 152 fileUsages.add(usage); 153 } 154 } 155 156 for (Integer usageIndex: testFile.getUsageIndices()) { 157 boolean found = false; 158 for (UsageInfo usage: fileUsages) { 159 int startOffset = usage.getElement().getNode().getStartOffset(); 160 int length = usage.getElement().getTextLength(); 161 162 if (usageIndex >= startOffset && usageIndex < startOffset + length) { 163 fileUsages.remove(usage); 164 found = true; 165 break; 166 } 167 } 168 Assert.assertTrue(found); 169 } 170 Assert.assertEquals(0, fileUsages.size()); 171 } 172 findUsages(@otNull PsiElement element)173 private Collection<UsageInfo> findUsages(@NotNull PsiElement element) { 174 FindUsagesManager findUsagesManager = 175 ((FindManagerImpl)FindManager.getInstance(getProject())).getFindUsagesManager(); 176 177 FindUsagesHandler findUsagesHandler = 178 findUsagesManager.getFindUsagesHandler(element, false); 179 Assert.assertNotNull(findUsagesHandler); 180 181 final FindUsagesOptions options = findUsagesHandler.getFindUsagesOptions(); 182 final CommonProcessors.CollectProcessor<UsageInfo> processor = 183 new CommonProcessors.CollectProcessor<UsageInfo>(); 184 185 for (PsiElement primaryElement : findUsagesHandler.getPrimaryElements()) { 186 findUsagesHandler.processElementUsages(primaryElement, processor, options); 187 } 188 189 for (PsiElement secondaryElement: findUsagesHandler.getSecondaryElements()) { 190 findUsagesHandler.processElementUsages(secondaryElement, processor, options); 191 } 192 193 return processor.getResults(); 194 } 195 } 196