| /* |
| * Copyright 2014, 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.debugging; |
| |
| import com.intellij.debugger.NoDataException; |
| import com.intellij.debugger.PositionManager; |
| import com.intellij.debugger.SourcePosition; |
| import com.intellij.debugger.engine.DebugProcess; |
| import com.intellij.debugger.requests.ClassPrepareRequestor; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.util.Computable; |
| import com.intellij.psi.PsiFile; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.sun.jdi.Location; |
| import com.sun.jdi.ReferenceType; |
| import com.sun.jdi.request.ClassPrepareRequest; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jf.smalidea.psi.impl.SmaliClass; |
| import org.jf.smalidea.psi.impl.SmaliFile; |
| import org.jf.smalidea.psi.impl.SmaliMethod; |
| import org.jf.smalidea.psi.index.SmaliClassNameIndex; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| public class SmaliPositionManager implements PositionManager { |
| private final DebugProcess debugProcess; |
| |
| public SmaliPositionManager(DebugProcess debugProcess) { |
| this.debugProcess = debugProcess; |
| } |
| |
| public SourcePosition getSourcePosition(final String declaringType, String methodName, String methodSignature, |
| int codeIndex) throws NoDataException { |
| |
| Collection<SmaliClass> classes = ApplicationManager.getApplication().runReadAction( |
| new Computable<Collection<SmaliClass>>() { |
| @Override public Collection<SmaliClass> compute() { |
| return SmaliClassNameIndex.INSTANCE.get(declaringType, debugProcess.getProject(), |
| GlobalSearchScope.projectScope(debugProcess.getProject())); |
| } |
| }); |
| |
| if (classes.size() > 0) { |
| SmaliClass smaliClass = classes.iterator().next(); |
| |
| // TODO: make an index for this? |
| for (SmaliMethod smaliMethod: smaliClass.getMethods()) { |
| if (smaliMethod.getName().equals(methodName) && |
| smaliMethod.getMethodPrototype().getText().equals(methodSignature)) { |
| return smaliMethod.getSourcePositionForCodeOffset(codeIndex * 2); |
| } |
| } |
| } |
| |
| throw NoDataException.INSTANCE; |
| } |
| |
| @Override |
| public SourcePosition getSourcePosition(@Nullable Location location) throws NoDataException { |
| if (location == null) { |
| throw NoDataException.INSTANCE; |
| } |
| |
| return getSourcePosition(location.declaringType().name(), location.method().name(), |
| location.method().signature(), (int)location.codeIndex()); |
| } |
| |
| @Override @NotNull |
| public List<ReferenceType> getAllClasses(@NotNull SourcePosition classPosition) throws NoDataException { |
| if (!(classPosition.getElementAt().getContainingFile() instanceof SmaliFile)) { |
| throw NoDataException.INSTANCE; |
| } |
| |
| String className = getClassFromPosition(classPosition); |
| return debugProcess.getVirtualMachineProxy().classesByName(className); |
| } |
| |
| @NotNull |
| private String getClassFromPosition(@NotNull final SourcePosition position) { |
| return ApplicationManager.getApplication().runReadAction(new Computable<String>() { |
| @Override public String compute() { |
| SmaliClass smaliClass = ((SmaliFile)position.getElementAt().getContainingFile()).getPsiClass(); |
| if (smaliClass == null) { |
| return ""; |
| } |
| return smaliClass.getQualifiedName(); |
| } |
| }); |
| } |
| |
| @Override @NotNull |
| public List<Location> locationsOfLine(@NotNull final ReferenceType type, |
| @NotNull final SourcePosition position) throws NoDataException { |
| PsiFile containingFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() { |
| @Override public PsiFile compute() { |
| return position.getElementAt().getContainingFile(); |
| } |
| }); |
| |
| if (!(containingFile instanceof SmaliFile)) { |
| throw NoDataException.INSTANCE; |
| } |
| |
| final ArrayList<Location> locations = new ArrayList<Location>(1); |
| |
| ApplicationManager.getApplication().runReadAction(new Runnable() { |
| @Override |
| public void run() { |
| |
| |
| String typeName = type.name(); |
| Collection<SmaliClass> classes = SmaliClassNameIndex.INSTANCE.get(typeName, debugProcess.getProject(), |
| GlobalSearchScope.projectScope(debugProcess.getProject())); |
| |
| if (classes.size() > 0) { |
| final SmaliClass smaliClass = classes.iterator().next(); |
| |
| Location location = smaliClass.getLocationForSourcePosition(type, position); |
| |
| if (location != null) { |
| locations.add(location); |
| } |
| } |
| } |
| }); |
| return locations; |
| } |
| |
| @Override |
| public ClassPrepareRequest createPrepareRequest(@NotNull final ClassPrepareRequestor requestor, |
| @NotNull final SourcePosition position) throws NoDataException { |
| Computable<Boolean> isSmaliFile = new Computable<Boolean>() { |
| @Override |
| public Boolean compute() { |
| return position.getFile() instanceof SmaliFile; |
| } |
| }; |
| |
| ApplicationManager.getApplication().runReadAction(isSmaliFile); |
| |
| if (!isSmaliFile.compute()) { |
| throw NoDataException.INSTANCE; |
| } |
| |
| String className = getClassFromPosition(position); |
| return debugProcess.getRequestsManager().createClassPrepareRequest(new ClassPrepareRequestor() { |
| @Override |
| public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) { |
| requestor.processClassPrepare(debuggerProcess, referenceType); |
| } |
| }, className); |
| } |
| } |