/**
* Copyright (c) 2015 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.types.rcp;
import static org.eclipse.recommenders.completion.rcp.processable.ProposalTag.RECOMMENDERS_SCORE;
import static org.eclipse.recommenders.rcp.SharedImages.Images.OVR_STAR;
import java.util.Set;
import javax.inject.Inject;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.recommenders.completion.rcp.IRecommendersCompletionContext;
import org.eclipse.recommenders.completion.rcp.processable.IProcessableProposal;
import org.eclipse.recommenders.completion.rcp.processable.OverlayImageProposalProcessor;
import org.eclipse.recommenders.completion.rcp.processable.ProposalProcessorManager;
import org.eclipse.recommenders.completion.rcp.processable.SessionProcessor;
import org.eclipse.recommenders.completion.rcp.processable.SimpleProposalProcessor;
import org.eclipse.recommenders.rcp.SharedImages;
import org.eclipse.recommenders.utils.names.ITypeName;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
public class TypesCompletionSessionProcessor extends SessionProcessor {
private static final CompletionProposal NULL_PROPOSAL = new CompletionProposal();
public static final int BOOST = 50;
private ImmutableSet<String> subtypes;
private final ITypesIndexService service;
private final OverlayImageProposalProcessor overlayDecorator;
@Inject
public TypesCompletionSessionProcessor(ITypesIndexService service, SharedImages images) {
this.service = service;
overlayDecorator = new OverlayImageProposalProcessor(images.getDescriptor(OVR_STAR), IDecoration.TOP_LEFT);
}
@Override
public boolean startSession(IRecommendersCompletionContext context) {
Set<ITypeName> expectedTypes = context.getExpectedTypeNames();
if (expectedTypes.isEmpty()) {
return false;
}
Builder<String> results = ImmutableSet.builder();
for (ITypeName expectedType : expectedTypes) {
if (expectedType.isPrimitiveType()) {
continue;
}
if (expectedType.isArrayType()) {
continue;
}
results.addAll(service.subtypes(expectedType, context.getProject()));
}
subtypes = results.build();
return !subtypes.isEmpty();
}
@Override
public void process(IProcessableProposal proposal) throws Exception {
if (subtypes == null || subtypes.isEmpty()) {
return;
}
final CompletionProposal coreProposal = proposal.getCoreProposal().or(NULL_PROPOSAL);
switch (coreProposal.getKind()) {
case CompletionProposal.FIELD_REF:
case CompletionProposal.LOCAL_VARIABLE_REF:
case CompletionProposal.TYPE_REF:
handleProposal(proposal, coreProposal.getSignature());
break;
case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION:
case CompletionProposal.CONSTRUCTOR_INVOCATION:
handleProposal(proposal, coreProposal.getDeclarationSignature());
break;
case CompletionProposal.METHOD_REF:
handleProposal(proposal, Signature.getReturnType(coreProposal.getSignature()));
break;
case CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER:
case CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER:
handleProposal(proposal, coreProposal.getReceiverSignature());
break;
}
}
private void handleProposal(IProcessableProposal proposal, char[] typeSignature) {
if (isSubtype(typeSignature)) {
proposal.setTag(RECOMMENDERS_SCORE, BOOST);
ProposalProcessorManager mgr = proposal.getProposalProcessorManager();
mgr.addProcessor(new SimpleProposalProcessor(BOOST));
mgr.addProcessor(overlayDecorator);
}
}
private boolean isSubtype(char[] typeSignature) {
if (Signature.getArrayCount(typeSignature) > 0) {
// No support for the subtype relation amongst array types yet.
return false;
}
if (isPrimitiveOrVoid(typeSignature)) {
return false;
}
// No support for generics yet.
char[] erasedTypeSignature = Signature.getTypeErasure(typeSignature);
String type = new String(erasedTypeSignature, 1, erasedTypeSignature.length - 2);
return subtypes.contains(type);
}
private boolean isPrimitiveOrVoid(char[] typeSignature) {
return typeSignature.length == 1;
}
}