fold as closures anonymous classes with a single implemented method, as long they... phpstorm/163.5757
authorpeter <peter@jetbrains.com>
Wed, 5 Oct 2016 10:41:18 +0000 (12:41 +0200)
committerpeter <peter@jetbrains.com>
Wed, 5 Oct 2016 10:44:21 +0000 (12:44 +0200)
java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/ClosureFolding.java
java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java
java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFolding8Test.groovy

index 78338f57623f8c5a7dc521aff4565559e0a46301..8d8408a6f12cc85d49b3d10a4ea5756919c5004a 100644 (file)
@@ -75,10 +75,7 @@ class ClosureFolding {
     String contents = getClosureContents(rangeStart, rangeEnd, seq);
     if (contents == null) return null;
 
-    String methodName = shouldShowMethodName() ? myMethod.getName() : "";
-    if (StringUtil.isEmpty(methodName) && PsiUtil.isLanguageLevel8OrHigher(myAnonymousClass)) return null;
-
-    String header = getFoldingHeader(methodName);
+    String header = getFoldingHeader();
     if (showSingleLineFolding(document, contents, header)) {
       return createDescriptors(classRBrace, trimStartSpaces(seq, rangeStart), trimTailSpaces(seq, rangeEnd), header + " ", " }");
     }
@@ -149,8 +146,8 @@ class ClosureFolding {
     return seq.subSequence(firstLineStart, lastLineEnd).toString();
   }
 
-  @NotNull
-  private String getFoldingHeader(String methodName) {
+  private String getFoldingHeader() {
+    String methodName = shouldShowMethodName() ? myMethod.getName() : "";
     String type = myQuick ? "" : getOptionalLambdaType();
     String params = StringUtil.join(myMethod.getParameterList().getParameters(), new Function<PsiParameter, String>() {
       @Override
@@ -166,7 +163,7 @@ class ClosureFolding {
     PsiElement parent = anonymousClass.getParent();
     if (parent instanceof PsiNewExpression && hasNoArguments((PsiNewExpression)parent)) {
       PsiClass baseClass = quick ? null : anonymousClass.getBaseClassType().resolve();
-      if (hasOnlyOneLambdaMethod(anonymousClass, !quick) && (quick || seemsLikeLambda(baseClass))) {
+      if (hasOnlyOneLambdaMethod(anonymousClass, !quick) && (quick || seemsLikeLambda(baseClass, anonymousClass))) {
         PsiMethod method = anonymousClass.getMethods()[0];
         PsiCodeBlock body = method.getBody();
         if (body != null) {
@@ -214,8 +211,14 @@ class ClosureFolding {
     return true;
   }
 
-  static boolean seemsLikeLambda(@Nullable PsiClass baseClass) {
-    return baseClass != null && PsiUtil.hasDefaultConstructor(baseClass, true);
+  static boolean seemsLikeLambda(@Nullable PsiClass baseClass, @NotNull PsiElement context) {
+    if (baseClass == null || !PsiUtil.hasDefaultConstructor(baseClass, true)) return false;
+
+    if (PsiUtil.isLanguageLevel8OrHigher(context) && LambdaUtil.isFunctionalClass(baseClass)) {
+      return false;
+    }
+
+    return true;
   }
 
   private String getOptionalLambdaType() {
index e93a6f9ead74b80c0ea2e36a58eda51a572e098d..b957e79c670f0988d4ff69955223560041b70611 100644 (file)
@@ -329,7 +329,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
       if (anonymousClass != null) {
         classReference = anonymousClass.getBaseClassReference();
 
-        if (quick || ClosureFolding.seemsLikeLambda(anonymousClass.getSuperClass())) {
+        if (quick || ClosureFolding.seemsLikeLambda(anonymousClass.getSuperClass(), anonymousClass)) {
           return;
         }
       }
index 3b8f58faa6d988de767568ca45b2c90be9f9c2af..132e836a7bb3185fb7f34568fe27106582bfb212 100644 (file)
@@ -78,6 +78,25 @@ class Test {
     assert !foldingModel.getCollapsedRegionAtOffset(text.indexOf("Runnable2("))
   }
 
+  void "test closure folding when implementing a single abstract method in a class"() {
+    myFixture.addClass('abstract class MyAction { public abstract void run(); }')
+    def text = """\
+class Test {
+  void test() {
+    MyAction action = new MyAction() {
+      public void run() {
+        System.out.println();
+      }
+    }
+  }
+}
+"""
+    configure text
+    def foldingModel = myFixture.editor.foldingModel as FoldingModelImpl
+
+    assert foldingModel.getCollapsedRegionAtOffset(text.indexOf("MyAction("))?.placeholderText == '() ' + JavaFoldingBuilder.rightArrow + ' { '
+  }
+
   private def configure(String text) {
     myFixture.configureByText("a.java", text)
     CodeFoldingManagerImpl.getInstance(getProject()).buildInitialFoldings(myFixture.editor)