From 694fb7ca906eb67a19a2f2483dba7a326796cace Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Sun, 8 Mar 2015 12:06:17 -0700 Subject: [PATCH] Add initial support for finding class usages in smali code --- smalidea/META-INF/plugin.xml | 3 + .../SmaliClassReferenceSearcher.java | 97 +++++++++++++++++++ .../findUsages/SmaliFindUsagesProvider.java | 81 ++++++++++++++++ .../smalidea/findUsages/SmaliWordScanner.java | 66 +++++++++++++ .../jf/smalidea/psi/impl/SmaliAnnotation.java | 1 + .../psi/impl/SmaliClassTypeElement.java | 2 +- 6 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliClassReferenceSearcher.java create mode 100644 smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliFindUsagesProvider.java create mode 100644 smalidea/src/main/java/org/jf/smalidea/findUsages/SmaliWordScanner.java 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