From b0a6574e64aded1bb99e09c4ee0b62c958b91735 Mon Sep 17 00:00:00 2001 From: Gergely Herenyi Date: Tue, 26 Jun 2018 14:33:52 +0200 Subject: [PATCH 1/4] Added Java7 default method for interface and java8 lambdas and method references with tests (cherry picked from commit 771f487984519204b8fd320484f5d9e606c46238) --- src/main/javacc/Java1.1.jj | 114 ++++++++++++++++++- src/test/java/javancss/ParseTest.java | 132 +++++++++++----------- src/test/resources/Test160.java | 153 +++++++++++++++++++++++--- 3 files changed, 318 insertions(+), 81 deletions(-) diff --git a/src/main/javacc/Java1.1.jj b/src/main/javacc/Java1.1.jj index 42f95b3..ab089fd 100644 --- a/src/main/javacc/Java1.1.jj +++ b/src/main/javacc/Java1.1.jj @@ -209,6 +209,7 @@ public class JavaParser implements JavaParserInterface public static final int TRANSIENT = 0x0100; public static final int VOLATILE = 0x0200; public static final int STRICTFP = 0x1000; + public static final int DEFAULT = 0x2000; /** A set of accessors that indicate whether the specified modifier is in the set. */ @@ -228,6 +229,11 @@ public class JavaParser implements JavaParserInterface return (modifiers & PRIVATE) != 0; } + public boolean isDefault(int modifiers) + { + return (modifiers & DEFAULT) != 0; + } + public boolean isStatic(int modifiers) { return (modifiers & STATIC) != 0; @@ -276,6 +282,36 @@ public class JavaParser implements JavaParserInterface return modifiers & ~mod; } } + + public static void main(String args[]) { + JavaParser parser; + if (args.length == 0) { + System.out.println("Java Parser Version 1.1: Reading from standard input . . ."); + parser = new JavaParser(System.in); + } else if (args.length == 1) { + System.out.println("Java Parser Version 1.1: Reading from file " + args[0] + " . . ."); + try { + parser = new JavaParser(new java.io.FileInputStream(args[0])); + } catch (java.io.FileNotFoundException e) { + System.out.println("Java Parser Version 1.1: File " + args[0] + " not found."); + return; + } + } else { + System.out.println("Java Parser Version 1.1: Usage is one of:"); + System.out.println(" java javancss.parser.JavaParser < inputfile"); + System.out.println("OR"); + System.out.println(" java javancss.parser.JavaParser inputfile"); + return; + } + try { + parser.CompilationUnit(); + System.out.println("Java Parser Version 1.1: Java program parsed successfully."); + } catch (ParseException e) { + System.out.println(e.getMessage()); + System.out.println("Java Parser Version 1.1: Encountered errors during parse."); + } + } + } PARSER_END(JavaParser) @@ -801,6 +837,8 @@ TOKEN : | < COMMA: "," > | < DOT: "." > | < AT: "@" > +| < LAMBDA: "->" > +| < DOUBLECOLON: "::" > } /* OPERATORS */ @@ -2281,7 +2319,14 @@ void Expression() : //System.out.println( "Expression start" ); } { + LOOKAHEAD(LambdaExpression()) LambdaExpression() +| + AssignmentExpression() +} +void AssignmentExpression() : +{} +{ LOOKAHEAD( PrimaryExpression() AssignmentOperator() ) //{ System.out.println( "Expression" ); } Assignment() @@ -2472,6 +2517,8 @@ void PrimaryExpression() : // { System.out.println( "Before PrimaryExpression" ); } } { + LOOKAHEAD(MethodReference()) MethodReference() +| PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* } @@ -2782,11 +2829,27 @@ void SwitchStatement() : _localCases = 0; } "switch" "(" Expression() ")" "{" - ( SwitchLabel() ( BlockStatement() )* )* + (SwitchCase())* "}" { _ncss++; log.finer( "_ncss++" );} } +void SwitchCase() : +{} +{ + SwitchLabel() SwitchBlockStatements() +} + +void SwitchBlockStatements() : +{} +{ + LOOKAHEAD(SwitchLabel()) {} +| + BlockStatement() SwitchBlockStatements() +| + {} +} + void SwitchLabel() : {} { @@ -3108,6 +3171,11 @@ int Modifiers(): } } | + "default" { modifiers |= ModifierSet.DEFAULT; if ( _tmpToken == null ) { + _tmpToken = getToken( 0 ); + } + } + | "final" { modifiers |= ModifierSet.FINAL; if ( _tmpToken == null ) { _tmpToken = getToken( 0 ); } @@ -3444,3 +3512,47 @@ void MemberSelector(): "." TypeArguments() } +void LambdaExpression(): +{} +{ + LambdaParameters() "->" LambdaBody() +} + +void LambdaParameters(): +{} +{ + +| + LOOKAHEAD("(" InferredFormalParameterList() ")") "(" InferredFormalParameterList() ")" +| + LOOKAHEAD( [FormalParameters()] ) [FormalParameters()] +} + +void InferredFormalParameterList(): +{} +{ + ( "," )* +} + + +void LambdaBody(): +{} +{ + Expression() +| + Block() +} + +void MethodReference(): +{} +{ + "super" "::" [TypeArguments()] +| + LOOKAHEAD( 4 ) Name() "." "super" "::" [TypeArguments()] +| +// ClassType() "::" [TypeArguments()] "new" and ArrayType() "::" "new" is included in below + LOOKAHEAD(ReferenceType() "::" [TypeArguments()] ( | "new" )) ReferenceType() "::" [TypeArguments()] ( | "new" ) +| +// Name() "::" [TypeArguments()] is included in below + PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* "::" [TypeArguments()] +} diff --git a/src/test/java/javancss/ParseTest.java b/src/test/java/javancss/ParseTest.java index cb08cd5..1013e3a 100644 --- a/src/test/java/javancss/ParseTest.java +++ b/src/test/java/javancss/ParseTest.java @@ -1,66 +1,66 @@ -/* -Copyright (C) 2000 Chr. Clemens Lee . - -This file is part of JavaNCSS -(http://www.kclee.de/clemens/java/javancss/). - -JavaNCSS is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -JavaNCSS is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with JavaNCSS; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - -package javancss; - -public class ParseTest extends AbstractTestCase -{ - public void testParse() - { - checkParse( 31 ); // java.net.Socket, why? - checkParse( 33 ); // java.text.Decimalformat, why? - checkParse( 34 ); // java.text.TextBoundaryData, why? - - checkParse( 48 ); - - checkParse( 50 ); - - checkParse( 71 ); // class declared in method - checkParse( 133 ); // char.class - checkParse( 135 ); // annotation - - checkParse( 142 ); // JAVANCSS-12 - checkParse( 143 ); // JAVANCSS-9 - checkParse( 144 ); // JAVANCSS-13 - checkParse( 145 ); // JAVANCSS-14 - checkParse( 146 ); // JAVANCSS-17 - checkParse( 147 ); // anonymous subcluss - checkParse( 148 ); // JAVANCSS-49 - checkParse( 149 ); // JAVANCSS-46 - checkParse( 150 ); // JAVANCSS-53 - checkParse( 151 ); // JAVANCSS-45 - checkParse( 152 ); // JAVANCSS-57 - checkParse( 153 ); // JAVANCSS-54 - checkParse( 154 ); // JAVANCSS-52 - checkParse( 155 ); // JAVANCSS-28 - checkParse( 156 ); // hexadecimal floating-point literals - checkParse( 157 ); // Java 7 literals - checkParse( 158 ); // JAVANCSS-48 - checkParse( 159 ); // default interface methods - checkParse( 160 ); // method references - } - - private void checkParse( int testFile ) - { - Javancss pJavancss = measureTestFile( testFile ); - assertFalse( "Parsing file Test" + testFile + ".java failed!", pJavancss.getNcss() <= 0 ); - } -} +/* +Copyright (C) 2000 Chr. Clemens Lee . + +This file is part of JavaNCSS +(http://www.kclee.de/clemens/java/javancss/). + +JavaNCSS is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +JavaNCSS is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with JavaNCSS; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +package javancss; + +public class ParseTest extends AbstractTestCase +{ + public void testParse() + { + checkParse( 31 ); // java.net.Socket, why? + checkParse( 33 ); // java.text.Decimalformat, why? + checkParse( 34 ); // java.text.TextBoundaryData, why? + + checkParse( 48 ); + + checkParse( 50 ); + + checkParse( 71 ); // class declared in method + checkParse( 133 ); // char.class + checkParse( 135 ); // annotation + + checkParse( 142 ); // JAVANCSS-12 + checkParse( 143 ); // JAVANCSS-9 + checkParse( 144 ); // JAVANCSS-13 + checkParse( 145 ); // JAVANCSS-14 + checkParse( 146 ); // JAVANCSS-17 + checkParse( 147 ); // anonymous subcluss + checkParse( 148 ); // JAVANCSS-49 + checkParse( 149 ); // JAVANCSS-46 + checkParse( 150 ); // JAVANCSS-53 + checkParse( 151 ); // JAVANCSS-45 + checkParse( 152 ); // JAVANCSS-57 + checkParse( 153 ); // JAVANCSS-54 + checkParse( 154 ); // JAVANCSS-52 + checkParse( 155 ); // JAVANCSS-28 + checkParse( 156 ); // hexadecimal floating-point literals + checkParse( 157 ); // Java 7 literals + checkParse( 158 ); // JAVANCSS-48 + checkParse( 159 ); // default interface methods + checkParse( 160 ); // java 8 lambda and method reference + } + + private void checkParse( int testFile ) + { + Javancss pJavancss = measureTestFile( testFile ); + assertFalse( "Parsing file Test" + testFile + ".java failed!", pJavancss.getNcss() <= 0 ); + } +} diff --git a/src/test/resources/Test160.java b/src/test/resources/Test160.java index 6ffa8e5..103a7b1 100644 --- a/src/test/resources/Test160.java +++ b/src/test/resources/Test160.java @@ -1,14 +1,139 @@ -package foobar; - -public class MethodReferencesTest { - - public static void main(String args[]) { - List list = new ArrayList<>(); - - list.add("A"); - list.add("B"); - list.add("C"); - - list.forEach(System.out::println); - } -} +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.IntBinaryOperator; +import java.util.function.IntFunction; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; +import java.util.function.ToIntFunction; +import java.util.function.UnaryOperator; + +class MyList extends ArrayList { + + public MyList replaceAll2(UnaryOperator operator) { + return this; + } +} + +class T { + + public void tvarMember() { + } +} + +class Foo { + + public void bar() { + } + + static class Bar { + } + +} + +class R { + + R() { + } + + R(Integer a) { + } + + R(String a) { + } +} + +public class LamdasAndMethodRefs { + + public LamdasAndMethodRefs() { + //Method references + Runnable a = super::toString; + Runnable b = LamdasAndMethodRefs.super::toString; + } + + public static void main(String[] args) { + //Method references + LongSupplier a = System::currentTimeMillis; // static method + ToIntFunction b = String::length; // instance method + ToIntFunction c = List::size; + ToIntFunction> d = List::size; // explicit type arguments for generic type + UnaryOperator e = int[]::clone; + Consumer f = T::tvarMember; + + Runnable g = System.out::println; + Consumer h = String::valueOf; // overload resolution needed + IntSupplier i = "abc"::length; + Consumer j = Arrays::sort; // type arguments inferred from context + Consumer k = Arrays::sort; // explicit type arguments + Supplier> l = ArrayList::new; // constructor for parameterized type + Supplier m = ArrayList::new; // inferred type arguments + IntFunction n = int[]::new; // array creation + Supplier o = Foo::new; // explicit type arguments + Supplier p = Foo.Bar::new; // inner class constructor + Supplier> q = R::new; // generic class, generic constructor + + Foo[] foo = new Foo[2]; + int r = 1; + foo[r] = new Foo(); + Runnable s = foo[r]::bar; + boolean test = false; + MyList list = new MyList<>(); + Supplier> fun = (test ? list.replaceAll2(String::trim) : list)::iterator; + + // Lamdas + Runnable t = () -> { + }; // No parameters; result is void + IntSupplier u = () -> 42; // No parameters, expression body + Supplier v = () -> null; // No parameters, expression body + v = () -> { + return 42; + }; // No parameters, block body with return + t = () -> { + System.gc(); + }; // No parameters, void block body + v = () -> { // Complex block body with returns + if (true) { + return 12; + } + else { + int result = 15; + for (int i2 = 1; i2 < 10; i2++) { + result *= i2; + } + return result; + } + }; + IntFunction w = (int x) -> x + 1; // Single declared-type parameter + w = (int x) -> { + return x + 1; + }; // Single declared-type parameter + w = (x) -> x + 1; // Single inferred-type parameter + w = x -> x + 1; // Parentheses optional for + // single inferred-type parameter + Function z = (String s2) -> s2.length(); // Single declared-type parameter + Consumer a2 = (Thread t2) -> { + t2.start(); + }; // Single declared-type parameter + z = s3 -> s3.length(); // Single inferred-type parameter + a2 = t3 -> { + t3.start(); + }; // Single inferred-type parameter + IntBinaryOperator b2 = (int x, int y) -> x + y; // Multiple declared-type parameters + b2 = (x, y) -> x + y; // Multiple inferred-type parameters + + List myList + = Arrays.asList("a1", "a2", "b1", "c2", "c1"); + + myList.stream().filter((s4) -> { + System.out.println("filter " + s4); + return s4.startsWith("c"); + }).map(String::toUpperCase).sorted().forEach( + System.out::println); + + } + +} \ No newline at end of file From 57942a51310c658f65d7934bdf39ab7498ee0c85 Mon Sep 17 00:00:00 2001 From: Gergely Herenyi Date: Fri, 9 Aug 2019 23:37:22 +0200 Subject: [PATCH 2/4] Added a fix and a test previously found in cobertura (cherry picked from commit 6e4ab3c957dafeee521d66e461617b1da859f0af) --- src/main/javacc/Java1.1.jj | 2 +- src/test/java/javancss/ParseTest.java | 1 + src/test/resources/Test161.java | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/Test161.java diff --git a/src/main/javacc/Java1.1.jj b/src/main/javacc/Java1.1.jj index ab089fd..41c14f0 100644 --- a/src/main/javacc/Java1.1.jj +++ b/src/main/javacc/Java1.1.jj @@ -2569,7 +2569,7 @@ void PrimarySuffix() : | "::" Identifier() | - Arguments() + Arguments() [ "{" MethodDeclaration() "}"] } void Literal() : diff --git a/src/test/java/javancss/ParseTest.java b/src/test/java/javancss/ParseTest.java index 1013e3a..a1ffb7f 100644 --- a/src/test/java/javancss/ParseTest.java +++ b/src/test/java/javancss/ParseTest.java @@ -56,6 +56,7 @@ public void testParse() checkParse( 158 ); // JAVANCSS-48 checkParse( 159 ); // default interface methods checkParse( 160 ); // java 8 lambda and method reference + checkParse( 161 ); // found by cobertura } private void checkParse( int testFile ) diff --git a/src/test/resources/Test161.java b/src/test/resources/Test161.java new file mode 100644 index 0000000..3281af6 --- /dev/null +++ b/src/test/resources/Test161.java @@ -0,0 +1,21 @@ + + package mypackage; + + public class FooMain { + public class Outer { + private Inner inner; + public Outer() { + inner = this.new Inner() { + @Override + public int getI() { + return 15; + } + }; + } + private class Inner { + public int getI() { + return 1; + } + } + } + } \ No newline at end of file From a2bdbd57fb28d363a5e0b4c019df6c1a5ef0977a Mon Sep 17 00:00:00 2001 From: Gergely Herenyi Date: Mon, 23 Jul 2018 14:56:58 +0200 Subject: [PATCH 3/4] Fixing try with resource parsing when multiple declarations and ends with a ; (cherry picked from commit 7a0182cb0b565e0a8e8f05088b3e556c7b875013) --- src/main/javacc/Java1.1.jj | 2 +- src/test/resources/Test148.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/javacc/Java1.1.jj b/src/main/javacc/Java1.1.jj index 41c14f0..d133b89 100644 --- a/src/main/javacc/Java1.1.jj +++ b/src/main/javacc/Java1.1.jj @@ -2997,7 +2997,7 @@ void TryWithResources() : {} { // LocalVariableDeclaration() [ ";" ] - LocalVariableDeclaration() ( ";" LocalVariableDeclaration() )* + LocalVariableDeclaration() ( LOOKAHEAD(2) ";" LocalVariableDeclaration() )* [ ";" ] } void Identifier() : diff --git a/src/test/resources/Test148.java b/src/test/resources/Test148.java index 7829598..d9a1309 100644 --- a/src/test/resources/Test148.java +++ b/src/test/resources/Test148.java @@ -33,6 +33,23 @@ public void baz() { // do nothing } } + + public void baz2() { + String zipFileName = ""; + String outputFileName = ""; + java.nio.charset.Charset charset = java.nio.charset.Charset.forName("US-ASCII"); + java.nio.file.Path outputFilePath = java.nio.file.Paths.get(outputFileName); + + try ( + java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName); + java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset); + ) { + // do nothing + } + catch (java.beans.PropertyVetoException e) { + // do nothing + } + } } From 791d83c52e2e0e9378d7b9c1d2acee81e9926eb3 Mon Sep 17 00:00:00 2001 From: Gergely Herenyi Date: Tue, 5 Mar 2019 10:23:23 +0100 Subject: [PATCH 4/4] Adding lambda cast (cherry picked from commit 90aca669d2dce3937f4f981dece4a77c4453c91c) --- src/main/javacc/Java1.1.jj | 2 ++ src/test/resources/Test160.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/javacc/Java1.1.jj b/src/main/javacc/Java1.1.jj index d133b89..0a4ce7a 100644 --- a/src/main/javacc/Java1.1.jj +++ b/src/main/javacc/Java1.1.jj @@ -2508,6 +2508,8 @@ void CastExpression() : { LOOKAHEAD("(" PrimitiveType()) "(" Type() ")" UnaryExpression() +| + LOOKAHEAD("(" Type() ")" LambdaExpression()) "(" Type() ")" LambdaExpression() | "(" Type() ")" UnaryExpressionNotPlusMinus() } diff --git a/src/test/resources/Test160.java b/src/test/resources/Test160.java index 103a7b1..41017ef 100644 --- a/src/test/resources/Test160.java +++ b/src/test/resources/Test160.java @@ -134,6 +134,8 @@ public static void main(String[] args) { }).map(String::toUpperCase).sorted().forEach( System.out::println); + Runnable runnable = (Runnable)() -> System.out.println("Test"); + } } \ No newline at end of file