diff --git a/smalidea/META-INF/plugin.xml b/smalidea/META-INF/plugin.xml
index a13d0d19..4f827bdf 100644
--- a/smalidea/META-INF/plugin.xml
+++ b/smalidea/META-INF/plugin.xml
@@ -29,6 +29,7 @@
+
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java
new file mode 100644
index 00000000..e87782b6
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliUsageTargetProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.smalidea.findUsages;
+
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.usages.UsageTarget;
+import com.intellij.usages.UsageTargetProvider;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.SmaliTokens;
+import org.jf.smalidea.psi.impl.SmaliMemberName;
+
+/**
+ * A usage target provider for smali member names consisting of primitive types.
+ *
+ * For member names like IIII, the default logic to find the usage target doesn't work, due to the member
+ * name being split up into multiple leaf tokens.
+ */
+public class SmaliUsageTargetProvider implements UsageTargetProvider {
+ @Nullable @Override public UsageTarget[] getTargets(Editor editor, PsiFile file) {
+ PsiElement element = file.findElementAt(
+ TargetElementUtilBase.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset()));
+ if (element == null) {
+ return null;
+ }
+ return getTargets(element);
+ }
+
+ @Nullable @Override public UsageTarget[] getTargets(PsiElement element) {
+ ASTNode node = element.getNode();
+ if (node == null) {
+ return null;
+ }
+
+ if (node.getElementType() == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof SmaliMemberName) {
+ return new UsageTarget[] { new PsiElement2UsageTargetAdapter(parent.getParent()) };
+ }
+ }
+ return null;
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
index 0252f796..56bbdafb 100644
--- a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
@@ -35,6 +35,7 @@ import com.intellij.lang.cacheBuilder.WordOccurrence;
import com.intellij.lang.cacheBuilder.WordOccurrence.Kind;
import com.intellij.lang.cacheBuilder.WordsScanner;
import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jf.smalidea.SmaliLexer;
@@ -42,6 +43,47 @@ import org.jf.smalidea.SmaliTokens;
public class SmaliWordScanner implements WordsScanner {
+ private static final TokenSet MEMBER_NAME_TOKENS = TokenSet.create(
+ SmaliTokens.MEMBER_NAME,
+ SmaliTokens.SIMPLE_NAME,
+ SmaliTokens.ACCESS_SPEC,
+ SmaliTokens.VERIFICATION_ERROR_TYPE,
+ SmaliTokens.POSITIVE_INTEGER_LITERAL,
+ SmaliTokens.NEGATIVE_INTEGER_LITERAL,
+ SmaliTokens.FLOAT_LITERAL_OR_ID,
+ SmaliTokens.DOUBLE_LITERAL_OR_ID,
+ SmaliTokens.BOOL_LITERAL,
+ SmaliTokens.NULL_LITERAL,
+ SmaliTokens.REGISTER,
+ SmaliTokens.PRIMITIVE_TYPE,
+ SmaliTokens.VOID_TYPE,
+ SmaliTokens.ANNOTATION_VISIBILITY,
+ SmaliTokens.INSTRUCTION_FORMAT10t,
+ SmaliTokens.INSTRUCTION_FORMAT10x,
+ SmaliTokens.INSTRUCTION_FORMAT10x_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT11x,
+ SmaliTokens.INSTRUCTION_FORMAT12x_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT21c_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT21c_FIELD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT21c_STRING,
+ SmaliTokens.INSTRUCTION_FORMAT21c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT21t,
+ SmaliTokens.INSTRUCTION_FORMAT22c_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT22c_FIELD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT22c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT22cs_FIELD,
+ SmaliTokens.INSTRUCTION_FORMAT22s_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT22t,
+ SmaliTokens.INSTRUCTION_FORMAT23x,
+ SmaliTokens.INSTRUCTION_FORMAT31i_OR_ID,
+ SmaliTokens.INSTRUCTION_FORMAT31t,
+ SmaliTokens.INSTRUCTION_FORMAT35c_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT35c_METHOD_ODEX,
+ SmaliTokens.INSTRUCTION_FORMAT35c_TYPE,
+ SmaliTokens.INSTRUCTION_FORMAT35mi_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT35ms_METHOD,
+ SmaliTokens.INSTRUCTION_FORMAT51l);
+
@Override public void processWords(CharSequence fileText, Processor processor) {
SmaliLexer lexer = new SmaliLexer();
lexer.start(fileText);
@@ -50,6 +92,16 @@ public class SmaliWordScanner implements WordsScanner {
while (type != null) {
if (type == SmaliTokens.CLASS_DESCRIPTOR) {
processClassDescriptor(fileText, lexer.getTokenStart(), lexer.getTokenEnd(), processor);
+ } else if (MEMBER_NAME_TOKENS.contains(type)) {
+ processor.process(new WordOccurrence(fileText, lexer.getTokenStart(), lexer.getTokenEnd(), Kind.CODE));
+ } else if (type == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ int tokenStart = lexer.getTokenStart();
+ while (type == SmaliTokens.PARAM_LIST_OR_ID_PRIMITIVE_TYPE) {
+ lexer.advance();
+ type = lexer.getTokenType();
+ }
+ int tokenEnd = lexer.getTokenStart();
+ processor.process(new WordOccurrence(fileText, tokenStart, tokenEnd, Kind.CODE));
}
lexer.advance();
type = lexer.getTokenType();
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
index ffde5bcf..400e509c 100644
--- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliMethod.java
@@ -322,4 +322,12 @@ public class SmaliMethod extends SmaliStubBasedPsiElement
super.subtreeChanged();
methodAnalyzer = null;
}
+
+ @Override public int getTextOffset() {
+ SmaliMemberName smaliMemberName = getNameIdentifier();
+ if (smaliMemberName != null) {
+ return smaliMemberName.getTextOffset();
+ }
+ return super.getTextOffset();
+ }
}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java
new file mode 100644
index 00000000..311c9eef
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindMethodUsagesTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.smalidea.findUsages;
+
+public class FindMethodUsagesTest extends FindUsagesTest {
+ public void testSmaliUsageInSmaliFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blah[Method()V\n" +
+ ".end method");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->blahMethod()V\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testSmaliUsageInJavaFile() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blah][Method()V\n" +
+ ".end method");
+ addFile("blarg.java", "" +
+ "public class blarg {\n" +
+ " public void blargMethod() {\n" +
+ " blah b = new blah();\n" +
+ " b.blahMethod();\n" +
+ " }\n" +
+ "}");
+ doTest();
+ }
+
+ public void testJavaUsageInSmaliFile() throws Exception {
+ addFile("blah.java", "" +
+ "public class blah {\n" +
+ " public void blah][Method() {\n" +
+ " }\n" +
+ "}");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->blahMethod()V\n" +
+ ".end method");
+ doTest();
+ }
+
+ public void testPrimitiveListMethod() throws Exception {
+ addFile("blah.smali", "" +
+ ".class public Lblah;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract II][II()V\n" +
+ ".end method");
+ addFile("blarg.smali", "" +
+ ".class public Lblarg;\n" +
+ ".super Ljava/lang/Object;\n" +
+ ".method abstract blargMethod()V\n" +
+ " invoke-virtual {v0}, Lblah;->IIII()V\n" +
+ ".end method");
+ doTest();
+ }
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java
index 84000505..f4e2b0ff 100644
--- a/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java
+++ b/smalidea/src/test/java/org/jf/smalidea/findUsages/FindUsagesTest.java
@@ -32,6 +32,7 @@
package org.jf.smalidea.findUsages;
import com.google.common.collect.Lists;
+import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.find.FindManager;
import com.intellij.find.findUsages.FindUsagesHandler;
import com.intellij.find.findUsages.FindUsagesManager;
@@ -42,6 +43,9 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.testFramework.PsiTestCase;
import com.intellij.usageView.UsageInfo;
+import com.intellij.usages.PsiElementUsageTarget;
+import com.intellij.usages.UsageTarget;
+import com.intellij.usages.UsageTargetUtil;
import com.intellij.util.CommonProcessors;
import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
@@ -101,18 +105,41 @@ public abstract class FindUsagesTest extends PsiTestCase {
}
protected void doTest() {
+
PsiReference reference = null;
+ PsiElement targetElement = null;
+
for (TestFile testFile: testFiles) {
int refIndex = testFile.getRefIndex();
if (refIndex != -1) {
- reference = testFile.psiFile.findReferenceAt(refIndex);
+ PsiElement element = testFile.psiFile.findElementAt(refIndex);
+
+ UsageTarget[] targets = UsageTargetUtil.findUsageTargets(element);
+ if (targets != null) {
+ for (UsageTarget target : targets) {
+ if (target instanceof PsiElementUsageTarget) {
+ targetElement = ((PsiElementUsageTarget)target).getElement();
+ break;
+ }
+ }
+ }
+
+ if (targetElement == null) {
+ reference = testFile.psiFile.findReferenceAt(refIndex);
+ if (reference != null) {
+ targetElement = reference.resolve();
+ } else {
+ targetElement = TargetElementUtilBase.getInstance().getNamedElement(
+ testFile.psiFile.findElementAt(refIndex), 0);
+ }
+ }
break;
}
}
- Assert.assertNotNull(reference);
+ Assert.assertNotNull(targetElement);
- Collection usages = findUsages(reference);
+ Collection usages = findUsages(targetElement);
for (TestFile testFile: testFiles) {
assertUsages(testFile, usages);
}
@@ -143,27 +170,24 @@ public abstract class FindUsagesTest extends PsiTestCase {
Assert.assertEquals(0, fileUsages.size());
}
- private Collection findUsages(@NotNull PsiReference reference) {
- PsiElement resolved = reference.resolve();
- Assert.assertNotNull(resolved);
-
+ private Collection findUsages(@NotNull PsiElement element) {
FindUsagesManager findUsagesManager =
((FindManagerImpl)FindManager.getInstance(getProject())).getFindUsagesManager();
FindUsagesHandler findUsagesHandler =
- findUsagesManager.getFindUsagesHandler(resolved, false);
+ findUsagesManager.getFindUsagesHandler(element, false);
Assert.assertNotNull(findUsagesHandler);
final FindUsagesOptions options = findUsagesHandler.getFindUsagesOptions();
final CommonProcessors.CollectProcessor processor =
new CommonProcessors.CollectProcessor();
- for (PsiElement element : findUsagesHandler.getPrimaryElements()) {
- findUsagesHandler.processElementUsages(element, processor, options);
+ for (PsiElement primaryElement : findUsagesHandler.getPrimaryElements()) {
+ findUsagesHandler.processElementUsages(primaryElement, processor, options);
}
- for (PsiElement element : findUsagesHandler.getSecondaryElements()) {
- findUsagesHandler.processElementUsages(element, processor, options);
+ for (PsiElement secondaryElement: findUsagesHandler.getSecondaryElements()) {
+ findUsagesHandler.processElementUsages(secondaryElement, processor, options);
}
return processor.getResults();
]