package net.sourceforge.pmd.eclipse.ui.preferences.br;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.sourceforge.pmd.PropertyDescriptor;
import net.sourceforge.pmd.PropertySource;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.Configuration;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.rule.RuleReference;
import net.sourceforge.pmd.lang.rule.XPathRule;
import net.sourceforge.pmd.util.CollectionUtil;
/**
*
* @author Brian Remedios
*/
public class RuleUtil {
private RuleUtil() {}
public static boolean isDefaultValue(Map.Entry<PropertyDescriptor<?>, Object> entry) {
PropertyDescriptor<?> desc = entry.getKey();
Object value = entry.getValue();
return areEqual(desc.defaultValue(), value);
}
// TODO fix rule!!
// public static boolean isXPathRule(Rule rule) {
//
// for (PropertyDescriptor<?> desc : rule.getPropertyDescriptors()) {
// if (desc.equals(XPathRule.XPATH_DESCRIPTOR)) return true;
// }
// return false;
// }
public static boolean isXPathRule(PropertySource source) {
//return rule.hasDescriptor(XPathRule.XPATH_DESCRIPTOR); // not reliable since it may not have it yet
if (source instanceof XPathRule) return true;
if (source instanceof RuleReference) {
Rule realOne = ((RuleReference)source).getRule();
return realOne instanceof XPathRule;
}
return false;
}
// TODO move elsewhere
public static boolean areEqual(Object value, Object otherValue) {
if (value == otherValue) {
return true;
}
if (value == null) {
return false;
}
if (otherValue == null) {
return false;
}
if (value.getClass().getComponentType() != null) {
return CollectionUtil.arraysAreEqual(value, otherValue);
}
if (value instanceof Float || value instanceof Double) {
return areEqualNumbers((Number)value, (Number)otherValue);
}
return value.equals(otherValue);
}
// TODO move elsewhere, handle div by zero
public static boolean areEqualNumbers(Number a, Number b) {
double da = a.doubleValue();
double db = b.doubleValue();
double delta = da-db;
double pctDelta = delta/da;
return pctDelta < 0.0001;
}
public static boolean hasDefaultValues(Rule rule) {
Map<PropertyDescriptor<?>, Object> valuesByProperty = Configuration.filteredPropertiesOf(rule);
for (Map.Entry<PropertyDescriptor<?>, Object> entry : valuesByProperty.entrySet()) {
if (!isDefaultValue(entry)) return false;
}
return true;
}
public static Set<PropertyDescriptor<?>> modifiedPropertiesIn(Rule rule) {
Set<PropertyDescriptor<?>> descs = new HashSet<PropertyDescriptor<?>>();
for (Map.Entry<PropertyDescriptor<?>, Object> entry: Configuration.filteredPropertiesOf(rule).entrySet() ) {
if (isDefaultValue(entry)) continue;
descs.add(entry.getKey());
}
return descs;
}
public static Set<Comparable<?>> uniqueItemsIn(Object item, RuleFieldAccessor getter) {
if (item instanceof Rule) {
Set<Comparable<?>> values = new HashSet<Comparable<?>>(1);
values.add( getter.valueFor((Rule) item) );
return values;
}
if (item instanceof RuleCollection) {
return getter.uniqueValuesFor((RuleCollection)item);
}
return Collections.emptySet();
}
/**
* Sometimes references reference references !
*
* @param reference
* @return
*/
private static Class<Rule> rootImplementationClassOf(RuleReference reference) {
Rule rule = reference.getRule();
while (rule.getClass() == RuleReference.class) {
rule = ((RuleReference)rule).getRule();
}
return (Class<Rule>)rule.getClass();
}
public static Class<Rule> implementationClassOf(Rule rule) {
if (rule instanceof RuleReference) {
return rootImplementationClassOf((RuleReference)rule);
} else {
return (Class<Rule>)rule.getClass();
}
}
public static boolean allUseDefaultValues(RuleCollection collection) {
if (collection.isEmpty()) return false;
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
return rule.usesDefaultValues();
}
};
return collection.rulesDo(visitor);
}
public static boolean allUseDfa(RuleCollection collection) {
if (collection.isEmpty()) return false;
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
return rule.usesDFA();
}
};
return collection.rulesDo(visitor);
}
public static boolean allUseTypeResolution(RuleCollection collection) {
if (collection.isEmpty()) return false;
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
return rule.usesTypeResolution();
}
};
return collection.rulesDo(visitor);
}
/**
* Iterates through the currently selected rules and returns
* their common priority setting or null if they differ.
*/
public static RulePriority commonPriority(RuleCollection collection) {
if (collection.isEmpty()) return null;
final RulePriority[] prio = new RulePriority[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
if (prio[0] == null) {
prio[0] = rule.getPriority();
}
if (prio[0] != rule.getPriority()) {
prio[0] = null;
return false;
}
return true;
}
};
collection.rulesDo(visitor);
return prio[0];
}
private static String format(Object item) {
return item == null ? "" : String.valueOf(item); // TODO custom format per type
}
public static String asString(Set<Comparable<?>> items) {
Iterator<Comparable<?>> iter = items.iterator();
if (items.size() == 1) return format(iter.next());
StringBuilder sb = new StringBuilder(format(iter.next()));
while (iter.hasNext()) {
sb.append(", ").append(format(iter.next()));
}
return sb.toString();
}
/**
*/
public static Map<RulePriority, Float> fractionsByPriority(RuleCollection collection) {
if (collection.isEmpty()) return Collections.emptyMap();
final Map<RulePriority, Integer> priorityCounts = new HashMap<RulePriority, Integer>(5);
final int[] count = new int[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
RulePriority priority = rule.getPriority();
count[0] = count[0] + 1;
Integer count = priorityCounts.get(priority);
if (count == null) {
priorityCounts.put(priority, Integer.valueOf(1));
} else {
priorityCounts.put(priority, Integer.valueOf(count + 1));
}
return true;
}
};
collection.rulesDo(visitor);
int total = count[0];
Map<RulePriority, Float> priorityFractions = new HashMap<RulePriority, Float>();
for (Map.Entry<RulePriority, Integer> entry : priorityCounts.entrySet()) {
float fraction = (float)entry.getValue() / total;
priorityFractions.put(entry.getKey(), fraction);
}
return priorityFractions;
}
/**
* Iterates through the currently selected rules and returns
* their common ruleset name or null if they differ.
*/
public static String commonRuleset(RuleCollection collection) {
if (collection.isEmpty()) return null;
final Set<String> names = new HashSet<String>(2);
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
names.add( rule.getRuleSetName().trim() );
return names.size() < 2;
}
};
collection.rulesDo(visitor);
return names.size() > 1 ?
null :
names.iterator().next();
}
public static Class<Rule> commonImplementationClass(RuleCollection collection) {
if (collection.isEmpty()) return null;
// TODO use array[1] approach like the others
final Set<Class<Rule>> types = new HashSet<Class<Rule>>(2);
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
types.add( implementationClassOf(rule) );
return types.size() < 2;
}
};
collection.rulesDo(visitor);
return types.size() > 1 ?
null :
types.iterator().next();
}
public static Comparable<?> commonAspect(RuleCollection collection, final RuleFieldAccessor accessor) {
if (collection.isEmpty()) return null;
final Comparable<?>[] aspect = new Comparable<?>[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
if (aspect[0] == null) {
aspect[0] = accessor.valueFor(rule);
return true;
}
if (areEqual(aspect[0], accessor.valueFor(rule)) ) {
aspect[0] = null;
return false;
}
return true;
}
};
collection.rulesDo(visitor);
return aspect[0];
}
/**
*
*/
public static int countNonOccurrencesOf(RuleCollection collection, final RuleFieldAccessor accessor, final Object item) {
if (collection.isEmpty()) return 0;
final int[] count = new int[] {0};
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
Object value = accessor.valueFor(rule);
if (value != item) count[0] = count[0]+1;
return true;
}
};
collection.rulesDo(visitor);
return count[0];
}
/**
* Iterates through the currently selected rules and returns
* the set of unique aspect values.
*/
public static Set<Comparable<?>> uniqueAspects(RuleCollection collection, final RuleFieldAccessor accessor) {
if (collection.isEmpty()) return Collections.emptySet();
final Set<Comparable<?>> aspects = new HashSet<Comparable<?>>();
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
aspects.add( accessor.valueFor(rule) );
return true;
}
};
collection.rulesDo(visitor);
return aspects;
}
public static Language commonLanguage(RuleCollection collection) {
if (collection.isEmpty()) return null;
final Language[] type = new Language[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
if (type[0] == null) {
type[0] = rule.getLanguage();
return true;
}
if (type[0] != rule.getLanguage() ) {
type[0] = null;
return false;
}
return true;
}
};
collection.rulesDo(visitor);
return type[0];
}
public static LanguageVersion commonLanguageMinVersion(RuleCollection collection) {
if (collection.isEmpty()) return null;
final LanguageVersion[] version = new LanguageVersion[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
if (version[0] == null) {
version[0] = rule.getMinimumLanguageVersion();
return true;
}
if (version[0] != rule.getMinimumLanguageVersion() ) {
version[0] = null;
return false;
}
return true;
}
};
collection.rulesDo(visitor);
return version[0];
}
public static LanguageVersion commonLanguageMaxVersion(RuleCollection collection) {
if (collection.isEmpty()) return null;
final LanguageVersion[] version = new LanguageVersion[1];
RuleVisitor visitor = new RuleVisitor() {
public boolean accept(Rule rule) {
if (version[0] == null) {
version[0] = rule.getMaximumLanguageVersion();
return true;
}
if (version[0] != rule.getMaximumLanguageVersion() ) {
version[0] = null;
return false;
}
return true;
}
};
collection.rulesDo(visitor);
return version[0];
}
}