mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
create method from method reference (IDEA-112556)
This commit is contained in:
@@ -179,6 +179,7 @@ public abstract class QuickFixFactory {
|
||||
int minUsagesNumberToShowDialog);
|
||||
|
||||
@NotNull public abstract IntentionAction createCreateMethodFromUsageFix(@NotNull PsiMethodCallExpression call);
|
||||
@NotNull public abstract IntentionAction createCreateMethodFromUsageFix(PsiMethodReferenceExpression methodReferenceExpression);
|
||||
|
||||
@NotNull public abstract IntentionAction createCreateAbstractMethodFromUsageFix(@NotNull PsiMethodCallExpression call);
|
||||
|
||||
|
||||
+6
-3
@@ -1328,9 +1328,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
}
|
||||
|
||||
if (description != null) {
|
||||
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF)
|
||||
.descriptionAndTooltip(description)
|
||||
.range(expression.getReferenceNameElement()).create());
|
||||
final PsiElement referenceNameElement = expression.getReferenceNameElement();
|
||||
final HighlightInfo highlightInfo =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).descriptionAndTooltip(description).range(referenceNameElement).create();
|
||||
myHolder.add(highlightInfo);
|
||||
final TextRange fixRange = HighlightMethodUtil.getFixRange(referenceNameElement);
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QuickFixFactory.getInstance().createCreateMethodFromUsageFix(expression));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfoImpl;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CreateMethodFromMethodReferenceFix extends CreateFromUsageBaseFix {
|
||||
private static final Logger LOG = Logger.getInstance("#" + CreateMethodFromMethodReferenceFix.class.getName());
|
||||
|
||||
private final SmartPsiElementPointer myMethodReferenceExpression;
|
||||
|
||||
public CreateMethodFromMethodReferenceFix(@NotNull PsiMethodReferenceExpression methodRef) {
|
||||
myMethodReferenceExpression = SmartPointerManager.getInstance(methodRef.getProject()).createSmartPsiElementPointer(methodRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAvailableImpl(int offset) {
|
||||
final PsiMethodReferenceExpression call = getMethodReference();
|
||||
if (call == null || !call.isValid()) return false;
|
||||
final PsiType functionalInterfaceType = call.getFunctionalInterfaceType();
|
||||
if (functionalInterfaceType == null ||
|
||||
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
final String name = call.getReferenceName();
|
||||
|
||||
if (name == null) return false;
|
||||
if (call.isConstructor() && name.equals("new") || PsiNameHelper.getInstance(call.getProject()).isIdentifier(name)) {
|
||||
setText(call.isConstructor() ? QuickFixBundle.message("create.constructor.from.new.text") : QuickFixBundle.message("create.method.from.usage.text", name));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getElement() {
|
||||
final PsiMethodReferenceExpression call = getMethodReference();
|
||||
if (call == null || !call.getManager().isInProject(call)) return null;
|
||||
return call;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected List<PsiClass> getTargetClasses(PsiElement element) {
|
||||
List<PsiClass> targets = super.getTargetClasses(element);
|
||||
PsiMethodReferenceExpression call = getMethodReference();
|
||||
if (call == null) return Collections.emptyList();
|
||||
return targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeImpl(final PsiClass targetClass) {
|
||||
if (targetClass == null) return;
|
||||
PsiMethodReferenceExpression expression = getMethodReference();
|
||||
if (expression == null) return;
|
||||
|
||||
if (isValidElement(expression)) return;
|
||||
|
||||
PsiClass parentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
|
||||
PsiMember enclosingContext = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, PsiField.class, PsiClassInitializer.class);
|
||||
|
||||
String methodName = expression.getReferenceName();
|
||||
LOG.assertTrue(methodName != null);
|
||||
|
||||
|
||||
final Project project = targetClass.getProject();
|
||||
JVMElementFactory elementFactory = JVMElementFactories.getFactory(targetClass.getLanguage(), project);
|
||||
if (elementFactory == null) elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
|
||||
PsiMethod method = expression.isConstructor() ? (PsiMethod)targetClass.add(elementFactory.createConstructor())
|
||||
: CreateMethodFromUsageFix.createMethod(targetClass, parentClass, enclosingContext, methodName);
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!expression.isConstructor()) {
|
||||
setupVisibility(parentClass, targetClass, method.getModifierList());
|
||||
}
|
||||
|
||||
expression = getMethodReference();
|
||||
LOG.assertTrue(expression.isValid());
|
||||
|
||||
if (!expression.isConstructor() && shouldCreateStaticMember(expression, targetClass)) {
|
||||
PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true);
|
||||
}
|
||||
|
||||
final PsiElement context = PsiTreeUtil.getParentOfType(expression, PsiClass.class, PsiMethod.class);
|
||||
|
||||
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
|
||||
final PsiClassType.ClassResolveResult classResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(classResolveResult);
|
||||
LOG.assertTrue(interfaceMethod != null);
|
||||
|
||||
final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);
|
||||
LOG.assertTrue(interfaceReturnType != null);
|
||||
|
||||
final ExpectedTypeInfo[] expectedTypes = {new ExpectedTypeInfoImpl(interfaceReturnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, interfaceReturnType, TailType.NONE, null, ExpectedTypeInfoImpl.NULL)};
|
||||
CreateMethodFromUsageFix.doCreate(targetClass, method, false,
|
||||
ContainerUtil.map2List(interfaceMethod.getParameterList().getParameters(), new Function<PsiParameter, Pair<PsiExpression, PsiType>>() {
|
||||
@Override
|
||||
public Pair<PsiExpression, PsiType> fun(PsiParameter parameter) {
|
||||
return Pair.create(null, parameter.getType());
|
||||
}
|
||||
}),
|
||||
LambdaUtil.getSubstitutor(interfaceMethod, classResolveResult),
|
||||
expectedTypes, context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean isValidElement(PsiElement element) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return QuickFixBundle.message("create.method.from.usage.family");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiMethodReferenceExpression getMethodReference() {
|
||||
return (PsiMethodReferenceExpression)myMethodReferenceExpression.getElement();
|
||||
}
|
||||
}
|
||||
+38
-25
@@ -66,7 +66,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
PsiReferenceExpression ref = call.getMethodExpression();
|
||||
String name = ref.getReferenceName();
|
||||
|
||||
if (name == null || !JavaPsiFacade.getInstance(ref.getProject()).getNameHelper().isIdentifier(name)) return false;
|
||||
if (name == null || !PsiNameHelper.getInstance(ref.getProject()).isIdentifier(name)) return false;
|
||||
if (hasErrorsInArgumentList(call)) return false;
|
||||
setText(getDisplayString(name));
|
||||
return true;
|
||||
@@ -133,7 +133,6 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
if (targetClass == null) return;
|
||||
PsiMethodCallExpression expression = getMethodCall();
|
||||
if (expression == null) return;
|
||||
final Project project = expression.getProject();
|
||||
PsiReferenceExpression ref = expression.getMethodExpression();
|
||||
|
||||
if (isValidElement(expression)) return;
|
||||
@@ -144,30 +143,11 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
String methodName = ref.getReferenceName();
|
||||
LOG.assertTrue(methodName != null);
|
||||
|
||||
JVMElementFactory factory = JVMElementFactories.getFactory(targetClass.getLanguage(), project);
|
||||
if (factory == null) {
|
||||
PsiMethod method = createMethod(targetClass, parentClass, enclosingContext, methodName);
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiMethod method = factory.createMethod(methodName, PsiType.VOID);
|
||||
|
||||
if (targetClass.equals(parentClass)) {
|
||||
method = (PsiMethod)targetClass.addAfter(method, enclosingContext);
|
||||
}
|
||||
else {
|
||||
PsiElement anchor = enclosingContext;
|
||||
while (anchor != null && anchor.getParent() != null && !anchor.getParent().equals(targetClass)) {
|
||||
anchor = anchor.getParent();
|
||||
}
|
||||
if (anchor != null && anchor.getParent() == null) anchor = null;
|
||||
if (anchor != null) {
|
||||
method = (PsiMethod)targetClass.addAfter(method, anchor);
|
||||
}
|
||||
else {
|
||||
method = (PsiMethod)targetClass.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
if (enclosingContext instanceof PsiMethod && methodName.equals(enclosingContext.getName()) &&
|
||||
PsiTreeUtil.isAncestor(targetClass, parentClass, true) && !ref.isQualified()) {
|
||||
RefactoringChangeUtil.qualifyReference(ref, method, null);
|
||||
@@ -201,6 +181,36 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
context);
|
||||
}
|
||||
|
||||
protected static PsiMethod createMethod(PsiClass targetClass,
|
||||
PsiClass parentClass,
|
||||
PsiMember enclosingContext,
|
||||
String methodName) {
|
||||
JVMElementFactory factory = JVMElementFactories.getFactory(targetClass.getLanguage(), targetClass.getProject());
|
||||
if (factory == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiMethod method = factory.createMethod(methodName, PsiType.VOID);
|
||||
|
||||
if (targetClass.equals(parentClass)) {
|
||||
method = (PsiMethod)targetClass.addAfter(method, enclosingContext);
|
||||
}
|
||||
else {
|
||||
PsiElement anchor = enclosingContext;
|
||||
while (anchor != null && anchor.getParent() != null && !anchor.getParent().equals(targetClass)) {
|
||||
anchor = anchor.getParent();
|
||||
}
|
||||
if (anchor != null && anchor.getParent() == null) anchor = null;
|
||||
if (anchor != null) {
|
||||
method = (PsiMethod)targetClass.addAfter(method, anchor);
|
||||
}
|
||||
else {
|
||||
method = (PsiMethod)targetClass.add(method);
|
||||
}
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
public static void doCreate(PsiClass targetClass, PsiMethod method, List<Pair<PsiExpression, PsiType>> arguments, PsiSubstitutor substitutor,
|
||||
ExpectedTypeInfo[] expectedTypes, @Nullable PsiElement context) {
|
||||
doCreate(targetClass, method, shouldBeAbstractImpl(targetClass), arguments, substitutor, expectedTypes, context);
|
||||
@@ -227,8 +237,11 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
TemplateBuilderImpl builder = new TemplateBuilderImpl(method);
|
||||
|
||||
CreateFromUsageUtils.setupMethodParameters(method, builder, context, substitutor, arguments);
|
||||
new GuessTypeParameters(JavaPsiFacade.getInstance(project).getElementFactory())
|
||||
.setupTypeElement(method.getReturnTypeElement(), expectedTypes, substitutor, builder, context, targetClass);
|
||||
final PsiTypeElement returnTypeElement = method.getReturnTypeElement();
|
||||
if (returnTypeElement != null) {
|
||||
new GuessTypeParameters(JavaPsiFacade.getInstance(project).getElementFactory())
|
||||
.setupTypeElement(returnTypeElement, expectedTypes, substitutor, builder, context, targetClass);
|
||||
}
|
||||
PsiCodeBlock body = method.getBody();
|
||||
builder.setEndVariableAfter(shouldBeAbstract || body == null ? method : body.getLBrace());
|
||||
method = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(method);
|
||||
|
||||
+6
@@ -467,6 +467,12 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
return new CreateMethodFromUsageFix(call);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public IntentionAction createCreateMethodFromUsageFix(PsiMethodReferenceExpression methodReferenceExpression) {
|
||||
return new CreateMethodFromMethodReferenceFix(methodReferenceExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public IntentionAction createCreateAbstractMethodFromUsageFix(@NotNull PsiMethodCallExpression call) {
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Create Constructor" "true"
|
||||
class FooBar {
|
||||
FooBar(int i) {
|
||||
}
|
||||
|
||||
{
|
||||
Runnable r = FooBar::new;
|
||||
}
|
||||
|
||||
public FooBar() {
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create Method 'fooBar'" "true"
|
||||
class FooBar {
|
||||
{
|
||||
Runnable r = FooBar::fooBar;
|
||||
}
|
||||
|
||||
private static void fooBar() {
|
||||
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create Method 'fooBar'" "true"
|
||||
class FooBar {
|
||||
{
|
||||
Runnable r = this::fooBar;
|
||||
}
|
||||
|
||||
private void fooBar() {
|
||||
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Create Constructor" "true"
|
||||
class FooBar {
|
||||
FooBar(int i) {
|
||||
}
|
||||
|
||||
{
|
||||
Runnable r = FooBar::ne<caret>w;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Create Method 'fooBar'" "true"
|
||||
class FooBar {
|
||||
{
|
||||
Runnable r = FooBar::foo<caret>Bar;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Create Method 'fooBar'" "true"
|
||||
class FooBar {
|
||||
{
|
||||
Runnable r = this::foo<caret>Bar;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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 com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
public class CreateMethodFromMethodReferenceFixTest extends LightQuickFixParameterizedTestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/createMethodFromMethodRef";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user