mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
show lambdas in File Structure (IDEA-151616; IDEA-157809; IDEA-151429)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.hint;
|
||||
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiLambdaExpression;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LambdaDeclarationRangeHandler implements DeclarationRangeHandler {
|
||||
@Override
|
||||
@NotNull
|
||||
public TextRange getDeclarationRange(@NotNull final PsiElement container) {
|
||||
final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)container;
|
||||
return lambdaExpression.getParameterList().getTextRange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.util;
|
||||
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.*;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PsiLambdaNameHelper {
|
||||
private static final Key<ParameterizedCachedValue<Map<PsiLambdaExpression, String>, PsiClass>> LAMBDA_NAME = Key.create("ANONYMOUS_CLASS_NAME");
|
||||
|
||||
@Nullable
|
||||
public static String getVMName(@NotNull PsiLambdaExpression lambdaExpression) {
|
||||
final PsiClass upper = PsiTreeUtil.getParentOfType(lambdaExpression, PsiClass.class);
|
||||
if (upper == null) {
|
||||
return null;
|
||||
}
|
||||
ParameterizedCachedValue<Map<PsiLambdaExpression, String>, PsiClass> value = upper.getUserData(LAMBDA_NAME);
|
||||
if (value == null) {
|
||||
value = CachedValuesManager.getManager(upper.getProject()).createParameterizedCachedValue(
|
||||
new ParameterizedCachedValueProvider<Map<PsiLambdaExpression, String>, PsiClass>() {
|
||||
@Override
|
||||
public CachedValueProvider.Result<Map<PsiLambdaExpression, String>> compute(final PsiClass upper) {
|
||||
final Map<PsiLambdaExpression, String> map = new THashMap<PsiLambdaExpression, String>();
|
||||
upper.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
int index;
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
map.put(expression, "$" + index++);
|
||||
super.visitLambdaExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
if (aClass == upper) {
|
||||
super.visitClass(aClass);
|
||||
}
|
||||
}
|
||||
});
|
||||
return CachedValueProvider.Result.create(map, upper);
|
||||
}
|
||||
}, false);
|
||||
upper.putUserData(LAMBDA_NAME, value);
|
||||
}
|
||||
return "lambda" + getLambdaPrefix(lambdaExpression) + value.getValue(upper).get(lambdaExpression);
|
||||
}
|
||||
|
||||
public static String getLambdaPrefix(@NotNull PsiLambdaExpression lambdaExpression) {
|
||||
PsiMember member = PsiTreeUtil.getParentOfType(lambdaExpression, PsiMethod.class, PsiClass.class, PsiField.class);
|
||||
final String methodPrefix;
|
||||
if (member instanceof PsiMethod) {
|
||||
methodPrefix = member.getContainingClass() instanceof PsiAnonymousClass ? "" : "$" + member.getName();
|
||||
}
|
||||
else if (member instanceof PsiField && member.getContainingClass() instanceof PsiAnonymousClass) {
|
||||
methodPrefix = "";
|
||||
}
|
||||
else {
|
||||
//inside class initializer everywhere or field in a named class
|
||||
methodPrefix = "$new";
|
||||
}
|
||||
return methodPrefix;
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,9 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class JavaFileTreeModel extends TextEditorBasedStructureViewModel implements StructureViewModel.ElementInfoProvider, PlaceHolder<String> {
|
||||
private static final Collection<NodeProvider> NODE_PROVIDERS = Arrays.<NodeProvider>asList(new JavaInheritedMembersNodeProvider(),
|
||||
new JavaAnonymousClassesNodeProvider());
|
||||
private static final Collection<NodeProvider> NODE_PROVIDERS = Arrays.asList(new JavaInheritedMembersNodeProvider(),
|
||||
new JavaAnonymousClassesNodeProvider(),
|
||||
new JavaLambdaNodeProvider());
|
||||
private String myPlace;
|
||||
|
||||
public JavaFileTreeModel(@NotNull PsiClassOwner file, @Nullable Editor editor) {
|
||||
@@ -112,6 +113,8 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme
|
||||
if (element instanceof PsiClass) {
|
||||
return ((PsiClass)element).getQualifiedName() != null;
|
||||
}
|
||||
|
||||
return element instanceof PsiLambdaExpression;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -119,7 +122,7 @@ public class JavaFileTreeModel extends TextEditorBasedStructureViewModel impleme
|
||||
@Override
|
||||
@NotNull
|
||||
protected Class[] getSuitableClasses() {
|
||||
return new Class[]{PsiClass.class, PsiMethod.class, PsiField.class, PsiJavaFile.class};
|
||||
return new Class[]{PsiClass.class, PsiMethod.class, PsiField.class, PsiLambdaExpression.class, PsiJavaFile.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.structureView.impl.java;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
|
||||
import com.intellij.ide.util.FileStructureNodeProvider;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentation;
|
||||
import com.intellij.ide.util.treeView.smartTree.ActionPresentationData;
|
||||
import com.intellij.ide.util.treeView.smartTree.TreeElement;
|
||||
import com.intellij.openapi.actionSystem.KeyboardShortcut;
|
||||
import com.intellij.openapi.actionSystem.Shortcut;
|
||||
import com.intellij.openapi.util.PropertyOwner;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaLambdaNodeProvider implements FileStructureNodeProvider<JavaLambdaTreeElement>, PropertyOwner {
|
||||
public static final String ID = "SHOW_LAMBDA";
|
||||
public static final String JAVA_LAMBDA_PROPERTY_NAME = "java.lambda.provider";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<JavaLambdaTreeElement> provideNodes(@NotNull TreeElement node) {
|
||||
if (node instanceof PsiMethodTreeElement ||
|
||||
node instanceof PsiFieldTreeElement ||
|
||||
node instanceof ClassInitializerTreeElement ||
|
||||
node instanceof JavaLambdaTreeElement) {
|
||||
final PsiElement el = ((PsiTreeElementBase)node).getElement();
|
||||
if (el != null) {
|
||||
final List<JavaLambdaTreeElement> result = new ArrayList<>();
|
||||
el.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
super.visitLambdaExpression(expression);
|
||||
result.add(new JavaLambdaTreeElement(expression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
//stop at class level
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getCheckBoxText() {
|
||||
return "Show Lambdas";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Shortcut[] getShortcut() {
|
||||
return new Shortcut[]{KeyboardShortcut.fromString(SystemInfo.isMac ? "meta L" : "control L")};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ActionPresentation getPresentation() {
|
||||
return new ActionPresentationData(getCheckBoxText(), null, AllIcons.Nodes.Function);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPropertyName() {
|
||||
return JAVA_LAMBDA_PROPERTY_NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.structureView.impl.java;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement;
|
||||
import com.intellij.ide.util.PsiLambdaNameHelper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaLambdaTreeElement extends JavaClassTreeElementBase<PsiLambdaExpression> {
|
||||
public static final JavaLambdaTreeElement[] EMPTY_ARRAY = {};
|
||||
|
||||
private String myName;
|
||||
private String myFunctionalName;
|
||||
|
||||
public JavaLambdaTreeElement(PsiLambdaExpression lambdaExpression) {
|
||||
super(false,lambdaExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPublic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableText() {
|
||||
if (myName != null) return myName;
|
||||
final PsiLambdaExpression element = getElement();
|
||||
|
||||
if (element != null) {
|
||||
myName = PsiLambdaNameHelper.getVMName(element);
|
||||
return myName;
|
||||
}
|
||||
return "Lambda";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isSearchInLocationString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocationString() {
|
||||
if (myFunctionalName == null) {
|
||||
PsiLambdaExpression lambdaExpression = getElement();
|
||||
if (lambdaExpression != null) {
|
||||
final PsiType interfaceType = lambdaExpression.getFunctionalInterfaceType();
|
||||
if (interfaceType != null) {
|
||||
myFunctionalName = interfaceType.getPresentableText();
|
||||
}
|
||||
}
|
||||
}
|
||||
return myFunctionalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + (myFunctionalName == null ? "" : " (" + getLocationString() + ")");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<StructureViewTreeElement> getChildrenBase() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(boolean open) {
|
||||
return AllIcons.Nodes.Function;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.ide.util;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiLambdaExpression;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class PsiLambdaNameHelperTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testNames() throws Exception {
|
||||
final PsiClass aClass = myFixture.addClass("class Test {\n" +
|
||||
" Runnable r = () -> {\n" +
|
||||
" };\n" +
|
||||
" public void method() {\n" +
|
||||
" Runnable r = () -> {\n" +
|
||||
" Integer s = RedundantRename.this.s;\n" +
|
||||
" Runnable rr = () -> {};\n" +
|
||||
" new Runnable() {\n" +
|
||||
" Runnable r1 = () -> {};\n" +
|
||||
" @Override\n" +
|
||||
" public void run() {}\n" +
|
||||
" };\n" +
|
||||
" };\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
final Collection<PsiLambdaExpression> lambdaExpressions = PsiTreeUtil.findChildrenOfType(aClass, PsiLambdaExpression.class);
|
||||
final String[] expectedNames = {"lambda$new$0",
|
||||
"lambda$method$1",
|
||||
"lambda$method$2",
|
||||
"lambda$0"};
|
||||
int idx = 0;
|
||||
for (PsiLambdaExpression expression : lambdaExpressions) {
|
||||
assertEquals(expectedNames[idx++], PsiLambdaNameHelper.getVMName(expression));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1315,6 +1315,8 @@
|
||||
|
||||
<declarationRangeHandler key="com.intellij.psi.PsiMethod"
|
||||
implementationClass="com.intellij.codeInsight.hint.MethodDeclarationRangeHandler"/>
|
||||
<declarationRangeHandler key="com.intellij.psi.PsiLambdaExpression"
|
||||
implementationClass="com.intellij.codeInsight.hint.LambdaDeclarationRangeHandler"/>
|
||||
<declarationRangeHandler key="com.intellij.psi.PsiClass"
|
||||
implementationClass="com.intellij.codeInsight.hint.ClassDeclarationRangeHandler"/>
|
||||
<declarationRangeHandler key="com.intellij.psi.PsiClassInitializer"
|
||||
|
||||
Reference in New Issue
Block a user