Compare commits
39 Commits
main
...
pmd_releas
Author | SHA1 | Date | |
---|---|---|---|
|
3412d55fc6 | ||
|
436b7dcb50 | ||
|
d25dadc4b4 | ||
|
1c051674a0 | ||
|
3daca86045 | ||
|
d95d960de3 | ||
|
ef7478c350 | ||
|
c080fdda08 | ||
|
e603844a53 | ||
|
52b8be6601 | ||
|
7cbb385dbb | ||
|
61c0b4ea7f | ||
|
26fa85a9fa | ||
|
98b903897e | ||
|
55b5aa7f27 | ||
|
ffac9894c9 | ||
|
d557ed9c01 | ||
|
e0b7f6f17c | ||
|
cb9861dd1f | ||
|
7ee96a6b52 | ||
|
ac8e3314a3 | ||
|
7989ae1863 | ||
|
e3708b5030 | ||
|
85e493d55f | ||
|
6abbea51dd | ||
|
9162917346 | ||
|
637006674f | ||
|
63c1a8fe47 | ||
|
063c4228e3 | ||
|
4b0063dfc1 | ||
|
13e36974a5 | ||
|
33c7af965c | ||
|
a66bbf2193 | ||
|
38af8f2433 | ||
|
a6bcfe2b65 | ||
|
6474fde42d | ||
|
8dcde0edb5 | ||
|
70347aedd5 | ||
|
eaf1385595 |
@ -1,4 +1,30 @@
|
||||
???? ??, 2012 - 5.1.0:
|
||||
February 3, 2013 - 5.0.2:
|
||||
|
||||
Fixed bug 878: False positive: UnusedFormalParameter for abstract methods
|
||||
Fixed bug 913: SignatureDeclareThrowsException is raised twice
|
||||
Fixed bug 947: CloseResource rule fails if field is marked with annotation
|
||||
Fixed bug 1004: targetjdk isn't attribute of PMD task
|
||||
Fixed bug 1007: Parse Exception with annotation
|
||||
Fixed bug 1011: CloseResource Rule ignores Constructors
|
||||
Fixed bug 1012: False positive: Useless parentheses.
|
||||
Fixed bug 1020: Parsing Error
|
||||
Fixed bug 1026: PMD doesn't handle 'value =' in SuppressWarnings annotation
|
||||
Fixed bug 1028: False-positive: Compare objects with equals for Enums
|
||||
Fixed bug 1030: CPD Java.lang.IndexOutOfBoundsException: Index:
|
||||
Fixed bug 1037: Facing a showstopper issue in PMD Report Class (report listeners)
|
||||
Fixed bug 1039: pmd-nicerhtml.xsl is packaged in wrong location
|
||||
Fixed bug 1043: node.getEndLine() always returns 0 (ECMAscript)
|
||||
Fixed bug 1044: Unknown option: -excludemarker
|
||||
Fixed bug 1046: ant task CPDTask doesn't accept ecmascript
|
||||
Fixed bug 1047: False Positive in 'for' loops for LocalVariableCouldBeFinal in 5.0.1
|
||||
Fixed bug 1048: CommentContent Rule, String Index out of range Exception
|
||||
Fixed bug 1049: Errors in "How to write a rule"
|
||||
Fixed bug 1055: Please add a colon in the ant output after line,column for Oracle JDeveloper IDE usage
|
||||
Fixed bug 1056: "Error while processing" while running on xml file with DOCTYPE reference
|
||||
Fixed bug 1060: GodClassRule >>> wrong method
|
||||
|
||||
|
||||
November 28, 2012 - 5.0.1:
|
||||
|
||||
Fixed bug 820: False+ AvoidReassigningParameters
|
||||
Fixed bug 1008: pmd-5.0.0: ImmutableField false positive on self-inc/dec
|
||||
@ -471,7 +497,7 @@ The RuleSet XML Schema namespace is now: http://pmd.sourceforge.net/ruleset/2.0.
|
||||
The RuleSet XML Schema is located in the source at: etc/ruleset_2_0_0.xsd
|
||||
The RuleSet DTD is located in the source at: etc/ruleset_2_0_0.dtd
|
||||
Improved include/exclude pattern matching performance for ends-with type patterns.
|
||||
Modify (and hopefully fixed) CPD algorithm thanks to a patch from Juan Jesús García de Soria.
|
||||
Modify (and hopefully fixed) CPD algorithm thanks to a patch from Juan Jesús GarcÃa de Soria.
|
||||
Fixed character reference in xml report - thanks to Seko
|
||||
Enhanced SuspiciousEqualsMethodName rule - thanks to Andy Throgmorton
|
||||
Add a script to launch CPDGUI on Unix system - thanks to Tom Wheeler
|
||||
@ -535,7 +561,7 @@ Fixed bug 2835074 - False -: DoubleCheckedLocking with reversed null check
|
||||
Fixed bug 2826119 - False +: DoubleCheckedLocking warning with volatile field
|
||||
Fixed bug 2904832 - Type resolution not working for ASTType when using an inner class
|
||||
|
||||
Modify (and hopefully fixed) CPD algorithm thanks to a patch from Juan Jesús García de Soria.
|
||||
Modify (and hopefully fixed) CPD algorithm thanks to a patch from Juan Jesús GarcÃa de Soria.
|
||||
Correct -benchmark reporting of Rule visits via the RuleChain
|
||||
Fix issue with Type Resolution incorrectly handling of Classes with same name as a java.lang Class.
|
||||
The JSP/JSF parser can now parse Unicode input.
|
||||
|
@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Fix ForStatement to allow Annotations within the initializer.
|
||||
*
|
||||
* Andreas Dangel 01/2013
|
||||
* ===================================================================
|
||||
* Fix wrong consumption of modifiers (e.g. "final") in a for-each loop.
|
||||
*
|
||||
* Andreas Dangel 12/2012
|
||||
* ===================================================================
|
||||
* Enhance grammar to use LocalVariableDeclaration in a for-each loop.
|
||||
* This enhances the symbol table to recognize variables declared in such
|
||||
* a for-each loop.
|
||||
@ -1914,9 +1922,9 @@ void ForStatement() :
|
||||
{
|
||||
"for" "("
|
||||
(
|
||||
LOOKAHEAD(Modifiers() Type() <IDENTIFIER> ":")
|
||||
LOOKAHEAD(LocalVariableDeclaration() ":")
|
||||
{checkForBadJDK15ForLoopSyntaxArgumentsUsage();}
|
||||
Modifiers() LocalVariableDeclaration() ":" Expression()
|
||||
LocalVariableDeclaration() ":" Expression()
|
||||
|
|
||||
[ ForInit() ] ";"
|
||||
[ Expression() ] ";"
|
||||
@ -1928,7 +1936,7 @@ void ForStatement() :
|
||||
void ForInit() :
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD( [ "final" ] Type() <IDENTIFIER> )
|
||||
LOOKAHEAD( LocalVariableDeclaration() )
|
||||
LocalVariableDeclaration()
|
||||
|
|
||||
StatementExpressionList()
|
||||
|
54
pmd/pom.xml
54
pmd/pom.xml
@ -1,11 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<name>PMD</name>
|
||||
<version>5.1.0-SNAPSHOT</version>
|
||||
<version>5.0.2</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
@ -233,6 +232,7 @@
|
||||
<connection>scm:git:git://github.com/pmd/pmd.git</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/pmd/pmd.git</developerConnection>
|
||||
<url>https://github.com/pmd/pmd</url>
|
||||
<tag>pmd_releases/5.0.2</tag>
|
||||
</scm>
|
||||
<organization>
|
||||
<name>InfoEther</name>
|
||||
@ -246,7 +246,7 @@
|
||||
If the xdocs files stay in src/site/xdoc/, mvn tries to copy over the generated
|
||||
one, and complains... -->
|
||||
<src.xdocs.dir>src/site/xdocs</src.xdocs.dir>
|
||||
<pmd.website.baseurl>http://pmd.sourceforge.net/snapshot</pmd.website.baseurl>
|
||||
<pmd.website.baseurl>http://pmd.sourceforge.net/pmd-${project.version}</pmd.website.baseurl>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@ -333,10 +333,8 @@
|
||||
<configuration>
|
||||
<target>
|
||||
<ant antfile="src/main/ant/alljavacc.xml">
|
||||
<property name="target"
|
||||
value="${project.build.directory}/generated-sources/javacc" />
|
||||
<property name="javacc.jar"
|
||||
value="${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar" />
|
||||
<property name="target" value="${project.build.directory}/generated-sources/javacc" />
|
||||
<property name="javacc.jar" value="${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar" />
|
||||
</ant>
|
||||
</target>
|
||||
</configuration>
|
||||
@ -350,15 +348,11 @@
|
||||
<configuration>
|
||||
<target>
|
||||
<echo>PMD specific tasks: generating xdocs from rulesets</echo>
|
||||
<mkdir
|
||||
dir="${project.build.directory}/generated-xdocs/" />
|
||||
<copy
|
||||
toDir="${project.build.directory}/generated-xdocs/"
|
||||
overwrite="true" verbose="true">
|
||||
<mkdir dir="${project.build.directory}/generated-xdocs/" />
|
||||
<copy toDir="${project.build.directory}/generated-xdocs/" overwrite="true" verbose="true">
|
||||
<fileset dir="${src.xdocs.dir}" />
|
||||
<filterset>
|
||||
<filter token="VERSION"
|
||||
value="${project.version}" />
|
||||
<filter token="VERSION" value="${project.version}" />
|
||||
</filterset>
|
||||
</copy>
|
||||
</target>
|
||||
@ -374,25 +368,18 @@
|
||||
<target>
|
||||
<echo>PMD site specific tasks</echo>
|
||||
<echo>1. Copying missing images to site directory.</echo>
|
||||
<copy
|
||||
todir="${project.build.directory}/site/images/">
|
||||
<fileset dir="${src.xdocs.dir}/images/"
|
||||
includes="**/*.*" />
|
||||
<copy todir="${project.build.directory}/site/images/">
|
||||
<fileset dir="${src.xdocs.dir}/images/" includes="**/*.*" />
|
||||
</copy>
|
||||
<echo>2. Adding missing text files to site.</echo>
|
||||
<copy todir="${project.build.directory}/site/">
|
||||
<fileset dir="${src.xdocs.dir}/"
|
||||
includes="**/*.txt" />
|
||||
<fileset dir="${src.xdocs.dir}/" includes="**/*.txt" />
|
||||
</copy>
|
||||
<echo>3. Deleting useless generated files.</echo>
|
||||
<delete quiet="true">
|
||||
<fileset dir="${src.xdocs.dir}/rules"
|
||||
includes="**/*.xml" />
|
||||
<fileset dir="${src.xdocs.dir}/"
|
||||
includes="mergedruleset.xml" />
|
||||
<fileset
|
||||
dir="${project.build.directory}"
|
||||
includes="site/mergedruleset.html" />
|
||||
<fileset dir="${src.xdocs.dir}/rules" includes="**/*.xml" />
|
||||
<fileset dir="${src.xdocs.dir}/" includes="mergedruleset.xml" />
|
||||
<fileset dir="${project.build.directory}" includes="site/mergedruleset.html" />
|
||||
</delete>
|
||||
</target>
|
||||
</configuration>
|
||||
@ -407,10 +394,8 @@
|
||||
<target>
|
||||
<echo>PMD specific tasks: cleaning generated xdocs</echo>
|
||||
<delete quiet="true">
|
||||
<fileset dir="${src.xdocs.dir}/rules"
|
||||
includes="**/*.xml" />
|
||||
<fileset dir="${src.xdocs.dir}/"
|
||||
includes="mergedruleset.xml" />
|
||||
<fileset dir="${src.xdocs.dir}/rules" includes="**/*.xml" />
|
||||
<fileset dir="${src.xdocs.dir}/" includes="mergedruleset.xml" />
|
||||
</delete>
|
||||
</target>
|
||||
</configuration>
|
||||
@ -620,6 +605,11 @@
|
||||
<artifactId>javacc</artifactId>
|
||||
<version>${javacc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
|
@ -335,8 +335,6 @@ public class PMD {
|
||||
return languages;
|
||||
}
|
||||
|
||||
private static final int ERROR_STATUS = 1;
|
||||
|
||||
/**
|
||||
* Entry to invoke PMD as command line tool
|
||||
*
|
||||
@ -367,7 +365,7 @@ public class PMD {
|
||||
} catch (Exception e) {
|
||||
PMDCommandLineInterface.buildUsageText();
|
||||
System.out.println(e.getMessage());
|
||||
status = ERROR_STATUS;
|
||||
status = PMDCommandLineInterface.ERROR_STATUS;
|
||||
} finally {
|
||||
logHandlerManager.close();
|
||||
LOG.setLevel(oldLogLevel);
|
||||
|
@ -22,15 +22,18 @@ import net.sourceforge.pmd.util.StringUtil;
|
||||
|
||||
public class Report {
|
||||
|
||||
public static Report createReport(RuleContext ctx, String fileName) {
|
||||
|
||||
Report report = new Report();
|
||||
ctx.setReport(report);
|
||||
ctx.setSourceCodeFilename(fileName);
|
||||
ctx.setSourceCodeFile(new File(fileName));
|
||||
return report;
|
||||
}
|
||||
|
||||
public static Report createReport(RuleContext ctx, String fileName) {
|
||||
Report report = new Report();
|
||||
|
||||
// overtake the listener
|
||||
report.addSynchronizedListeners(ctx.getReport().getSynchronizedListeners());
|
||||
|
||||
ctx.setReport(report);
|
||||
ctx.setSourceCodeFilename(fileName);
|
||||
ctx.setSourceCodeFile(new File(fileName));
|
||||
return report;
|
||||
}
|
||||
|
||||
public static class ReadableDuration {
|
||||
private final long duration;
|
||||
|
||||
@ -112,7 +115,7 @@ public class Report {
|
||||
// Note that this and the above data structure are both being maintained for a bit
|
||||
private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
|
||||
private final Set<Metric> metrics = new HashSet<Metric>();
|
||||
private final List<ReportListener> listeners = new ArrayList<ReportListener>();
|
||||
private final List<SynchronizedReportListener> listeners = new ArrayList<SynchronizedReportListener>();
|
||||
private List<ProcessingError> errors;
|
||||
private List<RuleConfigurationError> configErrors;
|
||||
private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
|
||||
@ -164,7 +167,7 @@ public class Report {
|
||||
}
|
||||
|
||||
public void addListener(ReportListener listener) {
|
||||
listeners.add(listener);
|
||||
listeners.add(new SynchronizedReportListener(listener));
|
||||
}
|
||||
|
||||
public List<SuppressedViolation> getSuppressedRuleViolations() {
|
||||
@ -266,13 +269,13 @@ public class Report {
|
||||
}
|
||||
|
||||
public Iterator<ProcessingError> errors() {
|
||||
return errors == null ? EmptyIterator.instance : errors.iterator();
|
||||
return errors == null ? EmptyIterator.<ProcessingError> instance() : errors.iterator();
|
||||
}
|
||||
|
||||
public Iterator<RuleConfigurationError> configErrors() {
|
||||
return configErrors == null ? EmptyIterator.instance : errors.iterator();
|
||||
return configErrors == null ? EmptyIterator.<RuleConfigurationError> instance() : configErrors.iterator();
|
||||
}
|
||||
|
||||
|
||||
public int treeSize() {
|
||||
return violationTree.size();
|
||||
}
|
||||
@ -292,4 +295,12 @@ public class Report {
|
||||
public long getElapsedTimeInMillis() {
|
||||
return end - start;
|
||||
}
|
||||
|
||||
public List<SynchronizedReportListener> getSynchronizedListeners() {
|
||||
return listeners;
|
||||
}
|
||||
|
||||
public void addSynchronizedListeners(List<SynchronizedReportListener> synchronizedListeners) {
|
||||
listeners.addAll(synchronizedListeners);
|
||||
}
|
||||
}
|
||||
|
@ -42,10 +42,11 @@ public class RuleContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which shares attributes with the given RuleContext.
|
||||
* Constructor which shares attributes and report listeners with the given RuleContext.
|
||||
*/
|
||||
public RuleContext(RuleContext ruleContext) {
|
||||
this.attributes = ruleContext.attributes;
|
||||
this.report.addSynchronizedListeners(ruleContext.getReport().getSynchronizedListeners());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd;
|
||||
|
||||
import net.sourceforge.pmd.stat.Metric;
|
||||
|
||||
/**
|
||||
* Wraps a report listener in order to synchronize calls to it.
|
||||
*/
|
||||
public final class SynchronizedReportListener implements ReportListener {
|
||||
|
||||
private final ReportListener wrapped;
|
||||
|
||||
public SynchronizedReportListener(ReportListener listener) {
|
||||
this.wrapped = listener;
|
||||
}
|
||||
|
||||
public synchronized void ruleViolationAdded(RuleViolation ruleViolation) {
|
||||
wrapped.ruleViolationAdded(ruleViolation);
|
||||
}
|
||||
|
||||
public synchronized void metricAdded(Metric metric) {
|
||||
wrapped.metricAdded(metric);
|
||||
}
|
||||
|
||||
}
|
@ -26,7 +26,6 @@ import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.RuleSetFactory;
|
||||
import net.sourceforge.pmd.RuleSetNotFoundException;
|
||||
import net.sourceforge.pmd.RuleSets;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.renderers.AbstractRenderer;
|
||||
import net.sourceforge.pmd.renderers.Renderer;
|
||||
@ -110,24 +109,10 @@ public class PMDTask extends Task {
|
||||
formatters.add(f);
|
||||
}
|
||||
|
||||
public void addConfiguredVersion(Version version) {
|
||||
LanguageVersion languageVersion = LanguageVersion.findByTerseName(version.getTerseName());
|
||||
public void addConfiguredSourceLanguage(SourceLanguage version) {
|
||||
LanguageVersion languageVersion = LanguageVersion.findVersionsForLanguageTerseName(version.getName(), version.getVersion());
|
||||
if (languageVersion == null) {
|
||||
StringBuilder buf = new StringBuilder("The <version> element, if used, must be one of ");
|
||||
boolean first = true;
|
||||
for (Language language : Language.values()) {
|
||||
if (language.getVersions().size() > 2) {
|
||||
for (LanguageVersion v : language.getVersions()) {
|
||||
if (!first) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append('\'').append(v.getTerseName()).append('\'');
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.append('.');
|
||||
throw new BuildException(buf.toString());
|
||||
throw new BuildException("The following language is not supported:" + version + ".");
|
||||
}
|
||||
configuration.setDefaultLanguageVersion(languageVersion);
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd.ant;
|
||||
|
||||
/**
|
||||
* Stores LanguageVersion terse name value.
|
||||
*/
|
||||
public class SourceLanguage {
|
||||
|
||||
private String name;
|
||||
private String version;
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "<language name=\"" + this.name + "\" version=\"" + this.version + "\" />";
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd.ant;
|
||||
|
||||
/**
|
||||
* Stores LanguageVersion terse name value.
|
||||
*/
|
||||
public class Version {
|
||||
private String terseName;
|
||||
|
||||
public void addText(String text) {
|
||||
this.terseName = text;
|
||||
}
|
||||
|
||||
public String getTerseName() {
|
||||
return terseName;
|
||||
}
|
||||
}
|
@ -27,17 +27,24 @@ public class PMDCommandLineInterface {
|
||||
public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit";
|
||||
public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
|
||||
|
||||
public static final int ERROR_STATUS = 1;
|
||||
|
||||
public static PMDParameters extractParameters(PMDParameters arguments, String[] args, String progName) {
|
||||
jcommander = new JCommander(arguments);
|
||||
jcommander.setProgramName(progName);
|
||||
|
||||
try {
|
||||
jcommander = new JCommander(arguments, args);
|
||||
jcommander.setProgramName(progName);
|
||||
jcommander.parse(args);
|
||||
if (arguments.isHelp()) {
|
||||
jcommander.usage();
|
||||
System.exit(0);
|
||||
System.out.println(buildUsageText());
|
||||
setStatusCodeOrExit(0);
|
||||
}
|
||||
} catch (ParameterException e) {
|
||||
jcommander.usage();
|
||||
System.out.println(buildUsageText());
|
||||
System.out.println(e.getMessage());
|
||||
setStatusCodeOrExit(ERROR_STATUS);
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
@ -61,7 +68,7 @@ public class PMDCommandLineInterface {
|
||||
+ "3) A ruleset filename or a comma-delimited string of ruleset filenames" + PMD.EOL
|
||||
+ PMD.EOL
|
||||
+ "For example: " + PMD.EOL
|
||||
+ "c:\\> " + launchCmd + "-d c:\\my\\source\\code -f html -R java-unusedcode" + PMD.EOL
|
||||
+ "c:\\> " + launchCmd + " -d c:\\my\\source\\code -f html -R java-unusedcode" + PMD.EOL
|
||||
+ PMD.EOL;
|
||||
|
||||
fullText += supportedVersions() + PMD.EOL;
|
||||
@ -148,12 +155,16 @@ public class PMDCommandLineInterface {
|
||||
}
|
||||
|
||||
public static void run(String[] args) {
|
||||
if ( isExitAfterRunSet() )
|
||||
System.exit(PMD.run(args));
|
||||
else
|
||||
setStatusCode(PMD.run(args));
|
||||
setStatusCodeOrExit(PMD.run(args));
|
||||
}
|
||||
|
||||
public static void setStatusCodeOrExit(int status) {
|
||||
if ( isExitAfterRunSet() )
|
||||
System.exit(status);
|
||||
else
|
||||
setStatusCode(status);
|
||||
}
|
||||
|
||||
private static boolean isExitAfterRunSet() {
|
||||
return (System.getenv(NO_EXIT_AFTER_RUN) == null ? false : true);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class PMDParameters {
|
||||
@Parameter(names = {"-debug", "-verbose", "-D", "-V"}, description = "Debug mode")
|
||||
private boolean debug = false;
|
||||
|
||||
@Parameter(names = {"-help","-h","-H"}, description = "Display help on usage")
|
||||
@Parameter(names = {"-help","-h","-H"}, description = "Display help on usage", help = true)
|
||||
private boolean help = false;
|
||||
|
||||
@Parameter(names= {"-encoding", "-e"} , description = "specifies the character set encoding of the source code files PMD is reading (i.e., UTF-8)")
|
||||
@ -67,7 +67,7 @@ public class PMDParameters {
|
||||
@Parameter(names = {"-language", "-l"}, description = "specify version of a language PMD should use")
|
||||
private String language = Language.getDefaultLanguage().getTerseName();
|
||||
|
||||
@Parameter(names = "-auxclasspath", description = "specifies the classpath for libraries used by the source code (used by type resolution)\n(alternatively, a 'file://' URL to a text file containing path elements on consecutive lines")
|
||||
@Parameter(names = "-auxclasspath", description = "specifies the classpath for libraries used by the source code. This is used by the type resolution. Alternatively, a 'file://' URL to a text file containing path elements on consecutive lines can be specified.")
|
||||
private String auxclasspath;
|
||||
|
||||
class PropertyConverter implements IStringConverter<Properties> {
|
||||
|
@ -31,6 +31,8 @@ public class CPD {
|
||||
|
||||
public CPD(CPDConfiguration theConfiguration) {
|
||||
configuration = theConfiguration;
|
||||
// before we start any tokenizing (add(File...)), we need to reset the static TokenEntry status
|
||||
TokenEntry.clearImages();
|
||||
}
|
||||
|
||||
public void setCpdListener(CPDListener cpdListener) {
|
||||
@ -38,7 +40,6 @@ public class CPD {
|
||||
}
|
||||
|
||||
public void go() {
|
||||
TokenEntry.clearImages();
|
||||
matchAlgorithm = new MatchAlgorithm(
|
||||
source, tokens,
|
||||
configuration.minimumTileSize(),
|
||||
|
@ -188,16 +188,9 @@ public class CPDTask extends Task {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME Can't we do something cleaner and
|
||||
* more dynamic ? Maybe externalise to a properties files that will
|
||||
* be generated when building pmd ? This will not have to add manually
|
||||
* new language here ?
|
||||
*/
|
||||
public static class LanguageAttribute extends EnumeratedAttribute {
|
||||
private static final String[] LANGUAGES = new String[]{"java","jsp","cpp", "c","php", "ruby", "fortran", "cs"};
|
||||
public String[] getValues() {
|
||||
return LANGUAGES;
|
||||
return LanguageFactory.supportedLanguages;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,19 +106,22 @@ public class GUI implements CPDListener {
|
||||
{"Fortran", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("fortran"); }
|
||||
public String[] extensions() { return new String[] {".rb" }; }; } },
|
||||
{"by extension...", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.BY_EXTENSION, p); }
|
||||
public String[] extensions() { return new String[] {"" }; }; } },
|
||||
{"PHP", new LanguageConfig() {
|
||||
{"PHP", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("php"); }
|
||||
public String[] extensions() { return new String[] {".php" }; }; } },
|
||||
{"C#", new LanguageConfig() {
|
||||
{"C#", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("cs"); }
|
||||
public String[] extensions() { return new String[] {".cs" }; }; } },
|
||||
{"Ecmascript", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage("js"); }
|
||||
public String[] extensions() { return new String[] {".js" }; }; } },
|
||||
{"by extension...", new LanguageConfig() {
|
||||
public Language languageFor(LanguageFactory lf, Properties p) { return lf.createLanguage(LanguageFactory.BY_EXTENSION, p); }
|
||||
public String[] extensions() { return new String[] {"" }; }; } },
|
||||
};
|
||||
|
||||
private static final int DEFAULT_CPD_MINIMUM_LENGTH = 75;
|
||||
private static final Map LANGUAGE_CONFIGS_BY_LABEL = new HashMap(LANGUAGE_SETS.length);
|
||||
private static final Map<String, LanguageConfig> LANGUAGE_CONFIGS_BY_LABEL = new HashMap<String, LanguageConfig>(LANGUAGE_SETS.length);
|
||||
private static final KeyStroke COPY_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C,ActionEvent.CTRL_MASK,false);
|
||||
private static final KeyStroke DELETE_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
|
||||
|
||||
@ -148,12 +151,12 @@ public class GUI implements CPDListener {
|
||||
|
||||
static {
|
||||
for (int i=0; i<LANGUAGE_SETS.length; i++) {
|
||||
LANGUAGE_CONFIGS_BY_LABEL.put(LANGUAGE_SETS[i][0], LANGUAGE_SETS[i][1]);
|
||||
LANGUAGE_CONFIGS_BY_LABEL.put((String)LANGUAGE_SETS[i][0], (LanguageConfig)LANGUAGE_SETS[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
private static LanguageConfig languageConfigFor(String label) {
|
||||
return (LanguageConfig)LANGUAGE_CONFIGS_BY_LABEL.get(label);
|
||||
return LANGUAGE_CONFIGS_BY_LABEL.get(label);
|
||||
}
|
||||
|
||||
private static class CancelListener implements ActionListener {
|
||||
|
@ -7,9 +7,16 @@ import java.util.Properties;
|
||||
|
||||
public class LanguageFactory {
|
||||
|
||||
// TODO derive and provide this at runtime instead, used by outside IDEs
|
||||
public static String[] supportedLanguages = new String[]{"java", "jsp", "cpp", "c", "php", "ruby","fortran", "ecmascript","cs" };
|
||||
|
||||
/*
|
||||
* TODO derive and provide this at runtime instead, used by outside IDEs
|
||||
* FIXME Can't we do something cleaner and
|
||||
* more dynamic ? Maybe externalise to a properties files that will
|
||||
* be generated when building pmd ? This will not have to add manually
|
||||
* new language here ?
|
||||
*/
|
||||
public static String[] supportedLanguages =
|
||||
new String[]{"java", "jsp", "cpp", "c", "php", "ruby", "fortran", "ecmascript", "cs"};
|
||||
|
||||
private static final String SUFFIX = "Language";
|
||||
public static final String EXTENSION = "extension";
|
||||
public static final String BY_EXTENSION = "by_extension";
|
||||
|
@ -200,6 +200,23 @@ public enum LanguageVersion {
|
||||
return versionsAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to retrieve the appropriate enum, given the provided parameters
|
||||
*
|
||||
* @param languageTerseName The LanguageVersion terse name.
|
||||
* @param languageVersion The version of the language requested.
|
||||
* @return A list of versions associated with the terse name.
|
||||
*/
|
||||
public static LanguageVersion findVersionsForLanguageTerseName(String languageTerseName, String languageVersion) {
|
||||
List<LanguageVersion> versionsAvailable = findVersionsForLanguageTerseName(languageTerseName);
|
||||
for ( LanguageVersion version : versionsAvailable ) {
|
||||
if ( version.getVersion().equalsIgnoreCase(languageVersion) )
|
||||
return version;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a comma-separated list of LanguageVersion terse names.
|
||||
* @param languageVersions The language versions.
|
||||
|
@ -119,7 +119,7 @@ public abstract class AbstractNode implements Node {
|
||||
if (children != null && children.length > 0) {
|
||||
return children[0].getBeginColumn();
|
||||
} else {
|
||||
throw new RuntimeException("Unable to determine begining line of Node.");
|
||||
throw new RuntimeException("Unable to determine beginning line of Node.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,18 +7,27 @@ import net.sourceforge.pmd.lang.ast.AbstractNode;
|
||||
|
||||
import org.mozilla.javascript.ast.AstNode;
|
||||
|
||||
public abstract class AbstractEcmascriptNode<T extends AstNode> extends AbstractNode implements EcmascriptNode {
|
||||
public abstract class AbstractEcmascriptNode<T extends AstNode> extends AbstractNode implements EcmascriptNode<T> {
|
||||
|
||||
protected final T node;
|
||||
|
||||
public AbstractEcmascriptNode(T node) {
|
||||
super(node.getType());
|
||||
this.node = node;
|
||||
this.beginLine = node.getLineno() + 1;
|
||||
this.beginLine = node.getLineno() + 1;
|
||||
// TODO Implement positions, or figure out how to do begin/end lines/column
|
||||
//this.beginPosition = node.getAbsolutePosition();
|
||||
//this.endPosition = this.beginPosition + node.getLength();
|
||||
}
|
||||
|
||||
/* package private */
|
||||
void calculateLineNumbers(SourceCodePositioner positioner) {
|
||||
int startOffset = node.getAbsolutePosition();
|
||||
int endOffset = startOffset + node.getLength();
|
||||
|
||||
this.beginLine = positioner.lineNumberFromOffset(startOffset);
|
||||
this.beginColumn = positioner.columnFromOffset(startOffset);
|
||||
this.endLine = positioner.lineNumberFromOffset(endOffset);
|
||||
this.endColumn = positioner.columnFromOffset(endOffset) - 1; // end column is inclusive
|
||||
if (this.endColumn < 0) {
|
||||
this.endColumn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -34,7 +43,9 @@ public abstract class AbstractEcmascriptNode<T extends AstNode> extends Abstract
|
||||
public Object childrenAccept(EcmascriptParserVisitor visitor, Object data) {
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.length; ++i) {
|
||||
((EcmascriptNode) children[i]).jjtAccept(visitor, data);
|
||||
@SuppressWarnings("unchecked") // we know that the children here are all EcmascriptNodes
|
||||
EcmascriptNode<T> ecmascriptNode = (EcmascriptNode<T>) children[i];
|
||||
ecmascriptNode.jjtAccept(visitor, data);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
@ -52,11 +63,6 @@ public abstract class AbstractEcmascriptNode<T extends AstNode> extends Abstract
|
||||
return node.hasSideEffects();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBeginColumn() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node.shortName();
|
||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.Parser;
|
||||
import org.mozilla.javascript.ast.AstRoot;
|
||||
@ -24,7 +25,7 @@ public class EcmascriptParser {
|
||||
this.parserOptions = parserOptions;
|
||||
}
|
||||
|
||||
protected AstRoot parseEcmascript(final Reader reader, final List<ParseProblem> parseProblems) throws ParseException {
|
||||
protected AstRoot parseEcmascript(final String sourceCode, final List<ParseProblem> parseProblems) throws ParseException {
|
||||
final CompilerEnvirons compilerEnvirons = new CompilerEnvirons();
|
||||
compilerEnvirons.setRecordingComments(parserOptions.isRecordingComments());
|
||||
compilerEnvirons.setRecordingLocalJsDocComments(parserOptions.isRecordingLocalJsDocComments());
|
||||
@ -35,23 +36,23 @@ public class EcmascriptParser {
|
||||
// TODO We should do something with Rhino errors...
|
||||
final ErrorCollector errorCollector = new ErrorCollector();
|
||||
final Parser parser = new Parser(compilerEnvirons, errorCollector);
|
||||
// TODO Fix hardcode
|
||||
final String sourceURI = "unknown";
|
||||
final int beginLineno = 1;
|
||||
AstRoot astRoot = parser.parse(sourceCode, sourceURI, beginLineno);
|
||||
parseProblems.addAll(errorCollector.getErrors());
|
||||
return astRoot;
|
||||
}
|
||||
|
||||
public EcmascriptNode<AstRoot> parse(final Reader reader) {
|
||||
try {
|
||||
// TODO Fix hardcode
|
||||
final String sourceURI = "unknown";
|
||||
// TODO Fix hardcode
|
||||
final int lineno = 0;
|
||||
AstRoot astRoot = parser.parse(reader, sourceURI, lineno);
|
||||
parseProblems.addAll(errorCollector.getErrors());
|
||||
return astRoot;
|
||||
} catch (final IOException e) {
|
||||
final List<ParseProblem> parseProblems = new ArrayList<ParseProblem>();
|
||||
final String sourceCode = IOUtils.toString(reader);
|
||||
final AstRoot astRoot = parseEcmascript(sourceCode, parseProblems);
|
||||
final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(sourceCode, parseProblems);
|
||||
return treeBuilder.build(astRoot);
|
||||
} catch (IOException e) {
|
||||
throw new ParseException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public EcmascriptNode parse(final Reader reader) {
|
||||
final List<ParseProblem> parseProblems = new ArrayList<ParseProblem>();
|
||||
final AstRoot astRoot = parseEcmascript(reader, parseProblems);
|
||||
final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(parseProblems);
|
||||
return treeBuilder.build(astRoot);
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ import org.mozilla.javascript.ast.XmlExpression;
|
||||
import org.mozilla.javascript.ast.XmlMemberGet;
|
||||
import org.mozilla.javascript.ast.XmlString;
|
||||
|
||||
public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
public final class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
|
||||
protected static final Map<Class<? extends AstNode>, Constructor<? extends EcmascriptNode>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<Class<? extends AstNode>, Constructor<? extends EcmascriptNode>>();
|
||||
private static final Map<Class<? extends AstNode>, Constructor<? extends EcmascriptNode<?>>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<Class<? extends AstNode>, Constructor<? extends EcmascriptNode<?>>>();
|
||||
static {
|
||||
register(ArrayComprehension.class, ASTArrayComprehension.class);
|
||||
register(ArrayComprehensionLoop.class, ASTArrayComprehensionLoop.class);
|
||||
@ -120,7 +120,7 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
register(XmlString.class, ASTXmlString.class);
|
||||
}
|
||||
|
||||
protected static void register(Class<? extends AstNode> nodeType, Class<? extends EcmascriptNode> nodeAdapterType) {
|
||||
private static <T extends AstNode> void register(Class<T> nodeType, Class<? extends EcmascriptNode<T>> nodeAdapterType) {
|
||||
try {
|
||||
NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType));
|
||||
} catch (SecurityException e) {
|
||||
@ -139,13 +139,18 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
// The Rhino nodes with children to build.
|
||||
protected Stack<AstNode> parents = new Stack<AstNode>();
|
||||
|
||||
public EcmascriptTreeBuilder(List<ParseProblem> parseProblems) {
|
||||
private final SourceCodePositioner sourceCodePositioner;
|
||||
|
||||
public EcmascriptTreeBuilder(String sourceCode, List<ParseProblem> parseProblems) {
|
||||
this.sourceCodePositioner = new SourceCodePositioner(sourceCode);
|
||||
this.parseProblems = parseProblems;
|
||||
}
|
||||
|
||||
protected EcmascriptNode createNodeAdapter(AstNode node) {
|
||||
private <T extends AstNode> EcmascriptNode<T> createNodeAdapter(T node) {
|
||||
try {
|
||||
Constructor<? extends EcmascriptNode> constructor = NODE_TYPE_TO_NODE_ADAPTER_TYPE.get(node.getClass());
|
||||
@SuppressWarnings("unchecked") // the register function makes sure only EcmascriptNode<T> can be added,
|
||||
// where T is "T extends AstNode".
|
||||
Constructor<? extends EcmascriptNode<T>> constructor = (Constructor<? extends EcmascriptNode<T>>) NODE_TYPE_TO_NODE_ADAPTER_TYPE.get(node.getClass());
|
||||
if (constructor == null) {
|
||||
throw new IllegalArgumentException("There is no Node adapter class registered for the Node class: "
|
||||
+ node.getClass());
|
||||
@ -160,8 +165,10 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
public EcmascriptNode build(AstNode astNode) {
|
||||
EcmascriptNode node = buildInternal(astNode);
|
||||
public <T extends AstNode> EcmascriptNode<T> build(T astNode) {
|
||||
EcmascriptNode<T> node = buildInternal(astNode);
|
||||
|
||||
calculateLineNumbers(node);
|
||||
|
||||
// Set all the trailing comma nodes
|
||||
for (TrailingCommaNode trailingCommaNode : parseProblemToNode.values()) {
|
||||
@ -171,9 +178,9 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
return node;
|
||||
}
|
||||
|
||||
protected EcmascriptNode buildInternal(AstNode astNode) {
|
||||
private <T extends AstNode> EcmascriptNode<T> buildInternal(T astNode) {
|
||||
// Create a Node
|
||||
EcmascriptNode node = createNodeAdapter(astNode);
|
||||
EcmascriptNode<T> node = createNodeAdapter(astNode);
|
||||
|
||||
// Append to parent
|
||||
Node parent = nodes.isEmpty() ? null : nodes.peek();
|
||||
@ -203,7 +210,7 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleParseProblems(EcmascriptNode node) {
|
||||
private void handleParseProblems(EcmascriptNode<? extends AstNode> node) {
|
||||
if (node instanceof TrailingCommaNode) {
|
||||
TrailingCommaNode trailingCommaNode = (TrailingCommaNode) node;
|
||||
int nodeStart = node.getNode().getAbsolutePosition();
|
||||
@ -216,7 +223,7 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
if ("Trailing comma is not legal in an ECMA-262 object initializer".equals(parseProblem.getMessage())) {
|
||||
// Report on the shortest code block containing the
|
||||
// problem (i.e. inner most code in nested structures).
|
||||
EcmascriptNode currentNode = (EcmascriptNode) parseProblemToNode.get(parseProblem);
|
||||
EcmascriptNode<? extends AstNode> currentNode = (EcmascriptNode<? extends AstNode>) parseProblemToNode.get(parseProblem);
|
||||
if (currentNode == null || node.getNode().getLength() < currentNode.getNode().getLength()) {
|
||||
parseProblemToNode.put(parseProblem, trailingCommaNode);
|
||||
}
|
||||
@ -225,4 +232,15 @@ public class EcmascriptTreeBuilder implements NodeVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateLineNumbers(EcmascriptNode<?> node) {
|
||||
EcmascriptParserVisitorAdapter visitor = new EcmascriptParserVisitorAdapter() {
|
||||
@Override
|
||||
public Object visit(EcmascriptNode node, Object data) {
|
||||
((AbstractEcmascriptNode<?>)node).calculateLineNumbers(sourceCodePositioner);
|
||||
return super.visit(node, data); // also visit the children
|
||||
}
|
||||
};
|
||||
node.jjtAccept(visitor, null);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.ecmascript.ast;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Calculates from an absolute offset in the source file the line/column coordinate.
|
||||
* This is needed as Rhino only offers absolute positions for each node.
|
||||
*
|
||||
* Idea from: http://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/javascript/jscomp/SourceFile.java
|
||||
*/
|
||||
public class SourceCodePositioner {
|
||||
|
||||
private int[] lineOffsets;
|
||||
|
||||
public SourceCodePositioner(String sourceCode) {
|
||||
analyzeLineOffsets(sourceCode);
|
||||
}
|
||||
|
||||
private void analyzeLineOffsets(String sourceCode) {
|
||||
String[] lines = sourceCode.split("\n");
|
||||
|
||||
int startOffset = 0;
|
||||
int lineNumber = 0;
|
||||
|
||||
lineOffsets = new int[lines.length];
|
||||
|
||||
for (String line : lines) {
|
||||
lineOffsets[lineNumber] = startOffset;
|
||||
lineNumber++;
|
||||
startOffset += line.length() + 1; // +1 for the "\n" character
|
||||
}
|
||||
}
|
||||
|
||||
public int lineNumberFromOffset(int offset) {
|
||||
int search = Arrays.binarySearch(lineOffsets, offset);
|
||||
int lineNumber;
|
||||
if (search >= 0) {
|
||||
lineNumber = search;
|
||||
} else {
|
||||
int insertionPoint = search;
|
||||
insertionPoint += 1;
|
||||
insertionPoint *= -1;
|
||||
lineNumber = insertionPoint - 1; // take the insertion point one before
|
||||
}
|
||||
return lineNumber + 1; // 1-based line numbers
|
||||
}
|
||||
|
||||
public int columnFromOffset(int offset) {
|
||||
int lineNumber = lineNumberFromOffset(offset);
|
||||
int columnOffset = offset - lineOffsets[lineNumber - 1];
|
||||
return columnOffset + 1; // 1-based column offsets
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
public class ASTAnnotation extends AbstractJavaNode {
|
||||
|
||||
@ -27,20 +28,27 @@ public class ASTAnnotation extends AbstractJavaNode {
|
||||
|
||||
if (jjtGetChild(0) instanceof ASTSingleMemberAnnotation) {
|
||||
ASTSingleMemberAnnotation n = (ASTSingleMemberAnnotation) jjtGetChild(0);
|
||||
return checkAnnototation(n, ruleAnno, rule);
|
||||
} else if (jjtGetChild(0) instanceof ASTNormalAnnotation) {
|
||||
ASTNormalAnnotation n = (ASTNormalAnnotation) jjtGetChild(0);
|
||||
return checkAnnototation(n, ruleAnno, rule);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n.jjtGetChild(0) instanceof ASTName) {
|
||||
ASTName annName = (ASTName) n.jjtGetChild(0);
|
||||
private boolean checkAnnototation(Node n, String ruleAnno, Rule rule) {
|
||||
if (n.jjtGetChild(0) instanceof ASTName) {
|
||||
ASTName annName = (ASTName) n.jjtGetChild(0);
|
||||
|
||||
if (annName.getImage().equals("SuppressWarnings")) {
|
||||
List<ASTLiteral> nodes = n.findDescendantsOfType(ASTLiteral.class);
|
||||
for (ASTLiteral element : nodes) {
|
||||
if (element.hasImageEqualTo("\"PMD\"") || element.hasImageEqualTo(ruleAnno)
|
||||
// Check for standard annotations values
|
||||
|| element.hasImageEqualTo("\"all\"")
|
||||
|| element.hasImageEqualTo("\"serial\"") && serialRules.contains(rule.getName())
|
||||
|| element.hasImageEqualTo("\"unused\"") && unusedRules.contains(rule.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (annName.getImage().equals("SuppressWarnings")) {
|
||||
List<ASTLiteral> nodes = n.findDescendantsOfType(ASTLiteral.class);
|
||||
for (ASTLiteral element : nodes) {
|
||||
if (element.hasImageEqualTo("\"PMD\"") || element.hasImageEqualTo(ruleAnno)
|
||||
// Check for standard annotations values
|
||||
|| element.hasImageEqualTo("\"all\"")
|
||||
|| element.hasImageEqualTo("\"serial\"") && serialRules.contains(rule.getName())
|
||||
|| element.hasImageEqualTo("\"unused\"") && unusedRules.contains(rule.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
package net.sourceforge.pmd.lang.java.rule.comments;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -95,7 +98,7 @@ public abstract class AbstractCommentRule extends AbstractJavaRule {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.charAt(0) == '*') {
|
||||
if (line.length() > 0 && line.charAt(0) == '*') {
|
||||
filteredLines.add(line.substring(1));
|
||||
continue;
|
||||
}
|
||||
@ -122,7 +125,7 @@ public abstract class AbstractCommentRule extends AbstractJavaRule {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.charAt(0) == '*') {
|
||||
if (line.length() > 0 && line.charAt(0) == '*') {
|
||||
filteredLines.add(line.substring(1));
|
||||
continue;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
@ -71,8 +72,19 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTConstructorDeclaration node, Object data) {
|
||||
checkForResources(node, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodDeclaration node, Object data) {
|
||||
checkForResources(node, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private void checkForResources(Node node, Object data) {
|
||||
List<ASTLocalVariableDeclaration> vars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class);
|
||||
List<ASTVariableDeclaratorId> ids = new ArrayList<ASTVariableDeclaratorId>();
|
||||
|
||||
@ -85,7 +97,7 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) {
|
||||
ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
|
||||
if (types.contains(clazz.getImage())) {
|
||||
ASTVariableDeclaratorId id = (ASTVariableDeclaratorId) var.jjtGetChild(1).jjtGetChild(0);
|
||||
ASTVariableDeclaratorId id = var.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
@ -96,7 +108,6 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
for (ASTVariableDeclaratorId x : ids) {
|
||||
ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void ensureClosed(ASTLocalVariableDeclaration var,
|
||||
@ -107,11 +118,11 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
String target = variableToClose + ".close";
|
||||
Node n = var;
|
||||
|
||||
while (!(n instanceof ASTBlock)) {
|
||||
while (!(n instanceof ASTBlock) && !(n instanceof ASTConstructorDeclaration)) {
|
||||
n = n.jjtGetParent();
|
||||
}
|
||||
|
||||
ASTBlock top = (ASTBlock) n;
|
||||
Node top = n;
|
||||
|
||||
List<ASTTryStatement> tryblocks = top.findDescendantsOfType(ASTTryStatement.class);
|
||||
|
||||
@ -206,7 +217,7 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
List<ASTReturnStatement> returns = new ArrayList<ASTReturnStatement>();
|
||||
top.findDescendantsOfType(ASTReturnStatement.class, returns, true);
|
||||
for (ASTReturnStatement returnStatement : returns) {
|
||||
ASTName name = returnStatement.getFirstChildOfType(ASTName.class);
|
||||
ASTName name = returnStatement.getFirstDescendantOfType(ASTName.class);
|
||||
if ((name != null) && name.getImage().equals(variableToClose)) {
|
||||
closed = true;
|
||||
break;
|
||||
@ -216,7 +227,7 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
|
||||
// if all is not well, complain
|
||||
if (!closed) {
|
||||
ASTType type = (ASTType) var.jjtGetChild(0);
|
||||
ASTType type = var.getFirstChildOfType(ASTType.class);
|
||||
ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0);
|
||||
ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0);
|
||||
addViolation(data, id, clazz.getImage());
|
||||
|
@ -5,6 +5,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
|
||||
@ -65,6 +66,14 @@ public class CompareObjectsWithEqualsRule extends AbstractJavaRule {
|
||||
}
|
||||
|
||||
if (nd0.isReferenceType() && nd1.isReferenceType()) {
|
||||
|
||||
ASTReferenceType type0 = (ASTReferenceType)((Node) nd0.getAccessNodeParent()).jjtGetChild(0).jjtGetChild(0);
|
||||
ASTReferenceType type1 = (ASTReferenceType)((Node) nd1.getAccessNodeParent()).jjtGetChild(0).jjtGetChild(0);
|
||||
// skip, if it is an enum
|
||||
if (type0.getType() != null && type0.getType().equals(type1.getType()) && type0.getType().isEnum()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
addViolation(data, node);
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class GenericClassCounterRule extends AbstractJavaRule {
|
||||
private int threshold;
|
||||
|
||||
private static String counterLabel;
|
||||
|
||||
|
||||
public GenericClassCounterRule() {
|
||||
definePropertyDescriptor(NAME_MATCH_DESCRIPTOR);
|
||||
definePropertyDescriptor(OPERAND_DESCRIPTOR);
|
||||
@ -178,7 +178,7 @@ public class GenericClassCounterRule extends AbstractJavaRule {
|
||||
}
|
||||
// Cleaning the context for the others rules
|
||||
ctx.removeAttribute(counterLabel);
|
||||
super.start(ctx);
|
||||
super.end(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,18 +154,20 @@ public class GodClassRule extends AbstractJavaRule {
|
||||
int pairs = 0;
|
||||
|
||||
if (methodCount > 1) {
|
||||
for (int i = 0; i < methodCount - 1; i++) {
|
||||
String firstMethodName = methods.get(i);
|
||||
String secondMethodName = methods.get(i + 1);
|
||||
Set<String> accessesOfFirstMethod = methodAttributeAccess.get(firstMethodName);
|
||||
Set<String> accessesOfSecondMethod = methodAttributeAccess.get(secondMethodName);
|
||||
Set<String> combinedAccesses = new HashSet<String>();
|
||||
|
||||
combinedAccesses.addAll(accessesOfFirstMethod);
|
||||
combinedAccesses.addAll(accessesOfSecondMethod);
|
||||
|
||||
if (combinedAccesses.size() < (accessesOfFirstMethod.size() + accessesOfSecondMethod.size())) {
|
||||
pairs++;
|
||||
for (int i = 0; i < methodCount; i++) {
|
||||
for (int j = i + 1; j < methodCount; j++) {
|
||||
String firstMethodName = methods.get(i);
|
||||
String secondMethodName = methods.get(j);
|
||||
Set<String> accessesOfFirstMethod = methodAttributeAccess.get(firstMethodName);
|
||||
Set<String> accessesOfSecondMethod = methodAttributeAccess.get(secondMethodName);
|
||||
Set<String> combinedAccesses = new HashSet<String>();
|
||||
|
||||
combinedAccesses.addAll(accessesOfFirstMethod);
|
||||
combinedAccesses.addAll(accessesOfSecondMethod);
|
||||
|
||||
if (combinedAccesses.size() < (accessesOfFirstMethod.size() + accessesOfSecondMethod.size())) {
|
||||
pairs++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.sourceforge.pmd.lang.java.rule.strictexception;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
@ -8,6 +9,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTNameList;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
|
||||
/**
|
||||
@ -46,7 +48,11 @@ public class SignatureDeclareThrowsExceptionRule extends AbstractJavaRule {
|
||||
return super.visit(methodDeclaration, o);
|
||||
}
|
||||
|
||||
List<ASTName> exceptionList = methodDeclaration.findDescendantsOfType(ASTName.class);
|
||||
List<ASTName> exceptionList = Collections.emptyList();
|
||||
ASTNameList nameList = methodDeclaration.getFirstChildOfType(ASTNameList.class);
|
||||
if (nameList != null) {
|
||||
exceptionList = nameList.findDescendantsOfType(ASTName.class);
|
||||
}
|
||||
if (!exceptionList.isEmpty()) {
|
||||
evaluateExceptions(exceptionList, o);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ public class UnusedFormalParameterRule extends AbstractJavaRule {
|
||||
if (!node.isPrivate() && !getProperty(CHECKALL_DESCRIPTOR)) {
|
||||
return data;
|
||||
}
|
||||
if (!node.isNative()) {
|
||||
if (!node.isNative() && !node.isAbstract()) {
|
||||
check(node, data);
|
||||
}
|
||||
return data;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user