Bug 521960 - An adapter for TextSelection to IVariable
Change-Id: I9982e3a7676e0006c4b3d5f96d0dfdacf5f0e498
diff --git a/org.eclipse.jdt.debug.ui/plugin.xml b/org.eclipse.jdt.debug.ui/plugin.xml
index 5cb7e20..d10637b 100644
--- a/org.eclipse.jdt.debug.ui/plugin.xml
+++ b/org.eclipse.jdt.debug.ui/plugin.xml
@@ -3682,17 +3682,4 @@
</enabledWhen>
</handler>
</extension>
- <extension
- point="org.eclipse.core.runtime.adapters">
- <factory
- adaptableType="org.eclipse.jface.text.TextSelection"
- class="org.eclipse.jdt.internal.debug.ui.SelectionToIVaraibleAdapterFactory">
- <adapter
- type="org.eclipse.debug.core.model.IVariable">
- </adapter>
- </factory>
- </extension>
-
-
-
</plugin>
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/SelectionToIVaraibleAdapterFactory.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/SelectionToIVaraibleAdapterFactory.java
deleted file mode 100644
index 28a49e7..0000000
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/SelectionToIVaraibleAdapterFactory.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017, Red Hat Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation (from JavaDebugHover)
- * Mickael Istria (Red Hat Inc.) - 521960 adaptation from JavaDebugHover
- *******************************************************************************/
-package org.eclipse.jdt.internal.debug.ui;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Optional;
-
-import org.eclipse.core.filebuffers.ITextFileBuffer;
-import org.eclipse.core.filebuffers.ITextFileBufferManager;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.core.runtime.IAdapterFactory;
-import org.eclipse.debug.core.DebugException;
-import org.eclipse.debug.core.model.IVariable;
-import org.eclipse.debug.ui.DebugUITools;
-import org.eclipse.jdt.core.Flags;
-import org.eclipse.jdt.core.IClassFile;
-import org.eclipse.jdt.core.ICodeAssist;
-import org.eclipse.jdt.core.IField;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.ILocalVariable;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.ITypeRoot;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.Signature;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTParser;
-import org.eclipse.jdt.core.dom.FieldAccess;
-import org.eclipse.jdt.core.dom.NodeFinder;
-import org.eclipse.jdt.core.dom.QualifiedName;
-import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
-import org.eclipse.jdt.core.dom.ThisExpression;
-import org.eclipse.jdt.debug.core.IJavaDebugTarget;
-import org.eclipse.jdt.debug.core.IJavaObject;
-import org.eclipse.jdt.debug.core.IJavaReferenceType;
-import org.eclipse.jdt.debug.core.IJavaStackFrame;
-import org.eclipse.jdt.debug.core.IJavaThread;
-import org.eclipse.jdt.debug.core.IJavaType;
-import org.eclipse.jdt.debug.core.IJavaValue;
-import org.eclipse.jdt.debug.core.IJavaVariable;
-import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
-import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIPlaceholderVariable;
-import org.eclipse.jdt.internal.debug.eval.ast.engine.ASTEvaluationEngine;
-import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.jdt.ui.SharedASTProvider;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.Document;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.Region;
-import org.eclipse.jface.text.TextSelection;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-
-public class SelectionToIVaraibleAdapterFactory implements IAdapterFactory {
-
- @Override
- public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
- if (!(adaptableObject instanceof TextSelection)) {
- return null;
- }
- if (!adapterType.isAssignableFrom(IVariable.class)) {
- return null;
- }
- TextSelection selection = (TextSelection) adaptableObject;
- IDocument document = null;
- try {
- Field documentField = TextSelection.class.getDeclaredField("fDocument"); //$NON-NLS-1$
- documentField.setAccessible(true);
- document = (Document) documentField.get(selection);
- }
- catch (Exception e) {
- JavaPlugin.log(e);
- }
- if (document == null) {
- return null;
- }
- return adapterType.cast(getVariable(document, new Region(selection.getOffset(), selection.getLength())));
- }
-
- @Override
- public Class<?>[] getAdapterList() {
- return new Class<?>[] { IVariable.class };
- }
-
- /**
- * Returns the stack frame in which to search for variables, or <code>null</code> if none.
- *
- * @return the stack frame in which to search for variables, or <code>null</code> if none
- */
- protected IJavaStackFrame getFrame() {
- IAdaptable adaptable = DebugUITools.getDebugContext();
- if (adaptable != null) {
- return adaptable.getAdapter(IJavaStackFrame.class);
- }
- return null;
- }
-
- private IVariable getVariable(IDocument document, IRegion region) {
- IJavaStackFrame frame = getFrame();
- if (frame == null) {
- return null;
- }
- String variableName = null;
- try {
- variableName = document.get(region.getOffset(), region.getLength());
- }
- catch (BadLocationException e) {
- return null;
- }
- if (variableName.equals("this")) { //$NON-NLS-1$
- try {
- IJavaVariable variable = frame.findVariable(variableName);
- if (variable != null) {
- return variable;
- }
- }
- catch (DebugException e) {
- JavaPlugin.log(e);
- return null;
- }
- }
- ICodeAssist codeAssist = getCodeAssist(document);
- if (codeAssist == null) {
- return findLocalVariable(frame, variableName);
- }
-
- IJavaElement[] resolve = null;
- try {
- resolve = codeAssist.codeSelect(region.getOffset(), 0);
- }
- catch (JavaModelException e1) {
- resolve = new IJavaElement[0];
- }
- try {
- for (int i = 0; i < resolve.length; i++) {
- IJavaElement javaElement = resolve[i];
- if (javaElement instanceof IField) {
- IField field = (IField) javaElement;
- IJavaVariable variable = null;
- IJavaDebugTarget debugTarget = (IJavaDebugTarget) frame.getDebugTarget();
- if (Flags.isStatic(field.getFlags())) {
- IJavaType[] javaTypes = debugTarget.getJavaTypes(field.getDeclaringType().getFullyQualifiedName());
- if (javaTypes != null) {
- for (int j = 0; j < javaTypes.length; j++) {
- IJavaType type = javaTypes[j];
- if (type instanceof IJavaReferenceType) {
- IJavaReferenceType referenceType = (IJavaReferenceType) type;
- variable = referenceType.getField(field.getElementName());
- }
- if (variable != null) {
- break;
- }
- }
- }
- if (variable == null) {
- // the class is not loaded yet, but may be an in-lined primitive constant
- Object constant = field.getConstant();
- if (constant != null) {
- IJavaValue value = null;
- if (constant instanceof Integer) {
- value = debugTarget.newValue(((Integer) constant).intValue());
- } else if (constant instanceof Byte) {
- value = debugTarget.newValue(((Byte) constant).byteValue());
- } else if (constant instanceof Boolean) {
- value = debugTarget.newValue(((Boolean) constant).booleanValue());
- } else if (constant instanceof Character) {
- value = debugTarget.newValue(((Character) constant).charValue());
- } else if (constant instanceof Double) {
- value = debugTarget.newValue(((Double) constant).doubleValue());
- } else if (constant instanceof Float) {
- value = debugTarget.newValue(((Float) constant).floatValue());
- } else if (constant instanceof Long) {
- value = debugTarget.newValue(((Long) constant).longValue());
- } else if (constant instanceof Short) {
- value = debugTarget.newValue(((Short) constant).shortValue());
- } else if (constant instanceof String) {
- value = debugTarget.newValue((String) constant);
- }
- if (value != null) {
- variable = new JDIPlaceholderVariable(field.getElementName(), value);
- }
- }
- if (variable == null) {
- return null; // class not loaded yet and not a constant
- }
- }
- } else {
- if (!frame.isStatic() && !frame.isNative()) {
- // ensure that we only resolve a field access on 'this':
- if (!(codeAssist instanceof ITypeRoot)) {
- return null;
- }
- ITypeRoot typeRoot = (ITypeRoot) codeAssist;
- ASTNode root = SharedASTProvider.getAST(typeRoot, SharedASTProvider.WAIT_NO, null);
- if (root == null) {
- ASTParser parser = ASTParser.newParser(AST.JLS9);
- parser.setSource(typeRoot);
- parser.setFocalPosition(region.getOffset());
- root = parser.createAST(null);
- }
- ASTNode node = NodeFinder.perform(root, region.getOffset(), region.getLength());
- if (node == null) {
- return null;
- }
- StructuralPropertyDescriptor locationInParent = node.getLocationInParent();
- if (locationInParent == FieldAccess.NAME_PROPERTY) {
- FieldAccess fieldAccess = (FieldAccess) node.getParent();
- if (!(fieldAccess.getExpression() instanceof ThisExpression)) {
- return null;
- }
- } else if (locationInParent == QualifiedName.NAME_PROPERTY) {
- return null;
- }
-
- String typeSignature = Signature.createTypeSignature(field.getDeclaringType().getFullyQualifiedName(), true);
- typeSignature = typeSignature.replace('.', '/');
- IJavaObject ths = frame.getThis();
- if (ths != null) {
- variable = ths.getField(field.getElementName(), typeSignature);
- }
- }
- }
- if (variable != null) {
- return variable;
- }
- break;
- }
- if (javaElement instanceof ILocalVariable) {
- ILocalVariable var = (ILocalVariable) javaElement;
- IJavaElement parent = var.getParent();
- while (!(parent instanceof IMethod) && parent != null) {
- parent = parent.getParent();
- }
- if (parent instanceof IMethod) {
- IMethod method = (IMethod) parent;
- boolean equal = false;
- if (method.isBinary()) {
- // compare resolved signatures
- if (method.getSignature().equals(frame.getSignature())) {
- equal = true;
- }
- } else {
- // compare unresolved signatures
-
- // Frames in classes with generics have declaringTypeName like class<V>
- // We must get rid of this '<V>' for proper comparison
- String frameDeclaringTypeName = frame.getDeclaringTypeName();
- int genericPartOffset = frameDeclaringTypeName.indexOf('<');
- if (genericPartOffset != -1) {
- frameDeclaringTypeName = frameDeclaringTypeName.substring(0, genericPartOffset);
- }
-
- if (((frame.isConstructor() && method.isConstructor()) || frame.getMethodName().equals(method.getElementName()))
- && frameDeclaringTypeName.endsWith(method.getDeclaringType().getElementName())
- && frame.getArgumentTypeNames().size() == method.getNumberOfParameters()) {
- equal = true;
- } else { // Finding variables in anonymous class
- int index = frame.getDeclaringTypeName().indexOf('$');
- if (index > 0) {
- String name = frame.getDeclaringTypeName().substring(index + 1);
- try {
- Integer.getInteger(name);
- return findLocalVariable(frame, ASTEvaluationEngine.ANONYMOUS_VAR_PREFIX + var.getElementName());
- }
- catch (NumberFormatException ex) {
- }
- }
- }
- }
- // find variable if equal or method is a Lambda Method
- if (equal || method.isLambdaMethod()) {
- return findLocalVariable(frame, var.getElementName());
- }
- }
- break;
- }
- }
- }
- catch (CoreException e) {
- JDIDebugPlugin.log(e);
- }
- return null;
- }
-
- private ICodeAssist getCodeAssist(IEditorInput input) {
- if (input == null) {
- return null;
- }
- Object element = JavaUI.getWorkingCopyManager().getWorkingCopy(input);
- if (element == null) {
- element = input.getAdapter(IClassFile.class);
- }
- if (element instanceof ICodeAssist) {
- return ((ICodeAssist) element);
- }
- return null;
- }
-
- private ICodeAssist getCodeAssist(IDocument document) {
- ITextFileBuffer textFileBuffer = ITextFileBufferManager.DEFAULT.getTextFileBuffer(document);
- if (textFileBuffer == null) {
- return null;
- }
- Optional<ICodeAssist> codeAssist = Arrays.stream(PlatformUI.getWorkbench().getWorkbenchWindows())
- .flatMap(window -> Arrays.stream(window.getPages()))
- .flatMap(page -> Arrays.stream(page.getEditorReferences())).filter(editor -> {
- try {
- return matches(editor.getEditorInput(), textFileBuffer);
- }
- catch (PartInitException e1) {
- JavaPlugin.log(e1);
- return false;
- }
- })
- .filter(editor -> editor.getEditor(false) != null) // editor that are initialized only
- .map(ref -> {
- try {
- return ref.getEditorInput();
- }
- catch (PartInitException e) {
- JavaPlugin.log(e);
- return null;
- }
- }).map(this::getCodeAssist)
- .filter(Objects::nonNull)
- .distinct()
- .findAny();
- if (codeAssist.isPresent()) {
- return codeAssist.get();
- }
- return null;
- }
-
- private boolean matches(IEditorInput input, ITextFileBuffer textFileBuffer) {
- if (input instanceof IFileEditorInput && textFileBuffer.getLocation().equals(((IFileEditorInput) input).getFile().getFullPath())) {
- return true;
- }
- // TODO maybe map URIs and other kinds of input
- return false;
- }
-
- /**
- * Returns a local variable in the given frame based on the the given name or <code>null</code> if none.
- *
- * @return local variable or <code>null</code>
- */
- private IVariable findLocalVariable(IJavaStackFrame frame, String variableName) {
- if (frame != null) {
- try {
- return frame.findVariable(variableName);
- }
- catch (DebugException x) {
- if (x.getStatus().getCode() != IJavaThread.ERR_THREAD_NOT_SUSPENDED) {
- JDIDebugUIPlugin.log(x);
- }
- }
- }
- return null;
- }
-
-
-}