diff --git a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java index a0316253221b..e33b90bab9aa 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java +++ b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java @@ -36,6 +36,5 @@ public class JavaCodeFoldingOptionsProvider extends BeanConfigurable elements, @NotNull Collection result) { - final Set recMethods = new HashSet(); + public void collectSlowLineMarkers(@NotNull List elements, + @NotNull Collection result) { + final Set statements = new HashSet(); for (PsiElement element : elements) { if (element instanceof PsiMethodCallExpression) { final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element; - final PsiMethod method = methodCall.resolveMethod(); - if (method != null && !recMethods.contains(method) && RecursionUtil.isRecursiveMethodCall(methodCall)) { - recMethods.add(method); - result.add(RecursiveMethodMarkerInfo.create(method)); + final PsiStatement statement = PsiTreeUtil.getParentOfType(methodCall, PsiStatement.class, true, PsiMethod.class); + if (!statements.contains(statement) && isRecursiveMethodCall(methodCall)) { + statements.add(statement); + result.add(new RecursiveMethodCallMarkerInfo(methodCall)); } } } } - @NotNull - private static List getRecursiveMethodCalls(final @NotNull PsiMethod method) { - final List result = new ArrayList(); - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - method.accept(new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - if (RecursionUtil.isRecursiveMethodCall(expression)) { - result.add(expression); - } - super.visitMethodCallExpression(expression); - } - }); - } - }); - return result; - } - - private static class RecursiveMethodMarkerInfo extends LineMarkerInfo { - public RecursiveMethodMarkerInfo(PsiMethod method, - TextRange range, - Icon icon, - int markers, - Function constant, - GutterIconNavigationHandler handler, - GutterIconRenderer.Alignment left) { - super(method, range, icon, markers, constant, handler, left); + public static boolean isRecursiveMethodCall(@NotNull PsiMethodCallExpression methodCall) { + final PsiMethod method = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); + if (method == null) { + return false; } - @NotNull - public static RecursiveMethodMarkerInfo create(@NotNull PsiMethod method){ - final PsiIdentifier identifier = method.getNameIdentifier(); - return new RecursiveMethodMarkerInfo(method, - identifier != null ? identifier.getTextRange() : method.getTextRange(), - RECURSIVE_METHOD_ICON, - Pass.UPDATE_OVERRIDEN_MARKERS, - FunctionUtil.constant("Potentially recursive method"), - getNavigationHandler(method), - GutterIconRenderer.Alignment.LEFT + final PsiMethod resolvedMethod = methodCall.resolveMethod(); + + if (!Comparing.equal(method, resolvedMethod)) { + return false; + } + final PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); + return qualifier == null || qualifier instanceof PsiThisExpression; + } + + private static class RecursiveMethodCallMarkerInfo extends LineMarkerInfo { + private RecursiveMethodCallMarkerInfo(@NotNull PsiMethodCallExpression methodCall) { + super(methodCall, + methodCall.getTextRange(), + RECURSIVE_METHOD_ICON, + Pass.UPDATE_OVERRIDEN_MARKERS, + FunctionUtil.constant("Recursive call"), + null, + GutterIconRenderer.Alignment.RIGHT ); } - - private static GutterIconNavigationHandler getNavigationHandler(final @NotNull PsiMethod method) { - return new GutterIconNavigationHandler() { + @Override + public GutterIconRenderer createGutterRenderer() { + if (myIcon == null) return null; + return new LineMarkerGutterIconRenderer(this){ @Override - public void navigate(@NotNull MouseEvent e, PsiMethod elt) { - final List calls = getRecursiveMethodCalls(method); - if (calls.size() == 1) { - navigateToMethodCall(calls.get(0)); - } - else { - showPopup(e, calls); - } - } - }; - } - - private static void showPopup(@NotNull MouseEvent e, @NotNull List calls) { - final JBList list = new JBList(calls); - list.setFixedCellHeight(20); - list.installCellRenderer(createCellRenderer()); - JBPopupFactory.getInstance(). - createListPopupBuilder(list). - setItemChoosenCallback(createItemChosenCallback(e, list)). - createPopup().show(new RelativePoint(e)); - } - - - @NotNull - private static Runnable createItemChosenCallback(final MouseEvent e, final @NotNull JBList list) { - return new Runnable() { - @Override - public void run() { - final Object value = list.getSelectedValue(); - if (!(value instanceof PsiMethodCallExpression)) { - return; - } - navigateToMethodCall((PsiMethodCallExpression)value); - } - }; - } - - private static void navigateToMethodCall(@NotNull PsiMethodCallExpression methodCall) { - final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(methodCall.getMethodExpression(), PsiIdentifier.class); - if (identifier != null) { - navigateTo(identifier); - }else { - navigateTo(methodCall); - } - } - - private static void navigateTo(@NotNull PsiElement element) { - final Editor editor = PsiUtilBase.findEditor(element); - if (editor == null) return; - - editor.getCaretModel().moveToOffset(element.getTextRange().getStartOffset()); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - } - - - @NotNull - private static NotNullFunction createCellRenderer() { - return new NotNullFunction() { - @NotNull - @Override - public JComponent fun(Object o) { - if (!(o instanceof PsiMethodCallExpression)) { - return new JBLabel(); - } - - final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)o; - String text = StringUtil.first(methodCall.getText(), 100, true).replace('\n', ' '); - - return new JBLabel(text, RECURSIVE_METHOD_ICON, SwingConstants.LEFT); + public AnAction getClickAction() { + return null; // to place breakpoint on mouse click } }; } diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsImpl.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsImpl.java index 82b2bc7cd7d1..918d1f365626 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsImpl.java @@ -165,16 +165,6 @@ public class JavaCodeFoldingSettingsImpl extends JavaCodeFoldingSettings impleme COLLAPSE_END_OF_LINE_COMMENTS = value; } - @Override - public boolean isCollapseRecursiveMethodCalls() { - return COLLAPSE_RECURSIVE_METHOD_CALLS; - } - - @Override - public void setCollapseRecursiveMethodCalls(boolean value) { - COLLAPSE_RECURSIVE_METHOD_CALLS = value; - } - @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_INNER_CLASSES = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANONYMOUS_CLASSES = false; @@ -184,7 +174,6 @@ public class JavaCodeFoldingSettingsImpl extends JavaCodeFoldingSettings impleme @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_I18N_MESSAGES = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_SUPPRESS_WARNINGS = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_END_OF_LINE_COMMENTS = false; - @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_RECURSIVE_METHOD_CALLS = false; @Override @NotNull diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/RecursiveMethodCallFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/RecursiveMethodCallFoldingBuilder.java deleted file mode 100644 index 126c1b7f6378..000000000000 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/RecursiveMethodCallFoldingBuilder.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2000-2012 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInsight.folding.impl; - -import com.intellij.codeInsight.RecursionUtil; -import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; -import com.intellij.lang.ASTNode; -import com.intellij.lang.folding.FoldingBuilderEx; -import com.intellij.lang.folding.FoldingDescriptor; -import com.intellij.openapi.editor.Document; -import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Danila Ponomarenko - */ -public class RecursiveMethodCallFoldingBuilder extends FoldingBuilderEx { - @NotNull - @Override - public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, boolean quick) { - if (!(root instanceof PsiJavaFile) || quick || !JavaCodeFoldingSettings.getInstance().isCollapseRecursiveMethodCalls()) { - return FoldingDescriptor.EMPTY; - } - final List result = new ArrayList(); - root.accept( - new JavaRecursiveElementWalkingVisitor() { - @Override - public void visitMethodCallExpression(PsiMethodCallExpression expression) { - if (RecursionUtil.isRecursiveMethodCall(expression)) { - final PsiIdentifier identifier = PsiTreeUtil.getChildOfType(expression.getMethodExpression(), PsiIdentifier.class); - if (identifier != null) { - result.add(new FoldingDescriptor(identifier, identifier.getTextRange())); - } - } - super.visitMethodCallExpression(expression); - } - } - ); - - return result.toArray(new FoldingDescriptor[result.size()]); - } - - @Override - public boolean isCollapsedByDefault(@NotNull ASTNode node) { - return JavaCodeFoldingSettings.getInstance().isCollapseRecursiveMethodCalls(); - } - - private static final String ANTICLOCKWISE_GAPPED_CIRCLE_ARROW = "\u27F2"; //⟲ - - @Override - public String getPlaceholderText(@NotNull ASTNode node) { - final PsiElement element = node.getPsi(); - - if (element instanceof PsiIdentifier) { - final PsiIdentifier identifier = (PsiIdentifier)element; - return ANTICLOCKWISE_GAPPED_CIRCLE_ARROW + identifier.getText(); - } - - return element.getText(); - } -} diff --git a/java/openapi/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java b/java/openapi/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java index f0325b5506f4..585ce02a81f6 100644 --- a/java/openapi/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java +++ b/java/openapi/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java @@ -62,7 +62,4 @@ public abstract class JavaCodeFoldingSettings { public abstract boolean isCollapseEndOfLineComments(); public abstract void setCollapseEndOfLineComments(boolean value); - - public abstract boolean isCollapseRecursiveMethodCalls(); - public abstract void setCollapseRecursiveMethodCalls(boolean value); } diff --git a/platform/icons/src/gutter/recursiveMethod.png b/platform/icons/src/gutter/recursiveMethod.png index d5c3702009d6..f74592556633 100644 Binary files a/platform/icons/src/gutter/recursiveMethod.png and b/platform/icons/src/gutter/recursiveMethod.png differ diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index 145f5ab1b536..c8f43e12f7c8 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -348,7 +348,6 @@ checkbox.collapse.method.bodies=Method bodies checkbox.collapse.javadoc.comments=Documentation comments checkbox.collapse.title.imports=Imports checkbox.collapse.file.header=File header -checkbox.collapse.recursive.method.calls=Recursive method calls label.collapse.by.default=Collapse by default: checkbox.show.code.folding.outline=Show code folding outline group.tab.appearance=Tab Appearance diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 9306ee852f97..0c7ab629edb4 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -749,7 +749,6 @@ -