blob: 4ab9d43fbc1d92434e287678a2bdfb1b71846625 [file] [log] [blame]
/*
* 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.daemon.QuickFixBundle;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.*;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public class AddMethodQualifierFix implements IntentionAction {
private static final boolean UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode();
private final SmartPsiElementPointer<PsiMethodCallExpression> myMethodCall;
private List<PsiVariable> myCandidates = null;
public AddMethodQualifierFix(final PsiMethodCallExpression methodCallExpression) {
myMethodCall = SmartPointerManager.getInstance(methodCallExpression.getProject()).createSmartPsiElementPointer(methodCallExpression);
}
@NotNull
@Override
public String getText() {
String text = QuickFixBundle.message("add.method.qualifier.fix.text", myCandidates.size() > 1 ? "" : myCandidates.get(0).getName());
if (myCandidates.size() > 1) {
text += "...";
}
return text;
}
@NotNull
@Override
public String getFamilyName() {
return getText();
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
final PsiMethodCallExpression element = myMethodCall.getElement();
if (element == null || !element.isValid()) {
return false;
}
return getOrFindCandidates().size() != 0;
}
private synchronized List<PsiVariable> getOrFindCandidates() {
if (myCandidates == null) {
findCandidates();
}
return myCandidates;
}
private void findCandidates() {
myCandidates = new ArrayList<PsiVariable>();
final PsiMethodCallExpression methodCallElement = myMethodCall.getElement();
final String methodName = methodCallElement.getMethodExpression().getReferenceName();
if (methodName == null) {
return;
}
for (final PsiVariable var : CreateFromUsageUtils.guessMatchingVariables(methodCallElement)) {
if (var.getName() == null) {
continue;
}
final PsiType type = var.getType();
if (!(type instanceof PsiClassType)) {
continue;
}
final PsiClass resolvedClass = ((PsiClassType)type).resolve();
if (resolvedClass == null) {
continue;
}
if (resolvedClass.findMethodsByName(methodName, true).length > 0) {
myCandidates.add(var);
}
}
}
@TestOnly
public List<PsiVariable> getCandidates() {
return myCandidates;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (myCandidates.size() == 1 || UNIT_TEST_MODE) {
qualify(myCandidates.get(0), editor);
}
else {
chooseAndQualify(editor);
}
}
private void chooseAndQualify(final Editor editor) {
final BaseListPopupStep<PsiVariable> step =
new BaseListPopupStep<PsiVariable>(QuickFixBundle.message("add.qualifier"), myCandidates) {
@Override
public PopupStep onChosen(final PsiVariable selectedValue, final boolean finalChoice) {
if (selectedValue != null && finalChoice) {
WriteCommandAction.runWriteCommandAction(selectedValue.getProject(), new Runnable() {
@Override
public void run() {
qualify(selectedValue, editor);
}
});
}
return FINAL_CHOICE;
}
@NotNull
@Override
public String getTextFor(final PsiVariable value) {
return value.getName();
}
@Override
public Icon getIconFor(final PsiVariable aValue) {
return aValue.getIcon(0);
}
};
final ListPopupImpl popup = new ListPopupImpl(step);
popup.showInBestPositionFor(editor);
}
private void qualify(final PsiVariable qualifier, final Editor editor) {
final String qualifierPresentableText = qualifier.getName();
final PsiMethodCallExpression oldExpression = myMethodCall.getElement();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(qualifier.getProject());
final PsiExpression expression = elementFactory
.createExpressionFromText(qualifierPresentableText + "." + oldExpression.getMethodExpression().getReferenceName() + "()", null);
final PsiElement replacedExpression = oldExpression.replace(expression);
editor.getCaretModel().moveToOffset(replacedExpression.getTextOffset() + replacedExpression.getTextLength());
}
@Override
public boolean startInWriteAction() {
return true;
}
}