Completed the automatic 'check on file save' function that initiates a code review whenever changes are saved to a code file. Enable it on the main PMD preference page as it is off by default.

git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@7599 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Brian Remedios
2011-12-20 05:57:33 +00:00
parent 8423633469
commit 0d46665c86
9 changed files with 219 additions and 33 deletions

View File

@ -5,6 +5,7 @@ v4.0.0 - xxx 2011?
. New rule creation wizard
. New report preferences panel
. New file filter panel for exclusion/inclusion entries
. New automatic "Check code on file save" function (off by default)
. User-definable rule violation markers
Highest priority markers also decorate folders & projects (selectable)
. Colour syntax highlighting in code viewers/editors

View File

@ -15,9 +15,6 @@ There's a whole lot of layers, can we simply things a bit?
Upgrade plugin code to Java 5.
Allow import of a single rule from a RuleSet.
Warn if Import of a Rule results in a duplicate (what is a duplicate exactly?), allow option to Import All, Import Non Duplicates, or Cancel.
Warn if newly Added Rule has the name of an existing Rule.
Warn if non reference Rule looks like it might be a built-in PMD rule, and ask if replace with reference. On Add? On Import? On Upgrade?
Add Upgrade button, which will check current workspace RuleSet against PMD rules showing differences (new PMD rules, rules in
Allow checking to see what rules from PMD are missing (useful for upgrade process).

View File

@ -0,0 +1,22 @@
package net.sourceforge.pmd.eclipse.plugin;
import org.eclipse.core.runtime.IProgressMonitor;
/**
*
* @author Brian Remedios
*/
public class EclipseUtil {
public static final IProgressMonitor DUMMY_MONITOR = new IProgressMonitor() {
public void beginTask(String name, int totalWork) { }
public void done() { }
public void internalWorked(double work) { }
public boolean isCanceled() { return false; }
public void setCanceled(boolean value) { }
public void setTaskName(String name) { }
public void subTask(String name) { }
public void worked(int work) { }
};
}

View File

@ -0,0 +1,163 @@
package net.sourceforge.pmd.eclipse.plugin;
import java.util.HashSet;
import java.util.Set;
import name.herlin.command.CommandException;
import net.sourceforge.pmd.eclipse.runtime.cmd.ReviewCodeCmd;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
/**
* Monitors for changes in the workspace and initiates the ReviewCodeCmd
* when suitable file changes in some meaningful way.
*
* @author Brian Remedios
*/
public class FileChangeReviewer implements IResourceChangeListener {
public FileChangeReviewer() {
}
private enum ChangeType {
ADDED,
REMOVED,
CHANGED
}
private class ResourceChange {
public final ChangeType resourceDeltaType;
public final int flags;
public final IFile file;
private ResourceChange(ChangeType type, IFile theFile, int theFlags) {
resourceDeltaType = type;
file = theFile;
flags = theFlags;
}
public int hashCode() { return resourceDeltaType.hashCode() + 13 + file.hashCode() + flags; }
public boolean equals(Object other) {
if (other == this) return true;
if (other.getClass() == getClass()) {
ResourceChange chg = (ResourceChange)other;
return chg.file.equals(file) &&
resourceDeltaType == chg.resourceDeltaType &&
flags == chg.flags;
}
return false;
}
}
/**
* @param event
*/
public void resourceChanged(IResourceChangeEvent event) {
Set<ResourceChange> itemsChanged = new HashSet<ResourceChange>();
switch (event.getType()) {
// case IResourceChangeEvent.PRE_DELETE:
// case IResourceChangeEvent.PRE_CLOSE:
// case IResourceChangeEvent.PRE_BUILD:
// case IResourceChangeEvent.POST_BUILD:
// case IResourceChangeEvent.PRE_REFRESH:
case IResourceChangeEvent.POST_CHANGE:
changed(itemsChanged, event.getDelta(), EclipseUtil.DUMMY_MONITOR);
}
ReviewCodeCmd cmd = new ReviewCodeCmd(); // separate one for each thread
cmd.reset();
for (ResourceChange chg : itemsChanged) cmd.addResource(chg.file);
try {
cmd.performExecute();
} catch (CommandException e) {
PMDPlugin.getDefault().log(IStatus.ERROR, "Error processing code review upon file changes", e);
}
}
private void changed(Set<ResourceChange> itemsChanged, IResourceDelta delta, IProgressMonitor monitor) {
IResource rsc = delta.getResource();
int flags = delta.getFlags();
switch (delta.getKind()) {
case IResourceDelta.NO_CHANGE : return;
case IResourceDelta.REMOVED :
// if (rsc instanceof IProject) {
// removed(itemsChanged, (IProject)rsc, delta.getFlags());
// }
// if (rsc instanceof IFile) {
// removed(itemsChanged, (IFile)rsc, flags, true);
// }
for (IResourceDelta grandkidDelta : delta.getAffectedChildren()) {
if (monitor.isCanceled()) return;
changed(itemsChanged, grandkidDelta, monitor);
}
case IResourceDelta.ADDED :
// if (rsc instanceof IProject) {
// removed(itemsChanged, (IProject)rsc, delta.getFlags());
// }
if (rsc instanceof IFile) {
added(itemsChanged, (IFile)rsc, flags, true);
}
for (IResourceDelta grandkidDelta : delta.getAffectedChildren()) {
if (monitor.isCanceled()) return;
changed(itemsChanged, grandkidDelta, monitor);
}
case IResourceDelta.CHANGED :
// if (rsc instanceof IProject) {
// changed(itemsChanged, (IProject)rsc, delta.getFlags());
// }
if (rsc instanceof IFile) {
changed(itemsChanged, (IFile)rsc, flags, true);
}
for (IResourceDelta grandkidDelta : delta.getAffectedChildren()) {
if (monitor.isCanceled()) return;
changed(itemsChanged, grandkidDelta, monitor);
}
default :
for (IResourceDelta grandkidDelta : delta.getAffectedChildren()) {
if (monitor.isCanceled()) return;
changed(itemsChanged, grandkidDelta, monitor);
}
}
}
private void changed(Set<ResourceChange> itemsChanged, IFile rsc, int flags, boolean b) {
if ((flags & IResourceDelta.CONTENT) > 0) {
itemsChanged.add( new ResourceChange(ChangeType.CHANGED, rsc, flags));
}
}
private void added(Set<ResourceChange> itemsChanged, IFile rsc, int flags, boolean b) {
itemsChanged.add( new ResourceChange(ChangeType.ADDED, rsc, flags));
// System.out.println("added: " + rsc);
}
// private void changed(Set<ResourceChange> itemsChanged, IProject rsc, int flags) {
// System.out.println("changed: " + rsc);
// }
//
//
// private void removed(Set<ResourceChange> itemsChanged, IFile rsc, int flags, boolean b) {
// itemsChanged.add( new ResourceChange(ChangeType.REMOVED, rsc, flags));
// System.out.println("removed: " + rsc);
// }
//
// private void removed(Set<ResourceChange> itemsChanged, IProject rsc, int flags) {
// System.out.println("removed: " + rsc);
// }
}

View File

@ -46,8 +46,6 @@ import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
@ -72,10 +70,12 @@ import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class PMDPlugin extends AbstractUIPlugin implements IResourceChangeListener {
public class PMDPlugin extends AbstractUIPlugin {
private static File pluginFolder;
private FileChangeReviewer changeReviewer;
private Map<RGB, Color> coloursByRGB = new HashMap<RGB, Color>();
public static final String PLUGIN_ID = "net.sourceforge.pmd.eclipse.plugin";
@ -181,17 +181,19 @@ public class PMDPlugin extends AbstractUIPlugin implements IResourceChangeListen
registerAdditionalRuleSets();
fileChangeListenerEnabled(prefs.isCheckAfterSaveEnabled());
}
public void fileChangeListenerEnabled(boolean flag) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
if (flag) {
workspace.addResourceChangeListener(this);
if (changeReviewer == null) changeReviewer = new FileChangeReviewer();
workspace.addResourceChangeListener(changeReviewer);
} else {
workspace.removeResourceChangeListener(this);
if (changeReviewer != null) {
workspace.removeResourceChangeListener(changeReviewer);
changeReviewer = null;
}
}
}
@ -564,14 +566,5 @@ public class PMDPlugin extends AbstractUIPlugin implements IResourceChangeListen
decorator.changed(changes);
}
public void resourceChanged(IResourceChangeEvent event) {
// switch (event.getType()) {
// case PRE_DELETE:
// case POST_CHANGE:
// }
}
}

View File

@ -36,6 +36,7 @@
package net.sourceforge.pmd.eclipse.runtime.cmd;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -191,7 +192,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
};
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
workspace.run(action, getschedulingRule(), IWorkspace.AVOID_UPDATE, getMonitor());
workspace.run(action, getSchedulingRule(), IWorkspace.AVOID_UPDATE, getMonitor());
// Switch to the PMD perspective if required
if (openPmdPerspective) {
@ -239,7 +240,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
/**
* @param resource The resource to set.
*/
public void setResources(final List<ISchedulingRule> resources) {
public void setResources(Collection<ISchedulingRule> resources) {
resources.clear();
resources.addAll(resources);
}
@ -249,7 +250,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
*
* @param resource a workbench resource
*/
public void addResource(final IResource resource) {
public void addResource(IResource resource) {
if (resource == null) {
throw new IllegalArgumentException("Resource parameter can not be null");
}
@ -260,14 +261,14 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
/**
* @param resourceDelta The resourceDelta to set.
*/
public void setResourceDelta(final IResourceDelta resourceDelta) {
public void setResourceDelta(IResourceDelta resourceDelta) {
this.resourceDelta = resourceDelta;
}
/**
* @param taskMarker The taskMarker to set.
*/
public void setTaskMarker(final boolean taskMarker) {
public void setTaskMarker(boolean taskMarker) {
this.taskMarker = taskMarker;
}
@ -302,7 +303,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
/**
* @return the scheduling rule needed to apply markers
*/
private ISchedulingRule getschedulingRule() {
private ISchedulingRule getSchedulingRule() {
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
final IResourceRuleFactory ruleFactory = workspace.getRuleFactory();
ISchedulingRule rule = null;
@ -548,6 +549,11 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
* @return the element count
*/
private int countResourceElement(IResource resource) {
if (resource instanceof IFile) {
return isSuitable((IFile)resource) ? 1 : 0;
}
final CountVisitor visitor = new CountVisitor();
try {
@ -589,17 +595,21 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
window.getActivePage().setPerspective(reg.findPerspectiveWithId(PMDRuntimeConstants.ID_PERSPECTIVE));
}
private static boolean isSuitable(IFile file) {
return isLanguageFile(file, Language.JAVA);
}
/**
* Private inner class to count the number of resources or delta elements
*/
private final class CountVisitor implements IResourceVisitor, IResourceDeltaVisitor {
public int count = 0;
public boolean visit(final IResource resource) {
public boolean visit(IResource resource) {
boolean fVisitChildren = true;
count++;
if (resource instanceof IFile && isLanguageFile((IFile) resource, Language.JAVA)) {
if (resource instanceof IFile && isSuitable((IFile) resource)) {
fVisitChildren = false;
}
@ -608,7 +618,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand {
}
// @PMD:REVIEWED:UnusedFormalParameter: by Herlin on 10/05/05 23:46
public boolean visit(final IResourceDelta delta) {
public boolean visit(IResourceDelta delta) {
count++;
return true;
}

View File

@ -167,7 +167,7 @@ public class PMDCheckAction extends AbstractUIAction {
}
// Run the command
setupAndExecute(cmd, countElement(selection));
setupAndExecute(cmd, countElements(selection));
}
private void addAdaptable(ReviewCodeCmd cmd, IAdaptable adaptable) {
@ -186,7 +186,7 @@ public class PMDCheckAction extends AbstractUIAction {
* @param selection a selection
* @return the element count
*/
private int countElement(IStructuredSelection selection) {
private int countElements(IStructuredSelection selection) {
CountVisitor visitor = new CountVisitor();
for (Iterator<?> i = selection.iterator(); i.hasNext();) {

View File

@ -550,7 +550,6 @@ public class GeneralPreferencesPage extends PreferencePage implements IWorkbench
Button button = new Button(viewGroup, SWT.CHECK);
button.setText("Check code after saving");
button.setSelection(preferences.isCheckAfterSaveEnabled());
button.setEnabled(false); // FIXME - make it real
return button;
}
@ -758,6 +757,8 @@ System.out.println("updating icons");
}
preferences.sync();
PMDPlugin.getDefault().fileChangeListenerEnabled(checkCodeOnSave.getSelection());
PMDPlugin.getDefault().applyLogPreferences(preferences);
return true;

View File

@ -27,7 +27,6 @@ new CPD view
Preferences
General Page
Enable 'check code after saving' button when working
Refresh whole Eclipse UI to obtain updated RulePriority settings
Rework Logging Options section - lose the slider!
Preferences window jumps around/resizes when changing rule selections