/*
* 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.relevance;
import java.util.HashSet;
import java.util.Set;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.FieldNode;
import org.codehaus.groovy.ast.MethodNode;
import org.codehaus.groovy.eclipse.codeassist.proposals.AbstractGroovyProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyCategoryMethodProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyFieldProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyMethodProposal;
import org.codehaus.groovy.eclipse.codeassist.proposals.GroovyPropertyProposal;
import org.eclipse.jdt.groovy.search.VariableScope;
/**
* This class defines relative relevance classes of proposals.
*
* There can be gradations of relevance within these relevance classes. Each
* relevance class is a factor of 10 greater than the previous class So, there
* are 10 gradations within each class for more fine grained control.
*
* Note that the reason we are using factors of 10 is that JDT will make small
* changes to the relevancy deep inside the Completion computer. By making the
* differences between the gradations so large, we ensure that these small
* changes have no effect on the final outcome.
*/
public enum Relevance {
/**
* Types
*/
LOWEST(1),
/**
* DGM, DGSM, Object, GroovyObject and other fields/methods available in all
* types
*/
VERY_LOW(10),
/**
* Static fields
*/
LOW(100),
/**
* Methods
*/
MEDIUM(1000),
/**
* Fields and properties
*/
MEDIUM_HIGH(10000),
/**
* Local variables, parameters
*/
HIGH(100000),
/**
* New method or field proposals, most recently used, favorites, or other
* special cases
*/
VERY_HIGH(1000000);
//
private final int value;
private Relevance(int value) {
this.value = value;
}
public int getRelavance() {
return value;
}
/**
* There are 10 gradations in each relevance class
*
* @param multiplier
* how many times the actual value multiplier is a float so that
* it is possible to reduce the relative relavance by passing in
* a value < 1
* @return the actual relavance of the associated proposal
*/
public int getRelevance(float multiplier) {
return Math.max(1, (int) (value * multiplier));
}
/**
* Calculates the relevance of an AST node based on a number of heuristics
*/
public static int calculateRelevance(AbstractGroovyProposal groovyProposal, float multiplier) {
return findRelevanceClass(groovyProposal).getRelevance(multiplier);
}
public static Relevance findRelevanceClass(AbstractGroovyProposal groovyProposal) {
if (groovyProposal instanceof GroovyFieldProposal || groovyProposal instanceof GroovyPropertyProposal) {
AnnotatedNode node = groovyProposal.getAssociatedNode();
if (node instanceof FieldNode && IGNORED_FIELD_NAMES.contains(((FieldNode) node).getName())) {
return VERY_LOW;
}
return MEDIUM_HIGH;
} else if (groovyProposal instanceof GroovyCategoryMethodProposal) {
AnnotatedNode node = groovyProposal.getAssociatedNode();
if (node instanceof MethodNode && VariableScope.ALL_DEFAULT_CATEGORIES.contains(((MethodNode) node).getDeclaringClass())) {
return VERY_LOW;
} else { // should be higher relevance than regular methods
return MEDIUM_HIGH;
}
} else if (groovyProposal instanceof GroovyMethodProposal) {
AnnotatedNode node = groovyProposal.getAssociatedNode();
if (node instanceof MethodNode && IGNORED_METHOD_NAMES.contains(((MethodNode) node).getName()) ||
VariableScope.OBJECT_CLASS_NODE.equals(((MethodNode) node).getDeclaringClass())) {
return VERY_LOW;
}
}
return MEDIUM;
}
// these are fields that we don't really want to see
private static final Set<String> IGNORED_FIELD_NAMES = new HashSet<String>();
static {
IGNORED_FIELD_NAMES.add("metaClass");
IGNORED_FIELD_NAMES.add("property");
IGNORED_FIELD_NAMES.add("class");
}
// these are methods that we don't really want to see
private static final Set<String> IGNORED_METHOD_NAMES = new HashSet<String>();
static {
IGNORED_METHOD_NAMES.add("getMetaClass");
IGNORED_METHOD_NAMES.add("setMetaClass");
IGNORED_METHOD_NAMES.add("getProperty");
IGNORED_METHOD_NAMES.add("setProperty");
IGNORED_METHOD_NAMES.add("invokeMethod");
}
}