diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index 909062dd50..7c99a9dbf5 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -57,7 +57,7 @@ public class ClassTypeResolverTest { @Test public void acceptanceTest() { - ASTCompilationUnit acu = parseAndTypeResolveForClass(ArrayListFound.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(ArrayListFound.class); assertEquals(ArrayListFound.class, acu.getFirstDescendantOfType(ASTTypeDeclaration.class).getType()); assertEquals(ArrayListFound.class, acu.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class).getType()); ASTImportDeclaration id = acu.getFirstDescendantOfType(ASTImportDeclaration.class); @@ -70,7 +70,7 @@ public class ClassTypeResolverTest { assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTVariableDeclarator.class).getType()); assertEquals(ArrayList.class, acu.getFirstDescendantOfType(ASTFieldDeclaration.class).getType()); - acu = parseAndTypeResolveForClass(DefaultJavaLangImport.class); + acu = parseAndTypeResolveForClass15(DefaultJavaLangImport.class); assertEquals(String.class, acu.getFirstDescendantOfType(ASTClassOrInterfaceType.class).getType()); assertEquals(Override.class, acu.findDescendantsOfType(ASTName.class).get(1).getType()); } @@ -80,7 +80,7 @@ public class ClassTypeResolverTest { */ @Test public void testEnumAnonymousInnerClass() { - ASTCompilationUnit acu = parseAndTypeResolveForClass(EnumWithAnonymousInnerClass.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(EnumWithAnonymousInnerClass.class); Class inner = acu.getFirstDescendantOfType(ASTAllocationExpression.class) .getFirstDescendantOfType(ASTClassOrInterfaceType.class).getType(); assertEquals("net.sourceforge.pmd.typeresolution.testdata.EnumWithAnonymousInnerClass$1", @@ -89,7 +89,7 @@ public class ClassTypeResolverTest { @Test public void testExtraTopLevelClass() throws ClassNotFoundException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(ExtraTopLevelClass.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(ExtraTopLevelClass.class); Class theExtraTopLevelClass = Class.forName("net.sourceforge.pmd.typeresolution.testdata.TheExtraTopLevelClass"); // First class ASTTypeDeclaration typeDeclaration = (ASTTypeDeclaration) acu.jjtGetChild(1); @@ -105,7 +105,7 @@ public class ClassTypeResolverTest { @Test public void testInnerClass() throws ClassNotFoundException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(InnerClass.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(InnerClass.class); Class theInnerClass = Class.forName("net.sourceforge.pmd.typeresolution.testdata.InnerClass$TheInnerClass"); // Outer class ASTTypeDeclaration typeDeclaration = acu.getFirstDescendantOfType(ASTTypeDeclaration.class); @@ -122,7 +122,7 @@ public class ClassTypeResolverTest { @Test public void testAnonymousInnerClass() throws ClassNotFoundException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(AnonymousInnerClass.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(AnonymousInnerClass.class); Class theAnonymousInnerClass = Class.forName("net.sourceforge.pmd.typeresolution.testdata.AnonymousInnerClass$1"); // Outer class ASTTypeDeclaration typeDeclaration = acu.getFirstDescendantOfType(ASTTypeDeclaration.class); @@ -137,7 +137,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testLiterals() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Literals.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Literals.class); List literals = acu.findChildNodesWithXPath("//Literal"); int index = 0; @@ -288,7 +288,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testUnaryNumericPromotion() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Promotion.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Promotion.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'unaryNumericPromotion']]//Expression[UnaryExpression]"); int index = 0; @@ -307,7 +307,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testBinaryNumericPromotion() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Promotion.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Promotion.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'binaryNumericPromotion']]//Expression[AdditiveExpression]"); int index = 0; @@ -375,7 +375,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testBinaryStringPromotion() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Promotion.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Promotion.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'binaryStringPromotion']]//Expression"); int index = 0; @@ -392,7 +392,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testUnaryLogicalOperators() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Operators.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Operators.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'unaryLogicalOperators']]//Expression"); int index = 0; @@ -406,7 +406,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testBinaryLogicalOperators() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Operators.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Operators.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'binaryLogicalOperators']]//Expression"); int index = 0; @@ -431,7 +431,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testUnaryNumericOperators() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Operators.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Operators.class); List expressions = new ArrayList(); expressions.addAll(acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'unaryNumericOperators']]//Expression")); expressions.addAll(acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'unaryNumericOperators']]//PostfixExpression")); @@ -453,7 +453,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testBinaryNumericOperators() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Operators.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Operators.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'binaryNumericOperators']]//Expression"); int index = 0; @@ -473,7 +473,7 @@ public class ClassTypeResolverTest { @Test @SuppressWarnings("unchecked") public void testAssignmentOperators() throws JaxenException { - ASTCompilationUnit acu = parseAndTypeResolveForClass(Operators.class); + ASTCompilationUnit acu = parseAndTypeResolveForClass15(Operators.class); List expressions = acu.findChildNodesWithXPath("//Block[preceding-sibling::MethodDeclarator[@Image = 'assignmentOperators']]//StatementExpression"); int index = 0; @@ -498,16 +498,20 @@ public class ClassTypeResolverTest { return new junit.framework.JUnit4TestAdapter(ClassTypeResolverTest.class); } + private ASTCompilationUnit parseAndTypeResolveForClass15(Class clazz) { + return parseAndTypeResolveForClass(clazz, "1.5"); + } + // Note: If you're using Eclipse or some other IDE to run this test, you _must_ have the regress folder in // the classpath. Normally the IDE doesn't put source directories themselves directly in the classpath, only // the output directories are in the classpath. - private ASTCompilationUnit parseAndTypeResolveForClass(Class clazz) { + private ASTCompilationUnit parseAndTypeResolveForClass(Class clazz, String version) { String sourceFile = clazz.getName().replace('.', '/') + ".java"; InputStream is = ClassTypeResolverTest.class.getClassLoader().getResourceAsStream(sourceFile); if (is == null) { throw new IllegalArgumentException("Unable to find source file " + sourceFile + " for " + clazz); } - LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5").getLanguageVersionHandler(); + LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler(); ASTCompilationUnit acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null, new InputStreamReader(is)); languageVersionHandler.getSymbolFacade().start(acu); languageVersionHandler.getTypeResolutionFacade(ClassTypeResolverTest.class.getClassLoader()).start(acu); diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml new file mode 100644 index 0000000000..1f8a2c4d33 --- /dev/null +++ b/pmd-java8/pom.xml @@ -0,0 +1,171 @@ + + + 4.0.0 + pmd-java8 + PMD Java 8 Integration + + + net.sourceforge.pmd + pmd + 5.3.0-SNAPSHOT + + + + ${basedir}/../pmd-core + 1.8 + + + + + + ${basedir}/src/test/resources + + + ${basedir}/src/test/java + + **/testdata/*.java + + + + + + ${basedir}/src/main/resources + true + + + + + maven-resources-plugin + + false + + ${*} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + net.sourceforge.pmd + pmd-build + + ${basedir}/src/main/resources/rulesets + ${basedir}/src/site/site.pre.xml + ${basedir}/src/site/site.xml + ${basedir}/src/site/xdoc/rules + + + + pre-site + + pmd-pre-site + + + + + + + + + net.sourceforge.pmd + pmd-java + ${project.version} + + + + jaxen + jaxen + + + net.java.dev.javacc + javacc + + + net.sourceforge.pmd + pmd-core + + + net.sourceforge.saxon + saxon + + + org.ow2.asm + asm + + + + net.sourceforge.saxon + saxon + dom + runtime + + + + net.sourceforge.pmd + pmd-test + test + + + org.slf4j + slf4j-api + test + + + diff --git a/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/InterfaceMethodTest.java b/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/InterfaceMethodTest.java new file mode 100644 index 0000000000..268caecc3c --- /dev/null +++ b/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/InterfaceMethodTest.java @@ -0,0 +1,39 @@ +package net.sourceforge.pmd.lang.java.bugs; + +//import java.util.stream.IntStream; +//import static java.util.stream.Collectors.toList; + +import java.io.InputStream; +import java.io.InputStreamReader; +import org.junit.Ignore; +import org.junit.Test; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.typeresolution.testdata.UsesJavaStreams; + +@Ignore +public class InterfaceMethodTest { + + @Test + public void should_not_fail() { + ASTCompilationUnit acu = parseAndTypeResolveForClass(UsesJavaStreams.class); + } + + // Note: If you're using Eclipse or some other IDE to run this test, you _must_ have the regress folder in + // the classpath. Normally the IDE doesn't put source directories themselves directly in the classpath, only + // the output directories are in the classpath. + private ASTCompilationUnit parseAndTypeResolveForClass(Class clazz) { + String sourceFile = clazz.getName().replace('.', '/') + ".java"; + InputStream is = InterfaceMethodTest.class.getClassLoader().getResourceAsStream(sourceFile); + if (is == null) { + throw new IllegalArgumentException("Unable to find source file " + sourceFile + " for " + clazz); + } + LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8").getLanguageVersionHandler(); + ASTCompilationUnit acu = (ASTCompilationUnit)languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null, new InputStreamReader(is)); + languageVersionHandler.getSymbolFacade().start(acu); + languageVersionHandler.getTypeResolutionFacade(InterfaceMethodTest.class.getClassLoader()).start(acu); + return acu; + } +} diff --git a/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/Java8MultipleLambdasTest.java b/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/Java8MultipleLambdasTest.java new file mode 100644 index 0000000000..451077bb20 --- /dev/null +++ b/pmd-java8/src/test/java/net/sourceforge/pmd/lang/java/bugs/Java8MultipleLambdasTest.java @@ -0,0 +1,48 @@ +package net.sourceforge.pmd.lang.java.bugs; + +import java.io.StringReader; +import org.junit.Ignore; +import org.junit.Test; +import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.symboltable.SymbolFacade; + +@Ignore +public class Java8MultipleLambdasTest { + + private static final String MULTIPLE_JAVA_8_LAMBDAS = + "public class MultipleLambdas {" + PMD.EOL + + " Observer a = (o, arg) -> System.out.println(\"a_\" + arg);" + PMD.EOL + + " Observer b = (o, arg) -> System.out.println(\"b_\" + arg);" + PMD.EOL + + "}"; + + @Test + public void should_not_fail() { + parseCode(MULTIPLE_JAVA_8_LAMBDAS); + } + + private void parseCode(String code) { + LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler(); + ASTCompilationUnit acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null, new StringReader(code)); + SymbolFacade stb = new SymbolFacade(); + stb.initializeWith(acu); + } + + + // Was failing with : + // java.lang.RuntimeException: Variable: image = 'i', line = 3 is already in the symbol table + // at net.AbstractJavaScope.checkForDuplicatedNameDeclaration(AbstractJavaScope.java:27) + // at net.sourceforge.pmd.lang.java.symboltable.AbstractJavaScope.addDeclaration(AbstractJavaScope.java:21) + // at net.sourceforge.pmd.lang.java.symboltable.ScopeAndDeclarationFinder.visit(ScopeAndDeclarationFinder.java:294) + // at net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId.jjtAccept(ASTVariableDeclaratorId.java:30) + // at net.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:55) + // at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:9) + // at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:455) + // at net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression.jjtAccept(ASTLambdaExpression.java:21) + // at net.sourceforge.pmd.lang.java.ast.AbstractJavaNode.childrenAccept(AbstractJavaNode.java:55) + // at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:9) + // at net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter.visit(JavaParserVisitorAdapter.java:312) +} diff --git a/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverJava8Test.java b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverJava8Test.java new file mode 100644 index 0000000000..c4a83abc6b --- /dev/null +++ b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverJava8Test.java @@ -0,0 +1,53 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd.typeresolution; + +import java.io.InputStream; +import java.io.InputStreamReader; +import org.junit.Test; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersionHandler; +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.typeresolution.testdata.UsesJavaStreams; +import net.sourceforge.pmd.typeresolution.testdata.UsesRepeatableAnnotations; + + +public class ClassTypeResolverJava8Test { + + @Test + public void interface_method_should_be_parseable() { + ASTCompilationUnit acu = parseAndTypeResolveForClass18(UsesJavaStreams.class); + } + + @Test + public void repeatable_annotations_method_should_be_parseable() { + ASTCompilationUnit acu = parseAndTypeResolveForClass18(UsesRepeatableAnnotations.class); + } + + + public static junit.framework.Test suite() { + return new junit.framework.JUnit4TestAdapter(ClassTypeResolverJava8Test.class); + } + + private ASTCompilationUnit parseAndTypeResolveForClass18(Class clazz) { + return parseAndTypeResolveForClass(clazz, "1.8"); + } + + // Note: If you're using Eclipse or some other IDE to run this test, you _must_ have the regress folder in + // the classpath. Normally the IDE doesn't put source directories themselves directly in the classpath, only + // the output directories are in the classpath. + private ASTCompilationUnit parseAndTypeResolveForClass(Class clazz, String version) { + String sourceFile = clazz.getName().replace('.', '/') + ".java"; + InputStream is = ClassTypeResolverJava8Test.class.getClassLoader().getResourceAsStream(sourceFile); + if (is == null) { + throw new IllegalArgumentException("Unable to find source file " + sourceFile + " for " + clazz); + } + LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler(); + ASTCompilationUnit acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()).parse(null, new InputStreamReader(is)); + languageVersionHandler.getSymbolFacade().start(acu); + languageVersionHandler.getTypeResolutionFacade(ClassTypeResolverJava8Test.class.getClassLoader()).start(acu); + return acu; + } +} diff --git a/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesJavaStreams.java b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesJavaStreams.java new file mode 100644 index 0000000000..4e3310b946 --- /dev/null +++ b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesJavaStreams.java @@ -0,0 +1,15 @@ +package net.sourceforge.pmd.typeresolution.testdata; + +public class UsesJavaStreams { + interface WithStaticAndDefaultMethod { + static void performOn() { } + default void myToString() {} + } + + class ImplWithStaticAndDefaultMethod implements WithStaticAndDefaultMethod {} + + public void performStuff() { + WithStaticAndDefaultMethod.performOn(); + new ImplWithStaticAndDefaultMethod().myToString(); + } +} diff --git a/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesRepeatableAnnotations.java b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesRepeatableAnnotations.java new file mode 100644 index 0000000000..e08c5c4fc9 --- /dev/null +++ b/pmd-java8/src/test/java/net/sourceforge/pmd/typeresolution/testdata/UsesRepeatableAnnotations.java @@ -0,0 +1,21 @@ +package net.sourceforge.pmd.typeresolution.testdata; + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import net.sourceforge.pmd.typeresolution.testdata.UsesRepeatableAnnotations.Multitude; + +@Multitude("1") +@Multitude("2") +@Multitude("3") +@Multitude("4") +public class UsesRepeatableAnnotations { + + @Repeatable(Multitudes.class) + @Retention(RetentionPolicy.RUNTIME) + @interface Multitude { String value(); } + + @Retention(RetentionPolicy.RUNTIME) + @interface Multitudes { Multitude[] value(); } + +} diff --git a/pom.xml b/pom.xml index 354c79c257..e53fafc1e2 100644 --- a/pom.xml +++ b/pom.xml @@ -847,6 +847,16 @@ + + jdk8-integration + + 1.8 + + + pmd-java8 + + + jdk9-disabled