StreamToLoopInspection: disable elements which type is PsiIntersection type or PsiImmediateClassType which is not resolvable in outer context (fixes EA-97901); better diagnostic for cases like EA-97901

This commit is contained in:
Tagir Valeev
2017-03-01 12:37:17 +07:00
parent 3f6a84d808
commit b5e80dfbd8
5 changed files with 46 additions and 6 deletions
@@ -420,11 +420,14 @@ abstract class FunctionHelper {
PsiTypeCastExpression castExpr = (PsiTypeCastExpression)lambdaExpression.getBody();
LOG.assertTrue(castExpr != null);
methodRef = (PsiMethodReferenceExpression)castExpr.getOperand();
LOG.assertTrue(methodRef != null);
}
}
}
PsiLambdaExpression lambda = LambdaRefactoringUtil.convertMethodReferenceToLambda(methodRef, true, true);
LOG.assertTrue(lambda != null);
if(lambda == null) {
throw new IllegalStateException("Unable to convert method reference to lambda: "+methodRef.getText());
}
PsiElement body = lambda.getBody();
LOG.assertTrue(body instanceof PsiExpression);
myExpression = (PsiExpression)body;
@@ -29,6 +29,7 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
@@ -164,10 +165,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
if(qualifier != null) {
PsiType elementType = StreamApiUtil.getStreamElementType(qualifier.getType());
if(elementType == null || ((elementType instanceof PsiClassType) && ((PsiClassType)elementType).isRaw())) {
// Raw type in any stream step is not supported
return null;
}
if (!isValidElementType(elementType, call)) return null;
Operation op = Operation.createIntermediate(name, args, outVar, elementType, supportUnknownSources);
if (op != null) return op;
op = TerminalOperation.createTerminal(name, args, elementType, callType, isVoidContext(call.getParent()));
@@ -178,6 +176,21 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
return SourceOperation.createSource(call, supportUnknownSources);
}
private static boolean isValidElementType(PsiType elementType, PsiElement context) {
if(elementType == null || ((elementType instanceof PsiClassType) && ((PsiClassType)elementType).isRaw())) {
// Raw type in any stream step is not supported
return false;
}
if(elementType instanceof PsiImmediateClassType) {
PsiType typeFromText =
JavaPsiFacade.getElementFactory(context.getProject()).createTypeFromText(elementType.getCanonicalText(), context);
if(!(typeFromText instanceof PsiClassType) || ((PsiClassType)typeFromText).resolve() == null) {
return false;
}
}
return true;
}
private static boolean isVoidContext(PsiElement element) {
return element instanceof PsiExpressionStatement ||
(element instanceof PsiLambdaExpression &&
@@ -198,7 +211,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
if (fn == null) return null;
PsiType elementType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_LANG_ITERABLE, 0, false);
if(elementType == null) return null;
if(!isValidElementType(elementType, terminalCall)) return null;
elementType = GenericsUtil.getVariableTypeByExpressionType(elementType);
TerminalOperation terminal = new TerminalOperation.ForEachTerminalOperation(fn);
SourceOperation source = new SourceOperation.ForEachSource(qualifier);
@@ -0,0 +1,12 @@
// "Replace Stream API chain with loop" "false"
import java.util.stream.Stream;
public class Test {
interface A {void a();}
interface B {void b();}
public void test(Object obj) {
Stream.of((A & B) obj).fo<caret>rEach(B::b);
}
}
@@ -0,0 +1,9 @@
// "Replace Stream API chain with loop" "false"
import java.util.List;
public class Main {
public void test2(List<? extends CharSequence> list) {
list.stream().map(String::length).for<caret>Each(System.out::println);
}
}
@@ -50,6 +50,9 @@ public class StreamApiUtil {
}
PsiType streamType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_UTIL_STREAM_STREAM, 0, false);
if (variableType) {
if (streamType instanceof PsiIntersectionType) {
return null;
}
streamType = GenericsUtil.getVariableTypeByExpressionType(streamType);
}
return streamType;