diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 7a77c4be..52cb4042 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -13,6 +13,8 @@ Eclipse Update Site: ### Fixed Issues +* [#52](https://github.com/pmd/pmd-eclipse-plugin/issues/52): Eclipse Internal Error - Out of Memory + ### External Contributions diff --git a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/plugin/PMDPlugin.java b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/plugin/PMDPlugin.java index 6f3eca9a..258a2bda 100644 --- a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/plugin/PMDPlugin.java +++ b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/plugin/PMDPlugin.java @@ -138,6 +138,7 @@ public Color colorFor(RGB rgb) { return color; } + @Deprecated // use IProjectProperties#getAuxclasspath() instead public static void setJavaClassLoader(PMDConfiguration config, IProject project) { IPreferences preferences = getDefault().loadPreferences(); diff --git a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/BaseVisitor.java b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/BaseVisitor.java index de25be37..483de596 100644 --- a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/BaseVisitor.java +++ b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/BaseVisitor.java @@ -288,7 +288,9 @@ protected final void reviewResource(IResource resource) { } LOG.debug("discovered language: " + languageVersion); - PMDPlugin.setJavaClassLoader(configuration(), resource.getProject()); + if (PMDPlugin.getDefault().loadPreferences().isProjectBuildPathEnabled()) { + configuration().setClassLoader(projectProperties.getAuxClasspath()); + } final File sourceCodeFile = file.getRawLocation().toFile(); if (included && getRuleSet().applies(sourceCodeFile) && isFileInWorkingSet(file) diff --git a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/ReviewCodeCmd.java b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/ReviewCodeCmd.java index d4f876ef..254a1832 100644 --- a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/ReviewCodeCmd.java +++ b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/cmd/ReviewCodeCmd.java @@ -39,7 +39,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -96,7 +96,7 @@ public class ReviewCodeCmd extends AbstractDefaultCommand { private static final Logger LOG = Logger.getLogger(ReviewCodeCmd.class); - private final List resources = new ArrayList(); + private final List resources = new ArrayList(); private IResourceDelta resourceDelta; private Map> markersByFile = new HashMap>(); private boolean taskMarker; @@ -138,7 +138,7 @@ public Set markedFiles() { /** * Easy way to refresh a set of files. - * + * * @param files * @throws CommandException */ @@ -254,6 +254,7 @@ public void run(IProgressMonitor monitor) throws CoreException { // Switch to the PMD perspective if required if (openPmdPerspective) { Display.getDefault().asyncExec(new Runnable() { + @Override public void run() { switchToPmdPerspective(); } @@ -263,7 +264,7 @@ public void run() { if (openPmdViolationsOverviewView) { PMDPlugin.getDefault().showView(PMDPlugin.VIOLATIONS_OVERVIEW_ID); } - + if (openPmdViolationsOutlineView) { PMDPlugin.getDefault().showView(PMDPlugin.VIOLATIONS_OUTLINE_ID); } @@ -277,12 +278,12 @@ public void run() { // Log performance information if (fileCount > 0 && ruleCount > 0) { - logInfo("Review code command terminated. " + ruleCount + " rules were executed against " + fileCount + logInfo("Review code command finished. " + ruleCount + " rules were executed against " + fileCount + " files. Actual PMD duration is about " + pmdDuration + "ms, that is about " + (float) pmdDuration / fileCount + " ms/file, " + (float) pmdDuration / ruleCount + " ms/rule, " + (float) pmdDuration / ((long) fileCount * (long) ruleCount) + " ms/filerule"); } else { - logInfo("Review code command terminated. " + ruleCount + " rules were executed against " + fileCount + logInfo("Review code command finished. " + ruleCount + " rules were executed against " + fileCount + " files. PMD was not executed."); } } @@ -351,19 +352,19 @@ public void setRunAlways(boolean runAlways) { public void setOpenPmdPerspective(boolean openPmdPerspective) { this.openPmdPerspective = openPmdPerspective; } - + /** * Set the open violations view to run after code review. - * + * * @param openPmdViolationsView should open */ public void setOpenPmdViolationsOverviewView(boolean openPmdViolationsView) { this.openPmdViolationsOverviewView = openPmdViolationsView; } - + /** * Set the open violations outline view to run after code review. - * + * * @param openPmdViolationsOutlineView should open */ public void setOpenPmdViolationsOutlineView(boolean openPmdViolationsOutlineView) { @@ -420,10 +421,13 @@ private ISchedulingRule getSchedulingRule() { * @throws CommandException */ private void processResources() throws CommandException { - final Iterator i = resources.iterator(); - while (i.hasNext()) { - final IResource resource = (IResource) i.next(); + Set projects = new HashSet(); + for (IResource resource : resources) { + projects.add(resource.getProject().getName()); + } + logInfo("ReviewCodeCmd started with " + resources.size() + " selected resources on projects " + projects); + for (IResource resource : resources) { // if resource is a project, visit only its source folders if (resource instanceof IProject) { processProject((IProject) resource); @@ -508,7 +512,8 @@ private void processResource(IResource resource) throws CommandException { private void processProject(IProject project) throws CommandException { try { setStepCount(countResourceElement(project)); - LOG.debug("Visiting project " + project.getName() + " : " + getStepCount()); + logInfo("ReviewCodeCmd: visiting project " + project.getName() + ": " + getStepCount() + " resources found."); + LOG.debug("Visiting project " + project.getName() + " : " + getStepCount() + " resources found."); if (project.hasNature(JavaCore.NATURE_ID)) { processJavaProject(project); @@ -609,6 +614,7 @@ private void processResourceDelta() throws CommandException { IResource resource = resourceDelta.getResource(); final IProject project = resource.getProject(); final IProjectProperties properties = getProjectProperties(project); + logInfo("ReviewCodeCmd started on resource delta " + resource.getName() + " in project " + project.getName()); RuleSet ruleSet = rulesetFromResourceDelta(); // properties.getProjectRuleSet(); @@ -680,7 +686,7 @@ private void applyMarkers() { } finally { timer.stop(); int count = markersByFile.size(); - logInfo("" + violationCount + " markers applied on " + count + " files in " + timer.getDuration() + "ms."); + LOG.info("" + violationCount + " markers applied on " + count + " files in " + timer.getDuration() + "ms."); LOG.info("End of processing marker directives. " + violationCount + " violations for " + count + " files."); } } diff --git a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/IProjectProperties.java b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/IProjectProperties.java index 7d170ec2..83e62d5e 100644 --- a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/IProjectProperties.java +++ b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/IProjectProperties.java @@ -198,4 +198,13 @@ public interface IProjectProperties { * @return include patterns */ Set getBuildPathIncludePatterns(); + + /** + * Determines the auxiliary classpath needed for type resolution. + * The classloader is cached and used for all PMD executions for the same project. + * The classloader is not stored to the project properties file. + * + * @return the classpath or null if the project is not a java project + */ + ClassLoader getAuxClasspath(); } diff --git a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/impl/ProjectPropertiesImpl.java b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/impl/ProjectPropertiesImpl.java index e4f53f79..079a2b10 100644 --- a/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/impl/ProjectPropertiesImpl.java +++ b/net.sourceforge.pmd.eclipse.plugin/src/main/java/net/sourceforge/pmd/eclipse/runtime/properties/impl/ProjectPropertiesImpl.java @@ -51,10 +51,13 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.ui.IWorkingSet; +import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; +import net.sourceforge.pmd.eclipse.runtime.cmd.JavaProjectClassLoader; import net.sourceforge.pmd.eclipse.runtime.properties.IProjectProperties; import net.sourceforge.pmd.eclipse.runtime.properties.IProjectPropertiesManager; import net.sourceforge.pmd.eclipse.runtime.properties.PropertiesException; @@ -89,6 +92,7 @@ public class ProjectPropertiesImpl implements IProjectProperties { private boolean fullBuildEnabled = true; // default in case didn't come from properties private Set buildPathExcludePatterns = new HashSet(); private Set buildPathIncludePatterns = new HashSet(); + private ClassLoader auxclasspath; /** * The default constructor takes a project as an argument @@ -452,4 +456,21 @@ public Set getBuildPathExcludePatterns() { public Set getBuildPathIncludePatterns() { return buildPathIncludePatterns; } + + @Override + public ClassLoader getAuxClasspath() { + try { + if (project != null && project.hasNature(JavaCore.NATURE_ID)) { + if (auxclasspath == null) { + PMDPlugin.getDefault().logInformation("Creating new auxclasspath class loader for project " + project.getName()); + auxclasspath = new JavaProjectClassLoader(PMD.class.getClassLoader(), project); + } + return auxclasspath; + } + } catch (CoreException e) { + LOG.error("Error determining aux classpath", e); + PMDPlugin.getDefault().logError("Error determining aux classpath", e); + } + return null; + } }