diff --git a/smalidea/META-INF/plugin.xml b/smalidea/META-INF/plugin.xml
index 4d11ec8c..a13d0d19 100644
--- a/smalidea/META-INF/plugin.xml
+++ b/smalidea/META-INF/plugin.xml
@@ -26,6 +26,9 @@
implementation="org.jf.smalidea.debugging.SmaliDebuggerSupport"/>
+
+
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java
new file mode 100644
index 00000000..56dbabb1
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java
@@ -0,0 +1,97 @@
+/*
+ * 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.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.QueryExecutorBase;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.search.LowLevelSearchUtil;
+import com.intellij.psi.search.*;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
+import com.intellij.util.Processor;
+import com.intellij.util.text.StringSearcher;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.util.NameUtils;
+
+public class SmaliClassReferenceSearcher extends QueryExecutorBase {
+ @Override public void processQuery(final SearchParameters queryParameters, final Processor consumer) {
+ final PsiElement element = queryParameters.getElementToSearch();
+ if (!(element instanceof PsiClass)) {
+ return;
+ }
+
+ String qualifiedName = ApplicationManager.getApplication().runReadAction(
+ new Computable() {
+ @Override public String compute() {
+ return ((PsiClass)element).getQualifiedName();
+ }
+ });
+ if (qualifiedName == null) {
+ return;
+ }
+
+ String smaliType = NameUtils.javaToSmaliType(qualifiedName);
+
+ final StringSearcher stringSearcher = new StringSearcher(smaliType, true, true, false, false);
+
+ final SingleTargetRequestResultProcessor processor = new SingleTargetRequestResultProcessor(element);
+
+ // TODO: is it possible to get a LocalSearchScope here? If so, how to handle it?
+ if (!(queryParameters.getEffectiveSearchScope() instanceof GlobalSearchScope)) {
+ return;
+ }
+
+ PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(element.getProject());
+ // TODO: limit search scope to only smali files. See, e.g. AnnotatedPackagesSearcher.PackageInfoFilesOnly
+ helper.processAllFilesWithWord(smaliType, (GlobalSearchScope)queryParameters.getEffectiveSearchScope(),
+ new Processor() {
+ @Override
+ public boolean process(PsiFile file) {
+ LowLevelSearchUtil.processElementsContainingWordInElement(
+ new TextOccurenceProcessor() {
+ @Override public boolean execute(
+ @NotNull PsiElement element, int offsetInElement) {
+ return processor.processTextOccurrence(element, offsetInElement, consumer);
+ }
+ },
+ file, stringSearcher, true, new EmptyProgressIndicator());
+ return true;
+ }
+ }, true);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java
new file mode 100644
index 00000000..818ee403
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java
@@ -0,0 +1,81 @@
+/*
+ * 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.find.impl.HelpID;
+import com.intellij.lang.LangBundle;
+import com.intellij.lang.cacheBuilder.WordsScanner;
+import com.intellij.lang.findUsages.FindUsagesProvider;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class SmaliFindUsagesProvider implements FindUsagesProvider {
+ @Override public boolean canFindUsagesFor(@NotNull PsiElement element) {
+ return element instanceof PsiClass;
+ }
+
+ @Nullable @Override public WordsScanner getWordsScanner() {
+ return new SmaliWordScanner();
+ }
+
+ @Nullable @Override public String getHelpId(@NotNull PsiElement element) {
+ return HelpID.FIND_CLASS_USAGES;
+ }
+
+ @NotNull @Override public String getType(@NotNull PsiElement element) {
+ return LangBundle.message("java.terms.class");
+ }
+
+ @NotNull @Override public String getDescriptiveName(@NotNull PsiElement element) {
+ PsiClass psiClass = (PsiClass)element;
+ String qualifiedName = psiClass.getQualifiedName();
+ if (qualifiedName != null) {
+ return qualifiedName;
+ }
+ return psiClass.getName();
+ }
+
+ @NotNull @Override public String getNodeText(@NotNull PsiElement element, boolean onlyQualifiedNames) {
+ PsiClass psiClass = (PsiClass)element;
+ String qualifiedName = psiClass.getQualifiedName();
+ if (qualifiedName != null) {
+ return qualifiedName;
+ } else if (onlyQualifiedNames) {
+ return "";
+ }
+ return psiClass.getName();
+ }
+
+
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
new file mode 100644
index 00000000..0252f796
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java
@@ -0,0 +1,66 @@
+/*
+ * 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.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.util.Processor;
+import org.jetbrains.annotations.NotNull;
+import org.jf.smalidea.SmaliLexer;
+import org.jf.smalidea.SmaliTokens;
+
+public class SmaliWordScanner implements WordsScanner {
+
+ @Override public void processWords(CharSequence fileText, Processor processor) {
+ SmaliLexer lexer = new SmaliLexer();
+ lexer.start(fileText);
+
+ IElementType type = lexer.getTokenType();
+ while (type != null) {
+ if (type == SmaliTokens.CLASS_DESCRIPTOR) {
+ processClassDescriptor(fileText, lexer.getTokenStart(), lexer.getTokenEnd(), processor);
+ }
+ lexer.advance();
+ type = lexer.getTokenType();
+ }
+ }
+
+ private void processClassDescriptor(CharSequence fileText, int tokenStart, int tokenEnd,
+ @NotNull Processor processor) {
+ CharSequence tokenText = fileText.subSequence(tokenStart, tokenEnd);
+
+ assert tokenText.charAt(0) == 'L' && tokenText.charAt(tokenText.length()-1) == ';';
+ processor.process(new WordOccurrence(fileText, tokenStart, tokenEnd, Kind.CODE));
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java
index b9e075c1..cdd68e12 100644
--- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliAnnotation.java
@@ -73,6 +73,7 @@ public class SmaliAnnotation extends SmaliStubBasedPsiElement