Compare commits

...

76 Commits

Author SHA1 Message Date
Andreas Dangel
b501de3fba [maven-release-plugin] prepare release pmd_releases/5.0.3 2013-04-05 19:31:38 +02:00
Andreas Dangel
79fb7e359d pmd: correct the command line examples 2013-04-05 19:19:14 +02:00
Andreas Dangel
6aa4897e21 pmd: prepare pmd release 5.0.3 2013-04-05 18:52:59 +02:00
Andreas Dangel
ee05fa73cd pmd: use the released pmd-build plugin 0.8 2013-04-05 18:49:11 +02:00
Andreas Dangel
0170a40dec pmd: fix NPE in LooseCouplingRule 2013-04-05 17:29:53 +02:00
Andreas Dangel
4d7b4bb1bc pmd: fix #1078 Package statement introduces false positive UnnecessaryFullyQualifiedName violation 2013-04-05 17:16:52 +02:00
Andreas Dangel
a6c1c1f57c pmd: fix #1077 Missing JavaDocs for Xref-Test Files 2013-03-30 15:46:15 +01:00
Andreas Dangel
9f8246caac pmd: fix #938 False positive on LooseCoupling for overriding methods 2013-03-30 15:46:04 +01:00
Andreas Dangel
f51e41b05c pmd: fix #940 False positive on UnsynchronizedStaticDateFormatter 2013-03-30 15:45:52 +01:00
Andreas Dangel
ad66153a2d pmd: fix #942 CheckResultSet False Positive
* replacing the xpath rule with a java based rule implementation
2013-03-30 13:58:42 +01:00
Andreas Dangel
c8c6aa16dd pmd: fix #943 PreserveStackTrace false positive if a StringBuffer exists 2013-03-30 12:01:42 +01:00
Andreas Dangel
b998e64819 pmd: fix #945 PMD generates RuleSets it cannot read. 2013-03-30 12:01:33 +01:00
Andreas Dangel
62fc70e816 pmd: fix #958 Intermittent NullPointerException while loading XPath node attributes
* synchronizing the method cache
 * adding additional null check
2013-03-30 12:01:14 +01:00
Andreas Dangel
34b868ad14 formatting, white spaces 2013-03-30 12:01:06 +01:00
Andreas Dangel
26a862a51b pmd: update changelog, verify #1076 2013-03-24 20:40:55 +01:00
Philip Graf
4569842965 pmd: fix #1076 Report.treeIterator() does not return all violations
The cause of the bug was the implementation of
ViolationNode.equalsNode(otherNode) which returned true when two
different violations start on the same line.

Note: this change also adds a maven dependency on Mockito 1.9.5 (scope:
test). Mockito helps creating mock objects and makes the test more
readable.
2013-03-24 20:40:20 +01:00
Andreas Dangel
fddccb5030 pmd: update changelog 2013-03-24 20:40:01 +01:00
Peter Kofler
00e27b4a37 fix Nullpointer Exception when using -l jsp 2013-03-24 20:39:52 +01:00
Andreas Dangel
b6c6899741 pmd: fix #1027 PMD Ant: java.lang.ClassCastException 2013-03-17 12:47:45 +01:00
Andreas Dangel
43ecf1e110 pmd: fix #999 Law of Demeter: False positives and negatives 2013-03-17 11:08:16 +01:00
Andreas Dangel
5f45a28621 pmd: fix #975 false positive in ClassCastExceptionWithToArray 2013-03-17 10:20:58 +01:00
Andreas Dangel
41c44e5d8d pmd: fix #968 Issues with JUnit4 @Test annotation with expected exception
Thanks to Yiannis Paschalidis
2013-03-17 10:20:49 +01:00
Andreas Dangel
040d465137 pmd: fix #976 UselessStringValueOf wrong when appending character arrays 2013-03-16 19:55:45 +01:00
Andreas Dangel
4e5ca16990 pmd: fix #977 MisplacedNullCheck makes false positives 2013-03-16 19:21:15 +01:00
Andreas Dangel
30af4f6381 pmd: fix #985 Suppressed methods shouldn't affect avg CyclomaticComplexity 2013-03-16 18:16:29 +01:00
Andreas Dangel
cece698b04 pmd: fix #984 Cyclomatic complexity should treat constructors like methods 2013-03-16 18:16:20 +01:00
Andreas Dangel
13ef401a63 pmd: fix #997 Rule NonThreadSafeSingleton gives analysis problem 2013-03-16 12:26:11 +01:00
Andreas Dangel
589ec3c6da pmd: fix #992 Class java.beans.Statement triggered in CloseResource rule 2013-03-16 12:25:53 +01:00
Andreas Dangel
c00ca9e44c pmd: fix NPE in ConstructorCallsOverridableMethodRule 2013-03-15 21:57:39 +01:00
Andreas Dangel
31f6b9af1a pmd: fix #1032 ImmutableField Rule: Private field in inner class gives false positive
Improved symbol table resolution to check inner classes, too.
2013-03-15 21:37:29 +01:00
Andreas Dangel
8eac048c03 pmd: fix #1005 False + for ConstructorCallsOverridableMethod - overloaded methods
It won't be perfect, but for constructor calls and method calls a
simple check of the argument types is done. Primitive types are
distinguished, reference types not.
In order to support all cases, full symbol resolution is needed.
2013-03-14 20:49:08 +01:00
Andreas Dangel
3b14b3f5cb pmd: #1002 False +: FinalFieldCouldBeStatic on inner class 2013-03-13 21:12:46 +01:00
Andreas Dangel
adcbdc204f pmd: fix #1073 Hard coded violation messages CommentSize 2013-03-10 09:54:34 +01:00
Andreas Dangel
a1b1e3f31c pmd: fix #1074 rule priority doesn't work on group definitions
and verify #1067 Custom Ruleset doesn't import the complete ruleset anymore by reference
2013-03-09 17:56:45 +01:00
Andreas Dangel
3e8c42384b pmd: fixed #1064 Exception running PrematureDeclaration 2013-03-01 22:20:46 +01:00
Andreas Dangel
a00532595a pmd: fixed #1068 CPD fails on broken symbolic links 2013-03-01 20:17:45 +01:00
Andreas Dangel
3feda38cc3 [maven-release-plugin] prepare for next development iteration 2013-02-03 18:35:38 +01:00
Andreas Dangel
3412d55fc6 [maven-release-plugin] prepare release pmd_releases/5.0.2 2013-02-03 18:35:37 +01:00
Andreas Dangel
436b7dcb50 pmd: set release date for 5.0.2 2013-02-03 18:29:37 +01:00
Andreas Dangel
d25dadc4b4 pmd: Prepare pmd release 5.0.2 2013-02-03 15:44:02 +01:00
Andreas Dangel
1c051674a0 pmd: update changelog for 5.0.2 2013-02-03 15:34:58 +01:00
Romain PELISSE
3daca86045 pmd: AntTask support for language
- fix  #1004 targetjdk isn't attribute of PMD task
- introduce a new element, called <language>, that replaces the already existing <version/> element
2013-02-03 15:33:46 +01:00
Romain PELISSE
d95d960de3 pmd: fix #1004 targetjdk isn't attribute of PMD task 2013-02-03 15:33:31 +01:00
Torsten Kleiber
ef7478c350 Fix for bug #1056 "Error while processing" while running on xml file with DOCTYPE reference
Change the initial value of XINCLUDE_AWARE_DESCRIPTOR to false
This does validate an invalid doctype reference as in some ide generated xml files exist.
Any xml rule, which needs this property should overwrite this value with true.
2013-02-03 15:32:54 +01:00
Romain PELISSE
c080fdda08 pmd: fix #1049 Errors in "How to write a rule" 2013-02-03 15:31:21 +01:00
Andreas Dangel
e603844a53 pmd: fix #1030 CPD Java.lang.IndexOutOfBoundsException: Index: 2013-01-26 20:08:54 +01:00
Andreas Dangel
52b8be6601 pmd: fixed #947 CloseResource rule fails if field is marked with annotation 2013-01-26 17:58:31 +01:00
Andreas Dangel
7cbb385dbb pmd: fixed #1011 CloseResource Rule ignores Constructors 2013-01-26 17:57:17 +01:00
Andreas Dangel
61c0b4ea7f pmd: fixed #1007 Parse Exception with annotation 2013-01-26 17:57:11 +01:00
Andreas Dangel
26fa85a9fa pmd: fixed #1046 ant task CPDTask doesn't accept ecmascript 2013-01-26 17:56:51 +01:00
Andreas Dangel
98b903897e pmd: fixed #1039 pmd-nicerhtml.xsl is packaged in wrong location 2013-01-26 17:55:22 +01:00
Andreas Dangel
55b5aa7f27 pmd: update rule-guidelines to changed package names 2013-01-26 17:54:09 +01:00
Andreas Dangel
ffac9894c9 pmd: fixed #1028 False-positive: Compare objects with equals for Enums 2013-01-26 17:54:03 +01:00
Andreas Dangel
d557ed9c01 pmd: verify #1020 Parsing Error 2013-01-26 17:53:56 +01:00
Andreas Dangel
e0b7f6f17c pmd: fixed #913 SignatureDeclareThrowsException is raised twice 2013-01-26 17:53:49 +01:00
Andreas Dangel
cb9861dd1f pmd: fixed #878 False positive: UnusedFormalParameter for abstract methods 2013-01-26 17:53:41 +01:00
Andreas Dangel
7ee96a6b52 pmd: fixed #1055 Please add a colon in the ant output after line,column for Oracle JDeveloper IDE usage 2013-01-26 17:53:33 +01:00
Andreas Dangel
ac8e3314a3 pmd: fixed bug #1012 False positive: Useless parentheses. 2013-01-19 19:13:09 +01:00
Andreas Dangel
7989ae1863 pmd: fixed #1060 GodClassRule >>> wrong method 2013-01-19 19:12:59 +01:00
Andreas Dangel
e3708b5030 pmd: fix #1037 Facing a showstopper issue in PMD Report Class
* wrapping the report listeners in a thread safe (synchronized) class
 * overtaking the listeners for each thread / report
2012-12-17 11:02:24 +01:00
Andreas Dangel
85e493d55f pmd: fixed #1026 PMD doesn't handle 'value =' in SuppressWarnings annotation 2012-12-16 23:12:29 +01:00
Andreas Dangel
6abbea51dd pmd: fix #1043 node.getEndLine() always returns 0 (ECMAscript)
* added commons-io dependency
 * added a SourceCodePositioner to calculate line/column from position
2012-12-16 18:16:39 +01:00
Andreas Dangel
9162917346 pmd: fix #1047 False Positive in 'for' loops for LocalVariableCouldBeFinal in 5.0.1 2012-12-16 12:10:06 +01:00
Andreas Dangel
637006674f pmd: Fixed bug 1048: CommentContent Rule, String Index out of range Exception 2012-12-07 11:17:44 +01:00
Andreas Dangel
63c1a8fe47 pmd: CLI - make sure we display the usage help text
Therefore make the -h option a help option.
Make the auxclasspath option description look nicer - newlines break the layout.
Always display the jcommander usage help text.
And exit with an error code in case there are parameter errors.
2012-12-05 22:02:49 +01:00
Andreas Dangel
063c4228e3 pmd: fix bug #1044 - update suppressing documentation with new cli paramter name 2012-12-05 22:02:40 +01:00
Andreas Dangel
4b0063dfc1 [maven-release-plugin] prepare for next development iteration 2012-11-28 21:43:38 +01:00
Andreas Dangel
13e36974a5 [maven-release-plugin] prepare release pmd_releases/5.0.1 2012-11-28 21:43:36 +01:00
Andreas Dangel
33c7af965c pmd: fix failing unit test 2012-11-28 21:25:56 +01:00
Andreas Dangel
a66bbf2193 pmd: prepare release 5.0.1 2012-11-28 21:02:35 +01:00
Andreas Dangel
38af8f2433 Merge branch 'master' into pmd/5.0.x 2012-11-28 20:42:58 +01:00
Andreas Dangel
a6bcfe2b65 pmd: added missing ssh/scp wagon support for maven3
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x@7669 51baf565-9d33-0410-a72c-fc3788e3496d
2012-05-01 11:41:10 +00:00
Andreas Dangel
6474fde42d [maven-release-plugin] prepare for next development iteration
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x@7668 51baf565-9d33-0410-a72c-fc3788e3496d
2012-05-01 07:43:32 +00:00
Andreas Dangel
8dcde0edb5 [maven-release-plugin] prepare release pmd_release_5_0_0
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x@7666 51baf565-9d33-0410-a72c-fc3788e3496d
2012-05-01 07:42:56 +00:00
Andreas Dangel
70347aedd5 pmd: Prepare pmd release 5.0.0
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x@7665 51baf565-9d33-0410-a72c-fc3788e3496d
2012-05-01 07:38:38 +00:00
Andreas Dangel
eaf1385595 update the version to the usual three components: 5.0.0-SNAPSHOT
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/5.0.x@7664 51baf565-9d33-0410-a72c-fc3788e3496d
2012-04-30 11:35:40 +00:00
128 changed files with 2831 additions and 523 deletions

View File

@ -1,4 +1,62 @@
???? ??, 2012 - 5.1.0:
April 5, 2013 - 5.0.3:
Fixed bug 938: False positive on LooseCoupling for overriding methods
Fixed bug 940: False positive on UnsynchronizedStaticDateFormatter
Fixed bug 942: CheckResultSet False Positive and Negative
Fixed bug 943: PreserveStackTrace false positive if a StringBuffer exists
Fixed bug 945: PMD generates RuleSets it cannot read.
Fixed bug 958: Intermittent NullPointerException while loading XPath node attributes
Fixed bug 968: Issues with JUnit4 @Test annotation with expected exception (Thanks to Yiannis Paschalidis)
Fixed bug 975: false positive in ClassCastExceptionWithToArray
Fixed bug 976: UselessStringValueOf wrong when appending character arrays
Fixed bug 977: MisplacedNullCheck makes false positives
Fixed bug 984: Cyclomatic complexity should treat constructors like methods
Fixed bug 985: Suppressed methods shouldn't affect avg CyclomaticComplexity
Fixed bug 992: Class java.beans.Statement triggered in CloseResource rule
Fixed bug 997: Rule NonThreadSafeSingleton gives analysis problem
Fixed bug 999: Law of Demeter: False positives and negatives
Fixed bug 1002: False +: FinalFieldCouldBeStatic on inner class
Fixed bug 1005: False + for ConstructorCallsOverridableMethod - overloaded methods
Fixed bug 1027: PMD Ant: java.lang.ClassCastException
Fixed bug 1032: ImmutableField Rule: Private field in inner class gives false positive
Fixed bug 1064: Exception running PrematureDeclaration
Fixed bug 1068: CPD fails on broken symbolic links
Fixed bug 1073: Hard coded violation messages CommentSize
Fixed bug 1074: rule priority doesn't work on group definitions
Fixed bug 1076: Report.treeIterator() does not return all violations
Fixed bug 1077: Missing JavaDocs for Xref-Test Files
Fixed bug 1078: Package statement introduces false positive UnnecessaryFullyQualifiedName violation
Merged pull request #14: fix Nullpointer Exception when using -l jsp
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 +529,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 +593,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.

View File

@ -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()

View File

@ -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.3</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.3</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>
@ -492,7 +477,7 @@
<plugin>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-build</artifactId>
<version>0.7</version>
<version>0.8</version>
<executions>
<execution>
<phase>pre-site</phase>
@ -620,6 +605,17 @@
<artifactId>javacc</artifactId>
<version>${javacc.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<reporting>
@ -638,9 +634,7 @@
<reportSet>
<reports>
<report>javadoc</report>
<!-- FIXME: The following report fails
<report>test-javadoc</report>
-->
</reports>
</reportSet>
</reportSets>

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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());
}
/**

View File

@ -5,7 +5,9 @@ package net.sourceforge.pmd;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
@ -162,6 +164,18 @@ public class RuleSet {
rules.addAll(rules.size(), ruleSet.getRules());
}
/**
* Add all rules by reference from one RuleSet to this RuleSet. The rules
* can be added as individual references, or collectively as an all rule
* reference.
*
* @param ruleSet the RuleSet to add
* @param allRules
*/
public void addRuleSetByReference(RuleSet ruleSet, boolean allRules) {
addRuleSetByReference(ruleSet, allRules, (String[])null);
}
/**
* Add all rules by reference from one RuleSet to this RuleSet. The rules
* can be added as individual references, or collectively as an all rule
@ -169,13 +183,17 @@ public class RuleSet {
*
* @param ruleSet the RuleSet to add
* @param allRules
* @param excludes names of the rules that should be excluded.
*/
public void addRuleSetByReference(RuleSet ruleSet, boolean allRules) {
public void addRuleSetByReference(RuleSet ruleSet, boolean allRules, String ... excludes) {
if (StringUtil.isEmpty(ruleSet.getFileName())) {
throw new RuntimeException("Adding a rule by reference is not allowed with an empty rule set file name.");
}
RuleSetReference ruleSetReference = new RuleSetReference(ruleSet.getFileName());
ruleSetReference.setAllRules(allRules);
if (excludes != null) {
ruleSetReference.setExcludes(new HashSet<String>(Arrays.asList(excludes)));
}
for (Rule rule : ruleSet.getRules()) {
RuleReference ruleReference = new RuleReference(rule, ruleSetReference);
rules.add(ruleReference);

View File

@ -280,11 +280,15 @@ public class RuleSetFactory {
RuleSetReference ruleSetReference = new RuleSetReference();
ruleSetReference.setAllRules(true);
ruleSetReference.setRuleSetFileName(ref);
NodeList excludeNodes = ruleElement.getChildNodes();
for (int i = 0; i < excludeNodes.getLength(); i++) {
if (isElementNode(excludeNodes.item(i),"exclude")) {
Element excludeElement = (Element) excludeNodes.item(i);
String priority = null;
NodeList childNodes = ruleElement.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
if (isElementNode(child,"exclude")) {
Element excludeElement = (Element) child;
ruleSetReference.addExclude(excludeElement.getAttribute("name"));
} else if (isElementNode(child, "priority")) {
priority = parseTextNode(child).trim();
}
}
@ -298,6 +302,11 @@ public class RuleSetFactory {
ruleReference.setRuleSetReference(ruleSetReference);
ruleReference.setRule(rule);
ruleSet.addRule(ruleReference);
// override the priority
if (priority != null) {
ruleReference.setPriority(RulePriority.valueOf(Integer.parseInt(priority)));
}
}
}
}

View File

@ -129,7 +129,9 @@ public class RuleSetWriter {
}
private Element createExcludeElement(String exclude) {
return createTextElement("exclude", exclude);
Element element = document.createElementNS(RULESET_NS_URI, "exclude");
element.setAttribute("name", exclude);
return element;
}
private Element createExampleElement(String example) {

View File

@ -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);
}
}

View File

@ -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);
}
@ -304,7 +289,12 @@ public class PMDTask extends Task {
log("Using the normal ClassLoader", Project.MSG_VERBOSE);
} else {
log("Using the AntClassLoader", Project.MSG_VERBOSE);
configuration.setClassLoader(new AntClassLoader(getProject(), classpath));
// must be true, otherwise you'll get ClassCastExceptions as classes are loaded twice
// and exist in multiple class loaders
boolean parentFirst = true;
configuration.setClassLoader(
new AntClassLoader(Thread.currentThread().getContextClassLoader(), getProject(),
classpath, parentFirst));
}
try {
/*

View File

@ -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 + "\" />";
}
}

View File

@ -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;
}
}

View File

@ -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;
@ -91,16 +98,16 @@ public class PMDCommandLineInterface {
+ WINDOWS_PROMPT + launchCmd + " -dir" + WINDOWS_PATH_TO_CODE + "-format text -R java-unusedcode,java-imports -version 1.5 -language java -debug" + PMD.EOL
+ WINDOWS_PROMPT + launchCmd + " -dir" + WINDOWS_PATH_TO_CODE + "-f xml -rulesets java-basic,java-design -encoding UTF-8" + PMD.EOL
+ WINDOWS_PROMPT + launchCmd + " -d" + WINDOWS_PATH_TO_CODE + "-rulesets java-typeresolution -auxclasspath commons-collections.jar;derby.jar" + PMD.EOL
+ WINDOWS_PROMPT + launchCmd + " -d" + WINDOWS_PATH_TO_CODE + "-f html -R java-typeresolution -auxclasspath -d file:///C:/my/classpathfile" + PMD.EOL
+ WINDOWS_PROMPT + launchCmd + " -d" + WINDOWS_PATH_TO_CODE + "-f html -R java-typeresolution -auxclasspath file:///C:/my/classpathfile" + PMD.EOL
+ PMD.EOL;
}
private static String getUnixExample(String launchCmd) {
final String UNIX_PROMPT = "$ ";
return "For example on *nix: " + PMD.EOL
+ UNIX_PROMPT + launchCmd + " -dir /home/workspace/src/main/java/code -f nicehtml -rulesets java-basic,java-design" + PMD.EOL
+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f nicehtml -r java-basic,java-design -xslt my-own.xsl" + PMD.EOL
+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f nicehtml -r java-typeresolution -auxclasspath commons-collections.jar:derby.jar"
+ UNIX_PROMPT + launchCmd + " -dir /home/workspace/src/main/java/code -f html -rulesets java-basic,java-design" + PMD.EOL
+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f xslt -R java-basic,java-design -property xsltFilename=my-own.xsl" + PMD.EOL
+ UNIX_PROMPT + launchCmd + " -d ./src/main/java/code -f html -R java-typeresolution -auxclasspath commons-collections.jar:derby.jar"
+ 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);
}

View File

@ -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> {
@ -118,7 +118,11 @@ public class PMDParameters {
configuration.setSuppressMarker(params.getSuppressmarker());
configuration.setThreads(params.getThreads());
for ( LanguageVersion language : LanguageVersion.findVersionsForLanguageTerseName( params.getLanguage() ) ) {
configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(language.getLanguage().getVersion(params.getVersion()));
LanguageVersion languageVersion = language.getLanguage().getVersion(params.getVersion());
if (languageVersion == null) {
languageVersion = language.getLanguage().getDefaultVersion();
}
configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(languageVersion);
}
try {
configuration.prependClasspath(params.getAuxclasspath());

View File

@ -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(),
@ -92,11 +93,16 @@ public class CPD {
current.add(signature);
}
if (!file.getCanonicalPath().equals(new File(file.getAbsolutePath()).getCanonicalPath())) {
if (!file.getCanonicalPath().equals(file.getAbsolutePath())) {
System.err.println("Skipping " + file + " since it appears to be a symlink");
return;
}
if (!file.exists()) {
System.err.println("Skipping " + file + " since it doesn't exist (broken symlink?)");
return;
}
listener.addedFile(fileCount, file);
SourceCode sourceCode = configuration.sourceCodeFor(file);
configuration.tokenizer().tokenize(sourceCode, tokens);

View File

@ -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;
}
}
}

View File

@ -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 {

View File

@ -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";

View File

@ -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.

View File

@ -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.");
}
}
}

View File

@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.ast.xpath;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -15,31 +16,32 @@ import net.sourceforge.pmd.lang.ast.Node;
public class AttributeAxisIterator implements Iterator<Attribute> {
private static class MethodWrapper {
public Method method;
public String name;
public Method method;
public String name;
public MethodWrapper(Method m) {
this.method = m;
this.name = truncateMethodName(m.getName());
}
public MethodWrapper(Method m) {
this.method = m;
this.name = truncateMethodName(m.getName());
}
private String truncateMethodName(String n) {
// about 70% of the methods start with 'get', so this case goes first
if (n.startsWith("get")) {
return n.substring("get".length());
}
if (n.startsWith("is")) {
return n.substring("is".length());
}
if (n.startsWith("has")) {
return n.substring("has".length());
}
if (n.startsWith("uses")) {
return n.substring("uses".length());
}
private String truncateMethodName(String n) {
// about 70% of the methods start with 'get', so this case goes
// first
if (n.startsWith("get")) {
return n.substring("get".length());
}
if (n.startsWith("is")) {
return n.substring("is".length());
}
if (n.startsWith("has")) {
return n.substring("has".length());
}
if (n.startsWith("uses")) {
return n.substring("uses".length());
}
return n;
}
return n;
}
}
private Attribute currObj;
@ -47,64 +49,65 @@ public class AttributeAxisIterator implements Iterator<Attribute> {
private int position;
private Node node;
private static Map<Class<?>, MethodWrapper[]> methodCache = new HashMap<Class<?>, MethodWrapper[]>();
private static Map<Class<?>, MethodWrapper[]> methodCache =
Collections.synchronizedMap(new HashMap<Class<?>, MethodWrapper[]>());
public AttributeAxisIterator(Node contextNode) {
this.node = contextNode;
if (!methodCache.containsKey(contextNode.getClass())) {
Method[] preFilter = contextNode.getClass().getMethods();
List<MethodWrapper> postFilter = new ArrayList<MethodWrapper>();
for (Method element : preFilter) {
if (isAttributeAccessor(element)) {
postFilter.add(new MethodWrapper(element));
}
}
methodCache.put(contextNode.getClass(), postFilter.toArray(new MethodWrapper[postFilter.size()]));
}
this.methodWrappers = methodCache.get(contextNode.getClass());
this.node = contextNode;
if (!methodCache.containsKey(contextNode.getClass())) {
Method[] preFilter = contextNode.getClass().getMethods();
List<MethodWrapper> postFilter = new ArrayList<MethodWrapper>();
for (Method element : preFilter) {
if (isAttributeAccessor(element)) {
postFilter.add(new MethodWrapper(element));
}
}
methodCache.put(contextNode.getClass(), postFilter.toArray(new MethodWrapper[postFilter.size()]));
}
this.methodWrappers = methodCache.get(contextNode.getClass());
this.position = 0;
this.currObj = getNextAttribute();
this.position = 0;
this.currObj = getNextAttribute();
}
public Attribute next() {
if (currObj == null) {
throw new IndexOutOfBoundsException();
}
Attribute ret = currObj;
currObj = getNextAttribute();
return ret;
if (currObj == null) {
throw new IndexOutOfBoundsException();
}
Attribute ret = currObj;
currObj = getNextAttribute();
return ret;
}
public boolean hasNext() {
return currObj != null;
return currObj != null;
}
public void remove() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException();
}
private Attribute getNextAttribute() {
if (position == methodWrappers.length) {
return null;
}
MethodWrapper m = methodWrappers[position++];
return new Attribute(node, m.name, m.method);
if (methodWrappers == null || position == methodWrappers.length) {
return null;
}
MethodWrapper m = methodWrappers[position++];
return new Attribute(node, m.name, m.method);
}
protected boolean isAttributeAccessor(Method method) {
String methodName = method.getName();
String methodName = method.getName();
return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType()
|| Double.TYPE == method.getReturnType() || String.class == method.getReturnType())
&& method.getParameterTypes().length == 0
&& Void.TYPE != method.getReturnType()
&& !methodName.startsWith("jjt")
&& !methodName.equals("toString")
&& !methodName.equals("getScope")
&& !methodName.equals("getClass")
&& !methodName.equals("getTypeNameNode")
&& !methodName.equals("getImportedNameNode") && !methodName.equals("hashCode");
return (Integer.TYPE == method.getReturnType() || Boolean.TYPE == method.getReturnType()
|| Double.TYPE == method.getReturnType() || String.class == method.getReturnType())
&& method.getParameterTypes().length == 0
&& Void.TYPE != method.getReturnType()
&& !methodName.startsWith("jjt")
&& !methodName.equals("toString")
&& !methodName.equals("getScope")
&& !methodName.equals("getClass")
&& !methodName.equals("getTypeNameNode")
&& !methodName.equals("getImportedNameNode") && !methodName.equals("hashCode");
}
}

View File

@ -1,3 +1,6 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.dfa.report;
import net.sourceforge.pmd.RuleViolation;
@ -23,6 +26,9 @@ public class ViolationNode extends AbstractReportNode {
return rv.getFilename().equals(getRuleViolation().getFilename()) &&
rv.getBeginLine() == getRuleViolation().getBeginLine() &&
rv.getBeginColumn() == getRuleViolation().getBeginColumn() &&
rv.getEndLine() == getRuleViolation().getEndLine() &&
rv.getEndColumn()== getRuleViolation().getEndColumn() &&
rv.getVariableName().equals(getRuleViolation().getVariableName());
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}

View File

@ -2,7 +2,7 @@
package net.sourceforge.pmd.lang.java.ast;
public class ASTNormalAnnotation extends AbstractJavaNode {
public class ASTNormalAnnotation extends AbstractJavaTypeNode {
public ASTNormalAnnotation(int id) {
super(id);
}

View File

@ -2,7 +2,7 @@
package net.sourceforge.pmd.lang.java.ast;
public class ASTSingleMemberAnnotation extends AbstractJavaNode {
public class ASTSingleMemberAnnotation extends AbstractJavaTypeNode {
public ASTSingleMemberAnnotation(int id) {
super(id);
}

Some files were not shown because too many files have changed in this diff Show More