diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/builder/STCScriptsTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/builder/STCScriptsTests.java index dedd75695e..e45a00c572 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/builder/STCScriptsTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.builder/src/org/eclipse/jdt/core/groovy/tests/builder/STCScriptsTests.java @@ -62,16 +62,15 @@ public void testStaticTypeCheckingDSL1() throws Exception { IPath projPath = createGenericProject(); //@formatter:off env.addGroovyClass(projPath.append("src"), "RobotMove", - "import org.codehaus.groovy.ast.expr.VariableExpression\n" + - "unresolvedVariable { VariableExpression var ->\n" + - " if ('robot' == var.name) {\n" + - " def robotClass = context.source.AST.classes.find { it.name == 'Robot' }\n" + - " storeType(var, robotClass)\n" + + "unresolvedVariable { VariableExpression vexp ->\n" + + " if ('robot' == vexp.name) {\n" + + " def robotClass = lookupClassNodeFor('Robot')\n" + + " storeType(vexp, robotClass)\n" + " handled = true\n" + " }\n" + "}\n"); env.addGroovyClass(projPath.append("src"), "Robot", - "@groovy.transform.TypeChecked(extensions = 'RobotMove.groovy')\n" + + "@groovy.transform.TypeChecked(extensions='RobotMove.groovy')\n" + "void operate() {\n" + " robot.move \"left\"\n" + "}\n"); @@ -92,21 +91,19 @@ public void testStaticTypeCheckingDSL2() throws Exception { IPath projPath = createGenericProject(); //@formatter:off env.addGroovyClass(projPath.append("src"), "RobotMove", - "import org.codehaus.groovy.ast.expr.VariableExpression\n" + - "unresolvedVariable { VariableExpression var ->\n" + - " if ('robot' == var.name) {\n" + - " def robotClass = context.source.AST.classes.find { it.name == 'Robot' }\n" + - " storeType(var, robotClass)\n" + + "unresolvedVariable { VariableExpression vexp ->\n" + + " if ('robot' == vexp.name) {\n" + + " def robotClass = lookupClassNodeFor('Robot')\n" + + " storeType(vexp, robotClass)\n" + " handled = true\n" + " }\n" + "}\n"); env.addGroovyClass(projPath.append("src"), "RobotScript", - "import groovy.transform.TypeChecked\n" + "class Robot {\n" + " void move(String dist) { println \"Moved $dist\" }\n" + "}\n" + "robot = new Robot()\n" + - "@TypeChecked(extensions = 'RobotMove.groovy')\n" + + "@groovy.transform.TypeChecked(extensions='RobotMove.groovy')\n" + "void operate() {\n" + " robot.move \"left\"\n" + "}\n"); @@ -127,7 +124,7 @@ public void testStaticTypeCheckingDSL2() throws Exception { env.addGroovyClass(projPath.append("src"), "TypeChecker", "onMethodSelection { expr, node ->\n" + " if (node.name == 'setS') {\n" + - " def closure = context.enclosingClosure.closureExpression\n" + + " def closure = enclosingClosure.closureExpression\n" + " def setting = closure.code.statements[0].expression\n" + " setting.putNodeMetaData('notified', true)\n" + " }\n" + diff --git a/base/org.codehaus.groovy25/plugin_dsld_support/dsld/type_checking.dsld b/base/org.codehaus.groovy25/plugin_dsld_support/dsld/type_checking.dsld new file mode 100644 index 0000000000..c34c035b29 --- /dev/null +++ b/base/org.codehaus.groovy25/plugin_dsld_support/dsld/type_checking.dsld @@ -0,0 +1,85 @@ +/* + * Copyright 2009-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 dsld + +import org.codehaus.groovy.ast.expr.* +import org.codehaus.groovy.ast.ClassNode +import org.codehaus.groovy.ast.MethodNode +import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingDSL + +assertVersion(groovyEclipse: '4.8.0') + +contribute(isScript() & currentType(subType(TypeCheckingDSL))) { + provider = "{@link ${GroovyTypeCheckingExtensionSupport.name}.TypeCheckingDSL TypeCheckingDSL}" + + delegatesTo type: AbstractTypeCheckingExtension // skip over GroovyTypeCheckingExtensionSupport + + method name: 'setDebug', type: void, params: [debug: boolean], declaringType: GroovyTypeCheckingExtensionSupport + + for (type in ['AnnotationConstant', 'ArgumentList', 'Array', 'Attribute', + 'Binary', 'BitwiseNegation', 'Boolean', + 'Cast', 'Class', 'Closure', 'Constant', 'ConstructorCall', + 'Declaration', + 'ElvisOperator', 'Empty', + 'Field', + 'GString', + 'List', + 'Map', 'MapEntry', 'MethodCall', 'MethodPointer', + 'NamedArgumentList', 'Not', + 'Postfix', 'Prefix', 'Property', + 'Range', + 'Spread', 'SpreadMap', 'StaticMethodCall', + 'Ternary', 'Tuple', + 'UnaryMinus', 'UnaryPlus', + 'Variable' + ]) method name: "is${type}Expression", type: boolean, params: [node: Object], declaringType: TypeCheckingDSL + + // event callback registration ----------------------------------------------------------------------------- + + method name: 'setup', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'finish', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'ambiguousMethods', type: void, params: [handler: "@ClosureParams(value=FromString, options=['java.util.List<${MethodNode.name}>,${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleAssignment', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},${ClassNode.name},${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleReturnType', type: void, params: [handler: "@ClosureParams(value=FromString, options=['org.codehaus.groovy.ast.stmt.ReturnStatement,${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'methodNotFound', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},java.lang.String,${ArgumentListExpression.name},${ClassNode.name}[],${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'onMethodSelection', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${Expression.name},${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedAttribute', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${AttributeExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedProperty', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${PropertyExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedVariable', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${VariableExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL +} diff --git a/base/org.codehaus.groovy30/plugin_dsld_support/dsld/type_checking.dsld b/base/org.codehaus.groovy30/plugin_dsld_support/dsld/type_checking.dsld new file mode 100644 index 0000000000..3403b0d04e --- /dev/null +++ b/base/org.codehaus.groovy30/plugin_dsld_support/dsld/type_checking.dsld @@ -0,0 +1,85 @@ +/* + * Copyright 2009-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 dsld + +import org.codehaus.groovy.ast.expr.* +import org.codehaus.groovy.ast.ClassNode +import org.codehaus.groovy.ast.MethodNode +import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingDSL + +assertVersion(groovyEclipse: '4.8.0') + +contribute(isScript() & currentType(subType(TypeCheckingDSL))) { + provider = "{@link ${GroovyTypeCheckingExtensionSupport.name}.TypeCheckingDSL TypeCheckingDSL}" + + delegatesTo type: AbstractTypeCheckingExtension // skip over GroovyTypeCheckingExtensionSupport + + method name: 'setDebug', type: void, params: [debug: boolean], declaringType: GroovyTypeCheckingExtensionSupport + + for (type in ['AnnotationConstant', 'ArgumentList', 'Array', 'Attribute', + 'Binary', 'BitwiseNegation', 'Boolean', + 'Cast', 'Class', 'Closure', 'Constant', 'ConstructorCall', + 'Declaration', + 'ElvisOperator', 'Empty', + 'Field', + 'GString', + 'Lambda', 'List', + 'Map', 'MapEntry', 'MethodCall', 'MethodPointer', 'MethodReference', + 'NamedArgumentList', 'Not', + 'Postfix', 'Prefix', 'Property', + 'Range', + 'Spread', 'SpreadMap', 'StaticMethodCall', + 'Ternary', 'Tuple', + 'UnaryMinus', 'UnaryPlus', + 'Variable' + ]) method name: "is${type}Expression", type: boolean, params: [node: Object], declaringType: TypeCheckingDSL + + // event callback registration ----------------------------------------------------------------------------- + + method name: 'setup', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'finish', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'ambiguousMethods', type: void, params: [handler: "@ClosureParams(value=FromString, options=['java.util.List<${MethodNode.name}>,${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleAssignment', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},${ClassNode.name},${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleReturnType', type: void, params: [handler: "@ClosureParams(value=FromString, options=['org.codehaus.groovy.ast.stmt.ReturnStatement,${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'methodNotFound', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},java.lang.String,${ArgumentListExpression.name},${ClassNode.name}[],${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'onMethodSelection', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${Expression.name},${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedAttribute', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${AttributeExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedProperty', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${PropertyExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedVariable', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${VariableExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL +} diff --git a/base/org.codehaus.groovy40/plugin_dsld_support/dsld/type_checking.dsld b/base/org.codehaus.groovy40/plugin_dsld_support/dsld/type_checking.dsld new file mode 100644 index 0000000000..3403b0d04e --- /dev/null +++ b/base/org.codehaus.groovy40/plugin_dsld_support/dsld/type_checking.dsld @@ -0,0 +1,85 @@ +/* + * Copyright 2009-2022 the original author or authors. + * + * Licensed 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 + * + * https://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 dsld + +import org.codehaus.groovy.ast.expr.* +import org.codehaus.groovy.ast.ClassNode +import org.codehaus.groovy.ast.MethodNode +import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport +import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingDSL + +assertVersion(groovyEclipse: '4.8.0') + +contribute(isScript() & currentType(subType(TypeCheckingDSL))) { + provider = "{@link ${GroovyTypeCheckingExtensionSupport.name}.TypeCheckingDSL TypeCheckingDSL}" + + delegatesTo type: AbstractTypeCheckingExtension // skip over GroovyTypeCheckingExtensionSupport + + method name: 'setDebug', type: void, params: [debug: boolean], declaringType: GroovyTypeCheckingExtensionSupport + + for (type in ['AnnotationConstant', 'ArgumentList', 'Array', 'Attribute', + 'Binary', 'BitwiseNegation', 'Boolean', + 'Cast', 'Class', 'Closure', 'Constant', 'ConstructorCall', + 'Declaration', + 'ElvisOperator', 'Empty', + 'Field', + 'GString', + 'Lambda', 'List', + 'Map', 'MapEntry', 'MethodCall', 'MethodPointer', 'MethodReference', + 'NamedArgumentList', 'Not', + 'Postfix', 'Prefix', 'Property', + 'Range', + 'Spread', 'SpreadMap', 'StaticMethodCall', + 'Ternary', 'Tuple', + 'UnaryMinus', 'UnaryPlus', + 'Variable' + ]) method name: "is${type}Expression", type: boolean, params: [node: Object], declaringType: TypeCheckingDSL + + // event callback registration ----------------------------------------------------------------------------- + + method name: 'setup', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'finish', type: void, params: [handler: Closure], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'afterVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'ambiguousMethods', type: void, params: [handler: "@ClosureParams(value=FromString, options=['java.util.List<${MethodNode.name}>,${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeMethodCall', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitClass', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'beforeVisitMethod', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleAssignment', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},${ClassNode.name},${Expression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'incompatibleReturnType', type: void, params: [handler: "@ClosureParams(value=FromString, options=['org.codehaus.groovy.ast.stmt.ReturnStatement,${ClassNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'methodNotFound', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${ClassNode.name},java.lang.String,${ArgumentListExpression.name},${ClassNode.name}[],${MethodCall.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'onMethodSelection', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${Expression.name},${MethodNode.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedAttribute', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${AttributeExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedProperty', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${PropertyExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL + + method name: 'unresolvedVariable', type: void, params: [handler: "@ClosureParams(value=FromString, options=['${VariableExpression.name}']) @DelegatesTo(${AbstractTypeCheckingExtension.name}) Closure"], noParens: true, declaringType: TypeCheckingDSL +} diff --git a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/integration/internal/GroovyLanguageSupport.java b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/integration/internal/GroovyLanguageSupport.java index 36cc72c83c..c607e9bd24 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/integration/internal/GroovyLanguageSupport.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/integration/internal/GroovyLanguageSupport.java @@ -103,6 +103,7 @@ import org.eclipse.jdt.internal.core.search.matching.MatchLocatorParser; import org.eclipse.jdt.internal.core.search.matching.PossibleMatch; import org.eclipse.jdt.internal.core.util.Util; +import org.osgi.framework.Version; /** * Groovy implementation of LanguageSupport. This class is dynamically loaded by @@ -245,6 +246,17 @@ public static CompilerConfiguration newCompilerConfiguration(final CompilerOptio config.setSourceEncoding(compilerOptions.defaultEncoding); } + if (compilerOptions.buildGroovyFiles > 2) { + // create type-checking script configuration + ImportCustomizer ic = new ImportCustomizer(); + ic.addStarImports("org.codehaus.groovy.ast.expr"); + if (GroovyUtils.getGroovyVersion().compareTo(new Version(4, 0, 6)) >= 0) ic.addStarImports("org.codehaus.groovy.ast"); + ic.addStaticStars("org.codehaus.groovy.ast.ClassHelper","org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport"); + config.addCompilationCustomizers(ic).setScriptBaseClass("org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingDSL"); + + return config; + } + if (compilerOptions.buildGroovyFiles > 1 && compilerOptions.groovyCompilerConfigScript != null) { Binding binding = new Binding(); binding.setVariable("configuration", config); diff --git a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/GroovyParser.java b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/GroovyParser.java index 4a5df489ab..a3e1abb359 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/GroovyParser.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/codehaus/jdt/groovy/internal/compiler/ast/GroovyParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -126,6 +126,8 @@ public static boolean isGroovyParserEligible(ICompilationUnit compilationUnit, / private static final Pattern GROOVY_SOURCE_DISCRIMINATOR = Pattern.compile("\\A(/\\*.*?\\*/\\s*)?package\\s+\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\s*\\.\\s*\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*\\s++(?!;)", Pattern.DOTALL); + private static final Pattern STC_EXTENSION_DISCRIMINATOR = Pattern.compile("^(?:unresolvedVariable|unresolvedProperty|unresolvedAttribute|methodNotFound|ambiguousMethods|onMethodSelection|incompatibleAssignment|incompatibleReturnType|(?:before|after)(?:MethodCall|VisitMethod|VisitClass))\\b", Pattern.MULTILINE); + //-------------------------------------------------------------------------- public GroovyParser(CompilerOptions compilerOptions, ProblemReporter problemReporter, boolean allowTransforms, boolean isReconcile) { @@ -209,7 +211,9 @@ public GroovyCompilationUnitDeclaration dietParse(final char[] contents, String if (compilationUnit == null) { if (isInJar || isScript || (eclipseFile != null && eclipseFile.getProject().isAccessible() && - !JavaCore.create(eclipseFile.getProject()).isOnClasspath(eclipseFile))) { + !JavaCore.create(eclipseFile.getProject()).isOnClasspath(eclipseFile))){ + if (isScript && STC_EXTENSION_DISCRIMINATOR.matcher(new CharArraySequence(contents)).find()) + compilerOptions.buildGroovyFiles |= 4; // need type-checking script config compilerOptions.groovyCompilerConfigScript = null; } compilationUnit = unitFactory.get(); diff --git a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java index 16ec82ca31..a02e555e71 100644 --- a/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java +++ b/base/org.eclipse.jdt.groovy.core/src/org/eclipse/jdt/groovy/core/util/GroovyUtils.java @@ -74,7 +74,7 @@ public static Version getGroovyVersion() { String version = GroovySystem.getVersion(); // convert "2.5.0-beta-2" -> "2.5.0.beta-2" version = version.replaceFirst("-", "."); - return new Version(version); + return Version.valueOf(version); } // FIXASC don't use this any more? diff --git a/ide/org.codehaus.groovy.eclipse.dsl/src/org/codehaus/groovy/eclipse/dsl/contributions/ParameterContribution.java b/ide/org.codehaus.groovy.eclipse.dsl/src/org/codehaus/groovy/eclipse/dsl/contributions/ParameterContribution.java index a1efad2fa5..79cf78bc8d 100644 --- a/ide/org.codehaus.groovy.eclipse.dsl/src/org/codehaus/groovy/eclipse/dsl/contributions/ParameterContribution.java +++ b/ide/org.codehaus.groovy.eclipse.dsl/src/org/codehaus/groovy/eclipse/dsl/contributions/ParameterContribution.java @@ -1,11 +1,11 @@ /* - * Copyright 2009-2018 the original author or authors. + * Copyright 2009-2022 the original author or authors. * * Licensed 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 + * https://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, @@ -15,15 +15,12 @@ */ package org.codehaus.groovy.eclipse.dsl.contributions; -import java.util.List; - -import org.codehaus.groovy.ast.ASTNode; import org.codehaus.groovy.ast.ClassHelper; -import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.Parameter; -import org.codehaus.groovy.ast.builder.AstBuilder; -import org.codehaus.groovy.control.CompilePhase; +import org.codehaus.groovy.control.CompilationUnit; +import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.control.Phases; import org.codehaus.groovy.eclipse.dsl.GroovyDSLCoreActivator; import org.codehaus.groovy.eclipse.dsl.lookup.ResolverCache; @@ -42,24 +39,35 @@ public ParameterContribution(String name, String type) { } public ParameterContribution(Parameter value) { + this(value.getName(), DSLContributionGroup.getTypeName(value.getType())); this.value = value; - this.name = value.getName(); - this.type = DSLContributionGroup.getTypeName(value.getType()); } public Parameter toParameter(ResolverCache resolver) { if (value == null) { - if (type.indexOf('@') >= 0) { - try { - List nodes = new AstBuilder().buildFromString(CompilePhase.CANONICALIZATION, false, + String typeName = type; + if (type.indexOf('@') != -1) { + try { // process annotation(s) using groovy compiler + CompilerConfiguration conf = new CompilerConfiguration(resolver.module.getContext().getConfiguration()); + conf.setPreviewFeatures(false); + conf.setScriptBaseClass(null); + conf.setTargetBytecode(CompilerConfiguration.DEFAULT.getTargetBytecode()); + + CompilationUnit unit = new CompilationUnit(conf, null, resolver.module.getContext().getClassLoader()); + unit.addSource("Script" + java.util.UUID.randomUUID().toString().replace('-', '$'), "import groovy.transform.stc.*\n" + "void meth(" + type + " " + name + ") {}"); - MethodNode meth = ((ClassNode) nodes.get(1)).getMethods("meth").get(0); + unit.compile(Phases.CANONICALIZATION); + + MethodNode meth = unit.getFirstClassNode().getMethods("meth").get(0); return meth.getParameters()[0]; - } catch (Exception e) { + } catch (Exception | LinkageError e) { GroovyDSLCoreActivator.logException(e); } + + String i = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; + typeName = type.replaceAll("@(?:"+i+"\\.)*"+i+"(?:\\([^\\)]*\\))?\\s*", ""); } - value = new Parameter(resolver != null ? resolver.resolve(type) : ClassHelper.DYNAMIC_TYPE, name); + value = new Parameter(resolver != null ? resolver.resolve(typeName) : ClassHelper.dynamicType(), name); } return value; } diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/editor/GroovyExtraInformationHover.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/editor/GroovyExtraInformationHover.java index a15f9ead10..bba413402e 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/editor/GroovyExtraInformationHover.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/editor/GroovyExtraInformationHover.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2021 the original author or authors. + * Copyright 2009-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,22 @@ package org.codehaus.groovy.eclipse.editor; import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; import org.codehaus.groovy.ast.ASTNode; +import org.codehaus.groovy.ast.AnnotationNode; +import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.PropertyNode; +import org.codehaus.groovy.ast.expr.ClassExpression; +import org.codehaus.groovy.ast.expr.ConstantExpression; +import org.codehaus.groovy.ast.expr.Expression; +import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.eclipse.codebrowsing.elements.IGroovyResolvedElement; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.Adapters; @@ -188,6 +197,10 @@ private String createLabel(ASTNode inferredElement) { return "" + label + "
\n"; } + private String createTypeLabel(final ClassNode node) { // TODO: create link html + return Signature.toString(GroovyUtils.getTypeSignature(node, false, false)); + } + private String createFieldLabel(final FieldNode node) { StringBuilder sb = new StringBuilder(); sb.append(createTypeLabel(node.getType())); @@ -210,9 +223,31 @@ private String createMethodLabel(final MethodNode node) { Parameter[] params = node.getParameters(); if (params != null) { for (int i = 0, n = params.length; i < n; i += 1) { - if (i > 0) { - sb.append(", "); + if (i > 0) sb.append(", "); + + List annotations = params[i].getAnnotations(); + if (!annotations.isEmpty()) { + sb.append(""); + for (AnnotationNode annotation : annotations) { + sb.append('@').append(createTypeLabel(annotation.getClassNode())); + + Map attributes = annotation.getMembers(); + if (!attributes.isEmpty()) { + sb.append('('); + int j = 0; + for (Map.Entry e : attributes.entrySet()) { + if (j++ > 0) sb.append(", "); + sb.append(e.getKey()); + sb.append('='); + sb.append(createValueLabel(e.getValue())); + } + sb.append(')'); + } + sb.append(' '); + } + sb.append(""); } + sb.append(createTypeLabel(params[i].getType())); sb.append(' ').append(params[i].getName()); } @@ -222,7 +257,25 @@ private String createMethodLabel(final MethodNode node) { return sb.toString(); } - private String createTypeLabel(final ClassNode node) { - return Signature.toString(GroovyUtils.getTypeSignature(node, false, false)); + private String createValueLabel(final Expression value) { + if (value instanceof ListExpression) { + StringJoiner sj = new StringJoiner(", ", "[", "]"); + for (Expression e : ((ListExpression) value).getExpressions()) { + sj.add(createValueLabel(e)); + } + return sj.toString(); + } + if (value instanceof ClassExpression) { + return createTypeLabel(value.getType()) + ".class"; + } + if (value instanceof ConstantExpression) { + if (value.getType().equals(ClassHelper.STRING_TYPE)) { + return "\"" + value.getText() + "\""; + } + if (value.getType().equals(ClassHelper.char_TYPE)) { + return "'" + value.getText() + "'"; + } + } + return value.getText(); } } diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/refactoring/actions/OrganizeGroovyImports.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/refactoring/actions/OrganizeGroovyImports.java index a1552d71e7..a0681903cc 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/refactoring/actions/OrganizeGroovyImports.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/refactoring/actions/OrganizeGroovyImports.java @@ -707,7 +707,7 @@ private void handleTypeReference(ClassNode node, boolean isAnnotation) { name = name.replaceAll(Pattern.quote(name.substring(i)) + "(?= |$)", ""); } doNotRemoveImport(name.replace('$', '.')); - } else if (current.getModule().getClasses().contains(node)) { + } else if (length < 1 || current.getModule().getClasses().contains(node)) { // keep in importsSlatedForRemoval and leave out of missingTypes } else if (!node.isResolved()) { String[] parts = name.split("\\."); @@ -722,7 +722,7 @@ private void handleTypeReference(ClassNode node, boolean isAnnotation) { SourceRange range = new SourceRange(node.getStart(), node.getEnd() - node.getStart()); missingTypes.put(name, new UnresolvedTypeData(name, isAnnotation, range)); } - } else if (length > 0 && length < name.length()) { + } else if (length < name.length()) { char[] chars = current.getModule().getContext().readSourceRange(start, length); if (chars != null) { int i = 0;