/**
* Copyright (c) 2014 Codetrails GmbH.
* 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:
* Marcel Bruch - initial API and implementation.
*/
package org.eclipse.recommenders.internal.completion.rcp;
import static com.google.common.base.Optional.of;
import static org.eclipse.jdt.core.CompletionProposal.*;
import static org.eclipse.jdt.core.compiler.CharOperation.NO_CHAR;
import static org.eclipse.jdt.internal.codeassist.CompletionEngine.createTypeSignature;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.recommenders.utils.names.IFieldName;
import org.eclipse.recommenders.utils.names.ITypeName;
import org.eclipse.recommenders.utils.names.Names;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
/**
* EXPERIMENTAL. Not recommended for public API use.
*/
@SuppressWarnings("restriction")
@Beta
public class AccessibleCompletionProposals {
public static AccessibleCompletionProposal newFieldRef(IField field, int completionOffset, int prefixLength,
int relevance) {
AccessibleCompletionProposal proposal = new AccessibleCompletionProposal(CompletionProposal.FIELD_REF,
completionOffset);
String typeSignature = "";
try {
typeSignature = field.getTypeSignature();
} catch (JavaModelException e1) {
// TODO log
}
String simpleName = Signature.getSignatureSimpleName(typeSignature);
proposal.setTypeName(simpleName.toCharArray());
proposal.setSignature(typeSignature.toCharArray());
// proposal.setPackageName(local.type.qualifiedPackageName());
proposal.setName(field.getElementName().toCharArray());
proposal.setCompletion(field.getElementName().toCharArray());
try {
proposal.setFlags(field.getFlags());
} catch (JavaModelException e) {
// TODO log
}
int replaceStartIndex = completionOffset - prefixLength;
int replaceEndIndex = completionOffset;
proposal.setReplaceRange(replaceStartIndex, replaceEndIndex);
// TODO we may need to respect ui settings here:
int tokenStartIndex = replaceStartIndex;
int tokenEndIndex = replaceEndIndex;
proposal.setTokenRange(tokenStartIndex, tokenEndIndex);
proposal.setRelevance(relevance);
proposal.setData(IField.class, field);
proposal.setData(IJavaProject.class, field.getJavaProject());
return proposal;
}
public static AccessibleCompletionProposal newLocalRef(ILocalVariable local, int completionOffset,
int prefixLength, int relevance) {
AccessibleCompletionProposal proposal = new AccessibleCompletionProposal(CompletionProposal.LOCAL_VARIABLE_REF,
completionOffset);
String typeSignature = local.getTypeSignature();
String simpleName = Signature.getSignatureSimpleName(typeSignature);
proposal.setTypeName(simpleName.toCharArray());
proposal.setSignature(typeSignature.toCharArray());
// proposal.setPackageName(local.type.qualifiedPackageName());
proposal.setName(local.getElementName().toCharArray());
proposal.setCompletion(local.getElementName().toCharArray());
proposal.setFlags(local.getFlags());
int replaceStartIndex = completionOffset - prefixLength;
int replaceEndIndex = completionOffset;
proposal.setReplaceRange(replaceStartIndex, replaceEndIndex);
// TODO we may need to respect ui settings here:
int tokenStartIndex = replaceStartIndex;
int tokenEndIndex = replaceEndIndex;
proposal.setTokenRange(tokenStartIndex, tokenEndIndex);
proposal.setRelevance(relevance);
return proposal;
}
public static AccessibleCompletionProposal newLocalRef(LocalVariableBinding local, int completionOffset,
int prefixLength, int relevance) {
// JDT sets these fields as well.
// proposal.nameLookup = this.nameEnvironment.nameLookup;
// proposal.completionEngine = this;
AccessibleCompletionProposal proposal = new AccessibleCompletionProposal(CompletionProposal.LOCAL_VARIABLE_REF,
completionOffset);
if (local.type == null) {
proposal.setTypeName(local.declaration.type.toString().toCharArray());
proposal.setSignature(createTypeSignature(NO_CHAR, local.declaration.type.toString().toCharArray()));
} else {
proposal.setTypeName(local.type.qualifiedSourceName());
proposal.setPackageName(local.type.qualifiedPackageName());
proposal.setSignature(CompletionEngine.getSignature(local.type));
}
proposal.setName(local.name);
proposal.setCompletion(local.name);
proposal.setFlags(local.modifiers);
int replaceStartIndex = completionOffset - prefixLength;
int replaceEndIndex = completionOffset;
proposal.setReplaceRange(replaceStartIndex, replaceEndIndex);
// TODO we may need to respect ui settings here:
int tokenStartIndex = replaceStartIndex;
int tokenEndIndex = replaceEndIndex;
proposal.setTokenRange(tokenStartIndex, tokenEndIndex);
proposal.setRelevance(relevance);
return proposal;
}
public static AccessibleCompletionProposal newTypeImport(ITypeName type) {
// we can't import array types. So, strip it off
if (type.isArrayType()) {
type = type.getArrayBaseType();
}
char[] signature = (Names.vm2srcQualifiedType(type) + ";").toCharArray();
AccessibleCompletionProposal res = new AccessibleCompletionProposal(TYPE_IMPORT, 0);
res.setSignature(signature);
return res;
}
public static AccessibleCompletionProposal newQualifiedFieldRef(IFieldName field, int completionOffset,
int prefixLength, int relevance) {
String declaringType = field.getDeclaringType().getClassName();
String fieldName = field.getFieldName();
String completion = declaringType + "." + fieldName;
char[] signature = (field.getDeclaringType().getIdentifier().replace('/', '.') + ";").toCharArray();
CompletionProposal fieldRef = new AccessibleCompletionProposal(FIELD_REF, 0);
fieldRef.setDeclarationSignature(signature);
fieldRef.setName(fieldName.toCharArray());
fieldRef.setReplaceRange(completionOffset - prefixLength, completionOffset);
fieldRef.setRequiredProposals(new CompletionProposal[] { newTypeImport(field.getDeclaringType()) });
AccessibleCompletionProposal res = new AccessibleCompletionProposal(TYPE_IMPORT, completionOffset);
res.setCompletion(completion.toCharArray());
res.setSignature(signature);
res.setRelevance(relevance);
return res;
}
public static Optional<AccessibleCompletionProposal> newMethodRef(IMethod method, int completionOffset,
int prefixLength, int relevance) {
String completion = method.getElementName() + "()";
String[] params = method.getParameterTypes();
String[] resolved = new String[params.length];
IType declaringType = method.getDeclaringType();
// boolean isVararg = Flags.isVarargs(method.getFlags());
int lastParam = params.length - 1;
for (int i = 0; i <= lastParam; i++) {
String resolvedParam = params[i];
String unresolvedParam = params[i];
resolvedParam = resolveToBinary(unresolvedParam, declaringType).orNull();
if (resolvedParam == null) {
return Optional.absent();
}
resolved[i] = resolvedParam;
// TODO no varargs support
}
String returnType;
try {
returnType = resolveToBinary(method.getReturnType(), declaringType).orNull();
} catch (JavaModelException e) {
e.printStackTrace();
return Optional.absent();
}
if (returnType == null) { // e.g. a type parameter "QE;"
return Optional.absent();
}
AccessibleCompletionProposal res = new AccessibleCompletionProposal(CompletionProposal.METHOD_REF, relevance);
try {
res.setFlags(method.getFlags());
} catch (JavaModelException e1) {
e1.printStackTrace();
}
res.setCompletion(completion.toCharArray());
String declarationSignature = Signature.createTypeSignature(method.getDeclaringType().getFullyQualifiedName(),
true);
res.setDeclarationSignature(declarationSignature.toCharArray());
String signature = Signature.createMethodSignature(resolved, returnType);
res.setSignature(signature.toCharArray());
res.setName(method.getElementName().toCharArray());
res.setReplaceRange(completionOffset - prefixLength, completionOffset);
char[][] paramNames = new char[params.length][];
try {
String[] parameterNames = method.getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
paramNames[i] = parameterNames[i].toCharArray();
}
} catch (JavaModelException e) {
e.printStackTrace();
paramNames = CompletionEngine.createDefaultParameterNames(params.length);
}
res.setParameterNames(paramNames);
res.setData(IMethod.class, method);
res.setData(IJavaProject.class, method.getJavaProject());
return of(res);
}
private static Optional<String> resolveToBinary(String unresolvedParam, IType declaringType) {
if (unresolvedParam.length() == 1) {
return of(unresolvedParam);
}
if (Signature.C_RESOLVED == unresolvedParam.charAt(0)) {
return of(unresolvedParam);
}
String curr = Signature.getTypeErasure(unresolvedParam);
try {
curr = JavaModelUtil.getResolvedTypeName(curr, declaringType);
} catch (JavaModelException e) {
e.printStackTrace();
return Optional.absent();
}
if (curr == null) { // e.g. a type parameter "QE;"
return Optional.absent();
}
return of("L" + curr + ";");
}
}