mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
invert boolean api
This commit is contained in:
@@ -76,7 +76,6 @@ public class HelpID {
|
||||
public static final String METHOD_DUPLICATES = "refactoring.replaceMethodCodeDuplicates";
|
||||
public static final String CHANGE_CLASS_SIGNATURE = "change.class.signature.dialog";
|
||||
public static final String MOVE_INSTANCE_METHOD = "refactoring.moveInstMethod";
|
||||
public static final String INVERT_BOOLEAN = "refactoring.invertBoolean";
|
||||
public static final String EXTRACT_METHOD_OBJECT = "refactoring.extractMethodObject";
|
||||
public static final String REPLACE_CONSTRUCTOR_WITH_BUILDER = "refactoring.replaceConstructorWithBuilder";
|
||||
@NonNls public static final String ExtractClass = "refactorj.extractClass";
|
||||
|
||||
@@ -17,8 +17,10 @@ package com.intellij.refactoring.actions;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.invertBoolean.InvertBooleanDelegate;
|
||||
import com.intellij.refactoring.invertBoolean.InvertBooleanHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -31,15 +33,24 @@ public class InvertBooleanAction extends BaseRefactoringAction {
|
||||
}
|
||||
|
||||
protected boolean isEnabledOnElements(@NotNull PsiElement[] elements) {
|
||||
return elements.length == 1 && (elements[0] instanceof PsiMethod || elements[0] instanceof PsiVariable);
|
||||
if (elements.length == 1) {
|
||||
for (InvertBooleanDelegate delegate : Extensions.getExtensions(InvertBooleanDelegate.EP_NAME)) {
|
||||
if (delegate.isVisibleOnElement(elements[0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isAvailableOnElementInEditorAndFile(@NotNull final PsiElement element, @NotNull final Editor editor, @NotNull PsiFile file, @NotNull DataContext context) {
|
||||
if (element instanceof PsiVariable) {
|
||||
return PsiType.BOOLEAN.equals(((PsiVariable) element).getType());
|
||||
}
|
||||
else if (element instanceof PsiMethod) {
|
||||
return PsiType.BOOLEAN.equals(((PsiMethod) element).getReturnType());
|
||||
protected boolean isAvailableOnElementInEditorAndFile(@NotNull final PsiElement element,
|
||||
@NotNull final Editor editor,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull DataContext context) {
|
||||
for (InvertBooleanDelegate delegate : Extensions.getExtensions(InvertBooleanDelegate.EP_NAME)) {
|
||||
if (delegate.isAvailableOnElement(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.ide.util.SuperMethodWarningUtil;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class InvertBooleanHandler implements RefactoringActionHandler {
|
||||
static final String REFACTORING_NAME = RefactoringBundle.message("invert.boolean.title");
|
||||
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
|
||||
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
if (element instanceof PsiMethod) {
|
||||
invoke((PsiMethod)element, project, editor);
|
||||
}
|
||||
else if (element instanceof PsiVariable) {
|
||||
invoke((PsiVariable)element, project, editor);
|
||||
}
|
||||
else {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(
|
||||
RefactoringBundle.message("error.wrong.caret.position.method.or.variable.name")), REFACTORING_NAME, HelpID.INVERT_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
private static void invoke(PsiVariable var, final Project project, Editor editor) {
|
||||
final PsiType returnType = var.getType();
|
||||
if (!PsiType.BOOLEAN.equals(returnType)) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("invert.boolean.wrong.type")), REFACTORING_NAME, HelpID.INVERT_BOOLEAN);
|
||||
return;
|
||||
}
|
||||
|
||||
if (var instanceof PsiParameter && ((PsiParameter)var).getDeclarationScope() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)((PsiParameter)var).getDeclarationScope();
|
||||
final PsiMethod superMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
|
||||
if (superMethod == null) return;
|
||||
var = superMethod.getParameterList().getParameters()[method.getParameterList().getParameterIndex((PsiParameter)var)];
|
||||
}
|
||||
|
||||
new InvertBooleanDialog(var).show();
|
||||
}
|
||||
|
||||
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
|
||||
if (elements.length == 1) {
|
||||
if (elements[0] instanceof PsiMethod) {
|
||||
invoke((PsiMethod)elements[0], project, null);
|
||||
}
|
||||
else if (elements[0] instanceof PsiVariable) {
|
||||
invoke((PsiVariable)elements[0], project, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void invoke(PsiMethod method, final Project project, Editor editor) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (!PsiType.BOOLEAN.equals(returnType)) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("invert.boolean.wrong.type")), REFACTORING_NAME, HelpID.INVERT_BOOLEAN);
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiMethod superMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
|
||||
if (superMethod == null) return;
|
||||
method = superMethod;
|
||||
|
||||
new InvertBooleanDialog(method).show();
|
||||
}
|
||||
}
|
||||
-308
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightServicesUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.RecursiveCallLineMarkerProvider;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.rename.RenameUtil;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class InvertBooleanProcessor extends BaseRefactoringProcessor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.invertBoolean.InvertBooleanMethodProcessor");
|
||||
|
||||
private PsiNamedElement myElement;
|
||||
private final String myNewName;
|
||||
private final RenameProcessor myRenameProcessor;
|
||||
private final Map<UsageInfo, SmartPsiElementPointer> myToInvert = new HashMap<UsageInfo, SmartPsiElementPointer>();
|
||||
private final SmartPointerManager mySmartPointerManager;
|
||||
|
||||
public InvertBooleanProcessor(final PsiNamedElement namedElement, final String newName) {
|
||||
super(namedElement.getProject());
|
||||
myElement = namedElement;
|
||||
myNewName = newName;
|
||||
final Project project = namedElement.getProject();
|
||||
myRenameProcessor = Comparing.equal(namedElement.getName(), myNewName) ? null : new RenameProcessor(project, namedElement, newName, false, false);
|
||||
mySmartPointerManager = SmartPointerManager.getInstance(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
|
||||
return new InvertBooleanUsageViewDescriptor(myElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
|
||||
for (UsageInfo info : myToInvert.keySet()) {
|
||||
final PsiElement element = info.getElement();
|
||||
if (element instanceof PsiMethodReferenceExpression) {
|
||||
conflicts.putValue(element, "Method is used in method reference expression");
|
||||
}
|
||||
}
|
||||
|
||||
if (!conflicts.isEmpty()) {
|
||||
return showConflicts(conflicts, null);
|
||||
}
|
||||
|
||||
if (myRenameProcessor == null || myRenameProcessor.preprocessUsages(refUsages)) {
|
||||
prepareSuccessful();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageInfo[] findUsages() {
|
||||
final List<SmartPsiElementPointer> toInvert = new ArrayList<SmartPsiElementPointer>();
|
||||
|
||||
addRefsToInvert(toInvert, myElement);
|
||||
|
||||
if (myElement instanceof PsiMethod) {
|
||||
final Collection<PsiMethod> overriders = OverridingMethodsSearch.search((PsiMethod)myElement).findAll();
|
||||
if (myRenameProcessor != null) {
|
||||
for (PsiMethod overrider : overriders) {
|
||||
myRenameProcessor.addElement(overrider, myNewName);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<PsiMethod> allMethods = new HashSet<PsiMethod>(overriders);
|
||||
allMethods.add((PsiMethod)myElement);
|
||||
|
||||
for (PsiMethod method : allMethods) {
|
||||
method.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override public void visitReturnStatement(PsiReturnStatement statement) {
|
||||
final PsiExpression returnValue = statement.getReturnValue();
|
||||
if (returnValue != null && PsiType.BOOLEAN.equals(returnValue.getType())) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(returnValue));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {}
|
||||
});
|
||||
}
|
||||
} else if (myElement instanceof PsiParameter && ((PsiParameter)myElement).getDeclarationScope() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)((PsiParameter)myElement).getDeclarationScope();
|
||||
int index = method.getParameterList().getParameterIndex((PsiParameter)myElement);
|
||||
LOG.assertTrue(index >= 0);
|
||||
final Query<PsiReference> methodQuery = MethodReferencesSearch.search(method);
|
||||
final Collection<PsiReference> methodRefs = methodQuery.findAll();
|
||||
for (PsiReference ref : methodRefs) {
|
||||
PsiElement parent = ref.getElement().getParent();
|
||||
if (parent instanceof PsiAnonymousClass) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (parent instanceof PsiCall) {
|
||||
final PsiCall call = (PsiCall)parent;
|
||||
final PsiReferenceExpression methodExpression = call instanceof PsiMethodCallExpression ?
|
||||
((PsiMethodCallExpression)call).getMethodExpression() :
|
||||
null;
|
||||
final PsiExpressionList argumentList = call.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
if (index < args.length) {
|
||||
if (methodExpression == null ||
|
||||
canInvert(methodExpression, args[index] instanceof PsiReferenceExpression && ((PsiReferenceExpression)args[index]).resolve() == myElement)) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(args[index]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Collection<PsiMethod> overriders = OverridingMethodsSearch.search(method).findAll();
|
||||
for (PsiMethod overrider : overriders) {
|
||||
final PsiParameter overriderParameter = overrider.getParameterList().getParameters()[index];
|
||||
if (myRenameProcessor != null) {
|
||||
myRenameProcessor.addElement(overriderParameter, myNewName);
|
||||
}
|
||||
addRefsToInvert(toInvert, overriderParameter);
|
||||
}
|
||||
}
|
||||
|
||||
final UsageInfo[] renameUsages = myRenameProcessor != null ? myRenameProcessor.findUsages() : UsageInfo.EMPTY_ARRAY;
|
||||
|
||||
final SmartPsiElementPointer[] usagesToInvert = toInvert.toArray(new SmartPsiElementPointer[toInvert.size()]);
|
||||
|
||||
//merge rename and invert usages
|
||||
Map<PsiElement, UsageInfo> expressionsToUsages = new HashMap<PsiElement, UsageInfo>();
|
||||
List<UsageInfo> result = new ArrayList<UsageInfo>();
|
||||
for (UsageInfo renameUsage : renameUsages) {
|
||||
expressionsToUsages.put(renameUsage.getElement(), renameUsage);
|
||||
result.add(renameUsage);
|
||||
}
|
||||
|
||||
for (SmartPsiElementPointer pointer : usagesToInvert) {
|
||||
final PsiExpression expression = (PsiExpression)pointer.getElement();
|
||||
if (!expressionsToUsages.containsKey(expression)) {
|
||||
final UsageInfo usageInfo = new UsageInfo(expression);
|
||||
expressionsToUsages.put(expression, usageInfo);
|
||||
result.add(usageInfo); //fake UsageInfo
|
||||
myToInvert.put(usageInfo, pointer);
|
||||
} else {
|
||||
myToInvert.put(expressionsToUsages.get(expression), pointer);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new UsageInfo[result.size()]);
|
||||
}
|
||||
|
||||
private static boolean canInvert(PsiReferenceExpression methodExpression, boolean checkRecursive) {
|
||||
PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
|
||||
if (qualifierExpression == null || !"super".equals(qualifierExpression.getText())) {
|
||||
PsiElement parent = methodExpression.getParent();
|
||||
if (parent instanceof PsiMethodCallExpression) {
|
||||
return !(checkRecursive && RecursiveCallLineMarkerProvider.isRecursiveMethodCall((PsiMethodCallExpression)parent));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addRefsToInvert(final List<SmartPsiElementPointer> toInvert, final PsiNamedElement namedElement) {
|
||||
final Query<PsiReference> query = namedElement instanceof PsiMethod ?
|
||||
MethodReferencesSearch.search((PsiMethod)namedElement) :
|
||||
ReferencesSearch.search(namedElement);
|
||||
final Collection<PsiReference> refs = query.findAll();
|
||||
|
||||
for (PsiReference ref : refs) {
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression refExpr = (PsiReferenceExpression)element;
|
||||
PsiElement parent = refExpr.getParent();
|
||||
if (parent instanceof PsiAssignmentExpression && refExpr.equals(((PsiAssignmentExpression)parent).getLExpression())) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(((PsiAssignmentExpression)parent).getRExpression()));
|
||||
}
|
||||
else {
|
||||
if (namedElement instanceof PsiParameter) { //filter usages in super method calls
|
||||
PsiElement gParent = refExpr.getParent().getParent();
|
||||
if (gParent instanceof PsiMethodCallExpression) {
|
||||
if (!canInvert(((PsiMethodCallExpression)gParent).getMethodExpression(), true)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(refExpr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (namedElement instanceof PsiVariable) {
|
||||
final PsiExpression initializer = ((PsiVariable)namedElement).getInitializer();
|
||||
if (initializer != null) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(initializer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshElements(@NotNull PsiElement[] elements) {
|
||||
LOG.assertTrue(elements.length == 1 && elements[0] instanceof PsiMethod);
|
||||
myElement = (PsiMethod)elements[0];
|
||||
}
|
||||
|
||||
private static UsageInfo[] extractUsagesForElement(PsiElement element, UsageInfo[] usages) {
|
||||
final ArrayList<UsageInfo> extractedUsages = new ArrayList<UsageInfo>(usages.length);
|
||||
for (UsageInfo usage : usages) {
|
||||
if (usage instanceof MoveRenameUsageInfo) {
|
||||
MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo)usage;
|
||||
if (element.equals(usageInfo.getReferencedElement())) {
|
||||
extractedUsages.add(usageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedUsages.toArray(new UsageInfo[extractedUsages.size()]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void performRefactoring(@NotNull UsageInfo[] usages) {
|
||||
if (myRenameProcessor != null) {
|
||||
for (final PsiElement element : myRenameProcessor.getElements()) {
|
||||
try {
|
||||
RenameUtil.doRename(element, myRenameProcessor.getNewName(element), extractUsagesForElement(element, usages), myProject, null);
|
||||
}
|
||||
catch (final IncorrectOperationException e) {
|
||||
RenameUtil.showErrorMessage(e, element, myProject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (UsageInfo usage : usages) {
|
||||
final SmartPsiElementPointer pointerToInvert = myToInvert.get(usage);
|
||||
if (pointerToInvert != null) {
|
||||
PsiExpression expression = (PsiExpression)pointerToInvert.getElement();
|
||||
LOG.assertTrue(expression != null);
|
||||
if (expression.getParent() instanceof PsiMethodCallExpression) expression = (PsiExpression)expression.getParent();
|
||||
try {
|
||||
while (expression.getParent() instanceof PsiPrefixExpression &&
|
||||
((PsiPrefixExpression)expression.getParent()).getOperationTokenType() == JavaTokenType.EXCL) {
|
||||
expression = (PsiExpression)expression.getParent();
|
||||
}
|
||||
if (!(expression.getParent() instanceof PsiExpressionStatement)) {
|
||||
expression.replace(CodeInsightServicesUtil.invertCondition(expression));
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (myElement instanceof PsiField && ((PsiField)myElement).getInitializer() == null) {
|
||||
((PsiField)myElement).setInitializer(JavaPsiFacade.getElementFactory(myProject).createExpressionFromText("true", myElement));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCommandName() {
|
||||
return InvertBooleanHandler.REFACTORING_NAME;
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightServicesUtil;
|
||||
import com.intellij.codeInsight.daemon.impl.RecursiveCallLineMarkerProvider;
|
||||
import com.intellij.ide.util.SuperMethodWarningUtil;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.MethodReferencesSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JavaInvertBooleanDelegate extends InvertBooleanDelegate {
|
||||
@Override
|
||||
public boolean isVisibleOnElement(@NotNull PsiElement element) {
|
||||
return element instanceof PsiVariable || element instanceof PsiMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailableOnElement(@NotNull PsiElement element) {
|
||||
if (element instanceof PsiVariable) {
|
||||
return PsiType.BOOLEAN.equals(((PsiVariable) element).getType());
|
||||
}
|
||||
else if (element instanceof PsiMethod) {
|
||||
return PsiType.BOOLEAN.equals(((PsiMethod) element).getReturnType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement adjustElement(PsiElement element, Project project, Editor editor) {
|
||||
if (element instanceof PsiVariable) {
|
||||
PsiVariable var = (PsiVariable)element;
|
||||
final PsiType returnType = var.getType();
|
||||
if (!PsiType.BOOLEAN.equals(returnType)) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor,
|
||||
RefactoringBundle
|
||||
.getCannotRefactorMessage(RefactoringBundle.message("invert.boolean.wrong.type")),
|
||||
InvertBooleanHandler.REFACTORING_NAME, InvertBooleanHandler.INVERT_BOOLEAN_HELP_ID);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (var instanceof PsiParameter && ((PsiParameter)var).getDeclarationScope() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)((PsiParameter)var).getDeclarationScope();
|
||||
final PsiMethod superMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
|
||||
if (superMethod == null) {
|
||||
return null;
|
||||
}
|
||||
var = superMethod.getParameterList().getParameters()[method.getParameterList().getParameterIndex((PsiParameter)var)];
|
||||
}
|
||||
return var;
|
||||
}
|
||||
else if (element instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)element;
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (!PsiType.BOOLEAN.equals(returnType)) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor,
|
||||
RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("invert.boolean.wrong.type")),
|
||||
InvertBooleanHandler.REFACTORING_NAME,
|
||||
InvertBooleanHandler.INVERT_BOOLEAN_HELP_ID);
|
||||
return null;
|
||||
}
|
||||
|
||||
return SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void collectRefsToInvert(PsiElement namedElement, Collection<PsiElement> elementsToInvert) {
|
||||
final Query<PsiReference> query = namedElement instanceof PsiMethod ?
|
||||
MethodReferencesSearch.search((PsiMethod)namedElement) :
|
||||
ReferencesSearch.search(namedElement);
|
||||
final Collection<PsiReference> refs = query.findAll();
|
||||
|
||||
for (PsiReference ref : refs) {
|
||||
PsiElement refElement = null;
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression refExpr = (PsiReferenceExpression)element;
|
||||
PsiElement parent = refExpr.getParent();
|
||||
if (parent instanceof PsiAssignmentExpression && refExpr.equals(((PsiAssignmentExpression)parent).getLExpression())) {
|
||||
refElement = ((PsiAssignmentExpression)parent).getRExpression();
|
||||
}
|
||||
else {
|
||||
if (namedElement instanceof PsiParameter) { //filter usages in super method calls
|
||||
PsiElement gParent = refExpr.getParent().getParent();
|
||||
if (gParent instanceof PsiMethodCallExpression) {
|
||||
if (!canInvertReferenceElement(((PsiMethodCallExpression)gParent).getMethodExpression(), true)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
refElement = refExpr;
|
||||
}
|
||||
}
|
||||
if (refElement != null) {
|
||||
elementsToInvert.add(refElement);
|
||||
}
|
||||
}
|
||||
|
||||
if (namedElement instanceof PsiVariable) {
|
||||
final PsiExpression initializer = ((PsiVariable)namedElement).getInitializer();
|
||||
if (initializer != null) {
|
||||
elementsToInvert.add(initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canInvertReferenceElement(PsiElement expression, boolean recursive) {
|
||||
PsiExpression qualifierExpression = expression instanceof PsiReferenceExpression ? ((PsiReferenceExpression)expression).getQualifierExpression()
|
||||
: null;
|
||||
if (qualifierExpression == null || !"super".equals(qualifierExpression.getText())) {
|
||||
PsiElement parent = expression.getParent();
|
||||
if (parent instanceof PsiMethodCallExpression) {
|
||||
return !(recursive && RecursiveCallLineMarkerProvider.isRecursiveMethodCall((PsiMethodCallExpression)parent));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceWithNegatedExpression(@NotNull PsiElement expression) {
|
||||
if (expression.getParent() instanceof PsiMethodCallExpression) {
|
||||
expression = expression.getParent();
|
||||
}
|
||||
while (expression.getParent() instanceof PsiPrefixExpression &&
|
||||
((PsiPrefixExpression)expression.getParent()).getOperationTokenType() == JavaTokenType.EXCL) {
|
||||
expression = expression.getParent();
|
||||
}
|
||||
|
||||
if (!(expression.getParent() instanceof PsiExpressionStatement)) {
|
||||
expression.replace(CodeInsightServicesUtil.invertCondition((PsiExpression)expression));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invertDefaultElementInitializer(final PsiElement element) {
|
||||
if (element instanceof PsiField && ((PsiField)element).getInitializer() == null) {
|
||||
((PsiField)element).setInitializer(JavaPsiFacade.getElementFactory(element.getProject()).createExpressionFromText("true", element));
|
||||
}
|
||||
}
|
||||
|
||||
public void collectRefElements(final PsiElement element,
|
||||
final Collection<PsiElement> elementsToInvert,
|
||||
final RenameProcessor renameProcessor,
|
||||
@NotNull final String newName) {
|
||||
collectRefsToInvert(element, elementsToInvert);
|
||||
|
||||
if (element instanceof PsiMethod) {
|
||||
final Collection<PsiMethod> overriders = OverridingMethodsSearch.search((PsiMethod)element).findAll();
|
||||
if (renameProcessor != null) {
|
||||
for (PsiMethod overrider : overriders) {
|
||||
renameProcessor.addElement(overrider, newName);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<PsiMethod> allMethods = new HashSet<PsiMethod>(overriders);
|
||||
allMethods.add((PsiMethod)element);
|
||||
|
||||
for (PsiMethod method : allMethods) {
|
||||
method.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override public void visitReturnStatement(PsiReturnStatement statement) {
|
||||
final PsiExpression returnValue = statement.getReturnValue();
|
||||
if (returnValue != null && PsiType.BOOLEAN.equals(returnValue.getType())) {
|
||||
elementsToInvert.add(returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (element instanceof PsiParameter && ((PsiParameter)element).getDeclarationScope() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)((PsiParameter)element).getDeclarationScope();
|
||||
int index = method.getParameterList().getParameterIndex((PsiParameter)element);
|
||||
assert index >= 0;
|
||||
final Query<PsiReference> methodQuery = MethodReferencesSearch.search(method);
|
||||
final Collection<PsiReference> methodRefs = methodQuery.findAll();
|
||||
for (PsiReference ref : methodRefs) {
|
||||
PsiElement parent = ref.getElement().getParent();
|
||||
if (parent instanceof PsiAnonymousClass) {
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if (parent instanceof PsiCall) {
|
||||
final PsiCall call = (PsiCall)parent;
|
||||
final PsiReferenceExpression methodExpression = call instanceof PsiMethodCallExpression ?
|
||||
((PsiMethodCallExpression)call).getMethodExpression() :
|
||||
null;
|
||||
final PsiExpressionList argumentList = call.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
if (index < args.length) {
|
||||
if (methodExpression == null ||
|
||||
canInvertReferenceElement(methodExpression,
|
||||
args[index] instanceof PsiReferenceExpression &&
|
||||
((PsiReferenceExpression)args[index]).resolve() == element)) {
|
||||
elementsToInvert.add(args[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Collection<PsiMethod> overriders = OverridingMethodsSearch.search(method).findAll();
|
||||
for (PsiMethod overrider : overriders) {
|
||||
final PsiParameter overriderParameter = overrider.getParameterList().getParameters()[index];
|
||||
if (renameProcessor != null) {
|
||||
renameProcessor.addElement(overriderParameter, newName);
|
||||
}
|
||||
collectRefsToInvert(overriderParameter, elementsToInvert);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findConflicts(MultiMap<PsiElement, String> conflicts, UsageInfo[] usageInfos) {
|
||||
for (UsageInfo info : usageInfos) {
|
||||
final PsiElement element = info.getElement();
|
||||
if (element instanceof PsiMethodReferenceExpression) {
|
||||
conflicts.putValue(element, "Method is used in method reference expression");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class InvertBooleanDelegate {
|
||||
public static final ExtensionPointName<InvertBooleanDelegate> EP_NAME = ExtensionPointName.create("com.intellij.refactoring.invertBoolean");
|
||||
|
||||
/**
|
||||
* Quick check if element is potentially acceptable by delegate
|
||||
*
|
||||
* @return true if element is possible to invert, e.g. variable or method
|
||||
*/
|
||||
public abstract boolean isVisibleOnElement(@NotNull PsiElement element);
|
||||
|
||||
/**
|
||||
* @return true if element is of boolean type
|
||||
*/
|
||||
public abstract boolean isAvailableOnElement(@NotNull PsiElement element);
|
||||
|
||||
/**
|
||||
* Adjust element to invert, e.g. suggest to refactor super method instead of current
|
||||
*
|
||||
* @return null if user canceled the operation
|
||||
*/
|
||||
@Nullable
|
||||
public abstract PsiElement adjustElement(PsiElement element, Project project, Editor editor);
|
||||
|
||||
/**
|
||||
* Eventually collect additional elements to rename, e.g. override methods
|
||||
* and find expressions which need to be inverted
|
||||
*
|
||||
* @param renameProcessor null if element is not named or name was not changed
|
||||
*/
|
||||
public abstract void collectRefElements(PsiElement element,
|
||||
Collection<PsiElement> elementsToInvert,
|
||||
@Nullable RenameProcessor renameProcessor,
|
||||
@NotNull String newName);
|
||||
|
||||
/**
|
||||
* Replace expression with created negation
|
||||
* @param expression to be inverted, found in {@link #collectRefElements(PsiElement, Collection, RenameProcessor, String)}
|
||||
*/
|
||||
public abstract void replaceWithNegatedExpression(PsiElement expression);
|
||||
|
||||
/**
|
||||
* Initialize variable with negated default initializer when default was initially omitted
|
||||
*/
|
||||
public void invertDefaultElementInitializer(PsiElement var) {}
|
||||
|
||||
/**
|
||||
* Detect usages which can't be inverted
|
||||
*/
|
||||
public void findConflicts(MultiMap<PsiElement, String> conflicts,
|
||||
UsageInfo[] usageInfos) {}
|
||||
}
|
||||
+6
-6
@@ -18,8 +18,8 @@ package com.intellij.refactoring.invertBoolean;
|
||||
import com.intellij.lang.findUsages.DescriptiveNameUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
@@ -36,12 +36,12 @@ public class InvertBooleanDialog extends RefactoringDialog {
|
||||
private JLabel myLabel;
|
||||
private JLabel myCaptionLabel;
|
||||
|
||||
private final PsiNamedElement myElement;
|
||||
private final PsiElement myElement;
|
||||
|
||||
public InvertBooleanDialog(final PsiNamedElement element) {
|
||||
public InvertBooleanDialog(final PsiElement element) {
|
||||
super(element.getProject(), false);
|
||||
myElement = element;
|
||||
final String name = myElement.getName();
|
||||
final String name = myElement instanceof PsiNamedElement ? ((PsiNamedElement)myElement).getName() : myElement.getText();
|
||||
myNameField.setText(name);
|
||||
myLabel.setLabelFor(myNameField);
|
||||
final String typeString = UsageViewUtil.getType(myElement);
|
||||
@@ -65,7 +65,7 @@ public class InvertBooleanDialog extends RefactoringDialog {
|
||||
CommonRefactoringUtil.showErrorMessage(InvertBooleanHandler.REFACTORING_NAME,
|
||||
RefactoringBundle.message("please.enter.a.valid.name.for.inverted.element",
|
||||
UsageViewUtil.getType(myElement)),
|
||||
HelpID.INVERT_BOOLEAN, project);
|
||||
InvertBooleanHandler.INVERT_BOOLEAN_HELP_ID, project);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class InvertBooleanDialog extends RefactoringDialog {
|
||||
}
|
||||
|
||||
protected void doHelpAction() {
|
||||
HelpManager.getInstance().invokeHelp(HelpID.INVERT_BOOLEAN);
|
||||
HelpManager.getInstance().invokeHelp(InvertBooleanHandler.INVERT_BOOLEAN_HELP_ID);
|
||||
}
|
||||
|
||||
protected JComponent createCenterPanel() {
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2000-2013 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class InvertBooleanHandler implements RefactoringActionHandler {
|
||||
public static final String INVERT_BOOLEAN_HELP_ID = "refactoring.invertBoolean";
|
||||
static final String REFACTORING_NAME = RefactoringBundle.message("invert.boolean.title");
|
||||
private static final Logger LOG = Logger.getInstance("#" + InvertBooleanHandler.class.getName());
|
||||
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
|
||||
editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
|
||||
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
PsiElement namedElement = adjustElement(element, project, editor);
|
||||
if (namedElement == null) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(
|
||||
RefactoringBundle.message("error.wrong.caret.position.method.or.variable.name")), REFACTORING_NAME, INVERT_BOOLEAN_HELP_ID);
|
||||
return;
|
||||
}
|
||||
new InvertBooleanDialog(namedElement).show();
|
||||
}
|
||||
|
||||
public static PsiElement adjustElement(PsiElement element, Project project, Editor editor) {
|
||||
for (InvertBooleanDelegate delegate : Extensions.getExtensions(InvertBooleanDelegate.EP_NAME)) {
|
||||
if (delegate.isVisibleOnElement(element)) {
|
||||
return delegate.adjustElement(element, project, editor);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
|
||||
LOG.assertTrue(elements.length == 1);
|
||||
PsiElement element = adjustElement(elements[0], project, null);
|
||||
if (element == null) {
|
||||
CommonRefactoringUtil.showErrorHint(project, null, RefactoringBundle.getCannotRefactorMessage(
|
||||
RefactoringBundle.message("error.wrong.caret.position.method.or.variable.name")), REFACTORING_NAME, INVERT_BOOLEAN_HELP_ID);
|
||||
return;
|
||||
}
|
||||
new InvertBooleanDialog(element).show();
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.rename.RenameUtil;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
*/
|
||||
public class InvertBooleanProcessor extends BaseRefactoringProcessor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.invertBoolean.InvertBooleanMethodProcessor");
|
||||
private final InvertBooleanDelegate myDelegate;
|
||||
|
||||
private PsiElement myElement;
|
||||
private final String myNewName;
|
||||
private final RenameProcessor myRenameProcessor;
|
||||
private final Map<UsageInfo, SmartPsiElementPointer> myToInvert = new HashMap<UsageInfo, SmartPsiElementPointer>();
|
||||
private final SmartPointerManager mySmartPointerManager;
|
||||
|
||||
public InvertBooleanProcessor(final PsiElement namedElement, final String newName) {
|
||||
super(namedElement.getProject());
|
||||
myElement = namedElement;
|
||||
myNewName = newName;
|
||||
final Project project = namedElement.getProject();
|
||||
myRenameProcessor = !(namedElement instanceof PsiNamedElement) || Comparing.equal(((PsiNamedElement)namedElement).getName(), myNewName)
|
||||
? null : new RenameProcessor(project, namedElement, newName, false, false);
|
||||
mySmartPointerManager = SmartPointerManager.getInstance(project);
|
||||
myDelegate = findInvertBooleanDelegate(myElement);
|
||||
}
|
||||
|
||||
private static InvertBooleanDelegate findInvertBooleanDelegate(PsiElement element) {
|
||||
for (InvertBooleanDelegate delegate : Extensions.getExtensions(InvertBooleanDelegate.EP_NAME)) {
|
||||
if (delegate.isVisibleOnElement(element)) {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
LOG.error(element);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
|
||||
return new InvertBooleanUsageViewDescriptor(myElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
|
||||
myDelegate.findConflicts(conflicts, refUsages.get());
|
||||
|
||||
if (!conflicts.isEmpty()) {
|
||||
return showConflicts(conflicts, null);
|
||||
}
|
||||
|
||||
if (myRenameProcessor == null || myRenameProcessor.preprocessUsages(refUsages)) {
|
||||
prepareSuccessful();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageInfo[] findUsages() {
|
||||
final List<SmartPsiElementPointer> toInvert = new ArrayList<SmartPsiElementPointer>();
|
||||
|
||||
final LinkedHashSet<PsiElement> elementsToInvert = new LinkedHashSet<PsiElement>();
|
||||
myDelegate.collectRefElements(myElement, elementsToInvert, myRenameProcessor, myNewName);
|
||||
for (PsiElement element : elementsToInvert) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(element));
|
||||
}
|
||||
|
||||
final UsageInfo[] renameUsages = myRenameProcessor != null ? myRenameProcessor.findUsages() : UsageInfo.EMPTY_ARRAY;
|
||||
|
||||
final SmartPsiElementPointer[] usagesToInvert = toInvert.toArray(new SmartPsiElementPointer[toInvert.size()]);
|
||||
|
||||
//merge rename and invert usages
|
||||
Map<PsiElement, UsageInfo> expressionsToUsages = new HashMap<PsiElement, UsageInfo>();
|
||||
List<UsageInfo> result = new ArrayList<UsageInfo>();
|
||||
for (UsageInfo renameUsage : renameUsages) {
|
||||
expressionsToUsages.put(renameUsage.getElement(), renameUsage);
|
||||
result.add(renameUsage);
|
||||
}
|
||||
|
||||
for (SmartPsiElementPointer pointer : usagesToInvert) {
|
||||
final PsiElement expression = pointer.getElement();
|
||||
if (!expressionsToUsages.containsKey(expression)) {
|
||||
final UsageInfo usageInfo = new UsageInfo(expression);
|
||||
expressionsToUsages.put(expression, usageInfo);
|
||||
result.add(usageInfo); //fake UsageInfo
|
||||
myToInvert.put(usageInfo, pointer);
|
||||
} else {
|
||||
myToInvert.put(expressionsToUsages.get(expression), pointer);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new UsageInfo[result.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshElements(@NotNull PsiElement[] elements) {
|
||||
myElement = elements[0];
|
||||
}
|
||||
|
||||
private static UsageInfo[] extractUsagesForElement(PsiElement element, UsageInfo[] usages) {
|
||||
final ArrayList<UsageInfo> extractedUsages = new ArrayList<UsageInfo>(usages.length);
|
||||
for (UsageInfo usage : usages) {
|
||||
if (usage instanceof MoveRenameUsageInfo) {
|
||||
MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo)usage;
|
||||
if (element.equals(usageInfo.getReferencedElement())) {
|
||||
extractedUsages.add(usageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedUsages.toArray(new UsageInfo[extractedUsages.size()]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void performRefactoring(@NotNull UsageInfo[] usages) {
|
||||
if (myRenameProcessor != null) {
|
||||
for (final PsiElement element : myRenameProcessor.getElements()) {
|
||||
try {
|
||||
RenameUtil.doRename(element, myRenameProcessor.getNewName(element), extractUsagesForElement(element, usages), myProject, null);
|
||||
}
|
||||
catch (final IncorrectOperationException e) {
|
||||
RenameUtil.showErrorMessage(e, element, myProject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (UsageInfo usage : usages) {
|
||||
final SmartPsiElementPointer pointerToInvert = myToInvert.get(usage);
|
||||
if (pointerToInvert != null) {
|
||||
PsiElement element = pointerToInvert.getElement();
|
||||
LOG.assertTrue(element != null);
|
||||
try {
|
||||
myDelegate.replaceWithNegatedExpression(element);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myDelegate.invertDefaultElementInitializer(myElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCommandName() {
|
||||
return InvertBooleanHandler.REFACTORING_NAME;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -27,9 +27,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @author ven
|
||||
*/
|
||||
public class InvertBooleanUsageViewDescriptor implements UsageViewDescriptor {
|
||||
private final PsiNamedElement myElement;
|
||||
private final PsiElement myElement;
|
||||
|
||||
public InvertBooleanUsageViewDescriptor(final PsiNamedElement element) {
|
||||
public InvertBooleanUsageViewDescriptor(final PsiElement element) {
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
@@ -368,6 +368,7 @@
|
||||
|
||||
<extensionPoint name="refactoring.copyHandler" interface="com.intellij.refactoring.copy.CopyHandlerDelegate"/>
|
||||
<extensionPoint name="refactoring.moveHandler" interface="com.intellij.refactoring.move.MoveHandlerDelegate"/>
|
||||
<extensionPoint name="refactoring.invertBoolean" interface="com.intellij.refactoring.invertBoolean.InvertBooleanDelegate"/>
|
||||
<extensionPoint name="refactoring.moveDirectoryWithClassesHelper"
|
||||
interface="com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesHelper"/>
|
||||
|
||||
|
||||
@@ -319,6 +319,7 @@
|
||||
</group>
|
||||
|
||||
<action id="Inline" class="com.intellij.refactoring.actions.InlineAction"/>
|
||||
<action id="InvertBoolean" class="com.intellij.refactoring.actions.InvertBooleanAction"/>
|
||||
<separator/>
|
||||
<action id="MembersPullUp" class="com.intellij.refactoring.actions.PullUpAction"/>
|
||||
<action id="MemberPushDown" class="com.intellij.refactoring.actions.PushDownAction"/>
|
||||
|
||||
@@ -562,6 +562,7 @@
|
||||
<multiHostInjector implementation="com.jetbrains.python.codeInsight.PyTypingAnnotationInjector"/>
|
||||
|
||||
<lang.inspectionSuppressor language="Python" implementationClass="com.jetbrains.python.inspections.PyInspectionsSuppressor"/>
|
||||
<refactoring.invertBoolean implementation="com.jetbrains.python.refactoring.invertBoolean.PyInvertBooleanDelegate"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
@@ -765,10 +766,6 @@
|
||||
<add-to-group group-id="Internal"/>
|
||||
</action>
|
||||
|
||||
<action id="PyInvertBooleanAction" class="com.jetbrains.python.refactoring.invertBoolean.PyInvertBooleanAction" text="Invert Boolean">
|
||||
<add-to-group group-id="RefactoringMenu" anchor="last" />
|
||||
</action>
|
||||
|
||||
<action id="PyDebugger.ViewArray" class="com.jetbrains.python.debugger.array.PyViewArrayAction" text="View as Array">
|
||||
<add-to-group group-id="XDebugger.ValueGroup" anchor="after" relative-to-action="Debugger.Tree.AddToWatches"/>
|
||||
</action>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.refactoring.invertBoolean.PyInvertBooleanDialog">
|
||||
<grid id="3c0f9" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="54" y="99" width="434" height="60"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="5b95d" class="javax.swing.JLabel" binding="myLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<inheritsPopupMenu value="false"/>
|
||||
<nextFocusableComponent value=""/>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="ceab0" class="javax.swing.JTextField" binding="myNameField">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<clientProperties>
|
||||
<caretAspectRatio class="java.lang.Float" value="0.04"/>
|
||||
</clientProperties>
|
||||
</component>
|
||||
<component id="42aac" class="javax.swing.JLabel" binding="myCaptionLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value=""/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.actions.BaseRefactoringAction;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyInvertBooleanAction extends BaseRefactoringAction {
|
||||
@Override
|
||||
protected boolean isAvailableInEditorOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledOnElements(@NotNull PsiElement[] elements) {
|
||||
if (elements.length == 1) {
|
||||
return isApplicable(elements[0], elements[0].getContainingFile());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isApplicable(@NotNull final PsiElement element, @NotNull final PsiFile file) {
|
||||
final VirtualFile virtualFile = file.getVirtualFile();
|
||||
if (virtualFile != null && ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInLibraryClasses(virtualFile)) return false;
|
||||
if (element instanceof PyTargetExpression) {
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) {
|
||||
final PyExpression assignedValue = assignmentStatement.getAssignedValue();
|
||||
if (assignedValue == null) return false;
|
||||
final String name = assignedValue.getText();
|
||||
return name != null && (PyNames.TRUE.equals(name) || PyNames.FALSE.equals(name));
|
||||
}
|
||||
}
|
||||
if (element instanceof PyNamedParameter) {
|
||||
final PyExpression defaultValue = ((PyNamedParameter)element).getDefaultValue();
|
||||
if (defaultValue instanceof PyBoolLiteralExpression) return true;
|
||||
}
|
||||
return element.getParent() instanceof PyBoolLiteralExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAvailableOnElementInEditorAndFile(@NotNull final PsiElement element, @NotNull final Editor editor, @NotNull PsiFile file, @NotNull DataContext context) {
|
||||
return isApplicable(element, element.getContainingFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RefactoringActionHandler getHandler(@NotNull DataContext dataContext) {
|
||||
return new PyInvertBooleanHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAvailableForLanguage(Language language) {
|
||||
return language.isKindOf(PythonLanguage.getInstance());
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.invertBoolean.InvertBooleanDelegate;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class PyInvertBooleanDelegate extends InvertBooleanDelegate {
|
||||
@Override
|
||||
public boolean isVisibleOnElement(@NotNull PsiElement element) {
|
||||
final VirtualFile virtualFile = element.getContainingFile().getVirtualFile();
|
||||
if (virtualFile != null &&
|
||||
ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInLibraryClasses(virtualFile)) {
|
||||
return false;
|
||||
}
|
||||
if (element instanceof PyTargetExpression || element instanceof PyNamedParameter) {
|
||||
return true;
|
||||
}
|
||||
return element.getParent() instanceof PyBoolLiteralExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailableOnElement(@NotNull PsiElement element) {
|
||||
final VirtualFile virtualFile = element.getContainingFile().getVirtualFile();
|
||||
if (virtualFile != null && ProjectRootManager.getInstance(element.getProject()).getFileIndex().isInLibraryClasses(virtualFile)) return false;
|
||||
if (element instanceof PyTargetExpression) {
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) {
|
||||
final PyExpression assignedValue = assignmentStatement.getAssignedValue();
|
||||
if (assignedValue == null) return false;
|
||||
final String name = assignedValue.getText();
|
||||
return name != null && (PyNames.TRUE.equals(name) || PyNames.FALSE.equals(name));
|
||||
}
|
||||
}
|
||||
if (element instanceof PyNamedParameter) {
|
||||
final PyExpression defaultValue = ((PyNamedParameter)element).getDefaultValue();
|
||||
if (defaultValue instanceof PyBoolLiteralExpression) return true;
|
||||
}
|
||||
return element.getParent() instanceof PyBoolLiteralExpression;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement adjustElement(PsiElement element, Project project, Editor editor) {
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) {
|
||||
return assignmentStatement.getTargets()[0];
|
||||
}
|
||||
else if (element instanceof PyNamedParameter) {
|
||||
return element;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectRefElements(PsiElement psiElement,
|
||||
Collection<PsiElement> elementsToInvert,
|
||||
@Nullable RenameProcessor renameProcessor,
|
||||
@NotNull String newName) {
|
||||
final Collection<PsiReference> refs = ReferencesSearch.search(psiElement).findAll();
|
||||
|
||||
for (PsiReference ref : refs) {
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof PyTargetExpression) {
|
||||
final PyTargetExpression target = (PyTargetExpression)element;
|
||||
final PyAssignmentStatement parent = PsiTreeUtil.getParentOfType(target, PyAssignmentStatement.class);
|
||||
if (parent != null && parent.getTargets().length == 1) {
|
||||
final PyExpression value = parent.getAssignedValue();
|
||||
if (value != null)
|
||||
elementsToInvert.add(value);
|
||||
}
|
||||
}
|
||||
else if (element.getParent() instanceof PyPrefixExpression) {
|
||||
elementsToInvert.add(element.getParent());
|
||||
}
|
||||
else if (element instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression refExpr = (PyReferenceExpression)element;
|
||||
elementsToInvert.add(refExpr);
|
||||
}
|
||||
}
|
||||
|
||||
if (psiElement instanceof PyNamedParameter) {
|
||||
PyExpression defaultValue = ((PyNamedParameter)psiElement).getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
elementsToInvert.add(defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceWithNegatedExpression(PsiElement expression) {
|
||||
if (expression != null && PsiTreeUtil.getParentOfType(expression, PyImportStatementBase.class, false) == null) {
|
||||
final PyExpression replacement = invertExpression(expression);
|
||||
expression.replace(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PyExpression invertExpression(@NotNull final PsiElement expression) {
|
||||
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(expression.getProject());
|
||||
if (expression instanceof PyBoolLiteralExpression) {
|
||||
final String value = ((PyBoolLiteralExpression)expression).getValue() ? PyNames.FALSE : PyNames.TRUE;
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), value);
|
||||
}
|
||||
if (expression instanceof PyReferenceExpression && (PyNames.FALSE.equals(expression.getText()) ||
|
||||
PyNames.TRUE.equals(expression.getText()))) {
|
||||
|
||||
final String value = PyNames.TRUE.equals(expression.getText()) ? PyNames.FALSE : PyNames.TRUE;
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), value);
|
||||
}
|
||||
else if (expression instanceof PyPrefixExpression) {
|
||||
if (((PyPrefixExpression)expression).getOperator() == PyTokenTypes.NOT_KEYWORD) {
|
||||
final PyExpression operand = ((PyPrefixExpression)expression).getOperand();
|
||||
if (operand != null)
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), operand.getText());
|
||||
}
|
||||
}
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), "not " + expression.getText());
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.lang.findUsages.DescriptiveNameUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.rename.RenameUtil;
|
||||
import com.intellij.refactoring.ui.RefactoringDialog;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyInvertBooleanDialog extends RefactoringDialog {
|
||||
private JTextField myNameField;
|
||||
private JPanel myPanel;
|
||||
private JLabel myLabel;
|
||||
private JLabel myCaptionLabel;
|
||||
|
||||
private final PsiElement myElement;
|
||||
private final String myName;
|
||||
|
||||
public PyInvertBooleanDialog(final PsiElement element) {
|
||||
super(element.getProject(), false);
|
||||
myElement = element;
|
||||
myName = element instanceof PsiNamedElement ? ((PsiNamedElement)element).getName() : element.getText();
|
||||
myNameField.setText(myName);
|
||||
myLabel.setLabelFor(myNameField);
|
||||
final String typeString = UsageViewUtil.getType(myElement);
|
||||
myLabel.setText(RefactoringBundle.message("invert.boolean.name.of.inverted.element", typeString));
|
||||
myCaptionLabel.setText(RefactoringBundle.message("invert.0.1",
|
||||
typeString,
|
||||
DescriptiveNameUtil.getDescriptiveName(myElement)));
|
||||
|
||||
setTitle(PyInvertBooleanHandler.REFACTORING_NAME);
|
||||
init();
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myNameField;
|
||||
}
|
||||
|
||||
protected void doAction() {
|
||||
Project project = myElement.getProject();
|
||||
final String name = myNameField.getText().trim();
|
||||
if (name.length() == 0 || (!name.equals(myName) && !RenameUtil.isValidName(myProject, myElement, name))) {
|
||||
CommonRefactoringUtil.showErrorMessage(PyInvertBooleanHandler.REFACTORING_NAME,
|
||||
RefactoringBundle.message("please.enter.a.valid.name.for.inverted.element",
|
||||
UsageViewUtil.getType(myElement)),
|
||||
"refactoring.invertBoolean", project);
|
||||
return;
|
||||
}
|
||||
|
||||
invokeRefactoring(new PyInvertBooleanProcessor(myElement, name));
|
||||
}
|
||||
|
||||
protected JComponent createCenterPanel() {
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
return "reference.invert.boolean";
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringActionHandler;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.jetbrains.python.psi.PyAssignmentStatement;
|
||||
import com.jetbrains.python.psi.PyNamedParameter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyInvertBooleanHandler implements RefactoringActionHandler {
|
||||
static final String REFACTORING_NAME = RefactoringBundle.message("invert.boolean.title");
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
|
||||
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
if (element == null && editor != null && file != null) {
|
||||
element = file.findElementAt(editor.getCaretModel().getOffset());
|
||||
}
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(element, PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) {
|
||||
invoke(assignmentStatement.getTargets()[0]);
|
||||
}
|
||||
else if (element instanceof PyNamedParameter) {
|
||||
invoke(element);
|
||||
}
|
||||
else {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(
|
||||
RefactoringBundle.message("error.wrong.caret.position.local.or.expression.name")), REFACTORING_NAME, "refactoring.invertBoolean");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
|
||||
if (elements.length == 1) {
|
||||
final PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(elements[0], PyAssignmentStatement.class);
|
||||
if (assignmentStatement != null) {
|
||||
invoke(assignmentStatement.getTargets()[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void invoke(@NotNull final PsiElement element) {
|
||||
new PyInvertBooleanDialog(element).show();
|
||||
}
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.rename.RenameProcessor;
|
||||
import com.intellij.refactoring.rename.RenameUtil;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyInvertBooleanProcessor extends BaseRefactoringProcessor {
|
||||
private PsiElement myElement;
|
||||
private String myNewName;
|
||||
private final RenameProcessor myRenameProcessor;
|
||||
private final Map<UsageInfo, SmartPsiElementPointer> myToInvert = new HashMap<UsageInfo, SmartPsiElementPointer>();
|
||||
private final SmartPointerManager mySmartPointerManager;
|
||||
|
||||
public PyInvertBooleanProcessor(@NotNull final PsiElement namedElement, @NotNull final String newName) {
|
||||
super(namedElement.getProject());
|
||||
myElement = namedElement;
|
||||
myNewName = newName;
|
||||
mySmartPointerManager = SmartPointerManager.getInstance(myProject);
|
||||
myRenameProcessor = new RenameProcessor(myProject, namedElement, newName, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageViewDescriptor createUsageViewDescriptor(@NotNull UsageInfo[] usages) {
|
||||
return new PyInvertBooleanUsageViewDescriptor(myElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean preprocessUsages(@NotNull Ref<UsageInfo[]> refUsages) {
|
||||
if (!myNewName.equals(myElement instanceof PsiNamedElement ? ((PsiNamedElement)myElement).getName() : myElement.getText())) {
|
||||
if (myRenameProcessor.preprocessUsages(refUsages)) {
|
||||
prepareSuccessful();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
prepareSuccessful();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected UsageInfo[] findUsages() {
|
||||
final List<SmartPsiElementPointer> toInvert = new ArrayList<SmartPsiElementPointer>();
|
||||
|
||||
addRefsToInvert(toInvert, myElement);
|
||||
|
||||
final UsageInfo[] renameUsages = myRenameProcessor.findUsages();
|
||||
|
||||
final Map<PsiElement, UsageInfo> expressionsToUsages = new HashMap<PsiElement, UsageInfo>();
|
||||
final List<UsageInfo> result = new ArrayList<UsageInfo>();
|
||||
for (UsageInfo renameUsage : renameUsages) {
|
||||
expressionsToUsages.put(renameUsage.getElement(), renameUsage);
|
||||
result.add(renameUsage);
|
||||
}
|
||||
|
||||
for (SmartPsiElementPointer pointer : toInvert) {
|
||||
final PyExpression expression = (PyExpression)pointer.getElement();
|
||||
if (!expressionsToUsages.containsKey(expression) && expression != null) {
|
||||
final UsageInfo usageInfo = new UsageInfo(expression);
|
||||
expressionsToUsages.put(expression, usageInfo);
|
||||
result.add(usageInfo);
|
||||
myToInvert.put(usageInfo, pointer);
|
||||
} else {
|
||||
myToInvert.put(expressionsToUsages.get(expression), pointer);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toArray(new UsageInfo[result.size()]);
|
||||
}
|
||||
|
||||
private void addRefsToInvert(@NotNull final List<SmartPsiElementPointer> toInvert, @NotNull final PsiElement psiElement) {
|
||||
final Collection<PsiReference> refs = ReferencesSearch.search(psiElement).findAll();
|
||||
|
||||
for (PsiReference ref : refs) {
|
||||
final PsiElement element = ref.getElement();
|
||||
if (element instanceof PyTargetExpression) {
|
||||
final PyTargetExpression target = (PyTargetExpression)element;
|
||||
final PyAssignmentStatement parent = PsiTreeUtil.getParentOfType(target, PyAssignmentStatement.class);
|
||||
if (parent != null && parent.getTargets().length == 1) {
|
||||
final PyExpression value = parent.getAssignedValue();
|
||||
if (value != null)
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(value));
|
||||
}
|
||||
}
|
||||
else if (element.getParent() instanceof PyPrefixExpression) {
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(element.getParent()));
|
||||
}
|
||||
else if (element instanceof PyReferenceExpression) {
|
||||
final PyReferenceExpression refExpr = (PyReferenceExpression)element;
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(refExpr));
|
||||
}
|
||||
}
|
||||
if (psiElement instanceof PyNamedParameter) {
|
||||
final PyExpression defaultValue = ((PyNamedParameter)psiElement).getDefaultValue();
|
||||
if (defaultValue != null)
|
||||
toInvert.add(mySmartPointerManager.createSmartPsiElementPointer(defaultValue));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static UsageInfo[] extractUsagesForElement(@NotNull final PsiElement element, @NotNull final UsageInfo[] usages) {
|
||||
final ArrayList<UsageInfo> extractedUsages = new ArrayList<UsageInfo>(usages.length);
|
||||
for (UsageInfo usage : usages) {
|
||||
if (usage instanceof MoveRenameUsageInfo) {
|
||||
MoveRenameUsageInfo usageInfo = (MoveRenameUsageInfo)usage;
|
||||
if (element.equals(usageInfo.getReferencedElement())) {
|
||||
extractedUsages.add(usageInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedUsages.toArray(new UsageInfo[extractedUsages.size()]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void performRefactoring(@NotNull UsageInfo[] usages) {
|
||||
for (final PsiElement element : myRenameProcessor.getElements()) {
|
||||
try {
|
||||
RenameUtil.doRename(element, myRenameProcessor.getNewName(element), extractUsagesForElement(element, usages), myProject, null);
|
||||
}
|
||||
catch (final IncorrectOperationException e) {
|
||||
RenameUtil.showErrorMessage(e, element, myProject);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (UsageInfo usage : usages) {
|
||||
final SmartPsiElementPointer pointerToInvert = myToInvert.get(usage);
|
||||
if (pointerToInvert != null) {
|
||||
PsiElement expression = pointerToInvert.getElement();
|
||||
if (expression != null && PsiTreeUtil.getParentOfType(expression, PyImportStatementBase.class, false) == null) {
|
||||
final PyExpression replacement = invertExpression(expression);
|
||||
expression.replace(replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PyExpression invertExpression(@NotNull final PsiElement expression) {
|
||||
final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(myProject);
|
||||
if (expression instanceof PyBoolLiteralExpression) {
|
||||
final String value = ((PyBoolLiteralExpression)expression).getValue() ? PyNames.FALSE : PyNames.TRUE;
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), value);
|
||||
}
|
||||
if (expression instanceof PyReferenceExpression && (PyNames.FALSE.equals(expression.getText()) ||
|
||||
PyNames.TRUE.equals(expression.getText()))) {
|
||||
|
||||
final String value = PyNames.TRUE.equals(expression.getText()) ? PyNames.FALSE : PyNames.TRUE;
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), value);
|
||||
}
|
||||
else if (expression instanceof PyPrefixExpression) {
|
||||
if (((PyPrefixExpression)expression).getOperator() == PyTokenTypes.NOT_KEYWORD) {
|
||||
final PyExpression operand = ((PyPrefixExpression)expression).getOperand();
|
||||
if (operand != null)
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), operand.getText());
|
||||
}
|
||||
}
|
||||
return elementGenerator.createExpressionFromText(LanguageLevel.forElement(expression), "not " + expression.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCommandName() {
|
||||
return PyInvertBooleanHandler.REFACTORING_NAME;
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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.jetbrains.python.refactoring.invertBoolean;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.usageView.UsageViewBundle;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyInvertBooleanUsageViewDescriptor implements UsageViewDescriptor {
|
||||
private final PsiElement myElement;
|
||||
|
||||
public PyInvertBooleanUsageViewDescriptor(final PsiElement element) {
|
||||
myElement = element;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiElement[] getElements() {
|
||||
return new PsiElement[] {myElement};
|
||||
}
|
||||
|
||||
public String getProcessedElementsHeader() {
|
||||
return RefactoringBundle.message("invert.boolean.elements.header", UsageViewUtil.getType(myElement));
|
||||
}
|
||||
|
||||
public String getCodeReferencesText(int usagesCount, int filesCount) {
|
||||
return RefactoringBundle.message("invert.boolean.refs.to.invert", UsageViewBundle.getReferencesString(usagesCount, filesCount));
|
||||
}
|
||||
|
||||
public String getCommentReferencesText(int usagesCount, int filesCount) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,9 @@ import com.google.common.collect.Lists;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNamedElement;
|
||||
import com.intellij.refactoring.invertBoolean.InvertBooleanProcessor;
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.jetbrains.python.fixtures.PyTestCase;
|
||||
import com.jetbrains.python.refactoring.invertBoolean.PyInvertBooleanProcessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -52,7 +52,7 @@ public class PyInvertBooleanTest extends PyTestCase {
|
||||
final PsiNamedElement target = (PsiNamedElement)element;
|
||||
final String name = target.getName();
|
||||
assertNotNull(name);
|
||||
new PyInvertBooleanProcessor(target, "not"+ StringUtil.toTitleCase(name)).run();
|
||||
new InvertBooleanProcessor(target, "not" + StringUtil.toTitleCase(name)).run();
|
||||
myFixture.checkResultByFile("refactoring/invertBoolean/" + getTestName(true) + ".after.py");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1685,6 +1685,7 @@
|
||||
<lang.inspectionSuppressor language="JAVA" implementationClass="com.intellij.codeInspection.SuppressManagerImpl"/>
|
||||
<refactoring.moveInnerClassUsagesHandler language="JAVA" implementationClass="com.intellij.refactoring.move.moveInner.MoveInnerClassJavaUsagesHandler" id="java"/>
|
||||
<actionPromoter implementation="com.intellij.execution.testframework.TestTreeViewActionsPromoter"/>
|
||||
<refactoring.invertBoolean implementation="com.intellij.refactoring.invertBoolean.JavaInvertBooleanDelegate"/>
|
||||
</extensions>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -60,7 +60,6 @@
|
||||
<group id="RefactoringMenu2">
|
||||
<action id="MethodDuplicates" class="com.intellij.refactoring.actions.MethodDuplicatesAction"/>
|
||||
|
||||
<action id="InvertBoolean" class="com.intellij.refactoring.actions.InvertBooleanAction"/>
|
||||
<add-to-group group-id="RefactoringMenu" anchor="after" relative-to-action="Inline"/>
|
||||
</group>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user