diff --git a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/Bundle.properties b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/Bundle.properties index ec59b7ec94c7..fb08af9426d6 100644 --- a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/Bundle.properties +++ b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/Bundle.properties @@ -79,6 +79,7 @@ ERR_PullUp_MemberAlreadyExists=Member "{0}" already exists in the target type. ERR_CannotPullupDuplicateMembers=Cannot pull up two members with the same signature. ERR_PullupNonPublicToInterface=Member "{0}" is being moved to interface, but is not public. ERR_PullupStaticToInterface=Member "{0}" cannot be pulled up to interface, it is static. +ERR_PullupNonNotInitializedToInterface=Member "{0}" cannot be pulled up to interface, it is not initialized. TXT_PullUp_AddMethod=Add abstract method\: {0} # Move member to the target type (0 = member name) diff --git a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/MoveMembersRefactoringPlugin.java b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/MoveMembersRefactoringPlugin.java index 3af5c11f9930..bc62819ea6fb 100644 --- a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/MoveMembersRefactoringPlugin.java +++ b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/MoveMembersRefactoringPlugin.java @@ -19,6 +19,7 @@ package org.netbeans.modules.refactoring.java.plugins; import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; import java.io.IOException; import java.net.URL; @@ -29,20 +30,17 @@ import javax.lang.model.util.ElementFilter; import org.netbeans.api.java.classpath.ClassPath; import org.netbeans.api.java.source.*; -import org.netbeans.api.java.source.ClasspathInfo.PathKind; import org.netbeans.api.project.FileOwnerQuery; import org.netbeans.api.project.Project; import org.netbeans.api.project.ProjectUtils; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.api.MoveRefactoring; import org.netbeans.modules.refactoring.api.Problem; -import org.netbeans.modules.refactoring.api.ProgressEvent; import org.netbeans.modules.refactoring.java.RefactoringUtils; import org.netbeans.modules.refactoring.java.api.JavaMoveMembersProperties; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.spi.JavaRefactoringPlugin; import org.netbeans.modules.refactoring.spi.RefactoringElementsBag; -import org.netbeans.spi.java.classpath.support.ClassPathSupport; import org.openide.filesystems.FileObject; import org.openide.filesystems.URLMapper; import org.openide.util.Lookup; @@ -66,6 +64,8 @@ "ERR_MoveAbstractMember=Cannot move abstract method \"{0}\"", "# {0} - Method name", "ERR_MoveMethodPolymorphic=Cannot move polymorphic method \"{0}\"", + "# {0} - Field name", + "ERR_MoveNotInitializedToInterface=Member \"{0}\" cannot be moved to interface, it is not initialized.", "WRN_InitNoAccess=Field initializer uses local accessors which will not be accessible", "# {0} - File displayname : line number", "WRN_NoAccessor=No accessor found to invoke the method from: {0}", @@ -239,6 +239,19 @@ protected Problem fastCheckParameters(CompilationController javac) throws IOExce if(targetPackage.isUnnamed() && !sourcePackage.isUnnamed()) { return new Problem(true, NbBundle.getMessage(MoveMembersRefactoringPlugin.class, "ERR_MovingMemberToDefaultPackage")); //NOI18N } + if (targetClass.getKind().isInterface()) { + + for (TreePathHandle treePathHandle : source) { + Element element = treePathHandle.resolveElement(javac); + if (element != null && element.getKind() == ElementKind.FIELD) { + VariableElement variableElement = (VariableElement) element; + VariableTree variableTree = (VariableTree) javac.getTrees().getTree(variableElement); + if (variableTree != null && variableTree.getInitializer() == null) { + return createProblem(p, true, NbBundle.getMessage(PullUpRefactoringPlugin.class, "ERR_MoveNotInitializedToInterface", element.getSimpleName())); + } + } + } + } for (TreePathHandle treePathHandle : source) { Element element = treePathHandle.resolveElement(javac); List enclosedElements = targetElement.getEnclosedElements(); diff --git a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/PullUpRefactoringPlugin.java b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/PullUpRefactoringPlugin.java index ad59b6be036e..9473239053a4 100644 --- a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/PullUpRefactoringPlugin.java +++ b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/PullUpRefactoringPlugin.java @@ -18,16 +18,17 @@ */ package org.netbeans.modules.refactoring.java.plugins; +import com.sun.source.tree.VariableTree; import java.io.IOException; import java.util.*; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; import org.netbeans.api.java.source.*; import org.netbeans.modules.refactoring.api.AbstractRefactoring; import org.netbeans.modules.refactoring.api.Problem; -import org.netbeans.modules.refactoring.api.ProgressEvent; import org.netbeans.modules.refactoring.java.RefactoringUtils; import org.netbeans.modules.refactoring.java.api.JavaRefactoringUtils; import org.netbeans.modules.refactoring.java.api.MemberInfo; @@ -120,7 +121,8 @@ protected Problem preCheck(CompilationController cc) throws IOException { @Override - public Problem fastCheckParameters() { + public Problem fastCheckParameters(CompilationController cc) throws IOException { + cc.toPhase(JavaSource.Phase.RESOLVED); MemberInfo>[] info = refactoring.getMembers(); // #1 - check whether there are any members to pull up if (info.length == 0) { @@ -144,7 +146,8 @@ public Problem fastCheckParameters() { Problem p=null; if (refactoring.getTargetType().getKind().isInterface()) { - for (MemberInfo i:info) { + for (MemberInfo> i :info) { + Element member = i.getElementHandle().resolve(cc); if (!i.getModifiers().contains(Modifier.PUBLIC)) { p = createProblem(p, false, NbBundle.getMessage(PullUpRefactoringPlugin.class,"ERR_PullupNonPublicToInterface" ,i.getName())); } @@ -152,7 +155,15 @@ public Problem fastCheckParameters() { if (i.getModifiers().contains(Modifier.STATIC)) { p = createProblem(p, true, NbBundle.getMessage(PullUpRefactoringPlugin.class,"ERR_PullupStaticToInterface" ,i.getName())); } + if (member.getKind() == ElementKind.FIELD) { + VariableElement variableElement = (VariableElement) member; + VariableTree variableTree = (VariableTree) cc.getTrees().getTree(variableElement); + if (variableTree != null && variableTree.getInitializer() == null) { + return createProblem(p, true, NbBundle.getMessage(PullUpRefactoringPlugin.class, "ERR_PullupNonNotInitializedToInterface", member.getSimpleName())); + } + } } + } for (MemberInfo> i : info) { @@ -237,7 +248,6 @@ protected Problem checkParameters(CompilationController cc) throws IOException { // !sourceResource.equals(targetResource), // !sourceResource.getPackageName().equals(targetResource.getPackageName())); // } - fireProgressListenerStep(); } diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/plugins/Bundle_test.properties b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/plugins/Bundle_test.properties index 067ec0affd78..330a1f1b1c78 100644 --- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/plugins/Bundle_test.properties +++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/plugins/Bundle_test.properties @@ -69,6 +69,7 @@ ERR_MoveToSameClass=ERR_MoveToSameClass ERR_MoveToSuperClass=ERR_MoveToSuperClass ERR_MoveToSubClass=ERR_MoveToSubClass ERR_MoveGenericField=ERR_MoveGenericField +ERR_MoveNotInitializedToInterface=ERR_MoveNotInitializedToInterface WRN_InitNoAccess=WRN_InitNoAccess WRN_NoAccessor=WRN_NoAccessor ERR_CannotMovePublicIntoSamePackage=ERR_CannotMovePublicIntoSamePackage @@ -82,6 +83,7 @@ ERR_ClassToMoveClashesInner=ERR_ClassToMoveClashesInner ERR_PullUp_MemberAlreadyExists=ERR_PullUp_MemberAlreadyExists ERR_PullUp_MemberTargetType=ERR_PullUp_MemberTargetType ERR_PullupStaticToInterface=ERR_PullupStaticToInterface +ERR_PullupNonNotInitializedToInterface=ERR_PullupNonNotInitializedToInterface # Copy ERR_ClassToMoveClashes=ERR_ClassToMoveClashes diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/MoveFieldTest.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/MoveFieldTest.java index b1cebd15aa46..07b579913409 100644 --- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/MoveFieldTest.java +++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/MoveFieldTest.java @@ -57,6 +57,50 @@ public void testMoveField() throws Exception { + "}\n")); } + public void testMoveNotInitializedFieldToInterface() throws Exception { + writeFilesAndWaitForScan(src, + new File("t/A.java", "package t;\n" + + "public class A {\n" + + " public static int i;\n" + + "}\n"), + new File("t/B.java", "package t;\n" + + "public interface B {\n" + + "}\n")); + performMove(src.getFileObject("t/A.java"), new int[]{1}, src.getFileObject("t/B.java"), Visibility.ESCALATE, false, new Problem(true, "ERR_MoveNotInitializedToInterface")); + } + + public void testMoveInitializedFieldToInterface() throws Exception { + writeFilesAndWaitForScan(src, + new File("t/A.java", + """ + package t; + public class A { + public static int i = 1; + } + """), + new File("t/B.java", + """ + package t; + public interface B { + } + """)); + performMove(src.getFileObject("t/A.java"), new int[]{1}, src.getFileObject("t/B.java"), Visibility.ESCALATE, false); + verifyContent(src, + new File("t/A.java", + """ + package t; + public class A { + } + """), + new File("t/B.java", + """ + package t; + public interface B { + public static int i = 1; + } + """)); + } + public void test242909() throws Exception { writeFilesAndWaitForScan(src, new File("t/A.java", "package t;\n" diff --git a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java index fb7cde7eda01..768f8f7127a2 100644 --- a/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java +++ b/java/refactoring.java/test/unit/src/org/netbeans/modules/refactoring/java/test/PullUpTest.java @@ -172,6 +172,23 @@ public void test206683() throws Exception { performPullUp(src.getFileObject("pullup/A.java"), 1, Boolean.FALSE, new Problem(true, "ERR_PullUp_MemberAlreadyExists")); } + public void testPullUpNotInitializedFieldToInterface() throws Exception { + writeFilesAndWaitForScan(src, + new File("pullup/A.java", "package pullup; public interface A {}"), + new File("pullup/B.java", "package pullup; public class B implements A { public int i; }")); + performPullUpIface(src.getFileObject("pullup/B.java"), 1, 0, Boolean.FALSE, new Problem(true, "ERR_PullupNonNotInitializedToInterface")); + } + + public void testPullUpInitializedFieldToInterface() throws Exception { + writeFilesAndWaitForScan(src, + new File("t/A.java", "package pullup; public interface A {}"), + new File("t/B.java", "package pullup; public class B implements A { public int i = 1; }")); + performPullUpIface(src.getFileObject("t/B.java"), 1,0, Boolean.FALSE); + verifyContent(src, + new File("t/A.java", "package pullup; public interface A { public int i = 1; }"), + new File("t/B.java", "package pullup; public class B implements A {}")); + } + public void testPullUpField() throws Exception { writeFilesAndWaitForScan(src, new File("pullup/A.java", "package pullup; public class A extends B { public int i; }"),