Merge remote-tracking branch 'origin/master'

This commit is contained in:
Evgeny Pasynkov
2012-09-10 10:58:22 +02:00
13 changed files with 152 additions and 22 deletions
@@ -48,11 +48,11 @@ public class HighlightControlFlowUtil {
private HighlightControlFlowUtil() { }
@Nullable
public static HighlightInfo checkMissingReturnStatement(PsiMethod method) {
PsiCodeBlock body = method.getBody();
public static HighlightInfo checkMissingReturnStatement(PsiCodeBlock body, PsiType returnType) {
if (body == null
|| method.getReturnType() == null
|| PsiType.VOID.equals(method.getReturnType())) {
|| returnType == null
|| PsiType.VOID.equals(returnType)) {
return null;
}
// do not compute constant expressions for if() statement condition
@@ -68,9 +68,13 @@ public class HighlightControlFlowUtil {
HighlightInfoType.ERROR,
context,
JavaErrorMessages.message("missing.return.statement"));
QuickFixAction.registerQuickFixAction(highlightInfo, new AddReturnFix(method));
IntentionAction fix = QUICK_FIX_FACTORY.createMethodReturnFix(method, PsiType.VOID, true);
QuickFixAction.registerQuickFixAction(highlightInfo, fix);
final PsiElement parent = body.getParent();
if (parent instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)parent;
QuickFixAction.registerQuickFixAction(highlightInfo, new AddReturnFix(method));
IntentionAction fix = QUICK_FIX_FACTORY.createMethodReturnFix(method, PsiType.VOID, true);
QuickFixAction.registerQuickFixAction(highlightInfo, fix);
}
return highlightInfo;
}
}
@@ -282,6 +282,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
} else {
myHolder.add(HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, "Lambda expression not expected here"));
}
if (!myHolder.hasErrorResults()) {
final PsiElement body = expression.getBody();
if (body instanceof PsiCodeBlock) {
myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body));
}
}
}
}
@@ -333,10 +339,24 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
super.visitJavaToken(token);
if (!myHolder.hasErrorResults()
&& token.getTokenType() == JavaTokenType.RBRACE
&& token.getParent() instanceof PsiCodeBlock
&& token.getParent().getParent() instanceof PsiMethod) {
PsiMethod method = (PsiMethod)token.getParent().getParent();
myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(method));
&& token.getParent() instanceof PsiCodeBlock) {
final PsiElement gParent = token.getParent().getParent();
final PsiCodeBlock codeBlock;
final PsiType returnType;
if (gParent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)gParent;
codeBlock = method.getBody();
returnType = method.getReturnType();
} else if (gParent instanceof PsiLambdaExpression) {
final PsiElement body = ((PsiLambdaExpression)gParent).getBody();
if (!(body instanceof PsiCodeBlock)) return;
codeBlock = (PsiCodeBlock)body;
returnType = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)gParent);
} else {
return;
}
myHolder.add(HighlightControlFlowUtil.checkMissingReturnStatement(codeBlock, returnType));
}
}
@@ -97,7 +97,12 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaLocalInspectionT
return returnStatement.getReturnValue();
}
else {
return ((PsiExpressionStatement)statements[0]).getExpression();
final PsiExpression expression = ((PsiExpressionStatement)statements[0]).getExpression();
final PsiType psiType = expression.getType();
if (psiType != PsiType.VOID) {
return null;
}
return expression;
}
}
}
@@ -92,12 +92,25 @@ public class LambdaUtil {
public static boolean isLambdaFullyInferred(PsiLambdaExpression expression, PsiType functionalInterfaceType) {
if (expression.getParameterList().getParametersCount() > 0 ||
getFunctionalInterfaceReturnType(functionalInterfaceType) != PsiType.VOID) { //todo check that void lambdas without params check
if (functionalInterfaceType instanceof PsiClassType && ((PsiClassType)functionalInterfaceType).isRaw()) return false;
if (!checkRawAcceptable(expression, functionalInterfaceType)) {
return false;
}
return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression, null);
}
return true;
}
private static boolean checkRawAcceptable(PsiLambdaExpression expression, PsiType functionalInterfaceType) {
PsiElement parent = expression.getParent();
while (parent instanceof PsiParenthesizedExpression) {
parent = parent.getParent();
}
if (parent instanceof PsiExpressionList && functionalInterfaceType instanceof PsiClassType && ((PsiClassType)functionalInterfaceType).isRaw()){
return false;
}
return true;
}
@Nullable
public static String checkInterfaceFunctional(PsiType functionalInterfaceType) {
final PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(functionalInterfaceType);
@@ -850,9 +850,17 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
}
else if (parent instanceof PsiReturnStatement) {
PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
if (method != null) {
expectedType = method.getReturnType();
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
if (lambdaExpression != null) {
expectedType = LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression.getFunctionalInterfaceType());
if (expectedType == null) {
return getFailedInferenceConstraint(typeParameter);
}
} else {
PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
if (method != null) {
expectedType = method.getReturnType();
}
}
}
else if (parent instanceof PsiExpressionList) {
@@ -25,7 +25,7 @@ class Test {
{
boolean flag = true;
I i = flag ? (() -> 123) : (() -> 222);
I i1 = flag ? (<error descr="Missing return value">() -> {}</error>) : (() -> 222);
I i1 = flag ? (() -> {<error descr="Missing return statement">}</error>) : (() -> 222);
Object i2 = flag ? (<error descr="Target type of a lambda conversion must be an interface">() -> 42</error>) : (<error descr="Target type of a lambda conversion must be an interface">() -> 222</error>);
I i3 = flag ? (<error descr="Incompatible parameter types in lambda expression">(x) -> 42</error>) : (() -> 222);
I i4 = flag ? (() -> 42) : new I() {
@@ -18,7 +18,7 @@ class Test2 {
}
{
IntReturnType aI = <error descr="Incompatible return type void in lambda expression">() -> System.out.println()</error>;
IntReturnType aI1 = <error descr="Missing return value">() -> {System.out.println();}</error>;
IntReturnType aI1 = () -> {System.out.println();<error descr="Missing return statement">}</error>;
IntReturnType aI2 = () -> {return 1;};
IntReturnType aI3 = () -> 1;
}
@@ -32,10 +32,10 @@ class Test3 {
}
{
XReturnType<Object> aI = <error descr="Incompatible return type void in lambda expression">() -> System.out.println()</error>;
XReturnType<Object> aI1 = <error descr="Missing return value">() -> {System.out.println();}</error>;
XReturnType<Object> aI1 = () -> {System.out.println();<error descr="Missing return statement">}</error>;
XReturnType<Object> aI2 = () -> {return 1;};
XReturnType<Object> aI3 = () -> 1;
XReturnType<Object> aI4 = <error descr="Missing return value">() -> {}</error>;
XReturnType<Object> aI4 = () -> {<error descr="Missing return statement">}</error>;
}
}
@@ -48,7 +48,7 @@ class Test4 {
{
YXReturnType<Object> aI = <error descr="Incompatible return type void in lambda expression">() -> System.out.println()</error>;
YXReturnType<Object> aI1 = <error descr="Missing return value">() -> {System.out.println();}</error>;
YXReturnType<Object> aI1 = () -> {System.out.println();<error descr="Missing return statement">}</error>;
YXReturnType<Object> aI2 = <error descr="Incompatible return type int in lambda expression">() -> {return 1;}</error>;
YXReturnType<Object> aI3 = <error descr="Incompatible return type int in lambda expression">() -> 1</error>;
YXReturnType<Object> aI4 = () -> new Y<Object>(){};
@@ -58,3 +58,15 @@ class Test4 {
public interface TerminalOp1<T, U> extends IntermediateOp1<T, U> {}
}
class Test5 {
{
Block empty = x -> {};
Block<?> empty1 = x -> {};
System.out.println((Block) x -> {});
}
interface Block<T> {
void apply(T t);
}
}
@@ -0,0 +1,43 @@
class Test1 {
interface Extractor<T, W> {
Option<W> unapply(T t);
}
public static abstract class Option<T> {
private static class None<T> extends Option<T> {}
private static final Option NONE = new None();
public static <T> Option<T> none() {
return NONE;
}
public static <T> Option<T> option(T value) {
if (value == null) {
return NONE;
} else {
return null;
}
}
}
public static void main(String[] args) {
Extractor<String, Integer> e = s -> {
if (s.equals("1")) {
return Option.option(1);
} else {
return Option.none();
}
};
Extractor<String, Integer> e1 = <error descr="Incompatible return type Option<String> in lambda expression">s -> {
if (s.equals("1")) {
return Option.option(1);
} else {
return Option.option("2");
}
}</error>;
}
}
@@ -0,0 +1,9 @@
class Test1 {
{
Comparable<String> c = o -> {
if (o == null) return 1;
return -1;
<error descr="Unreachable statement">System.out.println("Hello");</error>
};
}
}
@@ -0,0 +1,8 @@
// "Replace with one line expression" "false"
class Test {
{
Runnable c = () -> <caret>{foo();};
}
int foo() {return 1;}
}
@@ -132,6 +132,14 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testVariableInitialization() throws Exception {
doTest();
}
public void testUnreachableStatement() throws Exception {
doTest();
}
public void testReturnValue() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
@@ -53,7 +53,7 @@ public class DataLanguageBlockWrapper implements ASTBlock, BlockEx, BlockWithPar
if (node != null) {
final PsiElement psi = node.getPsi();
if (psi != null) {
language = psi.getLanguage();
language = psi.getContainingFile().getLanguage();
}
}
myLanguage = language;