diff --git a/java.source/apichanges.xml b/java.source/apichanges.xml --- a/java.source/apichanges.xml +++ b/java.source/apichanges.xml @@ -105,6 +105,18 @@ is the proper place. + + + Added GeneratorUtilities.createMethod + + + + + + Added method to create a new method tree for given method element. + + + Added ModificationResult.Difference.setCommitToGuards(boolean) and isCommitToGuards() methods permitting to write modifications even to guarded sections diff --git a/java.source/nbproject/project.properties b/java.source/nbproject/project.properties --- a/java.source/nbproject/project.properties +++ b/java.source/nbproject/project.properties @@ -43,7 +43,7 @@ javadoc.title=Java Source javadoc.title=Java Source javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=0.33.0 +spec.version.base=0.34.0 test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/javac-api-nb-7.0-b07.jar test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\ ${o.n.core.dir}/lib/boot.jar:\ diff --git a/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java b/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java --- a/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java +++ b/java.source/src/org/netbeans/api/java/source/GeneratorUtilities.java @@ -82,6 +82,7 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.Types; import javax.swing.text.Document; import org.netbeans.api.java.lexer.JavaTokenId; @@ -242,6 +243,79 @@ public final class GeneratorUtilities { return createMethod(method, (DeclaredType)clazz.asType()); } + /**Create a new method tree for the given method element. The method will be created as if it were member of {@link asMemberOf} type + * (see also {@link Types#asMemberOf(javax.lang.model.type.DeclaredType,javax.lang.model.element.Element)}). + * The new method will have an empty body. + * + * @param asMemberOf create the method as if it were member of this type + * @param method method to create + * @return a newly created method + * @see Types#asMemberOf(javax.lang.model.type.DeclaredType,javax.lang.model.element.Element) + * @since 0.34 + */ + public MethodTree createMethod(DeclaredType asMemberOf, ExecutableElement method) { + TreeMaker make = copy.getTreeMaker(); + Set mods = method.getModifiers(); + Set flags = mods.isEmpty() ? EnumSet.noneOf(Modifier.class) : EnumSet.copyOf(mods); + flags.remove(Modifier.ABSTRACT); + flags.remove(Modifier.NATIVE); + + ExecutableType et = (ExecutableType) method.asType(); + try { + et = (ExecutableType) copy.getTypes().asMemberOf(asMemberOf, method); + } catch (IllegalArgumentException iae) { + } + List typeParams = new ArrayList(); + for (TypeVariable typeVariable : et.getTypeVariables()) { + List bounds = new ArrayList(); + TypeMirror bound = typeVariable.getUpperBound(); + if (bound.getKind() != TypeKind.NULL) { + if (bound.getKind() == TypeKind.DECLARED) { + ClassSymbol boundSymbol = (ClassSymbol) ((DeclaredType) bound).asElement(); + if (boundSymbol.getSimpleName().length() == 0 && (boundSymbol.flags() & Flags.COMPOUND) != 0) { + bounds.add((ExpressionTree) make.Type(boundSymbol.getSuperclass())); + for (Type iface : boundSymbol.getInterfaces()) { + bounds.add((ExpressionTree) make.Type(iface)); + } + } else if (!boundSymbol.getQualifiedName().contentEquals("java.lang.Object")) { //NOI18N + //if the bound is java.lang.Object, do not generate the extends clause: + + bounds.add((ExpressionTree) make.Type(bound)); + } + } else { + bounds.add((ExpressionTree) make.Type(bound)); + } + } + typeParams.add(make.TypeParameter(typeVariable.asElement().getSimpleName(), bounds)); + } + + Tree returnType = make.Type(et.getReturnType()); + + List params = new ArrayList(); + boolean isVarArgs = method.isVarArgs(); + Iterator formArgNames = method.getParameters().iterator(); + Iterator formArgTypes = et.getParameterTypes().iterator(); + ModifiersTree parameterModifiers = make.Modifiers(EnumSet.noneOf(Modifier.class)); + while (formArgNames.hasNext() && formArgTypes.hasNext()) { + VariableElement formArgName = formArgNames.next(); + TypeMirror formArgType = formArgTypes.next(); + if (isVarArgs && !formArgNames.hasNext()) { + parameterModifiers = make.Modifiers(1L << 34, + Collections.emptyList()); + } + params.add(make.Variable(parameterModifiers, formArgName.getSimpleName(), make.Type(formArgType), null)); + } + + List throwsList = new ArrayList(); + for (TypeMirror tm : et.getThrownTypes()) { + throwsList.add((ExpressionTree) make.Type(tm)); + } + + ModifiersTree mt = make.Modifiers(flags, Collections.emptyList()); + + return make.Method(mt, method.getSimpleName(), returnType, typeParams, params, throwsList, "{}", null); + } + /** * Creates a class constructor. * @@ -428,60 +502,9 @@ public final class GeneratorUtilities { private MethodTree createMethod(ExecutableElement element, DeclaredType type) { TreeMaker make = copy.getTreeMaker(); - Set mods = element.getModifiers(); - Set flags = mods.isEmpty() ? EnumSet.noneOf(Modifier.class) : EnumSet.copyOf(mods); - boolean isAbstract = flags.remove(Modifier.ABSTRACT); - flags.remove(Modifier.NATIVE); - - ExecutableType et = (ExecutableType)element.asType(); - try { - et = (ExecutableType)copy.getTypes().asMemberOf(type, element); - } catch (IllegalArgumentException iae) {} - List typeParams = new ArrayList(); - for (TypeVariable typeVariable : et.getTypeVariables()) { - List bounds = new ArrayList(); - TypeMirror bound = typeVariable.getUpperBound(); - if (bound.getKind() != TypeKind.NULL) { - if (bound.getKind() == TypeKind.DECLARED) { - ClassSymbol boundSymbol = (ClassSymbol)((DeclaredType)bound).asElement(); - if (boundSymbol.getSimpleName().length() == 0 && (boundSymbol.flags() & Flags.COMPOUND) != 0) { - bounds.add((ExpressionTree)make.Type(boundSymbol.getSuperclass())); - for (Type iface : boundSymbol.getInterfaces()) { - bounds.add((ExpressionTree)make.Type(iface)); - } - } else if (!boundSymbol.getQualifiedName().contentEquals("java.lang.Object")) { //NOI18N - //if the bound is java.lang.Object, do not generate the extends clause: - bounds.add((ExpressionTree)make.Type(bound)); - } - } else { - bounds.add((ExpressionTree)make.Type(bound)); - } - } - typeParams.add(make.TypeParameter(typeVariable.asElement().getSimpleName(), bounds)); - } - - Tree returnType = make.Type(et.getReturnType()); - - List params = new ArrayList(); - boolean isVarArgs = element.isVarArgs(); - Iterator formArgNames = element.getParameters().iterator(); - Iterator formArgTypes = et.getParameterTypes().iterator(); - ModifiersTree parameterModifiers = make.Modifiers(EnumSet.noneOf(Modifier.class)); - while (formArgNames.hasNext() && formArgTypes.hasNext()) { - VariableElement formArgName = formArgNames.next(); - TypeMirror formArgType = formArgTypes.next(); - if (isVarArgs && !formArgNames.hasNext()) - parameterModifiers = make.Modifiers(1L<<34, Collections.emptyList()); - params.add(make.Variable(parameterModifiers, formArgName.getSimpleName(), make.Type(formArgType), null)); - } - - List throwsList = new ArrayList(); - for (TypeMirror tm : et.getThrownTypes()) { - throwsList.add((ExpressionTree)make.Type(tm)); - } + boolean isAbstract = element.getModifiers().contains(Modifier.ABSTRACT); BlockTree body; - List annotations = new ArrayList(); if (isAbstract) { List blockStatements = new ArrayList(); TypeElement uoe = copy.getElements().getTypeElement("java.lang.UnsupportedOperationException"); //NOI18N @@ -502,23 +525,26 @@ public final class GeneratorUtilities { body = make.Block(Collections.singletonList(statement), false); } + MethodTree prototype = createMethod(type, element); + ModifiersTree mt = prototype.getModifiers(); + //add @Override annotation: SpecificationVersion thisFOVersion = new SpecificationVersion(SourceLevelQuery.getSourceLevel(copy.getFileObject())); SpecificationVersion version15 = new SpecificationVersion("1.5"); //NOI18N if (thisFOVersion.compareTo(version15) >= 0) { boolean generate = true; - + if (thisFOVersion.compareTo(version15) == 0) { generate = !element.getEnclosingElement().getKind().isInterface(); } - + if (generate) { - annotations.add(make.Annotation(make.Identifier("Override"), Collections.emptyList())); //NOI18N + mt = make.addModifiersAnnotation(prototype.getModifiers(), make.Annotation(make.Identifier("Override"), Collections.emptyList())); } } - - return make.Method(make.Modifiers(flags, annotations), element.getSimpleName(), returnType, typeParams, params, throwsList, body, null); + + return make.Method(mt, prototype.getName(), prototype.getReturnType(), prototype.getTypeParameters(), prototype.getParameters(), prototype.getThrows(), body, null); } private static class ClassMemberComparator { diff --git a/java.source/test/unit/src/org/netbeans/api/java/source/GeneratorUtilitiesTest.java b/java.source/test/unit/src/org/netbeans/api/java/source/GeneratorUtilitiesTest.java --- a/java.source/test/unit/src/org/netbeans/api/java/source/GeneratorUtilitiesTest.java +++ b/java.source/test/unit/src/org/netbeans/api/java/source/GeneratorUtilitiesTest.java @@ -360,6 +360,22 @@ public class GeneratorUtilitiesTest exte public void testStaticBooleanSetter() throws Exception { performTest("package test;\npublic class Test {\nprivate static boolean test;\npublic Test(){\n}\n }\n", new GetterSetterTask(34, false), new GetterSetterValidator(false)); + } + + public void testCreateMethod() throws Exception { + performTest("package test;\npublic class Test { }\n", "1.5", new CreateMethodTask(34), new Validator() { + public void validate(CompilationInfo info) { + assertEquals(1, info.getDiagnostics().size()); + + for (ExecutableElement ee : ElementFilter.methodsIn(info.getElements().getTypeElement("test.Test").getEnclosedElements())) { + assertEquals("toArray", ee.getSimpleName().toString()); + assertEquals(1, ee.getTypeParameters().size()); + return ; + } + + fail("toArray method not found"); + } + }, false); } public static interface Validator { @@ -804,11 +820,48 @@ public class GeneratorUtilitiesTest exte } + private static class CreateMethodTask implements CancellableTask { + + private int offset; + + public CreateMethodTask(int offset) { + this.offset = offset; + } + + public void cancel() { + } + + public void run(WorkingCopy copy) throws Exception { + copy.toPhase(JavaSource.Phase.RESOLVED); + TreePath tp = copy.getTreeUtilities().pathFor(offset); + assertTrue(tp.getLeaf().getKind() == Tree.Kind.CLASS); + ClassTree ct = (ClassTree)tp.getLeaf(); + TypeElement te = (TypeElement)copy.getTrees().getElement(tp); + DeclaredType dt = (DeclaredType) copy.getTreeUtilities().parseType("java.util.List", te); + TypeElement list = copy.getElements().getTypeElement("java.util.List"); + ExecutableElement ee = null; + for (ExecutableElement m : ElementFilter.methodsIn(list.getEnclosedElements())) { + if (m.getSimpleName().contentEquals("toArray") && !m.getTypeParameters().isEmpty()) { + ee = m; + } + } + assertNotNull(ee); + GeneratorUtilities utilities = GeneratorUtilities.get(copy); + assertNotNull(utilities); + ClassTree newCt = utilities.insertClassMembers(ct, Collections.singletonList(utilities.createMethod(dt, ee))); + copy.rewrite(ct, newCt); + } + } + private void performTest(String sourceCode, final Task task, final Validator validator) throws Exception { performTest(sourceCode, "1.5", task, validator); } private void performTest(String sourceCode, String sourceLevel, final Task task, final Validator validator) throws Exception { + performTest(sourceCode, sourceLevel, task, validator, true); + } + + private void performTest(String sourceCode, String sourceLevel, final Task task, final Validator validator, final boolean requireNoErrors) throws Exception { FileObject root = makeScratchDir(this); FileObject sourceDir = root.createFolder("src"); @@ -836,7 +889,9 @@ public class GeneratorUtilitiesTest exte System.err.println(controller.getText()); controller.toPhase(JavaSource.Phase.RESOLVED); - assertEquals(controller.getDiagnostics().toString(), 0, controller.getDiagnostics().size()); + if (requireNoErrors) { + assertEquals(controller.getDiagnostics().toString(), 0, controller.getDiagnostics().size()); + } if (validator != null) validator.validate(controller);