mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 06:05:01 +07:00
IDEA-157065 "Jump to type source" doesn't work for lambdas
This commit is contained in:
@@ -21,6 +21,8 @@ import com.intellij.debugger.engine.JVMNameUtil;
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
|
||||
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.jdi.MethodBytecodeUtil;
|
||||
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
|
||||
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
|
||||
import com.intellij.debugger.ui.tree.ValueDescriptor;
|
||||
@@ -32,6 +34,11 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.sun.jdi.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class JumpToObjectAction extends DebuggerAction{
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JumpToObjectAction");
|
||||
@@ -96,7 +103,35 @@ public class JumpToObjectAction extends DebuggerAction{
|
||||
}
|
||||
if(type instanceof ClassType) {
|
||||
final ClassType clsType = (ClassType)type;
|
||||
final Location location = ContainerUtil.getFirstItem(clsType.allLineLocations());
|
||||
Location lambdaLocation = null;
|
||||
if (DebuggerUtilsEx.isLambdaClassName(clsType.name())) {
|
||||
List<Method> notConstructorMethods = ContainerUtil.filter(clsType.methods(), m -> !m.isConstructor());
|
||||
if (notConstructorMethods.size() == 1) {
|
||||
AtomicReference<Location> locationRef = new AtomicReference<>();
|
||||
MethodBytecodeUtil.visit(clsType, notConstructorMethods.get(0), new MethodVisitor(Opcodes.ASM5) {
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
ReferenceType cls = ContainerUtil.getFirstItem(clsType.virtualMachine().classesByName(owner));
|
||||
if (cls != null) {
|
||||
Method method = ContainerUtil.getFirstItem(cls.methodsByName(name));
|
||||
if (method != null) {
|
||||
try {
|
||||
Location loc = ContainerUtil.getFirstItem(method.allLineLocations());
|
||||
if (loc != null) {
|
||||
locationRef.set(loc);
|
||||
}
|
||||
}
|
||||
catch (AbsentInformationException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
lambdaLocation = locationRef.get();
|
||||
}
|
||||
}
|
||||
final Location location = lambdaLocation != null ? lambdaLocation : ContainerUtil.getFirstItem(clsType.allLineLocations());
|
||||
if (location != null) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
|
||||
@Override
|
||||
@@ -118,10 +153,7 @@ public class JumpToObjectAction extends DebuggerAction{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ClassNotPreparedException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch (AbsentInformationException e) {
|
||||
catch (ClassNotPreparedException | AbsentInformationException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.debugger.jdi;
|
||||
|
||||
import com.sun.jdi.ClassType;
|
||||
import com.sun.jdi.Method;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
public class MethodBytecodeUtil {
|
||||
private MethodBytecodeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to use ASM MethodVisitor with jdi method bytecode
|
||||
*/
|
||||
public static void visit(ClassType classType, Method method, MethodVisitor methodVisitor) {
|
||||
try {
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos)) {
|
||||
dos.writeInt(0xCAFEBABE); // magic
|
||||
dos.writeInt(Opcodes.V1_8); // version
|
||||
dos.writeShort(classType.constantPoolCount()); // constant_pool_count
|
||||
dos.write(classType.constantPool()); // constant_pool
|
||||
|
||||
// we generate and put code attribute right after the constant pool
|
||||
byte[] bytecodes = method.bytecodes();
|
||||
int codeSize = dos.size();
|
||||
dos.writeShort(0); // max_stack
|
||||
dos.writeShort(0); // max_locals
|
||||
dos.writeInt(bytecodes.length); // code_length
|
||||
dos.write(bytecodes); // code
|
||||
dos.writeShort(0); // exception_table_length
|
||||
dos.writeShort(0); // attributes_count
|
||||
codeSize = dos.size() - codeSize;
|
||||
|
||||
ClassReader clsReader = new ClassReader(bos.toByteArray());
|
||||
ClassWriter clsWriter = new ClassWriter(clsReader, 0);
|
||||
clsWriter.visit(Opcodes.V1_8,
|
||||
Opcodes.ACC_PUBLIC,
|
||||
classType.name(),
|
||||
classType.signature(),
|
||||
classType.superclass().name(),
|
||||
classType.interfaces().stream().map(ReferenceType::name).toArray(String[]::new));
|
||||
MethodVisitor mv = clsWriter.visitMethod(Opcodes.ACC_PUBLIC, method.name(), method.signature(), method.signature(), null);
|
||||
mv.visitAttribute(createCode(clsReader, codeSize));
|
||||
|
||||
new ClassReader(clsWriter.toByteArray()).accept(new ClassVisitor(Opcodes.ASM5) {
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
return methodVisitor;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static Attribute createCode(ClassReader cr, int len) {
|
||||
return new Attribute("Code") {
|
||||
@Override
|
||||
public Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
|
||||
return super.read(cr, off, len, buf, codeOff, labels);
|
||||
}
|
||||
}.read(cr, cr.header, len, null, 0, null);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user