/*
* Copyright 2009-2017 the original author or authors.
*
* 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 org.codehaus.groovy.eclipse.codeassist.creators;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.ast.Parameter;
import org.codehaus.groovy.eclipse.codeassist.ProposalUtils;
import org.codehaus.groovy.eclipse.codeassist.preferences.DGMProposalFilter;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyCategoryMethodProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyFieldProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.IGroovyProposal;
import org.eclipse.jdt.groovy.core.util.GroovyUtils;
import org.eclipse.jdt.groovy.search.VariableScope;
public class CategoryProposalCreator extends AbstractProposalCreator {
public List<IGroovyProposal> findAllProposals(ClassNode selfType, Set<ClassNode> categories, String prefix, boolean isStatic, boolean isPrimary) {
DGMProposalFilter filter = new DGMProposalFilter();
List<IGroovyProposal> groovyProposals = new LinkedList<IGroovyProposal>();
Set<String> existingFieldProposals = new HashSet<String>();
Map<String, List<MethodNode>> existingMethodProposals = new HashMap<String, List<MethodNode>>();
for (ClassNode category : categories) {
List<MethodNode> allMethods = category.getAllDeclaredMethods();
boolean isDGMCategory = isDGMCategory(category);
for (MethodNode method : allMethods) {
// Check for DGMs filtered from preferences
if (isDGMCategory && filter.isFiltered(method)) {
continue;
}
String methodName = method.getName();
if (method.isStatic() && method.isPublic()) {
Parameter[] params = method.getParameters();
// need to check if the method is being accessed directly or as a property (eg- getText() --> text)
if (ProposalUtils.looselyMatches(prefix, methodName)) {
if (params.length > 0 && GroovyUtils.isAssignable(selfType, params[0].getType()) && !isDuplicate(method, existingMethodProposals)) {
GroovyCategoryMethodProposal methodProposal = new GroovyCategoryMethodProposal(method);
methodProposal.setRelevanceMultiplier(isInterestingType(method.getReturnType()) ? 101 : 1);
groovyProposals.add(methodProposal);
List<MethodNode> methodList = existingMethodProposals.get(methodName);
if (methodList == null) {
methodList = new ArrayList<MethodNode>(2);
existingMethodProposals.put(methodName, methodList);
}
methodList.add(method);
}
} else if (params.length == 1 && findLooselyMatchedAccessorKind(prefix, methodName, true).isAccessorKind(method, true) && !existingFieldProposals.contains(methodName) && hasNoField(selfType, methodName)) {
// add property variant of accessor name
GroovyFieldProposal fieldProposal = new GroovyFieldProposal(createMockField(method));
fieldProposal.setRelevanceMultiplier(1);
groovyProposals.add(fieldProposal);
existingFieldProposals.add(methodName);
}
}
}
}
return groovyProposals;
}
/**
* Checks that the new method hasn't already been added.
*/
private boolean isDuplicate(MethodNode newMethod, Map<String, List<MethodNode>> existingMethodProposals) {
List<MethodNode> otherMethods = existingMethodProposals.get(newMethod.getName());
if (otherMethods != null) {
Parameter[] newParameters = newMethod.getParameters();
iterator: for (Iterator<MethodNode> it = otherMethods.iterator(); it.hasNext();) {
MethodNode otherMethod = it.next();
Parameter[] otherParameters = otherMethod.getParameters();
if (otherParameters.length == newParameters.length) {
for (int i = 1, n = otherParameters.length; i < n; i += 1) {
if (!otherParameters[i].getType().getName().equals(newParameters[i].getType().getName())) {
// there is a mismatched parameter
continue iterator;
}
}
// all parameters match
/*if (GroovyUtils.isAssignable(otherParameters[0].getType(), newParameters[0].getType())) {
it.remove();
break;
} else {*/
return true;
/*}*/
}
}
}
return false;
}
private boolean isDGMCategory(ClassNode category) {
String className = category.getName();
for (ClassNode dgClass : VariableScope.ALL_DEFAULT_CATEGORIES) {
if (dgClass.getName().equals(className)) {
return true;
}
}
return false;
}
@Override
public boolean redoForLoopClosure() {
return true;
}
}