invert boolean api

This commit is contained in:
Anna Kozlova
2015-08-26 12:08:51 +03:00
parent 56814d0df8
commit 7a25539900
24 changed files with 776 additions and 959 deletions
@@ -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();
}
}
@@ -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;
}
}
@@ -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");
}
}
}
}
@@ -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) {}
}
@@ -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() {
@@ -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();
}
}
@@ -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;
}
}
@@ -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"/>
+1 -4
View File
@@ -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());
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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");
}
}
+1
View File
@@ -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>
-1
View File
@@ -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>