/* * <copyright> * Copyright 1997-2003 PMD for Eclipse Development team * under sponsorship of the Defense Advanced Research Projects * Agency (DARPA). * * This program is free software; you can redistribute it and/or modify * it under the terms of the Cougaar Open Source License as published by * DARPA on the Cougaar Open Source Website (www.cougaar.org). * * THE COUGAAR SOFTWARE AND ANY DERIVATIVE SUPPLIED BY LICENSOR IS * PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS OR * IMPLIED, INCLUDING (BUT NOT LIMITED TO) ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND WITHOUT * ANY WARRANTIES AS TO NON-INFRINGEMENT. IN NO EVENT SHALL COPYRIGHT * HOLDER BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT OR CONSEQUENTIAL * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE OF DATA OR PROFITS, * TORTIOUS CONDUCT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THE COUGAAR SOFTWARE. * * </copyright> */ package net.sourceforge.pmd.eclipse.ui.quickfix; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; import net.sourceforge.pmd.eclipse.runtime.builder.MarkerUtil; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.core.resources.IMarker; import org.eclipse.ui.IMarkerResolution; import org.eclipse.ui.IMarkerResolutionGenerator; /** * Implementation of a resolution generator to bring the quick fixes feature * of Eclipse to PMD * * @author Philippe Herlin, Brian Remedios * * TODO * resource bundles are read-only, migrate to a persistence mechanism * that allows for updates to the fixes associated with the rules. */ public class PMDResolutionGenerator implements IMarkerResolutionGenerator { private static final Map<String, Fix[]> fixersByRuleName = new HashMap<String, Fix[]>(); private static final Set<String> missingFixes = new HashSet<String>(); private static final Map<String, String> brokenFixes = new HashMap<String, String>(); private static String QUICKFIX_BUNDLE = "properties.QuickFix"; // NOPMD public static final IMarkerResolution[] EMPTY_RESOLUTIONS = new IMarkerResolution[0]; public static Class<Fix> fixClassFor(String className, String ruleName) { if (StringUtil.isEmpty(className)) return null; try { Class<?> cls = Class.forName(className); if (Fix.class.isAssignableFrom(cls)) { return (Class<Fix>)cls; } else { brokenFixes.put(ruleName, className); return null; } } catch (ClassNotFoundException ex) { return null; } } private static void add(String ruleName, Fix fix) { if (fixersByRuleName.containsKey(ruleName)) { Fix[] existingFixers = fixersByRuleName.get(ruleName); Fix[] newFixers = new Fix[existingFixers.length+1]; System.arraycopy(existingFixers, 0, newFixers, 0, existingFixers.length); newFixers[newFixers.length-1] = fix; fixersByRuleName.put(ruleName, newFixers); } else { fixersByRuleName.put(ruleName, new Fix[] { fix }); } } public static int fixCountFor(Rule rule) { String ruleName = rule.getName(); if (missingFixes.contains(ruleName)) return 0; loadFixesFor(ruleName); if (!fixersByRuleName.containsKey(ruleName)) return 0; return fixersByRuleName.get(ruleName).length; } public static void saveFixesFor(String ruleName) { // TODO } private static void loadFixesFor(String ruleName) { ResourceBundle bundle = ResourceBundle.getBundle(QUICKFIX_BUNDLE); if (!bundle.containsKey(ruleName)) { missingFixes.add(ruleName); return; } String fixClassNameSet = bundle.getString(ruleName); String[] fixClassNames = fixClassNameSet.split(","); for (String fixClassName : fixClassNames) { if (StringUtil.isEmpty(fixClassName)) continue; Class<Fix> fixClass = fixClassFor(fixClassName.trim(), ruleName); if (fixClass != null) { Fix fix = fixFor(ruleName, fixClass); if (fix != null) { add(ruleName, fix); } } } if (!fixersByRuleName.containsKey(ruleName)) missingFixes.add(ruleName); } public static boolean hasFixesFor(Rule rule) { String ruleName = rule.getName(); if (fixersByRuleName.containsKey(ruleName)) return true; if (missingFixes.contains(ruleName)) return false; if (brokenFixes.containsKey(ruleName)) return false; loadFixesFor(ruleName); return fixersByRuleName.containsKey(ruleName); } private static Fix fixFor(String ruleName, Class<Fix> fixClass) { try { return fixClass.newInstance(); } catch (Exception ex) { brokenFixes.put(ruleName, fixClass.getName()); return null; } } public static Fix[] fixesFor(Rule rule) { return fixersByRuleName.get(rule.getName()); } public static void fixesFor(Rule rule, Fix[] fixes) { fixersByRuleName.put(rule.getName(), fixes); } /** * @see org.eclipse.ui.IMarkerResolutionGenerator#getResolutions(org.eclipse.core.resources.IMarker) */ public IMarkerResolution[] getResolutions(IMarker marker) { final List<PMDResolution> markerResolutionList = new ArrayList<PMDResolution>(); try { final String ruleName = MarkerUtil.ruleNameFor(marker); if (ruleName != null) { final RuleSet ruleSet = PMDPlugin.getDefault().getPreferencesManager().getRuleSet(); final Rule rule = ruleSet.getRuleByName(ruleName); if (rule == null || !hasFixesFor(rule)) return EMPTY_RESOLUTIONS; Fix[] fixes = fixesFor(rule); for (Fix fix : fixes) markerResolutionList.add( new PMDResolution(fix) ); } } catch (RuntimeException e) { PMDPlugin.getDefault().showError(PMDPlugin.getDefault().getStringTable().getString(StringKeys.ERROR_RUNTIME_EXCEPTION), e); } return markerResolutionList.toArray(new IMarkerResolution[markerResolutionList.size()]); } }