Skip to content

Commit

Permalink
Added lambdas and method references to the parser and a test for them
Browse files Browse the repository at this point in the history
  • Loading branch information
herenyi committed Jan 15, 2018
1 parent f037efe commit 46fc2aa
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 0 deletions.
55 changes: 55 additions & 0 deletions cobertura/src/main/javacc/Java1.1.jj
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,8 @@ TOKEN :
| < COMMA: "," >
| < DOT: "." >
| < AT: "@" >
| < LAMBDA: "->" >
| < DOUBLECOLON: "::" >
}

/* OPERATORS */
Expand Down Expand Up @@ -2324,7 +2326,14 @@ void Expression() :
//System.out.println( "Expression start" );
}
{
LOOKAHEAD(LambdaExpression()) LambdaExpression()
|
AssignmentExpression()
}

void AssignmentExpression() :
{}
{
LOOKAHEAD( PrimaryExpression() AssignmentOperator() )
//{ System.out.println( "Expression" ); }
Assignment()
Expand Down Expand Up @@ -2515,6 +2524,8 @@ void PrimaryExpression() :
// { System.out.println( "Before PrimaryExpression" ); }
}
{
LOOKAHEAD(MethodReference()) MethodReference()
|
PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )*
}

Expand Down Expand Up @@ -3490,3 +3501,47 @@ void MemberSelector():
"." TypeArguments() <IDENTIFIER>
}

void LambdaExpression():
{}
{
LambdaParameters() "->" LambdaBody()
}

void LambdaParameters():
{}
{
<IDENTIFIER>
|
LOOKAHEAD("(" InferredFormalParameterList() ")") "(" InferredFormalParameterList() ")"
|
LOOKAHEAD( [FormalParameters()] ) [FormalParameters()]
}

void InferredFormalParameterList():
{}
{
<IDENTIFIER> ( "," <IDENTIFIER> )*
}


void LambdaBody():
{}
{
Expression()
|
Block()
}

void MethodReference():
{}
{
"super" "::" [TypeArguments()] <IDENTIFIER>
|
LOOKAHEAD( 4 ) Name() "." "super" "::" [TypeArguments()] <IDENTIFIER>
|
// ClassType() "::" [TypeArguments()] "new" and ArrayType() "::" "new" is included in below
LOOKAHEAD(ReferenceType() "::" [TypeArguments()] ( <IDENTIFIER> | "new" )) ReferenceType() "::" [TypeArguments()] ( <IDENTIFIER> | "new" )
|
// Name() "::" [TypeArguments()] <IDENTIFIER> is included in below
PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )* "::" [TypeArguments()] <IDENTIFIER>
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,171 @@ public void testJava8defaultAndStaticInterface() throws Exception {
"Testing default and static interface functions",
1.0, ccn1, 0.01);
}

/**
* This test highlights an issue with Javancss not supporting java8 function pointers and lambdas.
* <p>
* @throws Exception
* <p>
*/
public void testJava8functionPointersAndLambdas() throws Exception {
File tempDir = TestUtils.getTempDir();
String filename = "LamdasAndMethodRefs.java";
File sourceFile = new File(tempDir, filename);
FileUtils
.write(
sourceFile,
"import java.util.ArrayList;\n"
+ "import java.util.Arrays;\n"
+ "import java.util.Iterator;\n"
+ "import java.util.List;\n"
+ "import java.util.function.Consumer;\n"
+ "import java.util.function.Function;\n"
+ "import java.util.function.IntBinaryOperator;\n"
+ "import java.util.function.IntFunction;\n"
+ "import java.util.function.IntSupplier;\n"
+ "import java.util.function.LongSupplier;\n"
+ "import java.util.function.Supplier;\n"
+ "import java.util.function.ToIntFunction;\n"
+ "import java.util.function.UnaryOperator;\n"
+ "\n"
+ "class MyList<E> extends ArrayList<E> {\n"
+ "\n"
+ " public MyList replaceAll2(UnaryOperator<E> operator) {\n"
+ " return this;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "class T {\n"
+ "\n"
+ " public void tvarMember() {\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "class Foo {\n"
+ "\n"
+ " public void bar() {\n"
+ " }\n"
+ "\n"
+ " static class Bar {\n"
+ " }\n"
+ "\n"
+ "}\n"
+ "\n"
+ "class R<A> {\n"
+ "\n"
+ " R() {\n"
+ " }\n"
+ "\n"
+ " R(Integer a) {\n"
+ " }\n"
+ "\n"
+ " R(String a) {\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public class LamdasAndMethodRefs {\n"
+ "\n"
+ " public LamdasAndMethodRefs() {\n"
+ " //Method references\n"
+ " Runnable a = super::toString;\n"
+ " Runnable b = LamdasAndMethodRefs.super::toString;\n"
+ " }\n"
+ "\n"
+ " public static void main(String[] args) {\n"
+ " //Method references\n"
+ " LongSupplier a = System::currentTimeMillis; // static method\n"
+ " ToIntFunction<String> b = String::length; // instance method\n"
+ " ToIntFunction<List> c = List::size;\n"
+ " ToIntFunction<List<String>> d = List<String>::size; // explicit type arguments for generic type\n"
+ " UnaryOperator<int[]> e = int[]::clone;\n"
+ " Consumer<T> f = T::tvarMember;\n"
+ "\n"
+ " Runnable g = System.out::println;\n"
+ " Consumer<Integer> h = String::valueOf; // overload resolution needed\n"
+ " IntSupplier i = \"abc\"::length;\n"
+ " Consumer<int[]> j = Arrays::sort; // type arguments inferred from context\n"
+ " Consumer<String[]> k = Arrays::<String>sort; // explicit type arguments\n"
+ " Supplier<ArrayList<String>> l = ArrayList<String>::new; // constructor for parameterized type\n"
+ " Supplier<ArrayList> m = ArrayList::new; // inferred type arguments\n"
+ " IntFunction<int[]> n = int[]::new; // array creation\n"
+ " Supplier<Foo> o = Foo::<Integer>new; // explicit type arguments\n"
+ " Supplier<Foo.Bar> p = Foo.Bar::new; // inner class constructor\n"
+ " Supplier<R<String>> q = R<String>::<Integer>new; // generic class, generic constructor\n"
+ "\n"
+ " Foo[] foo = new Foo[2];\n"
+ " int r = 1;\n"
+ " foo[r] = new Foo();\n"
+ " Runnable s = foo[r]::bar;\n"
+ " boolean test = false;\n"
+ " MyList<String> list = new MyList<>();\n"
+ " Supplier<Iterator<String>> fun = (test ? list.replaceAll2(String::trim) : list)::iterator;\n"
+ "\n"
+ " // Lamdas\n"
+ " Runnable t = () -> {\n"
+ " }; // No parameters; result is void\n"
+ " IntSupplier u = () -> 42; // No parameters, expression body\n"
+ " Supplier<Object> v = () -> null; // No parameters, expression body\n"
+ " v = () -> {\n"
+ " return 42;\n"
+ " }; // No parameters, block body with return\n"
+ " t = () -> {\n"
+ " System.gc();\n"
+ " }; // No parameters, void block body\n"
+ " v = () -> { // Complex block body with returns\n"
+ " if (true) {\n"
+ " return 12;\n"
+ " }\n"
+ " else {\n"
+ " int result = 15;\n"
+ " for (int i2 = 1; i2 < 10; i2++) {\n"
+ " result *= i2;\n"
+ " }\n"
+ " return result;\n"
+ " }\n"
+ " };\n"
+ " IntFunction<Integer> w = (int x) -> x + 1; // Single declared-type parameter\n"
+ " w = (int x) -> {\n"
+ " return x + 1;\n"
+ " }; // Single declared-type parameter\n"
+ " w = (x) -> x + 1; // Single inferred-type parameter\n"
+ " w = x -> x + 1; // Parentheses optional for\n"
+ " // single inferred-type parameter\n"
+ " Function<String, Integer> z = (String s2) -> s2.length(); // Single declared-type parameter\n"
+ " Consumer<Thread> a2 = (Thread t2) -> {\n"
+ " t2.start();\n"
+ " }; // Single declared-type parameter\n"
+ " z = s3 -> s3.length(); // Single inferred-type parameter\n"
+ " a2 = t3 -> {\n"
+ " t3.start();\n"
+ " }; // Single inferred-type parameter\n"
+ " IntBinaryOperator b2 = (int x, int y) -> x + y; // Multiple declared-type parameters\n"
+ " b2 = (x, y) -> x + y; // Multiple inferred-type parameters\n"
+ "\n"
+ " List<String> myList\n"
+ " = Arrays.asList(\"a1\", \"a2\", \"b1\", \"c2\", \"c1\");\n"
+ "\n"
+ " myList.stream().filter((s4) -> {\n"
+ " System.out.println(\"filter \" + s4);\n"
+ " return s4.startsWith(\"c\");\n"
+ " }).map(String::toUpperCase).sorted().forEach(\n"
+ " System.out::println);\n"
+ "\n"
+ " }\n"
+ "\n"
+ "}");

//create a ComplexityCalculator that will use the archive
FileFinder fileFinder = new FileFinder();
fileFinder.addSourceDirectory(tempDir.getAbsolutePath());
ComplexityCalculator complexity = new ComplexityCalculator(fileFinder);

double ccn1 = complexity.getCCNForSourceFile(new SourceFileData(
filename));
assertNotNull(ccn1);
assertEquals(
"Testing method references and lambda functions",
1.875, ccn1, 0.01);
}

}

0 comments on commit 46fc2aa

Please sign in to comment.