mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
don't visit jdk Stream API usages when searching for unrelated functional interface implementations
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.search;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
@@ -51,8 +52,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.*;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.assertNotNull;
|
||||
|
||||
@@ -64,6 +64,9 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
* and then for their usages,
|
||||
*/
|
||||
public static final int SMART_SEARCH_THRESHOLD = 5;
|
||||
private static final java.util.HashSet<String> KNOWN_STREAM_CLASSES =
|
||||
ContainerUtil.newHashSet(Stream.class.getName(),
|
||||
IntStream.class.getName(), DoubleStream.class.getName(), LongStream.class.getName());
|
||||
|
||||
@Override
|
||||
public void processQuery(@NotNull FunctionalExpressionSearch.SearchParameters queryParameters,
|
||||
@@ -186,6 +189,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
private static Set<Location> getPossibleCallLocations(PsiClass samClass, PsiMethod calledMethod) {
|
||||
Set<Location> keys = new HashSet<>();
|
||||
|
||||
String samName = samClass.getQualifiedName();
|
||||
boolean includeStreamApi = samName != null && samName.startsWith("java.util.function.") ||
|
||||
hasStreamLikeApi(samClass.getProject());
|
||||
|
||||
String methodName = calledMethod.getName();
|
||||
PsiParameter[] parameters = calledMethod.getParameterList().getParameters();
|
||||
for (int paramIndex = 0; paramIndex < parameters.length; paramIndex++) {
|
||||
@@ -193,7 +200,10 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
if (canPassFunctionalExpression(samClass, parameter)) {
|
||||
for (int argCount : getPossibleArgCounts(parameters, paramIndex)) {
|
||||
for (int argIndex : getPossibleArgIndices(parameter, paramIndex, argCount)) {
|
||||
keys.add(new CallLocation(methodName, argCount, argIndex));
|
||||
keys.add(new CallLocation(methodName, argCount, argIndex, false));
|
||||
if (includeStreamApi) {
|
||||
keys.add(new CallLocation(methodName, argCount, argIndex, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,4 +385,35 @@ public class JavaFunctionalExpressionSearcher extends QueryExecutorBase<PsiFunct
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static boolean hasStreamLikeApi(final Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, () ->
|
||||
CachedValueProvider.Result.create(hasStreamLikeApi(project, "Arrays", "stream") || hasStreamLikeApi(project, "Stream", "of"),
|
||||
PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT));
|
||||
}
|
||||
|
||||
private static boolean hasStreamLikeApi(Project project, String qualifier, String methodName) {
|
||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
||||
for (PsiClass candidate : cache.getClassesByName(qualifier, GlobalSearchScope.allScope(project))) {
|
||||
if (hasMethodWithNonStreamType(methodName, candidate)) return true;
|
||||
}
|
||||
|
||||
for (PsiField field : cache.getFieldsByName(qualifier, GlobalSearchScope.allScope(project))) {
|
||||
PsiClass fieldType = PsiUtil.resolveClassInClassTypeOnly(field.getType());
|
||||
if (fieldType == null || fieldType instanceof PsiTypeParameter || hasMethodWithNonStreamType(methodName, fieldType)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasMethodWithNonStreamType(@NotNull String methodName, @NotNull PsiClass candidate) {
|
||||
for (PsiMethod method : candidate.findMethodsByName(methodName, true)) {
|
||||
PsiClass returnType = PsiUtil.resolveClassInClassTypeOnly(method.getReturnType());
|
||||
if (returnType == null || !KNOWN_STREAM_CLASSES.contains(returnType.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,10 @@ import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.PsiBinaryExpression;
|
||||
import com.intellij.psi.PsiFunctionalExpression;
|
||||
import com.intellij.psi.impl.cache.RecordUtil;
|
||||
import com.intellij.psi.impl.java.stubs.FunctionalExpressionKey.CoarseType;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
|
||||
import com.intellij.psi.impl.source.Constants;
|
||||
import com.intellij.psi.impl.source.JavaLightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
|
||||
@@ -75,12 +75,12 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
@NotNull
|
||||
private static FunctionalExpressionKey.Location calcLocation(LighterAST tree, LighterASTNode funExpr) {
|
||||
LighterASTNode call = getContainingCall(tree, funExpr);
|
||||
List<LighterASTNode> args = getArgList(tree, call);
|
||||
List<LighterASTNode> args = JavaLightTreeUtil.getArgList(tree, call);
|
||||
int argIndex = args == null ? -1 : getArgIndex(args, funExpr);
|
||||
String methodName = call == null ? null : getCalledMethodName(tree, call);
|
||||
return methodName == null || argIndex < 0
|
||||
? createTypedLocation(tree, funExpr)
|
||||
: new FunctionalExpressionKey.CallLocation(methodName, args.size(), argIndex);
|
||||
: new FunctionalExpressionKey.CallLocation(methodName, args.size(), argIndex, StreamApiDetector.isStreamApiCall(tree, call));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -94,7 +94,7 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
}
|
||||
|
||||
LighterASTNode typeElement = LightTreeUtil.firstChildOfType(tree, scope, TYPE);
|
||||
String typeText = getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, typeElement, JAVA_CODE_REFERENCE));
|
||||
String typeText = JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, typeElement, JAVA_CODE_REFERENCE));
|
||||
if (typeText != null) {
|
||||
return new FunctionalExpressionKey.TypedLocation(typeText);
|
||||
}
|
||||
@@ -111,13 +111,6 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static List<LighterASTNode> getArgList(LighterAST tree, LighterASTNode call) {
|
||||
LighterASTNode anonClass = LightTreeUtil.firstChildOfType(tree, call, ANONYMOUS_CLASS);
|
||||
LighterASTNode exprList = LightTreeUtil.firstChildOfType(tree, anonClass != null ? anonClass : call, EXPRESSION_LIST);
|
||||
return exprList == null ? null : LightTreeUtil.getChildrenOfType(tree, exprList, ElementType.EXPRESSION_BIT_SET);
|
||||
}
|
||||
|
||||
private static CoarseType calcType(final LighterAST tree, LighterASTNode funExpr) {
|
||||
if (funExpr.getTokenType() == METHOD_REF_EXPRESSION) return CoarseType.UNKNOWN;
|
||||
|
||||
@@ -209,7 +202,7 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
if (call.getTokenType() == NEW_EXPRESSION) {
|
||||
LighterASTNode anonClass = LightTreeUtil.firstChildOfType(tree, call, ANONYMOUS_CLASS);
|
||||
LighterASTNode ref = LightTreeUtil.firstChildOfType(tree, anonClass != null ? anonClass : call, JAVA_CODE_REFERENCE);
|
||||
return ref == null ? null : getNameIdentifierText(tree, ref);
|
||||
return ref == null ? null : JavaLightTreeUtil.getNameIdentifierText(tree, ref);
|
||||
}
|
||||
|
||||
LighterASTNode methodExpr = tree.getChildren(call).get(0);
|
||||
@@ -217,23 +210,17 @@ public abstract class FunctionalExpressionElementType<T extends PsiFunctionalExp
|
||||
return getSuperClassName(tree, call);
|
||||
}
|
||||
if (LightTreeUtil.firstChildOfType(tree, methodExpr, JavaTokenType.THIS_KEYWORD) != null) {
|
||||
return getNameIdentifierText(tree, findClass(tree, call));
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, findClass(tree, call));
|
||||
}
|
||||
|
||||
return getNameIdentifierText(tree, methodExpr);
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, methodExpr);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getSuperClassName(LighterAST tree, LighterASTNode call) {
|
||||
LighterASTNode aClass = findClass(tree, call);
|
||||
LighterASTNode extendsList = LightTreeUtil.firstChildOfType(tree, aClass, EXTENDS_LIST);
|
||||
return getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, extendsList, JAVA_CODE_REFERENCE));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getNameIdentifierText(LighterAST tree, LighterASTNode idOwner) {
|
||||
LighterASTNode id = LightTreeUtil.firstChildOfType(tree, idOwner, JavaTokenType.IDENTIFIER);
|
||||
return id != null ? RecordUtil.intern(tree.getCharTable(), id) : null;
|
||||
return JavaLightTreeUtil.getNameIdentifierText(tree, LightTreeUtil.firstChildOfType(tree, extendsList, JAVA_CODE_REFERENCE));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.java.stubs;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
@@ -114,7 +114,7 @@ public class FunctionalExpressionKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("lambdaParameterCount", lambdaParameterCount)
|
||||
.add("type", lambdaType)
|
||||
.add("location", location)
|
||||
@@ -140,11 +140,13 @@ public class FunctionalExpressionKey {
|
||||
@NotNull public final String methodName;
|
||||
public final int methodArgsLength;
|
||||
public final int callArgIndex;
|
||||
public final boolean streamApi;
|
||||
|
||||
public CallLocation(@NotNull String methodName, int methodArgsLength, int callArgIndex) {
|
||||
public CallLocation(@NotNull String methodName, int methodArgsLength, int callArgIndex, boolean streamApi) {
|
||||
this.methodName = methodName;
|
||||
this.methodArgsLength = Math.min(methodArgsLength, MAX_ARG_COUNT);
|
||||
this.callArgIndex = Math.min(callArgIndex, MAX_ARG_COUNT - 1);
|
||||
this.streamApi = streamApi;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,6 +159,7 @@ public class FunctionalExpressionKey {
|
||||
if (methodArgsLength != location.methodArgsLength) return false;
|
||||
if (callArgIndex != location.callArgIndex) return false;
|
||||
if (!methodName.equals(location.methodName)) return false;
|
||||
if (streamApi != location.streamApi) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -166,15 +169,17 @@ public class FunctionalExpressionKey {
|
||||
int result = methodName.hashCode();
|
||||
result = 31 * result + methodArgsLength;
|
||||
result = 31 * result + callArgIndex;
|
||||
result = 31 * result + (streamApi ? 0 : 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("methodName", methodName)
|
||||
.add("methodArgsLength", methodArgsLength)
|
||||
.add("callArgIndex", callArgIndex)
|
||||
.add("streamApi", streamApi)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@@ -183,13 +188,15 @@ public class FunctionalExpressionKey {
|
||||
String methodName = IOUtil.readUTF(dataStream);
|
||||
int methodArgsLength = dataStream.readByte();
|
||||
int argIndex = dataStream.readByte();
|
||||
return new CallLocation(methodName, methodArgsLength, argIndex);
|
||||
boolean streamApi = dataStream.readBoolean();
|
||||
return new CallLocation(methodName, methodArgsLength, argIndex, streamApi);
|
||||
}
|
||||
|
||||
private void serializeCall(@NotNull DataOutput dataStream) throws IOException {
|
||||
IOUtil.writeUTF(dataStream, methodName);
|
||||
dataStream.writeByte(methodArgsLength);
|
||||
dataStream.writeByte(callArgIndex);
|
||||
dataStream.writeBoolean(streamApi);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -220,7 +227,7 @@ public class FunctionalExpressionKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("fieldType", varType)
|
||||
.toString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.psi.impl.java.stubs;
|
||||
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.psi.impl.source.JavaLightTreeUtil;
|
||||
import com.intellij.psi.impl.source.tree.RecursiveLighterASTNodeWalkingVisitor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.*;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class StreamApiDetector {
|
||||
public static final Set<String> STREAM_INTERMEDIATE_METHODS = ContainerUtil.newHashSet("filter",
|
||||
"map", "mapToInt", "mapToLong", "mapToDouble",
|
||||
"flatMap", "flatMapToInt", "flatMapToLong", "flatMapToDouble",
|
||||
"distinct", "sorted", "peek", "limit", "skip",
|
||||
"forEach", "forEachOrdered",
|
||||
"reduce", "collect", "max",
|
||||
"anyMatch", "allMatch", "noneMatch",
|
||||
"findFirst", "findAny");
|
||||
|
||||
static boolean isStreamApiCall(LighterAST tree, LighterASTNode methodCall) {
|
||||
LighterASTNode methodExpr = tree.getChildren(methodCall).get(0);
|
||||
String name = JavaLightTreeUtil.getNameIdentifierText(tree, methodExpr);
|
||||
if (STREAM_INTERMEDIATE_METHODS.contains(name)) {
|
||||
LighterASTNode qualifier = tree.getChildren(methodExpr).get(0);
|
||||
return qualifier.getTokenType() == METHOD_CALL_EXPRESSION && isStreamApiCall(tree, qualifier);
|
||||
}
|
||||
return isRootCall(tree, methodCall, methodExpr, name);
|
||||
}
|
||||
|
||||
private static boolean isRootCall(LighterAST tree, LighterASTNode methodCall, LighterASTNode methodExpr, String name) {
|
||||
if ("stream".equals(name) || "parallelStream".equals(name)) {
|
||||
List<LighterASTNode> argList = JavaLightTreeUtil.getArgList(tree, methodCall);
|
||||
if (argList == null) return false;
|
||||
return argList.isEmpty() || !argList.isEmpty() && hasQualifier(tree, methodExpr, "Arrays");
|
||||
}
|
||||
if ("of".equals(name)) {
|
||||
List<LighterASTNode> argList = JavaLightTreeUtil.getArgList(tree, methodCall);
|
||||
return argList != null && !argList.isEmpty() && hasQualifier(tree, methodExpr, "Stream");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasQualifier(LighterAST tree, LighterASTNode methodExpr, String refName) {
|
||||
LighterASTNode node = tree.getChildren(methodExpr).get(0);
|
||||
return node.getTokenType() == REFERENCE_EXPRESSION &&
|
||||
refName.equals(JavaLightTreeUtil.getNameIdentifierText(tree, node)) &&
|
||||
!hasContextVariable(tree, node, refName);
|
||||
}
|
||||
|
||||
private static boolean hasContextVariable(final LighterAST tree, LighterASTNode node, final String varName) {
|
||||
final AtomicBoolean result = new AtomicBoolean(false);
|
||||
new RecursiveLighterASTNodeWalkingVisitor(tree) {
|
||||
@Override
|
||||
public void visitNode(@NotNull LighterASTNode element) {
|
||||
if (element.getTokenType() == LOCAL_VARIABLE && varName.equals(JavaLightTreeUtil.getNameIdentifierText(tree, element))) {
|
||||
result.set(true);
|
||||
}
|
||||
super.visitNode(element);
|
||||
}
|
||||
}.visitNode(tree.getRoot());
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ import java.io.IOException;
|
||||
* @author max
|
||||
*/
|
||||
public class JavaFileElementType extends ILightStubFileElementType<PsiJavaFileStub> {
|
||||
public static final int STUB_VERSION = 33;
|
||||
public static final int STUB_VERSION = 34;
|
||||
|
||||
public JavaFileElementType() {
|
||||
super("java.FILE", JavaLanguage.INSTANCE);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.psi.impl.source;
|
||||
|
||||
import com.intellij.lang.LighterAST;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
import com.intellij.psi.impl.cache.RecordUtil;
|
||||
import com.intellij.psi.impl.source.tree.ElementType;
|
||||
import com.intellij.psi.impl.source.tree.LightTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.ANONYMOUS_CLASS;
|
||||
import static com.intellij.psi.impl.source.tree.JavaElementType.EXPRESSION_LIST;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class JavaLightTreeUtil {
|
||||
@Nullable
|
||||
public static List<LighterASTNode> getArgList(@NotNull LighterAST tree, @Nullable LighterASTNode call) {
|
||||
LighterASTNode anonClass = LightTreeUtil.firstChildOfType(tree, call, ANONYMOUS_CLASS);
|
||||
LighterASTNode exprList = LightTreeUtil.firstChildOfType(tree, anonClass != null ? anonClass : call, EXPRESSION_LIST);
|
||||
return exprList == null ? null : LightTreeUtil.getChildrenOfType(tree, exprList, ElementType.EXPRESSION_BIT_SET);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getNameIdentifierText(@NotNull LighterAST tree, @Nullable LighterASTNode idOwner) {
|
||||
LighterASTNode id = LightTreeUtil.firstChildOfType(tree, idOwner, JavaTokenType.IDENTIFIER);
|
||||
return id != null ? RecordUtil.intern(tree.getCharTable(), id) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
interface I {
|
||||
Object fun(Object o);
|
||||
}
|
||||
|
||||
class Arrays {
|
||||
static MyStream stream(int a) { }
|
||||
}
|
||||
|
||||
interface MyStream {
|
||||
MyStream map(I i);
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
{
|
||||
Arrays.stream().map(p -> "a");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
interface I {
|
||||
Object fun(Object o);
|
||||
}
|
||||
|
||||
interface MyStream {
|
||||
MyStream map(I i);
|
||||
}
|
||||
|
||||
class StrType {
|
||||
static MyStream of(int b) {}
|
||||
}
|
||||
|
||||
|
||||
class Test extends Base {
|
||||
|
||||
{
|
||||
new Runnable() {
|
||||
void run() {
|
||||
Stream.of(1).map(p -> "b"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
interface I {
|
||||
Object fun(Object o);
|
||||
}
|
||||
|
||||
interface MyStream {
|
||||
MyStream map(I i);
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
class StrType {
|
||||
static MyStream of(int b) {}
|
||||
}
|
||||
|
||||
{
|
||||
StrType Stream = null;
|
||||
new Runnable() {
|
||||
void run() {
|
||||
Stream.of(1).map(p -> "b"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.lambda;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.search.JavaFunctionalExpressionSearcher;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -105,6 +106,24 @@ public class FindFunctionalInterfaceTest extends LightCodeInsightFixtureTestCase
|
||||
assertSize(6, FunctionalExpressionSearch.search(findClass("DumbAware")).findAll());
|
||||
}
|
||||
|
||||
public void testArraysStreamLikeApi() {
|
||||
configure();
|
||||
assertSize(1, FunctionalExpressionSearch.search(findClass("I")).findAll());
|
||||
}
|
||||
|
||||
public void testStreamOfLikeApiWithLocalVar() {
|
||||
configure();
|
||||
assertSize(1, FunctionalExpressionSearch.search(findClass("I")).findAll());
|
||||
}
|
||||
|
||||
public void testStreamOfLikeApiWithField() {
|
||||
assertFalse(JavaFunctionalExpressionSearcher.hasStreamLikeApi(getProject()));
|
||||
myFixture.addClass("class Base { StrType Stream = null; }");
|
||||
configure();
|
||||
assertTrue(JavaFunctionalExpressionSearcher.hasStreamLikeApi(getProject()));
|
||||
assertSize(1, FunctionalExpressionSearch.search(findClass("I")).findAll());
|
||||
}
|
||||
|
||||
private PsiClass findClass(String i) {
|
||||
return JavaPsiFacade.getInstance(getProject()).findClass(i, GlobalSearchScope.allScope(getProject()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user