This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_4_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit eeec29e6e89a2ee2a1655717494abffb6c87135d Author: Eric Milles <[email protected]> AuthorDate: Thu Nov 10 14:56:31 2022 -0600 GROOVY-10820: STC: static methods for `Type.name()` except from `Class` --- .../transform/stc/StaticTypeCheckingVisitor.java | 86 +-- src/spec/test/typing/TypeCheckingTest.groovy | 3 +- src/test/groovy/bugs/Groovy7204.groovy | 4 +- src/test/groovy/bugs/Groovy7987.groovy | 44 -- src/test/groovy/bugs/Groovy8609Bug.groovy | 171 +++-- .../groovy/transform/stc/GenericsSTCTest.groovy | 20 +- .../groovy/transform/stc/MethodCallsSTCTest.groovy | 129 ++-- .../classgen/asm/sc/BugsStaticCompileTest.groovy | 689 +++++++++++---------- .../asm/sc/StaticCompilationTestSupport.groovy | 2 + .../main/groovy/groovy/console/ui/Console.groovy | 24 +- 10 files changed, 568 insertions(+), 604 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index b0f18982a0..7e53d497e3 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -1803,10 +1803,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { boolean isStatic; if (member instanceof FieldNode) { isStatic = ((FieldNode) member).isStatic(); - } else if (member instanceof MethodNode) { - isStatic = ((MethodNode) member).isStatic(); - } else { + } else if (member instanceof PropertyNode) { isStatic = ((PropertyNode) member).isStatic(); + } else { // assume member instanceof MethodNode + isStatic = member instanceof ExtensionMethodNode ? ((ExtensionMethodNode) member).isStaticExtension() : ((MethodNode) member).isStatic(); } return (isStatic ? member : null); } @@ -3324,7 +3324,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { if (dmd.getParent() == null) { receivers.addAll(owners); } else { - //receivers.add(new Receiver<String>(CLOSURE_TYPE, path + "owner")); + //receivers.add(new Receiver<String>(CLOSURE_TYPE, path + "owner")); addReceivers(receivers, owners, dmd.getParent(), path + "owner."); } } @@ -3334,7 +3334,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { if (dmd.getParent() == null) { receivers.addAll(owners); } else { - //receivers.add(new Receiver<String>(CLOSURE_TYPE, path + "owner")); + //receivers.add(new Receiver<String>(CLOSURE_TYPE, path + "owner")); addReceivers(receivers, owners, dmd.getParent(), path + "owner."); } if (strategy == Closure.OWNER_FIRST) { @@ -3345,6 +3345,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } private static void addDelegateReceiver(final List<Receiver<String>> receivers, final ClassNode delegate, final String path) { + if (isClassClassNodeWrappingConcreteType(delegate)) { // add Type from Class<Type> + addDelegateReceiver(receivers, delegate.getGenericsTypes()[0].getType(), path); + } if (receivers.stream().map(Receiver::getType).noneMatch(delegate::equals)) { receivers.add(new Receiver<>(delegate, path)); } @@ -3477,38 +3480,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { List<Receiver<String>> receivers = new ArrayList<>(); addReceivers(receivers, makeOwnerList(objectExpression), call.isImplicitThis()); + MethodNode first = null; List<MethodNode> mn = null; Receiver<String> chosenReceiver = null; for (Receiver<String> currentReceiver : receivers) { - ClassNode receiverType = currentReceiver.getType(); - mn = findMethod(receiverType, name, args); - - // if receiver is "this" in a static context then only static methods are compatible - // if not in a static context but the current receiver is a static class ensure that - // all methods are either static or declared by the current receiver or a superclass - if (!mn.isEmpty() && currentReceiver.getData() == null && (isThisObjectExpression || call.isImplicitThis()) - && (typeCheckingContext.isInStaticContext || (receiverType.getModifiers() & Opcodes.ACC_STATIC) != 0)) { - // we create separate method lists just to be able to print out - // a nice error message to the user - // a method is accessible if it is static, or if we are not in a static context and it is - // declared by the current receiver or a superclass - List<MethodNode> accessibleMethods = new LinkedList<>(); - List<MethodNode> inaccessibleMethods = new LinkedList<>(); - for (final MethodNode node : mn) { - if (node.isStatic() || (!typeCheckingContext.isInStaticContext - && implementsInterfaceOrIsSubclassOf(receiverType, node.getDeclaringClass()))) { - accessibleMethods.add(node); - } else { - inaccessibleMethods.add(node); - } - } - mn = accessibleMethods; - if (accessibleMethods.isEmpty()) { - MethodNode node = inaccessibleMethods.get(0); // choose an arbitrary method to display an error message - addStaticTypeError("Non-static method " + prettyPrintTypeName(node.getDeclaringClass()) + "#" + node.getName() + " cannot be called from static context", call); + mn = findMethod(currentReceiver.getType().getPlainNodeReference(), name, args); + if (!mn.isEmpty()) { + first = mn.get(0); // capture for error string + // for "this" in a static context, only static methods are compatible + if (currentReceiver.getData() == null && !isClassType(currentReceiver.getType())) { + boolean staticThis = (isThisObjectExpression || call.isImplicitThis()) && typeCheckingContext.isInStaticContext; + boolean staticThat = isClassClassNodeWrappingConcreteType(receiver); // GROOVY-10819, GROOVY-10820 + mn = allowStaticAccessToMember(mn, staticThis || staticThat); } } - if (!mn.isEmpty()) { chosenReceiver = currentReceiver; break; @@ -3517,19 +3502,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { if (mn.isEmpty() && isThisObjectExpression && call.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) { mn = CLOSURE_TYPE.getDeclaredMethods(name); if (!mn.isEmpty()) { - chosenReceiver = Receiver.make(CLOSURE_TYPE); objectExpression.removeNodeMetaData(INFERRED_TYPE); } } if (mn.isEmpty()) { mn = extension.handleMissingMethod(receiver, name, argumentList, args, call); + if (mn.isEmpty() && first != null) mn.add(first); // non-static method error? } if (mn.isEmpty()) { addNoMatchingMethodError(receiver, name, args, call); } else { - if (areCategoryMethodCalls(mn, name, args)) { - addCategoryMethodCallError(call); - } + if (areCategoryMethodCalls(mn, name, args)) addCategoryMethodCallError(call); { ClassNode obj = chosenReceiver != null ? chosenReceiver.getType() : null; @@ -3548,8 +3531,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { if (mn.size() == 1) { MethodNode targetMethodCandidate = mn.get(0); ClassNode declaringClass = targetMethodCandidate.getDeclaringClass(); - if (!targetMethodCandidate.isStatic() && !isClassType(declaringClass) - && objectExpression instanceof ClassExpression && call.getNodeMetaData(DYNAMIC_RESOLUTION) == null) { + if (chosenReceiver == null) { + chosenReceiver = Receiver.make(declaringClass.getPlainNodeReference()); + } + if (!targetMethodCandidate.isStatic() && !isClassType(declaringClass) && isClassType(receiver) + && chosenReceiver.getData() == null && call.getNodeMetaData(DYNAMIC_RESOLUTION) == null) { addStaticTypeError("Non-static method " + prettyPrintTypeName(declaringClass) + "#" + targetMethodCandidate.getName() + " cannot be called from static context", call); } else if (targetMethodCandidate.isAbstract() && isSuperExpression(objectExpression)) { // GROOVY-10341 String target = toMethodParametersString(targetMethodCandidate.getName(), extractTypesFromParameters(targetMethodCandidate.getParameters())); @@ -3559,9 +3545,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { addStaticTypeError("Abstract method " + target + " cannot be called directly", call); } } - if (chosenReceiver == null) { - chosenReceiver = Receiver.make(declaringClass); - } // note second pass here to differentiate from extension that sets type boolean mergeType = (call.getNodeMetaData(INFERRED_TYPE) != null); storeTargetMethod(call, targetMethodCandidate); @@ -4966,11 +4949,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { methods.add(callMethod); } } - if (!receiver.isStaticClass() && receiver.getOuterClass() != null - && typeCheckingContext.getEnclosingClassNodes().contains(receiver)) { - ClassNode outer = receiver.getOuterClass(); - do { methods.addAll(findMethodsWithGenerated(outer, name)); - } while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null); + if (typeCheckingContext.getEnclosingClassNodes().contains(receiver)) { + boolean staticOnly = Modifier.isStatic(receiver.getModifiers()); + for (ClassNode outer = receiver; (outer = outer.getOuterClass()) != null; + staticOnly = staticOnly || Modifier.isStatic(outer.getModifiers())) { + methods.addAll(allowStaticAccessToMember(findMethodsWithGenerated(outer, name), staticOnly)); + } } if (methods.isEmpty()) { addArrayMethods(methods, receiver, name, args); @@ -5034,7 +5018,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } } - if (isClassClassNodeWrappingConcreteType(receiver)) { // GROOVY-6802, GROOVY-6803 + if (isClassClassNodeWrappingConcreteType(receiver)) { // GROOVY-6802, GROOVY-6803, GROOVY-9415 List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args); if (!result.isEmpty()) return result; } @@ -5897,11 +5881,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } } - protected void addNoMatchingMethodError(ClassNode receiver, final String name, final ClassNode[] args, final Expression call) { - if (isClassClassNodeWrappingConcreteType(receiver)) { - receiver = receiver.getGenericsTypes()[0].getType(); - } - addStaticTypeError("Cannot find matching method " + prettyPrintTypeName(receiver) + "#" + toMethodParametersString(name, args) + ". Please check if the declared type is correct and if the method exists.", call); + protected void addNoMatchingMethodError(final ClassNode receiver, final String name, final ClassNode[] args, final Expression call) { + ClassNode type = isClassClassNodeWrappingConcreteType(receiver) ? receiver.getGenericsTypes()[0].getType() : receiver; + addStaticTypeError("Cannot find matching method " + prettyPrintTypeName(type) + "#" + toMethodParametersString(name, args) + ". Please check if the declared type is correct and if the method exists.", call); } protected void addAmbiguousErrorMessage(final List<MethodNode> foundMethods, final String name, final ClassNode[] args, final Expression expr) { diff --git a/src/spec/test/typing/TypeCheckingTest.groovy b/src/spec/test/typing/TypeCheckingTest.groovy index 75d85b92ee..84c18ac9ef 100644 --- a/src/spec/test/typing/TypeCheckingTest.groovy +++ b/src/spec/test/typing/TypeCheckingTest.groovy @@ -700,7 +700,8 @@ import static org.codehaus.groovy.ast.tools.WideningCategories.lowestUpperBound } // end::flowtyping_typeconstraints_failure[] flowTypingWithExplicitType() - ''', '[Static type checking] - Cannot find matching method java.util.ArrayList#add(int)' + ''', + 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments [int]' assertScript ''' // tag::flowtyping_typeconstraints_fixed[] diff --git a/src/test/groovy/bugs/Groovy7204.groovy b/src/test/groovy/bugs/Groovy7204.groovy index 67e5f1ff34..e68ecbf823 100644 --- a/src/test/groovy/bugs/Groovy7204.groovy +++ b/src/test/groovy/bugs/Groovy7204.groovy @@ -473,7 +473,7 @@ final class Groovy7204 { ''' } - @Test + @NotYetImplemented @Test void testCompileStatic6() { assertScript shell, ''' class Repository<T, S extends Serializable> { @@ -482,7 +482,7 @@ final class Groovy7204 { } @CompileStatic - def test() { + void test() { Repository<String, Long> r = new Repository<String, Long>() r.delete('foo') } diff --git a/src/test/groovy/bugs/Groovy7987.groovy b/src/test/groovy/bugs/Groovy7987.groovy deleted file mode 100644 index 7f15e085b4..0000000000 --- a/src/test/groovy/bugs/Groovy7987.groovy +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package groovy.bugs - -import org.junit.Test - -import static groovy.test.GroovyAssert.shouldFail - -final class Groovy7987 { - - @Test - void testNonStaticMethodViaStaticReceiver() { - def err = shouldFail ''' - class Foo { - def bar() { - } - } - - @groovy.transform.TypeChecked - void test() { - Foo.bar() - } - - test() - ''' - assert err =~ 'Non-static method Foo#bar cannot be called from static context' - } -} diff --git a/src/test/groovy/bugs/Groovy8609Bug.groovy b/src/test/groovy/bugs/Groovy8609Bug.groovy index 08720909fe..28bb9232eb 100644 --- a/src/test/groovy/bugs/Groovy8609Bug.groovy +++ b/src/test/groovy/bugs/Groovy8609Bug.groovy @@ -26,121 +26,118 @@ final class Groovy8609Bug extends GroovyTestCase { void testUpperBoundWithGenerics() { assertScript ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E extends Map<String, Integer>> { - E getFirstRecord(T recordList) { - return recordList.get(0) + @groovy.transform.CompileStatic + public class A<T extends List<E>, E extends Map<String, Integer>> { + E getFirstRecord(T recordList) { + return recordList.get(0) + } + + static void main(args) { + def list = new ArrayList<HashMap<String, Integer>>() + def record = new HashMap<String, Integer>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - - static void main(args) { - def list = new ArrayList<HashMap<String, Integer>>() - def record = new HashMap<String, Integer>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) - } - } ''' } void testUpperBoundWithoutGenerics() { assertScript ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E extends Map> { - E getFirstRecord(T recordList) { - return recordList.get(0); - } - - static void main(args) { - def list = new ArrayList<HashMap<String, Integer>>() - def record = new HashMap<String, Integer>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) + @groovy.transform.CompileStatic + public class A<T extends List<E>, E extends Map> { + E getFirstRecord(T recordList) { + return recordList.get(0); + } + + static void main(args) { + def list = new ArrayList<HashMap<String, Integer>>() + def record = new HashMap<String, Integer>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - } ''' } void testNoUpperBound() { assertScript ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E> { - E getFirstRecord(T recordList) { - return recordList.get(0); + @groovy.transform.CompileStatic + public class A<T extends List<E>, E> { + E getFirstRecord(T recordList) { + return recordList.get(0); + } + + static void main(args) { + def list = new ArrayList<HashMap<String, Integer>>() + def record = new HashMap<String, Integer>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - - static void main(args) { - def list = new ArrayList<HashMap<String, Integer>>() - def record = new HashMap<String, Integer>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) - } - } ''' } void testUpperBoundWithGenericsThroughWrongType() { - def errMsg = shouldFail ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E extends Map<String, Integer>> { - E getFirstRecord(T recordList) { - return recordList.get(0) - } - - static void main(args) { - def list = new ArrayList<TreeMap<String, Integer>>() - def record = new TreeMap<String, Integer>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) + def err = shouldFail ''' + @groovy.transform.CompileStatic + public class A<T extends List<E>, E extends Map<String, Integer>> { + E getFirstRecord(T recordList) { + return recordList.get(0) + } + + static void main(args) { + def list = new ArrayList<TreeMap<String, Integer>>() + def record = new TreeMap<String, Integer>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - } ''' - - assert errMsg.contains('[Static type checking] - Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.TreeMap<java.lang.String, java.lang.Integer>>)') + assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.TreeMap<java.lang.String, java.lang.Integer>>]') } void testUpperBoundWithGenericsThroughWrongType2() { - def errMsg = shouldFail ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E extends Map<String, Integer>> { - E getFirstRecord(T recordList) { - return recordList.get(0) - } - - static void main(args) { - def list = new ArrayList<HashMap<String, Long>>() - def record = new HashMap<String, Long>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) + def err = shouldFail ''' + @groovy.transform.CompileStatic + public class A<T extends List<E>, E extends Map<String, Integer>> { + E getFirstRecord(T recordList) { + return recordList.get(0) + } + + static void main(args) { + def list = new ArrayList<HashMap<String, Long>>() + def record = new HashMap<String, Long>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - } ''' - - assert errMsg.contains('[Static type checking] - Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Long>>)') + assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Long>>]') } void testUpperBoundWithGenericsThroughWrongType3() { - def errMsg = shouldFail ''' - @groovy.transform.CompileStatic - public class A<T extends List<E>, E extends Map<String, Integer>> { - E getFirstRecord(T recordList) { - return recordList.get(0) + def err = shouldFail ''' + @groovy.transform.CompileStatic + public class A<T extends List<E>, E extends Map<String, Integer>> { + E getFirstRecord(T recordList) { + return recordList.get(0) + } + + static void main(args) { + def list = new ArrayList<HashMap<StringBuffer, Integer>>() + def record = new HashMap<StringBuffer, Integer>() + list.add(record) + def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() + assert record.is(a.getFirstRecord(list)) + } } - - static void main(args) { - def list = new ArrayList<HashMap<StringBuffer, Integer>>() - def record = new HashMap<StringBuffer, Integer>() - list.add(record) - def a = new A<ArrayList<HashMap<String, Integer>>, HashMap<String, Integer>>() - assert record.is(a.getFirstRecord(list)) - } - } ''' - - assert errMsg.contains('[Static type checking] - Cannot find matching method A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.StringBuffer, java.lang.Integer>>)') + assert err.contains('Cannot call A#getFirstRecord(java.util.ArrayList<java.util.HashMap<java.lang.String, java.lang.Integer>>) with arguments [java.util.ArrayList<java.util.HashMap<java.lang.StringBuffer, java.lang.Integer>>]') } } diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy index 3ecce489e4..f935323ee9 100644 --- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy +++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy @@ -58,7 +58,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { List<String> list = [] list.add(1) ''', - 'Cannot find matching method java.util.ArrayList#add(int)' + 'Cannot call java.util.ArrayList#add(java.lang.String) with arguments [int]' } void testAddOnList2() { @@ -134,7 +134,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { List<Integer> list = new LinkedList<>() list.add 'Hello' ''', - 'Cannot find matching method java.util.LinkedList#add(java.lang.String). Please check if the declared type is correct and if the method exists.' + 'Cannot call java.util.LinkedList#add(java.lang.Integer) with arguments [java.lang.String]' } void testAddOnListWithDiamondAndWrongTypeUsingLeftShift() { @@ -241,7 +241,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { Number number = Optional.of(42).orElse(Double.NaN) assert number.intValue() == 42 ''', - 'Cannot find matching method java.util.Optional#orElse(double).' + 'Cannot call java.util.Optional#orElse(java.lang.Integer) with arguments [double]' } void testReturnTypeInferenceWithMethodGenerics5() { @@ -257,7 +257,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { Number number = Optional.ofNullable((Integer) null).orElse(42d) assert number.intValue() == 42 ''', - 'Cannot find matching method java.util.Optional#orElse(double).' + 'Cannot call java.util.Optional#orElse(java.lang.Integer) with arguments [double]' } void testReturnTypeInferenceWithMethodGenerics7() { @@ -2079,7 +2079,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { def map = new HashMap<String, Integer>() map.put('hello', new Object()) ''', - 'Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object). Please check if the declared type is correct and if the method exists.' + 'Cannot call java.util.HashMap#put(java.lang.String, java.lang.Integer) with arguments [java.lang.String, java.lang.Object]' } void testPutAtWithWrongValueType() { @@ -2103,7 +2103,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { } } ''', - 'Cannot find matching method java.util.Map#put(java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>). Please check if the declared type is correct and if the method exists.', + 'Cannot call java.util.Map#put(java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>) with arguments [java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>]', 'Cannot call <K,V> org.codehaus.groovy.runtime.DefaultGroovyMethods#putAt(java.util.Map<K, V>, K, V) with arguments [java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.util.List<java.lang.String>>>, java.lang.String, java.util.LinkedHashMap<java.lang.String, java.util.List<ConfigAttribute>>]' } @@ -2883,7 +2883,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { Map<Date, Date> map = new HashMap<>() map.put('foo', new Date()) ''', - 'Cannot find matching method java.util.HashMap#put(java.lang.String, java.util.Date). Please check if the declared type is correct and if the method exists.' + 'Cannot call java.util.HashMap#put(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]' } void testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingSquareBracket() { shouldFailWithMessages ''' @@ -2923,7 +2923,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { Map<Date, Date> map = new HashMap<>() map.put(new Date(), 'foo') ''', - 'Cannot find matching method java.util.HashMap#put(java.util.Date, java.lang.String). Please check if the declared type is correct and if the method exists.' + 'Cannot call java.util.HashMap#put(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]' } void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingSquareBracket() { shouldFailWithMessages ''' @@ -3314,8 +3314,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { test(new Holder<Object>()) ''', 'Cannot call TypedProperty#eq(java.lang.String) with arguments [groovy.lang.GString]', - 'Cannot find matching method TypedProperty#eq(int)', // chooseBestMethod removes "eq" - 'Cannot find matching method TypedProperty#eq(java.lang.String)' + 'Cannot call TypedProperty#eq(java.lang.String) with arguments [int]', + 'Cannot call TypedProperty#eq(java.lang.Number) with arguments [java.lang.String]' } // GROOVY-5748 diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy index 251bce0fdd..f53596a312 100644 --- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy +++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy @@ -56,7 +56,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { shouldFailWithMessages ''' A a = new A() assert a.foo(1,1)==2 - ''', 'Cannot find matching method' + ''', + 'Cannot find matching method' } void testMethodCallOnInstanceWithVarArgs() { @@ -84,7 +85,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { void testMissingStaticMethod() { shouldFailWithMessages ''' A.missing 'echo' - ''', 'Cannot find matching method' + ''', + 'Cannot find matching method' } void testStaticMethodWithVarArgs() { @@ -206,7 +208,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { B c = new B<Integer>() String[] args = ['a','b','c'] assert c.identity(args) == args - ''', 'Cannot call groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2#identity(java.lang.Integer[]) with arguments [java.lang.String[]]' + ''', + 'Cannot call groovy.transform.stc.MethodCallsSTCTest$MyMethodCallTestClass2#identity(java.lang.Integer[]) with arguments [java.lang.String[]]' } // GROOVY-8909 @@ -222,7 +225,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { void m(Set<Integer> set) { } m([1,2,3,3]) - ''', 'm(java.util.List<java.lang.Integer>). Please check if the declared type is correct and if the method exists.' + ''', + 'm(java.util.List<java.lang.Integer>). Please check if the declared type is correct and if the method exists.' } // GROOVY-7106, GROOVY-7274, GROOVY-9844 @@ -384,7 +388,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { class Peer { def foo() { new Main() } } - ''', '[Static type checking] - Cannot find matching method Main#<init>()' + ''', + 'Cannot find matching method Main#<init>()' } // GROOVY-8509 @@ -512,7 +517,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { bar(null, new Date()) } } - ''', 'Reference to method is ambiguous' + ''', + 'Reference to method is ambiguous' } // GROOVY-5175 @@ -572,7 +578,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { 'Boolean' } ['foo',123,true].each { foo(it) } - ''', 'Cannot find matching method' + ''', + 'Cannot find matching method' } void testShouldNotFailThanksToInstanceOfChecks() { @@ -660,7 +667,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { foo(it) } } - ''', 'Reference to method is ambiguous' + ''', + 'Reference to method is ambiguous' } void testShouldFailWithMultiplePossibleMethods2() { @@ -679,7 +687,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { foo(argument) } } - ''', 'Reference to method is ambiguous' + ''', + 'Reference to method is ambiguous' } // GROOVY-5703 @@ -781,7 +790,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { it = new Date() foo(it) } - ''', 'foo(java.util.Date)' + ''', + 'foo(java.util.Date)' } void testShouldNotFailEvenIfVariableIsReassigned() { @@ -832,7 +842,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { return val.toUpperCase() } assert m(123) == 'HELLO' - ''', '#m(int)' + ''', + '#m(int)' } void testOneDefaultParamAndOneWithout() { @@ -851,7 +862,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { return val.toUpperCase() + append } m('test', new Object()) - ''', 'm(java.lang.String, java.lang.Object)' + ''', + 'm(java.lang.String, java.lang.Object)' } void testMultipleDefaultArgs() { @@ -880,7 +892,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { return first.toUpperCase() + ' ' + second + ' ' + third.toUpperCase() } m('f',123,'s', 'too many args') - ''', '#m(java.lang.String, int, java.lang.String, java.lang.String)' + ''', + '#m(java.lang.String, int, java.lang.String, java.lang.String)' } void testMultipleDefaultArgsWithMixedTypesAndWrongType() { @@ -889,7 +902,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { return first.toUpperCase() + ' ' + second + ' ' + third.toUpperCase() } m('hello') // no value set for "second" - ''', '#m(java.lang.String)' + ''', + '#m(java.lang.String)' } void testShouldNotFailWithAmbiguousMethodSelection() { @@ -915,7 +929,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { shouldFailWithMessages ''' float square(float x) { x*x } assert square(2.0d) == 4.0d - ''', '#square(double)' + ''', + '#square(double)' } void testShouldNotBeAbleToCallMethodUsingLongWithFloatOrDouble() { @@ -923,31 +938,34 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { float square(long x) { x*x } assert square(2.0d) == 4.0d assert square(2.0f) == 4.0d - ''', '#square(double)', '#square(float)' + ''', + '#square(double)', '#square(float)' } - void testShouldNotAllowMethodCallFromStaticContext() { + void testShouldNotAllowMethodCallFromStaticInitializer() { shouldFailWithMessages ''' class A { void instanceMethod() {} - static void staticMethod() { - instanceMethod() // calling instance method from static context + static { + instanceMethod() } } - A.staticMethod() - ''', 'Non-static method A#instanceMethod cannot be called from static context' + new A() + ''', + 'Non-static method A#instanceMethod cannot be called from static context' } - void testShouldNotAllowMethodCallFromStaticConstructor() { + void testShouldNotAllowMethodCallFromStaticMethod() { shouldFailWithMessages ''' class A { void instanceMethod() {} - static { - instanceMethod() // calling instance method from static context + static void staticMethod() { + instanceMethod() } } - new A() - ''', 'Non-static method A#instanceMethod cannot be called from static context' + A.staticMethod() + ''', + 'Non-static method A#instanceMethod cannot be called from static context' } void testShouldNotAllowMethodCallFromStaticField() { @@ -957,7 +975,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { static FOO = instanceMethod() } new A() - ''', 'Non-static method A#instanceMethod cannot be called from static context' + ''', + 'Non-static method A#instanceMethod cannot be called from static context' } // GROOVY-5495 @@ -1600,11 +1619,13 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { void testMoreExplicitErrorMessageOnStaticMethodNotFound() { shouldFailWithMessages ''' Double.isFiniteMissing(2.0d) - ''', 'Cannot find matching method java.lang.Double#isFiniteMissing(double)' + ''', + 'Cannot find matching method java.lang.Double#isFiniteMissing(double)' shouldFailWithMessages ''' String.doSomething() - ''', 'Cannot find matching method java.lang.String#doSomething()' + ''', + 'Cannot find matching method java.lang.String#doSomething()' } // GROOVY-6776 @@ -1615,7 +1636,8 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { foo null } bar() - ''', '#foo(int) with arguments [<unknown parameter type>]' + ''', + '#foo(int) with arguments [<unknown parameter type>]' } // GROOVY-6751 @@ -1637,49 +1659,58 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-7987 + void testNonStaticMethodViaStaticReceiver() { + shouldFailWithMessages ''' + class Foo { + def m() {} + } + Foo.m() + ''', + 'Non-static method Foo#m cannot be called from static context' + } + // GROOVY-7813 void testNonStaticOuterMethodCannotBeCalledFromStaticClass() { shouldFailWithMessages ''' class Foo { - def bar() { 2 } - - static class Baz { - def doBar() { bar() } + def m() {} + static class Bar { + void test() { m() } } } - null - ''', 'Non-static method Foo#bar cannot be called from static context' + ''', + 'Cannot find matching method Foo$Bar#m()' } void testStaticOuterMethodCanBeCalledFromStaticClass() { assertScript ''' class Foo { - static def bar() { 2 } - - static class Baz { - def doBar() { - bar() + static def sm() { 2 } + static class Bar { + void test() { + assert sm() == 2 } } } - assert new Foo.Baz().doBar() == 2 + new Foo.Bar().test() ''' } void testInheritedMethodCanBeCalledFromStaticClass() { assertScript ''' - class Bar { - def bar() { 1 } + class Foo { + def m() { 1 } } - class Foo { - static class Baz extends Bar { - def doBar() { - bar() + class Bar { + static class Baz extends Foo { + void test() { + assert m() == 1 } } } - assert new Foo.Baz().doBar() == 1 + new Bar.Baz().test() ''' } diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy index c78f02a04a..1c26771c7f 100644 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy +++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy @@ -49,8 +49,7 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5512 void testCreateRangeInInnerClass() { - def shell = new GroovyShell() - shell.evaluate ''' + new GroovyShell().evaluate ''' class Outer { static class Inner { @groovy.transform.CompileStatic @@ -67,54 +66,46 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5526 void testAssertEqualsShouldNotThrowVerifyError() { - assertScript ''' - import static org.junit.Assert.*; - import groovy.transform.CompileStatic; - + assertScript '''import static org.junit.Assert.* class CompilerBugs { - - public static void main(String[] args) { - int expected = 0 - assertEquals(expected, args.length) - } - + public static void main(String[] args) { + int expected = 0 + assertEquals(expected, args.length) + } } ''' } // GROOVY-5529 void testStaticCompilationOfClosureWhenSingleMethodAnnotated() { - new GroovyShell().evaluate '''import groovy.transform.ASTTest - import static org.codehaus.groovy.control.CompilePhase.* - - interface Row { - int getKey() - } - - class RowImpl implements Row { - int getKey() { 1 } - } + new GroovyShell().evaluate ''' + interface Row { + int getKey() + } - @groovy.transform.CompileStatic - def test() { - def rows = [new RowImpl(), new RowImpl(), new RowImpl()] + class RowImpl implements Row { + int getKey() { 1 } + } - rows.each { Row row -> - println row.key + @groovy.transform.CompileStatic + def test() { + def rows = [new RowImpl(), new RowImpl(), new RowImpl()] + rows.each { Row row -> + println row.key + } } - } - test() + test() ''' } // GROOVY-5536 void testShouldNotThrowVerifyErrorWithNullDereferenceInIf() { assertScript ''' - boolean getDescriptorForPlugin(File pluginDir) { - if (pluginDir?.exists()) { true } else { false } - } - assert getDescriptorForPlugin(null) == false + boolean getDescriptorForPlugin(File pluginDir) { + if (pluginDir?.exists()) { true } else { false } + } + assert getDescriptorForPlugin(null) == false ''' } @@ -138,7 +129,8 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY- void testPowerShouldNotThrowVerifyError() { - assertScript '''int squarePlusOne(int num) { + assertScript ''' + int squarePlusOne(int num) { num ** num + 1 } assert squarePlusOne(2) == 5 @@ -148,17 +140,17 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5570 void testShouldNotThrowVerifyErrorRegisterContainsWrongType() { assertScript ''' - void foo() { + void foo() { boolean idx = false def cl = { idx } - } - ''' + } + ''' assertScript ''' - void foo() { + void foo() { int idx = 0 def cl = { idx } - } - ''' + } + ''' } // GROOVY-5572 @@ -212,7 +204,6 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati } } - @groovy.transform.CompileStatic class Main { void test() { @ASTTest(phase=INSTRUCTION_SELECTION, value={ @@ -228,104 +219,104 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati void testCompileStaticTwiceShouldNotBeAProblem() { new GroovyShell().evaluate '''import groovy.transform.CompileStatic - @CompileStatic - class Tool { - @CompileStatic // annotated too, even if class is already annotated - String relativePath(File relbase, File file) { - def pathParts = [] - def currentFile = file - while (currentFile != null && currentFile != relbase) { - pathParts += currentFile.name - currentFile = currentFile.parentFile + @CompileStatic + class Tool { + @CompileStatic // annotated too, even if class is already annotated + String relativePath(File relbase, File file) { + def pathParts = [] + def currentFile = file + while (currentFile != null && currentFile != relbase) { + pathParts += currentFile.name + currentFile = currentFile.parentFile + } + pathParts.reverse().join('/') } - pathParts.reverse().join('/') } - } - File a = new File('foo') - File b = new File(new File(a, 'bar'), 'baz') - assert new Tool().relativePath(a,b) == 'bar/baz' + File a = new File('foo') + File b = new File(new File(a, 'bar'), 'baz') + assert new Tool().relativePath(a,b) == 'bar/baz' ''' } void testCompileStaticTwiceShouldNotBeAProblemUsingCustomizer() { - assertScript '''import groovy.transform.CompileStatic - @CompileStatic - class Tool { - @CompileStatic // annotated too, even if class is already annotated - String relativePath(File relbase, File file) { - def pathParts = [] - def currentFile = file - while (currentFile != null && currentFile != relbase) { - pathParts += currentFile.name - currentFile = currentFile.parentFile + assertScript ''' + @CompileStatic + class Tool { + @CompileStatic // annotated too, even if class is already annotated + String relativePath(File relbase, File file) { + def pathParts = [] + def currentFile = file + while (currentFile != null && currentFile != relbase) { + pathParts += currentFile.name + currentFile = currentFile.parentFile + } + pathParts.reverse().join('/') } - pathParts.reverse().join('/') } - } - File a = new File('foo') - File b = new File(new File(a, 'bar'), 'baz') - assert new Tool().relativePath(a,b) == 'bar/baz' + File a = new File('foo') + File b = new File(new File(a, 'bar'), 'baz') + assert new Tool().relativePath(a,b) == 'bar/baz' ''' } // GROOVY-5613 void testNullSafeAssignment() { assertScript ''' - class A { - int x = -1 - } - A a = new A() - @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE - }) - def x = a?.x + class A { + int x = -1 + } + A a = new A() + @ASTTest(phase=INSTRUCTION_SELECTION, value={ + assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE + }) + def x = a?.x ''' } void testNullSafeAssignmentWithLong() { assertScript ''' - class A { - long x = -1 - } - A a = new A() - @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE - }) - def x = a?.x + class A { + long x = -1 + } + A a = new A() + @ASTTest(phase=INSTRUCTION_SELECTION, value={ + assert node.getNodeMetaData(INFERRED_TYPE) == Long_TYPE + }) + def x = a?.x ''' } void testNullSafeAssignmentWithChar() { assertScript ''' - class A { - char x = 'a' - } - A a = new A() - @ASTTest(phase=INSTRUCTION_SELECTION, value={ - assert node.getNodeMetaData(INFERRED_TYPE) == Character_TYPE - }) - def x = a?.x - assert x == 'a' + class A { + char x = 'a' + } + A a = new A() + @ASTTest(phase=INSTRUCTION_SELECTION, value={ + assert node.getNodeMetaData(INFERRED_TYPE) == Character_TYPE + }) + def x = a?.x + assert x == 'a' ''' } void testCallStaticallyImportedMethodWithNullSafeArgument() { assertScript '''import static java.lang.Math.abs - class A { - int x = -1 - } - def a = new A() - def x = a?.x - assert abs(a?.x) == 1 + class A { + int x = -1 + } + def a = new A() + def x = a?.x + assert abs(a?.x) == 1 ''' } void testClosureAsInterfaceArgument() { assertScript ''' - Closure c = { Integer x, Integer y -> x <=> y } - def list = [ 3,1,5,2,4 ] - assert ((Collection)list).sort(c) == [1,2,3,4,5] - ''' + Closure c = { Integer x, Integer y -> x <=> y } + def list = [ 3,1,5,2,4 ] + assert ((Collection)list).sort(c) == [1,2,3,4,5] + ''' } void testInferredTypeForInteger() { @@ -351,35 +342,35 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati void testPostfixIncInteger() { assertScript ''' - Integer x = 0 - x++ - x++ - assert x == 2 - assert x++ == 2 - assert x == 3 - ''' + Integer x = 0 + x++ + x++ + assert x == 2 + assert x++ == 2 + assert x == 3 + ''' } void testPostfixDecInt() { assertScript ''' - int x = 0 - x-- - x-- - assert x == -2 - assert x-- == -2 - assert x == -3 - ''' + int x = 0 + x-- + x-- + assert x == -2 + assert x-- == -2 + assert x == -3 + ''' } void testPostfixDecInteger() { assertScript ''' - Integer x = 0 - x-- - x-- - assert x == -2 - assert x-- == -2 - assert x == -3 - ''' + Integer x = 0 + x-- + x-- + assert x == -2 + assert x-- == -2 + assert x == -3 + ''' } void testPrefixIncPrimitiveInteger() { @@ -395,42 +386,42 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati void testPrefixIncInteger() { assertScript ''' - Integer x = 0 - ++x - ++x - assert x == 2 - assert ++x == 3 - assert x == 3 - ''' + Integer x = 0 + ++x + ++x + assert x == 2 + assert ++x == 3 + assert x == 3 + ''' } void testPrefixDecInt() { assertScript ''' - int x = 0 - --x - --x - assert --x == -3 - assert x == -3 - ''' + int x = 0 + --x + --x + assert --x == -3 + assert x == -3 + ''' } void testPrefixDecInteger() { assertScript ''' - Integer x = 0 - --x - --x - assert --x == -3 - assert x == -3 - ''' + Integer x = 0 + --x + --x + assert --x == -3 + assert x == -3 + ''' } void testShouldSkipSpreadOperator() { - new GroovyShell().evaluate '''import groovy.transform.TypeCheckingMode - import groovy.transform.CompileStatic + new GroovyShell().evaluate '''import groovy.transform.CompileStatic + import static groovy.transform.TypeCheckingMode.SKIP @CompileStatic // top level must be @CS class Foo { - @CompileStatic(TypeCheckingMode.SKIP) + @CompileStatic(SKIP) static void foo(fun, args) { new Runnable() { // create an anonymous class which should *not* be visited void run() { @@ -445,16 +436,14 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5672 void testTypeCheckedPlusCompileStatic() { - new GroovyShell().evaluate '''import groovy.transform.CompileStatic - import groovy.transform.TypeChecked - - @TypeChecked - @CompileStatic - class SampleClass { - def a = "some string" - def b = a.toString() - } - new SampleClass() + new GroovyShell().evaluate '''import groovy.transform.* + @TypeChecked + @CompileStatic + class SampleClass { + def a = "some string" + def b = a.toString() + } + new SampleClass() ''' } @@ -479,79 +468,86 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati void testIncrementOperatorOnInt() { assertScript ''' - int incInt(int n) { - def result = n - ++result - result++ - return result - } - assert incInt(5) == 7''' + int incInt(int n) { + def result = n + ++result + result++ + return result + } + assert incInt(5) == 7 + ''' } void testIncrementOperatorOnShort() { assertScript ''' - short incInt(short n) { - def result = n - ++result - result++ - return result - } - assert incInt((short)5) == 7''' + short incInt(short n) { + def result = n + ++result + result++ + return result + } + assert incInt((short)5) == 7 + ''' } void testIncrementOperatorOnByte() { assertScript ''' - byte incInt(byte n) { - def result = n - ++result - result++ - return result - } - assert incInt((byte)5) == 7''' + byte incInt(byte n) { + def result = n + ++result + result++ + return result + } + assert incInt((byte)5) == 7 + ''' } void testIncrementOperatorOnLong() { assertScript ''' - long incInt(long n) { - def result = n - ++result - result++ - return result - } - assert incInt(5) == 7''' + long incInt(long n) { + def result = n + ++result + result++ + return result + } + assert incInt(5) == 7 + ''' } void testIncrementOperatorOnFloat() { assertScript ''' - float incInt(float n) { - def result = n - ++result - result++ - return result - } - assert incInt(5) == 7''' + float incInt(float n) { + def result = n + ++result + result++ + return result + } + assert incInt(5) == 7 + ''' } void testIncrementOperatorOnDouble() { assertScript ''' - double incInt(double n) { - def result = n - ++result - result++ - return result - } - assert incInt(5) == 7''' + double incInt(double n) { + def result = n + ++result + result++ + return result + } + assert incInt(5) == 7 + ''' } void testIncrementOperatorOnChar() { assertScript ''' - char incInt(char n) { - def result = n - ++result - result++ - return result - } - assert incInt((char)'a') == (char)('c')''' + char incInt(char n) { + def result = n + ++result + result++ + return result + } + assert incInt((char)'a') == (char)('c') + ''' } void testIncrementField() { @@ -570,13 +566,13 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5789 void testLoopWithIncrement() { assertScript ''' - int execute() { - // using a list, so that if the loop is endless, the test eventually fails with OOM - List<Integer> list = new LinkedList<Integer>() - for (def i = 0; i < 4; ++i) { println i; list << i } - list.size() - } - assert execute() == 4 + int execute() { + // using a list, so that if the loop is endless, the test eventually fails with OOM + List<Integer> list = new LinkedList<Integer>() + for (def i = 0; i < 4; ++i) { println i; list << i } + list.size() + } + assert execute() == 4 ''' } @@ -588,7 +584,7 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati } assert m(1) == true assert m(4) == false - ''' + ''' } // GROOVY-5814 @@ -650,16 +646,16 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati // GROOVY-5804 void testNegateSharedBooleanInClosure() { assertScript ''' - boolean x = false - def cl = { - if (!x) { - assert true - } else { - assert false - } + boolean x = false + def cl = { + if (!x) { + assert true + } else { + assert false } - cl() - ''' + } + cl() + ''' } void testCallClosureInInnerClass() { @@ -711,13 +707,12 @@ final class BugsStaticCompileTest extends BugsSTCTest implements StaticCompilati } void testSuperMethodCallInSkippedSection() { - assertScript '''import groovy.transform.CompileStatic -import groovy.transform.TypeCheckingMode + assertScript ''' class Top { public int foo() { 123 } } class Bottom extends Top { - @CompileStatic(TypeCheckingMode.SKIP) + @CompileStatic(SKIP) public int bar() { foo() } @@ -732,7 +727,8 @@ import groovy.transform.TypeCheckingMode def foo(Object o) { o[0] } - ''', 'Cannot find matching method java.lang.Object#getAt(int)' + ''', + 'Cannot find matching method java.lang.Object#getAt(int)' } void testStaticCompileWithPattern() { @@ -745,25 +741,26 @@ import groovy.transform.TypeCheckingMode def value = fieldMatcher[0] // should not pass def str = value[0] - ''', 'Cannot find matching method java.lang.Object#getAt(int)' + ''', + 'Cannot find matching method java.lang.Object#getAt(int)' } void testChainedNullSafePropertyOnMap() { assertScript ''' - Map<String, Map<String,Map<String,Integer>>> m=[:] - // this is ok - assert m?.a == null - assert m?.a?.b == null - assert m?.a?.b?.c == null - assert m?.a?.b?.c?.intValue() == null + Map<String, Map<String,Map<String,Integer>>> m = [:] + // this is ok + assert m?.a == null + assert m?.a?.b == null + assert m?.a?.b?.c == null + assert m?.a?.b?.c?.intValue() == null ''' } void testNullSafePropertyOnList() { assertScript ''' - List<Class> classes = null - // this is ok - assert classes?.name == null + List<Class> classes = null + // this is ok + assert classes?.name == null ''' } @@ -784,21 +781,21 @@ import groovy.transform.TypeCheckingMode // GROOVY-6101 void testShouldNotGenerateInvalidClassWithNullSafeInvocationOnMethodReturningPrimitiveType() { assertScript ''' - class Piece { - int x() { 333 } - } + class Piece { + int x() { 333 } + } - void foo() { - Piece[] pieces = [new Piece(), null] as Piece[] - int sum = 0 - for (int i=0;i<pieces.length;i++) { - if (pieces[i]?.x()) { - sum += pieces[i].x() + void foo() { + Piece[] pieces = [new Piece(), null] as Piece[] + int sum = 0 + for (int i=0;i<pieces.length;i++) { + if (pieces[i]?.x()) { + sum += pieces[i].x() + } } + assert sum == 333 } - assert sum == 333 - } - foo() + foo() ''' } @@ -841,7 +838,6 @@ import groovy.transform.TypeCheckingMode def b = new Groovy5921() b.doSomething() - ''' } @@ -857,7 +853,6 @@ import groovy.transform.TypeCheckingMode def b = new Groovy5921() b.doSomething() - ''' } @@ -873,7 +868,6 @@ import groovy.transform.TypeCheckingMode def b = new Groovy5921() b.doSomething() - ''' } @@ -889,7 +883,6 @@ import groovy.transform.TypeCheckingMode def b = new Groovy5921() b.doSomething() - ''' } @@ -931,24 +924,20 @@ import groovy.transform.TypeCheckingMode // GROOVY-6095 void testServletError() { - assertScript ''' + new GroovyShell().evaluate ''' @Grab('javax.servlet:javax.servlet-api:3.0.1') - import groovy.transform.CompileStatic - import javax.servlet.ServletContext import javax.servlet.ServletRegistration /** * author: Richard Vowles - http://gplus.to/RichardVowles */ - @CompileStatic + @groovy.transform.CompileStatic class ServletExample { - public void myMethod(ServletContext ctx) { ctx.getServletRegistrations().each { String name, ServletRegistration sr -> println name } - } } new ServletExample() @@ -958,67 +947,67 @@ import groovy.transform.TypeCheckingMode // GROOVY-6137 void testIsCaseShouldBeNullSafe() { assertScript ''' - def isCaseNullCS(a, b) { - a in b - } - assert isCaseNullCS(1, null) == false - assert isCaseNullCS(null, 1) == false - assert isCaseNullCS(1,1) == true - assert isCaseNullCS(1,2) == false - assert isCaseNullCS(2,1) == false + def isCaseNullCS(a, b) { + a in b + } + assert isCaseNullCS(1, null) == false + assert isCaseNullCS(null, 1) == false + assert isCaseNullCS(1,1) == true + assert isCaseNullCS(1,2) == false + assert isCaseNullCS(2,1) == false ''' } // GROOVY-6242 void testGetAtBigInt() { assertScript ''' -class Sequence { - public Sequence() {} - static BigInteger getAt(final int index) { 1G } - static BigInteger getAt(final BigInteger index) { getAt(index as int) } -} - -class Iterator implements java.util.Iterator { - private BigInteger currentIndex = 0G - private final Sequence sequence - Iterator(final Sequence s) { sequence = s } - boolean hasNext() { return true } - @ASTTest(phase=INSTRUCTION_SELECTION,value={ - def expr = node.code.statements[0].expression - def indexType = expr.rightExpression.getNodeMetaData(INFERRED_TYPE) - assert indexType == make(BigInteger) - }) - BigInteger next() { sequence[currentIndex++] } - void remove() { throw new UnsupportedOperationException() } -} + class Sequence { + public Sequence() {} + static BigInteger getAt(final int index) { 1G } + static BigInteger getAt(final BigInteger index) { getAt(index as int) } + } + + class Iterator implements java.util.Iterator { + private BigInteger currentIndex = 0G + private final Sequence sequence + Iterator(final Sequence s) { sequence = s } + boolean hasNext() { return true } + @ASTTest(phase=INSTRUCTION_SELECTION,value={ + def expr = node.code.statements[0].expression + def indexType = expr.rightExpression.getNodeMetaData(INFERRED_TYPE) + assert indexType == make(BigInteger) + }) + BigInteger next() { sequence[currentIndex++] } + void remove() { throw new UnsupportedOperationException() } + } -def it = new Iterator(new Sequence()) -assert it.next() == 1G -''' + def it = new Iterator(new Sequence()) + assert it.next() == 1G + ''' } // GROOVY-6243 void testSwapUsingMultipleAssignment() { assertScript ''' - def swap(result,next) { - print "($result,$next) -> " - (result, next) = [next, result] - println "($result,$next)" - [result, next] - } + def swap(result,next) { + print "($result,$next) -> " + (result, next) = [next, result] + println "($result,$next)" + [result, next] + } - assert swap(0,1) == [1,0] - assert swap('a','b') == ['b','a'] - assert swap('a', 1) == [1, 'a'] - def o1 = new Object() - def o2 = new Date() - assert swap(o1,o2) == [o2, o1] + assert swap(0,1) == [1,0] + assert swap('a','b') == ['b','a'] + assert swap('a', 1) == [1, 'a'] + def o1 = new Object() + def o2 = new Date() + assert swap(o1,o2) == [o2, o1] ''' } // GROOVY-5882 void testMod() { - assertScript """ + assertScript ''' int foo(Map<Integer, Object> markers, int i) { int res = 0 for (e in markers.entrySet()) { @@ -1027,9 +1016,9 @@ assert it.next() == 1G return res } assert foo([(1):null,(2):null,(3):null],2)==2 - """ + ''' - assertScript """ + assertScript ''' int foo(Map<Integer, Object> markers, int i) { int res = 0 for (e in markers.entrySet()) { @@ -1039,8 +1028,8 @@ assert it.next() == 1G return res } assert foo([(1):null,(2):null,(3):null],2)==2 - """ - assertScript """ + ''' + assertScript ''' int foo(Map<Integer, Object> markers, int i) { int res = 0 for (e in markers.entrySet()) { @@ -1049,7 +1038,7 @@ assert it.next() == 1G return res } assert foo([(1):null,(2):null,(3):null],2)==2 - """ + ''' } void testSuperCallShouldBeDirect() { @@ -1088,7 +1077,7 @@ assert it.next() == 1G println seq.next?.longValue() } assert seq.next == 5 -''' + ''' } void testNullSafeOperatorShouldNotCallMethodTwiceWithPrimitive() { @@ -1108,7 +1097,7 @@ assert it.next() == 1G println seq.next?.longValue() } assert seq.next == 5 -''' + ''' } void testNullSafeOperatorShouldNotCallMethodTwice1Arg() { @@ -1128,7 +1117,7 @@ assert it.next() == 1G println seq.getNext(2)?.longValue() } assert seq.getNext(2) == 10 -''' + ''' } void testNullSafeOperatorShouldNotCallMethodTwiceWithPrimitive1Arg() { @@ -1148,7 +1137,7 @@ assert it.next() == 1G println seq.getNext(2)?.longValue() } assert seq.getNext(2) == 10 -''' + ''' } void testShouldAllowSubscriptOperatorOnSet() { @@ -1180,21 +1169,20 @@ assert it.next() == 1G // GROOVY-6552 void testShouldNotThrowClassCastException() { assertScript '''import java.util.concurrent.Callable - - String text(Class clazz) { - new Callable<String>() { - String call() throws Exception { + String text(Class clazz) { new Callable<String>() { String call() throws Exception { - clazz.getName() + new Callable<String>() { + String call() throws Exception { + clazz.getName() + } + }.call() } }.call() } - }.call() - } - assert text(String) == 'java.lang.String' - ''' + assert text(String) == 'java.lang.String' + ''' } // GROOVY-6851 @@ -1212,19 +1200,19 @@ assert it.next() == 1G } } new GrailsHomeWorkspaceReader() - ''' + ''' } // GROOVY-6342 void testShouldNotThrowNPEIfElvisOperatorIsUsedInsideTernary() { - assertScript '''class Inner { - int somestuff -} -Inner inner = null -int someInt = inner?.somestuff ?: 0 -println someInt - -''' + assertScript ''' + class Inner { + int somestuff + } + Inner inner = null + int someInt = inner?.somestuff ?: 0 + println someInt + ''' } void testAccessOuterClassMethodFromInnerClassConstructor() { @@ -1381,26 +1369,26 @@ println someInt void testShouldNotThrowIncompatibleClassChangeError() { try { assertScript '''import org.codehaus.groovy.classgen.asm.sc.Groovy6924Support - class Test { - static void foo() { - Groovy6924Support bean = new Groovy6924Support() - bean.with { - foo = 'foo' - bar = 'bar' + class Test { + static void foo() { + Groovy6924Support bean = new Groovy6924Support() + bean.with { + foo = 'foo' + bar = 'bar' + } + String val = "$bean.foo and $bean.bar" + assert val == 'foo and bar' } - String val = "$bean.foo and $bean.bar" - assert val == 'foo and bar' } - } - Test.foo() - ''' + Test.foo() + ''' } finally { assert astTrees['Test$_foo_closure1'][1].contains('INVOKEVIRTUAL org/codehaus/groovy/classgen/asm/sc/Groovy6924Support.setFoo (Ljava/lang/String;)V') } } // GROOVY-7381 - void testNonVoidSetterCalls(){ + void testNonVoidSetterCalls() { assertScript ''' class Foo { int num @@ -1523,4 +1511,21 @@ println someInt test() ''' } + + // GROOVY-10819, GROOVY-10820 + void testClassVersusObjectMethods() { + assertScript ''' + assert String.metaClass != Class.metaClass + assert String.metaClass != Class.getMetaClass() + assert String.getMetaClass() != Class.getMetaClass() + ''' + assertScript ''' + @ASTTest(phase=INSTRUCTION_SELECTION, value={ + def source = node.rightExpression // "String.getMetaClass()" + def target = source.getNodeMetaData(DIRECT_METHOD_CALL_TARGET) + assert target.declaringClass == CLASS_Type // not OBJECT_TYPE! + }) + def smc = String.getMetaClass() + ''' + } } diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy index 0f9a644822..7b67973346 100644 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy +++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy @@ -56,10 +56,12 @@ trait StaticCompilationTestSupport { new ImportCustomizer().tap { addImports( 'groovy.transform.ASTTest', + 'groovy.transform.CompileStatic', 'groovy.transform.stc.ClosureParams', 'org.codehaus.groovy.ast.ClassHelper', 'org.codehaus.groovy.transform.stc.StaticTypesMarker') addStaticStars( + 'groovy.transform.TypeCheckingMode', 'org.codehaus.groovy.ast.ClassHelper', 'org.codehaus.groovy.control.CompilePhase', 'org.codehaus.groovy.transform.stc.StaticTypesMarker') diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy index bc1b9a66f9..c78aac38e0 100644 --- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy +++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/Console.groovy @@ -1426,26 +1426,16 @@ class Console implements CaretListener, HyperlinkListener, ComponentListener, Fo @CompileStatic private static Optional<String> findPrimaryClassName(String javaSrc) { - List<TypeDeclaration<?>> result = new LinkedList<>() - CompilationUnit compilationUnit = StaticJavaParser.parse(javaSrc) - + CompilationUnit compilationUnit= StaticJavaParser.parse(javaSrc) for (TypeDeclaration<?> td : compilationUnit.getTypes()) { - if (!(td.isTopLevelType() && td.isClassOrInterfaceDeclaration() && td.getModifiers().contains(Modifier.publicModifier()))) continue - - if (td.fullyQualifiedName.isPresent()) { - result << td - } - } - - String className = null - if (!result.isEmpty()) { - Optional<String> optionalClassName = result.get(0).getFullyQualifiedName() - if (optionalClassName.isPresent()) { - className = optionalClassName.get() + if (td.isPublic() + && td.isTopLevelType() + && td.isClassOrInterfaceDeclaration() + && td.getFullyQualifiedName().isPresent()) { + return td.getFullyQualifiedName(); } } - - return Optional.ofNullable(className) + return Optional.empty() } void compileAsJava(EventObject evt = null) {
