Javafx: Rename static FXML property and corresponding static Java method simultaneously. Add index of FXML imports. Add searcher for Java methods referenced in FXML. Move reusable code to base class. Tests added. (IDEA-105038, IDEA-105231)

This commit is contained in:
Pavel Dolgov
2016-04-27 18:50:53 +03:00
parent 455d2b1c31
commit 06c8b177bc
12 changed files with 96 additions and 127 deletions
@@ -170,6 +170,11 @@ public class JavaFXRenameTest extends DaemonAnalyzerTestCase {
assertMethodExists(psiClass, newName);
}
public void testStaticPropertyFromLibrary() throws Exception {
doTestErrorHint("Foo", "Cannot perform refactoring.\n" +
"Selected method is not located inside the project");
}
public void testControllerMethod() throws Exception {
final PsiClass psiClass = doTestHandler("newName", null);
assertMethodExists(psiClass, "getNewName");
@@ -283,7 +283,7 @@ public class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
@NotNull
@Override
protected String getPropertyName() {
public String getPropertyName() {
return myFieldName;
}
@@ -150,7 +150,7 @@ public class JavaFxFieldIdReferenceProvider extends JavaFxControllerBasedReferen
@Nullable
@Override
protected String getPropertyName() {
public String getPropertyName() {
return PropertyUtil.getPropertyName(myFieldOrMethod);
}
@@ -30,7 +30,7 @@ import com.intellij.util.Processor;
import com.intellij.util.QueryExecutor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.javaFX.indexing.JavaFxImportsIndex;
import org.jetbrains.plugins.javaFX.refactoring.JavaFxStaticPropertyElement;
import org.jetbrains.plugins.javaFX.refactoring.JavaFxPropertyElement;
import java.util.List;
@@ -45,8 +45,13 @@ public class JavaFxMethodSearcher implements QueryExecutor<PsiReference, Referen
if (elementToSearch instanceof PsiMethod) {
searchMethod((PsiMethod)elementToSearch, queryParameters, consumer);
}
if (elementToSearch instanceof JavaFxStaticPropertyElement) {
searchMethod(((JavaFxStaticPropertyElement)elementToSearch).getMethod(), queryParameters, consumer);
if (elementToSearch instanceof JavaFxPropertyElement) {
final JavaFxPropertyElement propertyElement = (JavaFxPropertyElement)elementToSearch;
final JavaFxPropertyReference propertyReference = propertyElement.getPropertyReference();
final PsiMethod staticSetter = propertyReference.getStaticSetter();
if (staticSetter != null) {
searchMethod(staticSetter, queryParameters, consumer);
}
}
return true;
}
@@ -45,11 +45,16 @@ public abstract class JavaFxPropertyReference<T extends PsiElement> extends PsiR
return JavaFxPsiUtil.findObservablePropertyGetter(myPsiClass, getPropertyName());
}
@Nullable
public PsiMethod getStaticSetter() {
return null;
}
@Nullable
public PsiType getType() {
return JavaFxPsiUtil.getReadablePropertyType(resolve());
}
@Nullable
protected abstract String getPropertyName();
public abstract String getPropertyName();
}
@@ -11,14 +11,14 @@ import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
/**
* @author Pavel.Dolgov
*/
public class JavaFxStaticPropertyReference extends PsiReferenceBase<XmlAttribute> {
public class JavaFxStaticPropertyReference extends JavaFxPropertyReference<XmlAttribute> {
private String myPropertyName;
private PsiMethod myStaticMethod;
public JavaFxStaticPropertyReference(@NotNull XmlAttribute xmlAttribute,
@Nullable PsiClass psiClass,
@NotNull String propertyName) {
super(xmlAttribute);
super(xmlAttribute, psiClass);
myPropertyName = propertyName;
myStaticMethod = JavaFxPsiUtil.findStaticPropertySetter(propertyName, psiClass);
}
@@ -29,6 +29,37 @@ public class JavaFxStaticPropertyReference extends PsiReferenceBase<XmlAttribute
return myStaticMethod;
}
@Nullable
@Override
public PsiMethod getGetter() {
return null;
}
@Nullable
@Override
public PsiMethod getSetter() {
return null;
}
@Nullable
@Override
public PsiField getField() {
return null;
}
@Nullable
@Override
public PsiMethod getObservableGetter() {
return null;
}
@Nullable
@Override
public PsiMethod getStaticSetter() {
return myStaticMethod;
}
@Override
public PsiType getType() {
if (myStaticMethod != null) {
final PsiParameter[] parameters = myStaticMethod.getParameterList().getParameters();
@@ -39,14 +70,11 @@ public class JavaFxStaticPropertyReference extends PsiReferenceBase<XmlAttribute
return null;
}
@Override
public String getPropertyName() {
return myPropertyName;
}
public PsiMethod getStaticMethod() {
return myStaticMethod;
}
@NotNull
@Override
public Object[] getVariants() {
@@ -33,7 +33,6 @@ import com.intellij.util.xml.NanoXmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.JavaFxNamespaceDataProvider;
import java.io.Reader;
import java.io.StringReader;
@@ -5,7 +5,6 @@ import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
import com.intellij.psi.util.PropertyUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxPropertyReference;
@@ -13,10 +12,10 @@ import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxPropertyReference;
/**
* @author Pavel.Dolgov
*/
class JavaFxPropertyElement extends BeanPropertyElement {
public class JavaFxPropertyElement extends BeanPropertyElement {
private final JavaFxPropertyReference myPropertyReference;
private JavaFxPropertyElement(JavaFxPropertyReference propertyReference, String propertyName, PsiMethod method) {
private JavaFxPropertyElement(PsiMethod method, String propertyName, JavaFxPropertyReference propertyReference) {
super(method, propertyName);
myPropertyReference = propertyReference;
}
@@ -32,14 +31,18 @@ class JavaFxPropertyElement extends BeanPropertyElement {
return "property";
}
@NotNull
public JavaFxPropertyReference getPropertyReference() {
return myPropertyReference;
}
@Nullable
static PsiElement fromReference(@NotNull final JavaFxPropertyReference propertyReference) {
final PsiElement element = propertyReference.resolve();
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
final String propertyName = PropertyUtil.getPropertyName(method);
final String propertyName = propertyReference.getPropertyName();
if (propertyName != null) {
return new JavaFxPropertyElement(propertyReference, propertyName, method);
return new JavaFxPropertyElement((PsiMethod)element, propertyName, propertyReference);
}
}
if (element instanceof PsiField) {
@@ -6,7 +6,10 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.*;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.xml.XmlFile;
@@ -16,7 +19,7 @@ import com.intellij.refactoring.rename.PsiElementRenameHandler;
import com.intellij.refactoring.rename.RenameDialog;
import com.intellij.refactoring.rename.RenameHandler;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.NotNullProducer;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,9 +27,7 @@ import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxComponentIdReferenceProvider;
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxPropertyReference;
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxStaticPropertyReference;
import java.util.Collections;
import java.util.Map;
/**
@@ -64,38 +65,24 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
}
if (reference instanceof JavaFxPropertyReference && reference.resolve() != null) {
final JavaFxPropertyReference propertyReference = (JavaFxPropertyReference)reference;
final Map<PsiElement, String> elementsToRename = getElementsToRename(propertyReference, "a");
final boolean cannotRename = !elementsToRename.isEmpty() &&
elementsToRename.keySet().stream()
.anyMatch(element -> !PsiElementRenameHandler.canRename(project, editor, element));
if (cannotRename) {
return;
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
final String newName = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext);
assert newName != null : "Rename property";
doRename(propertyReference, newName, false, false);
return;
}
final Map<String, PsiElement> elementsToRename = getElementsToRename(propertyReference, "a");
for (PsiElement element : elementsToRename.values()) {
if (!PsiElementRenameHandler.canRename(project, editor, element)) return;
}
final PsiElement psiElement = JavaFxPropertyElement.fromReference(propertyReference);
if (psiElement != null) {
new PropertyRenameDialog(propertyReference, psiElement, project, editor).show();
}
}
if (reference instanceof JavaFxStaticPropertyReference) {
final JavaFxStaticPropertyReference propertyReference = (JavaFxStaticPropertyReference)reference;
if (ApplicationManager.getApplication().isUnitTestMode()) {
final String newName = PsiElementRenameHandler.DEFAULT_NAME.getData(dataContext);
assert newName != null : "Rename property";
doRenameStatic(propertyReference, newName, false, false);
return;
}
final Map<String, PsiElement> elementsToRename = getStaticElementsToRename(propertyReference, "a");
for (PsiElement element : elementsToRename.values()) {
if (!PsiElementRenameHandler.canRename(project, editor, element)) return;
}
final PsiElement psiElement = JavaFxStaticPropertyElement.fromReference(propertyReference);
if (psiElement != null) {
new PropertyRenameDialog(reference, psiElement, project, editor).show();
}
}
}
private static void doRename(JavaFxPropertyReference reference, String newName, final boolean searchInComments, boolean isPreview) {
@@ -104,28 +91,11 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
final RenameRefactoring rename = new JavaRenameRefactoringImpl(psiElement.getProject(), psiElement, newName, searchInComments, false);
rename.setPreviewUsages(isPreview);
final Map<String, PsiElement> elementsToRename = getElementsToRename(reference, newName);
for (Map.Entry<String, PsiElement> entry : elementsToRename.entrySet()) {
rename.addElement(entry.getValue(), entry.getKey());
}
final Map<PsiElement, String> elementsToRename = getElementsToRename(reference, newName);
elementsToRename.forEach(rename::addElement);
rename.run();
}
private static void doRenameStatic(JavaFxStaticPropertyReference reference,
String newName,
final boolean searchInComments,
boolean isPreview) {
final PsiElement psiElement = JavaFxStaticPropertyElement.fromReference(reference);
if (psiElement == null) return;
final RenameRefactoring rename = new JavaRenameRefactoringImpl(psiElement.getProject(), psiElement, newName, searchInComments, false);
rename.setPreviewUsages(isPreview);
final Map<String, PsiElement> elementsToRename = getStaticElementsToRename(reference, newName);
for (Map.Entry<String, PsiElement> entry : elementsToRename.entrySet()) {
rename.addElement(entry.getValue(), entry.getKey());
}
rename.run();
}
@Nullable
private static PsiReference getReference(DataContext dataContext) {
@@ -159,7 +129,6 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
private static boolean isKnown(PsiReference reference) {
if (reference instanceof JavaFxPropertyReference) return true;
if (reference instanceof JavaFxStaticPropertyReference) return ((JavaFxStaticPropertyReference)reference).getStaticMethod() != null;
if (reference instanceof JavaFxComponentIdReferenceProvider.JavaFxIdReferenceBase) {
return ((JavaFxComponentIdReferenceProvider.JavaFxIdReferenceBase)reference).isBuiltIn();
}
@@ -167,28 +136,26 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
}
@NotNull
private static Map<String, PsiElement> getElementsToRename(@NotNull JavaFxPropertyReference reference, @NotNull String newPropertyName) {
final Map<String, PsiElement> rename = new THashMap<>();
ContainerUtil.putIfNotNull(newPropertyName, reference.getField(), rename);
ContainerUtil.putIfNotNull(PropertyUtil.suggestGetterName(newPropertyName, reference.getType()), reference.getGetter(), rename);
ContainerUtil.putIfNotNull(PropertyUtil.suggestSetterName(newPropertyName), reference.getSetter(), rename);
ContainerUtil.putIfNotNull(newPropertyName + JavaFxCommonNames.PROPERTY_METHOD_SUFFIX, reference.getObservableGetter(), rename);
private static Map<PsiElement, String> getElementsToRename(@NotNull JavaFxPropertyReference reference, @NotNull String newPropertyName) {
final Map<PsiElement, String> rename = new THashMap<>();
putIfKeyNotNull(rename, reference.getGetter(), () -> PropertyUtil.suggestGetterName(newPropertyName, reference.getType()));
putIfKeyNotNull(rename, reference.getField(), () -> newPropertyName);
putIfKeyNotNull(rename, reference.getSetter(), () -> PropertyUtil.suggestSetterName(newPropertyName));
putIfKeyNotNull(rename, reference.getObservableGetter(), () -> newPropertyName + JavaFxCommonNames.PROPERTY_METHOD_SUFFIX);
putIfKeyNotNull(rename, reference.getStaticSetter(), () -> PropertyUtil.suggestSetterName(newPropertyName));
//TODO add "name" parameter of the observable property constructor (like new SimpleObjectProperty(this, "name", null);
return rename;
}
private static Map<String, PsiElement> getStaticElementsToRename(@NotNull JavaFxStaticPropertyReference reference,
@NotNull String newPropertyName) {
final PsiMethod method = reference.getStaticMethod();
if (method == null) return Collections.emptyMap();
return Collections.singletonMap(PropertyUtil.suggestSetterName(newPropertyName), method);
private static <K, V> void putIfKeyNotNull(Map<K, V> map, K key, NotNullProducer<V> valueProducer) {
if (key != null) map.put(key, valueProducer.produce());
}
private static class PropertyRenameDialog extends RenameDialog {
private final PsiReference myPropertyReference;
private final JavaFxPropertyReference myPropertyReference;
protected PropertyRenameDialog(@NotNull PsiReference propertyReference,
protected PropertyRenameDialog(@NotNull JavaFxPropertyReference propertyReference,
@NotNull PsiElement psiElement,
@NotNull Project project,
Editor editor) {
@@ -199,12 +166,7 @@ public class JavaFxPropertyRenameHandler implements RenameHandler {
protected void doAction() {
final String newName = getNewName();
final boolean searchInComments = isSearchInComments();
if (myPropertyReference instanceof JavaFxPropertyReference) {
doRename((JavaFxPropertyReference)myPropertyReference, newName, searchInComments, isPreviewUsages());
}
else if (myPropertyReference instanceof JavaFxStaticPropertyReference) {
doRenameStatic((JavaFxStaticPropertyReference)myPropertyReference, newName, searchInComments, isPreviewUsages());
}
doRename(myPropertyReference, newName, searchInComments, isPreviewUsages());
close(DialogWrapper.OK_EXIT_CODE);
}
}
@@ -1,44 +0,0 @@
package org.jetbrains.plugins.javaFX.refactoring;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.beanProperties.BeanPropertyElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.refs.JavaFxStaticPropertyReference;
/**
* @author Pavel.Dolgov
*/
public class JavaFxStaticPropertyElement extends BeanPropertyElement {
private final JavaFxStaticPropertyReference myPropertyReference;
private JavaFxStaticPropertyElement(JavaFxStaticPropertyReference propertyReference, String propertyName, PsiMethod method) {
super(method, propertyName);
myPropertyReference = propertyReference;
}
@Nullable
@Override
public PsiType getPropertyType() {
return myPropertyReference.getType();
}
@Override
public String getTypeName() {
return "property";
}
@Nullable
static PsiElement fromReference(@NotNull final JavaFxStaticPropertyReference propertyReference) {
final PsiMethod method = propertyReference.getStaticMethod();
if (method != null) {
final String propertyName = propertyReference.getPropertyName();
if (propertyName != null) {
return new JavaFxStaticPropertyElement(propertyReference, propertyName, method);
}
}
return null;
}
}
@@ -0,0 +1 @@
class StaticPropertyFromLibrary {}
@@ -0,0 +1,5 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Label?>
<HBox>
<Label HBox.hg<caret>row="ALWAYS"/>
</HBox>