/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.ide.ext.java.jdt.internal.core; import org.eclipse.che.ide.ext.java.jdt.core.Signature; import org.eclipse.che.ide.ext.java.jdt.core.compiler.CategorizedProblem; import org.eclipse.che.ide.ext.java.jdt.core.compiler.CharOperation; import org.eclipse.che.ide.ext.java.jdt.core.dom.ASTNode; import org.eclipse.che.ide.ext.java.jdt.core.dom.AbstractTypeDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.AnnotationTypeMemberDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.BodyDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.CompilationUnit; import org.eclipse.che.ide.ext.java.jdt.core.dom.DefaultBindingResolver; import org.eclipse.che.ide.ext.java.jdt.core.dom.ITypeBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.IVariableBinding; import org.eclipse.che.ide.ext.java.jdt.core.dom.MethodDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.che.ide.ext.java.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.che.ide.ext.java.jdt.internal.codeassist.ISelectionRequestor; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.Argument; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.TypeReference; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.FieldBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.LocalTypeBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.LocalVariableBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.che.ide.ext.java.jdt.internal.compiler.lookup.TypeVariableBinding; import java.util.List; import java.util.Map; import static org.eclipse.che.ide.ext.java.jdt.internal.core.SelectionResult.Type; /** * Implementation of <code>ISelectionRequestor</code> to assist with * code resolve in a compilation unit. Translates names to elements. */ public class SelectionRequestor implements ISelectionRequestor { private CompilationUnit compilationUnit; private String content; private SelectionResult selectionResult; // /* // * The name lookup facility used to resolve packages // */ // protected NameLookup nameLookup; /* * The compilation unit or class file we are resolving in */ // protected Openable openable; /* * The collection of resolved elements. */ // protected IJavaElement[] elements = JavaElement.NO_ELEMENTS; // protected int elementIndex = -1; // protected HandleFactory handleFactory = new HandleFactory(); /** * Creates a selection requestor that uses that given * name lookup facility to resolve names. * <p/> * Fix for 1FVXGDK */ public SelectionRequestor(CompilationUnit compilationUnit, String content) { super(); // this.nameLookup = nameLookup; // this.openable = openable; this.compilationUnit = compilationUnit; this.content = content; } /** * Resolve the type. */ public void acceptType(char[] packageName, char[] typeName, int modifiers, boolean isDeclaration, char[] uniqueKey, int start, int end) { String key; if (uniqueKey == null) { key = "L" + new String(packageName).replaceAll("\\.", "/") + "/" + new String(typeName) + ";"; } else { key = new String(uniqueKey); } ASTNode node = compilationUnit.findDeclaringNode(key); if (node == null) { String binaryName = new String(packageName) + "."; String name = new String(typeName); if (name.contains(".")) { name = name.replaceAll("\\.", "\\$"); } binaryName += name; DefaultBindingResolver resolver = ((DefaultBindingResolver)compilationUnit.getAST().getBindingResolver()); Map bindingsToAstNodes = resolver.bindingsToAstNodes; for (Object o : bindingsToAstNodes.keySet()) { if (o instanceof ITypeBinding) { ITypeBinding binding = ((ITypeBinding)o); if (binding.getBinaryName().equals(binaryName)) { node = (ASTNode)bindingsToAstNodes.get(binding); key = binding.getKey(); break; } } } } int offset = -1; boolean source = false; if (node != null) { AbstractTypeDeclaration field = (AbstractTypeDeclaration)node; offset = field.getName().getStartPosition(); source = true; } String fqn = ""; if (packageName.length > 0) { fqn = new String(packageName) + "."; } fqn += new String(typeName); selectionResult = new SelectionResult(Type.CLASS, fqn, key, offset, isDeclaration, source); } /** */ public void acceptError(CategorizedProblem error) { System.out.println(error); // do nothing } /** * Resolve the field. */ public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, boolean isDeclaration, char[] uniqueKey, int start, int end) { ASTNode node = null; String key = null; String className = new String(declaringTypeName); if (uniqueKey != null) { key = Signature.getTypeErasure(new String(uniqueKey)); node = compilationUnit.findDeclaringNode(key); } else { String fieldName = new String(name); DefaultBindingResolver resolver = ((DefaultBindingResolver)compilationUnit.getAST().getBindingResolver()); Map bindingsToAstNodes = resolver.bindingsToAstNodes; for (Object o : bindingsToAstNodes.keySet()) { if (o instanceof IVariableBinding) { IVariableBinding binding = (IVariableBinding)o; if (binding.isField()) { if (binding.getDeclaringClass().getName().equals(className) && binding.getName().equals(fieldName)) { node = (ASTNode)bindingsToAstNodes.get(o); break; } } } } } int offset = -1; boolean source = false; if (node != null) { VariableDeclarationFragment field = (VariableDeclarationFragment)node; offset = field.getName().getStartPosition(); source = true; } String fqn = ""; if (declaringTypePackageName.length > 0) { fqn = new String(declaringTypePackageName) + "."; } fqn += className; selectionResult = new SelectionResult(Type.FIELD, fqn, key, offset, isDeclaration, source); } public void acceptLocalField(FieldBinding fieldBinding) { String key = String.valueOf(fieldBinding.computeUniqueKey()); if (fieldBinding.declaringClass instanceof ParameterizedTypeBinding) { LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)fieldBinding.declaringClass).genericType(); FieldBinding field = localTypeBinding.getField(fieldBinding.name, false); key = String.valueOf(field.computeUniqueKey()); } ASTNode node = compilationUnit.findDeclaringNode(key); int offset = -1; boolean source = false; if (node != null) { VariableDeclarationFragment field = (VariableDeclarationFragment)node; offset = field.getName().getStartPosition(); source = true; } String fqn = null; // if(fieldBinding.length > 0){ // fqn = new String(declaringTypePackageName) + "."; // } // fqn += new String(declaringTypeName); selectionResult = new SelectionResult(Type.FIELD, fqn, key, offset, true, source); } public void acceptLocalMethod(MethodBinding methodBinding) { String key = String.valueOf(methodBinding.computeUniqueKey()); ASTNode node = compilationUnit.findDeclaringNode(key); String classSignature = new String(methodBinding.declaringClass.computeUniqueKey()); String methodSignature = String.valueOf(methodBinding.signature()); if (node == null) { node = compilationUnit.findDeclaringNode( classSignature + ".(" + classSignature.substring(0, classSignature.indexOf("$")) + ";" + methodSignature.substring(1)); } int offset = -1; boolean source = false; if (node != null) { MethodDeclaration declaration = ((MethodDeclaration)node); offset = declaration.getName().getStartPosition(); source = true; } selectionResult = new SelectionResult(Type.METHOD, Signature.toString(classSignature.replace('/', '.')), methodSignature, offset, false, source); } public void acceptLocalType(TypeBinding typeBinding) { String key = String.valueOf(typeBinding.computeUniqueKey()); ASTNode node = compilationUnit.findDeclaringNode(key); if (node == null) { node = compilationUnit.findDeclaringNode(String.valueOf(typeBinding.signature())); } if (node == null) { if (typeBinding instanceof ParameterizedTypeBinding) { LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeBinding).genericType(); node = compilationUnit.findDeclaringNode(new String(localTypeBinding.computeUniqueKey())); } } int offset = -1; boolean source = false; if (node != null) { AbstractTypeDeclaration type = (AbstractTypeDeclaration)node; offset = type.getName().getStartPosition(); source = true; } String fqn = Signature.toString(new String(typeBinding.signature()).replace('/', '.')); selectionResult = new SelectionResult(Type.CLASS, fqn, key, offset, false, source); } private String getFqnEnclosing(ReferenceBinding binding) { String encl = ""; if (binding.isLocalType()) { encl = getFqnEnclosing(binding.enclosingType()); } String s = new String(binding.sourceName()); if (!encl.isEmpty()) { s = encl + "$" + s; } return s; } public void acceptLocalTypeParameter(TypeVariableBinding typeVariableBinding) { // IJavaElement res; // if(typeVariableBinding.declaringElement instanceof ParameterizedTypeBinding) { // LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeVariableBinding.declaringElement) // .genericType(); // res = findLocalElement(localTypeBinding.sourceStart()); // } else { // SourceTypeBinding typeBinding = (SourceTypeBinding)typeVariableBinding.declaringElement; // res = findLocalElement(typeBinding.sourceStart()); // } // if (res != null && res.getElementType() == IJavaElement.TYPE) { // IType type = (IType) res; // ITypeParameter typeParameter = type.getTypeParameter(new String(typeVariableBinding.sourceName)); // if (typeParameter.exists()) { // addElement(typeParameter); // if(SelectionEngine.DEBUG){ // System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$ // System.out.print(typeParameter.toString()); // System.out.println(")"); //$NON-NLS-1$ // } // } // } System.out.println("SelectionRequestor.acceptLocalTypeParameter"); System.out.println(typeVariableBinding); } public void acceptLocalMethodTypeParameter(TypeVariableBinding typeVariableBinding) { // MethodBinding methodBinding = (MethodBinding)typeVariableBinding.declaringElement; // IJavaElement res = findLocalElement(methodBinding.sourceStart()); // if(res != null && res.getElementType() == IJavaElement.METHOD) { // IMethod method = (IMethod) res; // // ITypeParameter typeParameter = method.getTypeParameter(new String(typeVariableBinding.sourceName)); // if (typeParameter.exists()) { // addElement(typeParameter); // if(SelectionEngine.DEBUG){ // System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$ // System.out.print(typeParameter.toString()); // System.out.println(")"); //$NON-NLS-1$ // } // } // } System.out.println("SelectionRequestor.acceptLocalMethodTypeParameter"); System.out.println(typeVariableBinding); } public void acceptLocalVariable(LocalVariableBinding binding) { LocalDeclaration declaration = binding.declaration; String key = String.valueOf(binding.computeUniqueKey()); ASTNode node = compilationUnit.findDeclaringNode(key); int offset = -1; boolean source = true; if (node != null) { if (node instanceof SingleVariableDeclaration) { SingleVariableDeclaration field = (SingleVariableDeclaration)node; offset = field.getName().getStartPosition(); } else if (node instanceof VariableDeclarationFragment) { offset = ((VariableDeclarationFragment)node).getName().getStartPosition(); } } else { String substring = content.substring(declaration.declarationSourceStart, declaration.declarationSourceEnd); offset = declaration.declarationSourceStart + substring.indexOf(String.valueOf(binding.name)); } selectionResult = new SelectionResult(Type.VARIABLE, null, key, offset, false, source); } /** * Resolve the method */ public void acceptMethod( char[] declaringTypePackageName, char[] declaringTypeName, String enclosingDeclaringTypeSignature, char[] selector, char[][] parameterPackageNames, char[][] parameterTypeNames, String[] parameterSignatures, char[][] typeParameterNames, char[][][] typeParameterBoundNames, boolean isConstructor, boolean isDeclaration, char[] uniqueKey, int start, int end, TypeDeclaration typeDeclaration) { String key = String.valueOf(uniqueKey); ASTNode node = compilationUnit.findDeclaringNode(key); if (node == null) { node = compilationUnit.findDeclaringNode(Signature.getTypeErasure(key)); } int offset = -1; boolean source = false; if (node != null) { MethodDeclaration method = (MethodDeclaration)node; offset = method.getName().getStartPosition(); key = method.resolveBinding().getKey(); if(method.isConstructor()){ key = getKeyForConstructor(key, method.resolveBinding().getName()); } source = true; } else if (typeDeclaration != null) { for (AbstractMethodDeclaration method : typeDeclaration.methods) { if (CharOperation.equals(method.selector, selector) && getArgumentsCount(method.arguments) == parameterTypeNames.length) { TypeBinding[] parameters = method.binding.parameters; boolean match = true; for (int i = 0; i < parameters.length; i++) { TypeBinding parameter = parameters[i]; String simpleName = new String(parameter.sourceName());//Signature.getSimpleName(name); char[] simpleParameterName = CharOperation.lastSegment(parameterTypeNames[i], '.'); if (!simpleName.equals(new String(simpleParameterName))) { match = false; break; } } if (match && !areTypeParametersCompatible(method, typeParameterNames, typeParameterBoundNames)) { match = false; } if (match) { String typeSignature = new String(method.binding.declaringClass.signature()); String sig = ""; if (method.binding.genericSignature() != null) { sig = getMethodName(method, sig); sig += new String(method.binding.genericSignature()); } else { sig = getMethodName(method, sig); sig += new String(method.binding.signature()); } String key2 = typeSignature + "." + sig; ASTNode astNode = compilationUnit.findDeclaringNode(key2); if (astNode != null) { if (astNode instanceof AnnotationTypeMemberDeclaration) { AnnotationTypeMemberDeclaration annotationTypeMemberDeclaration = (AnnotationTypeMemberDeclaration)astNode; offset = annotationTypeMemberDeclaration.getName().getStartPosition(); key2 = annotationTypeMemberDeclaration.resolveBinding().getKey(); } else { MethodDeclaration declaration = ((MethodDeclaration)astNode); offset = declaration.getName().getStartPosition(); key2 = declaration.resolveBinding().getKey(); if(declaration.isConstructor()){ key2 = getKeyForConstructor(key2, declaration.resolveBinding().getName()); } } selectionResult = new SelectionResult(Type.METHOD, Signature.toString(typeSignature.replace('/', '.')), key2, offset, isDeclaration, true); return; } } } } if (typeDeclaration.isSecondary()) { acceptLocalType(typeDeclaration.binding); return; } } else { char[][] compoundName = CharOperation.splitOn('.', declaringTypeName); if (compoundName.length > 0) { AbstractTypeDeclaration type = findType(new String(compoundName[0]), compilationUnit.types()); for (int i = 1, length = compoundName.length; i < length; i++) { if (type != null) { type = findType(new String(compoundName[i]), type.bodyDeclarations()); } } if (type != null) { String methodName = new String(selector); for (Object o : type.bodyDeclarations()) { if (o instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = (MethodDeclaration)o; if (methodDeclaration.getName().getFullyQualifiedName().equals(methodName) && methodDeclaration.parameters().size() == typeParameterNames.length) { offset = methodDeclaration.getName().getStartPosition(); String key1 = methodDeclaration.resolveBinding().getKey(); if(methodDeclaration.isConstructor()){ key1 = getKeyForConstructor(key1, methodDeclaration.resolveBinding().getName()); } selectionResult = new SelectionResult(Type.METHOD, type.resolveBinding().getQualifiedName(), key1, offset, isDeclaration, true); return; } } } } } } String fqn = ""; if (declaringTypePackageName.length > 0) { fqn = new String(declaringTypePackageName) + "."; } fqn += new String(declaringTypeName); if(isConstructor && !source) { key = getKeyForConstructor(key, new String(selector)); } selectionResult = new SelectionResult(Type.METHOD, fqn, key, offset, isDeclaration, source); } private String getKeyForConstructor(String key, String name) { String fqn = key.substring(0, key.indexOf(';') + 1); String substring = key.substring(key.indexOf(';') + 1, key.length()); substring = substring.substring(1); substring = "." + name + substring; key = fqn + substring; return key; } private String getMethodName(AbstractMethodDeclaration method, String sig) { String methodName = new String(method.binding.selector); if (!methodName.equals("<init>")) { sig = methodName; } return sig; } private int getArgumentsCount(Argument[] arguments) { if (arguments == null) { return 0; } return arguments.length; } public SelectionResult getSelectionResult() { return selectionResult; } /** * Resolve the package */ public void acceptPackage(char[] packageName) { //we don't support package selection } public void acceptTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] typeParameterName, boolean isDeclaration, int start, int end) { String key = "L" + new String(declaringTypePackageName).replaceAll("\\.", "/") + "/"; String className = new String(declaringTypeName); if (className.contains(".")) { className = className.replaceAll("\\.", "\\$"); } key += className + ";:T" + new String(typeParameterName) + ";"; ASTNode node = compilationUnit.findDeclaringNode(key); boolean source = false; int offset = -1; if (node != null) { source = true; org.eclipse.che.ide.ext.java.jdt.core.dom.TypeParameter parameter = ((org.eclipse.che.ide.ext.java.jdt.core.dom.TypeParameter)node); offset = parameter.getName().getStartPosition(); } selectionResult = new SelectionResult(Type.TYPE_PARAMETER, new String(typeParameterName), key, offset, isDeclaration, source); } @SuppressWarnings("unchecked") public void acceptMethodTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, int selectorStart, int selectorEnd, char[] typeParameterName, boolean isDeclaration, int start, int end) { String className = new String(declaringTypeName); MethodDeclaration method = null; AbstractTypeDeclaration type = null; if (className.contains(".")) { String[] split = className.split("\\."); List<? extends BodyDeclaration> bodyDeclarations = compilationUnit.types(); for (String name : split) { type = findType(name, bodyDeclarations); if (type != null) { bodyDeclarations = type.bodyDeclarations(); } } } else { type = findType(className, compilationUnit.types()); } if (type != null) { List<BodyDeclaration> bodyDeclarations = type.bodyDeclarations(); for (BodyDeclaration bodyDeclaration : bodyDeclarations) { if (bodyDeclaration instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = (MethodDeclaration)bodyDeclaration; if (methodDeclaration.getName().getIdentifier().equals(new String(selector))) { method = methodDeclaration; break; } } } if (method == null) { //todo add type return; } String parameterName = new String(typeParameterName); List<org.eclipse.che.ide.ext.java.jdt.core.dom.TypeParameter> list = method.typeParameters(); for (org.eclipse.che.ide.ext.java.jdt.core.dom.TypeParameter parameter : list) { if (parameter.getName().getFullyQualifiedName().equals(parameterName)) { selectionResult = new SelectionResult(Type.METHOD_TYPE_PARAMETER, parameterName, null, parameter.getName().getStartPosition(), false, true); break; } } } } private AbstractTypeDeclaration findType(String name, List<? extends BodyDeclaration> declarations) { for (BodyDeclaration bodyDeclaration : declarations) { if (bodyDeclaration instanceof AbstractTypeDeclaration) { if (((AbstractTypeDeclaration)bodyDeclaration).getName().getFullyQualifiedName().equals(name)) { return ((AbstractTypeDeclaration)bodyDeclaration); } } } return null; } private boolean areTypeParametersCompatible(AbstractMethodDeclaration method, char[][] typeParameterNames, char[][][] typeParameterBoundNames) { TypeParameter[] typeParameters = method.typeParameters(); int length1 = typeParameters == null ? 0 : typeParameters.length; int length2 = typeParameterNames == null ? 0 : typeParameterNames.length; if (length1 != length2) { return false; } else { for (int j = 0; j < length1; j++) { TypeParameter typeParameter = typeParameters[j]; String typeParameterName = String.valueOf(typeParameter.name); if (!typeParameterName.equals(new String(typeParameterNames[j]))) { return false; } TypeReference[] bounds = typeParameter.bounds == null ? new TypeReference[0] : typeParameter.bounds; int boundCount = typeParameterBoundNames[j] == null ? 0 : typeParameterBoundNames[j].length; if (bounds.length != boundCount) { return false; } else { for (int k = 0; k < boundCount; k++) { String simpleName = Signature.getSimpleName(bounds[k].toString()); int index = simpleName.indexOf('<'); if (index != -1) { simpleName = simpleName.substring(0, index); } if (!simpleName.equals(new String(typeParameterBoundNames[j][k]))) { return false; } } } } } return true; } }