MethodReturnTypeFix: highlight only return statements when method return type doesn't match expected (IDEA-216275)

GitOrigin-RevId: d5f7dc3b03d68d249ba29532b0e8c0555cae60d6
This commit is contained in:
Artemiy Sartakov
2019-07-08 18:53:24 +07:00
committed by intellij-monorepo-bot
parent ba328fd25a
commit 642c65dd11
37 changed files with 167 additions and 217 deletions

View File

@@ -37,11 +37,7 @@ import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.MostlySingularMultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import one.util.streamex.StreamEx;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -1217,123 +1213,6 @@ public class HighlightMethodUtil {
return errorResult;
}
@Nullable
static HighlightInfo checkReturnType(@NotNull PsiMethod method) {
PsiElement element = method.getNameIdentifier();
if (element == null) return null;
PsiType returnType = method.getReturnType();
PsiType expectedReturnType = constructReturnType(method);
if (expectedReturnType == null || expectedReturnType.equals(returnType)) return null;
String description = JavaErrorMessages.message("invalid.return.type");
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMethodReturnFix(method, expectedReturnType, true, true));
return info;
}
@Nullable
private static PsiType constructReturnType(@NotNull PsiMethod method) {
PsiManager manager = method.getManager();
PsiType returnType = method.getReturnType();
PsiReturnStatement[] returnStatements = PsiUtil.findReturnStatements(method);
if (returnStatements.length == 0) {
return ControlFlowUtils.codeBlockMayCompleteNormally(method.getBody()) ? PsiType.VOID : returnType;
}
List<ReturnValueType> valueTypes = getValueTypes(returnStatements);
if (valueTypes == null) return null;
if (isValidReturnType(returnType, valueTypes, method, manager)) return returnType;
return StreamEx.of(valueTypes).foldLeft(null, (acc, vt) -> lub(acc, vt.myLeastType, vt.myType, method, manager));
}
@Nullable
private static List<ReturnValueType> getValueTypes(@NotNull PsiReturnStatement[] statements) {
List<ReturnValueType> valueTypes = new ArrayList<>();
for (PsiReturnStatement statement : statements) {
ReturnValueType valueType = ReturnValueType.create(statement);
if (valueType == null) return null;
valueTypes.add(valueType);
}
return valueTypes;
}
@Contract("null, _, _, _ -> false")
private static boolean isValidReturnType(@Nullable PsiType returnType, @NotNull List<ReturnValueType> valueTypes,
@NotNull PsiMethod method, @NotNull PsiManager manager) {
if (returnType == null) return false;
return valueTypes.stream()
.allMatch(vt -> TypeConversionUtil.isAssignable(returnType, lub(returnType, vt.myLeastType, vt.myType, method, manager)));
}
@Contract("null, _, _, _, _ -> param3")
@NotNull
private static PsiType lub(@Nullable PsiType returnType,
@NotNull PsiType leastValueType,
@NotNull PsiType valueType,
@NotNull PsiMethod method,
@NotNull PsiManager manager) {
if (returnType == null || PsiType.VOID.equals(returnType)) return valueType;
if (returnType == valueType) return returnType;
if (TypeConversionUtil.isPrimitiveAndNotNull(valueType)) {
if (TypeConversionUtil.isPrimitiveAndNotNull(returnType)) {
int r1 = TypeConversionUtil.getTypeRank(returnType);
int r2 = TypeConversionUtil.getTypeRank(leastValueType);
return r1 >= r2 ? returnType : valueType;
}
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(returnType);
if (unboxedType != null && unboxedType.equals(valueType)) return returnType;
valueType = ((PsiPrimitiveType)valueType).getBoxedType(method);
}
if (TypeConversionUtil.isPrimitiveAndNotNull(returnType)) {
returnType = ((PsiPrimitiveType)returnType).getBoxedType(method);
}
return Objects.requireNonNull(GenericsUtil.getLeastUpperBound(returnType, valueType, manager));
}
private static class ReturnValueType {
final PsiType myType;
final PsiType myLeastType;
@Contract(pure = true)
private ReturnValueType(@NotNull PsiType type) {
myType = myLeastType = type;
}
@Contract(pure = true)
private ReturnValueType(@NotNull PsiType type, @NotNull PsiType leastType) {
myType = type;
myLeastType = leastType;
}
@Nullable
static ReturnValueType create(@NotNull PsiReturnStatement statement) {
PsiExpression value = statement.getReturnValue();
if (value == null) return new ReturnValueType(PsiType.VOID);
if (ExpressionUtils.nonStructuralChildren(value).anyMatch(c -> c instanceof PsiFunctionalExpression)) return null;
PsiType type = value.getType();
if (type == null || type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) return null;
return new ReturnValueType(type, getLeastValueType(value, type));
}
@NotNull
private static PsiType getLeastValueType(@NotNull PsiExpression returnValue, @NotNull PsiType type) {
if (type instanceof PsiPrimitiveType) {
int rank = TypeConversionUtil.getTypeRank(type);
if (rank < TypeConversionUtil.BYTE_RANK || rank > TypeConversionUtil.INT_RANK) return type;
PsiConstantEvaluationHelper evaluator = JavaPsiFacade.getInstance(returnValue.getProject()).getConstantEvaluationHelper();
Object res = evaluator.computeConstantExpression(returnValue);
if (res instanceof Number) {
long value = ((Number)res).longValue();
if (-128 <= value && value <= 127) return PsiType.BYTE;
if (-32768 <= value && value <= 32767) return PsiType.SHORT;
if (0 <= value && value <= 0xFFFF) return PsiType.CHAR;
}
}
return type;
}
}
static HighlightInfo checkConstructorName(@NotNull PsiMethod method) {
PsiClass aClass = method.getContainingClass();
if (aClass != null) {
@@ -1345,10 +1224,6 @@ public class HighlightMethodUtil {
if (className != null) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createRenameElementFix(method, className));
}
PsiType returnType = constructReturnType(method);
if (returnType != null) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMethodReturnFix(method, returnType, false, true));
}
return info;
}
}

View File

@@ -54,6 +54,7 @@ import com.intellij.util.containers.hash.HashSet;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
@@ -524,32 +525,20 @@ public class HighlightUtil extends HighlightUtilBase {
}
@Nullable
static HighlightInfo checkReturnStatementType(@NotNull PsiReturnStatement statement) {
PsiMethod method = null;
PsiLambdaExpression lambda = null;
PsiElement parent = statement.getParent();
while (true) {
if (parent instanceof PsiFile) break;
if (parent instanceof PsiClassInitializer) break;
if (parent instanceof PsiLambdaExpression){
lambda = (PsiLambdaExpression)parent;
break;
}
if (parent instanceof PsiMethod) {
method = (PsiMethod)parent;
break;
}
parent = parent.getParent();
}
if (parent instanceof PsiCodeFragment) {
static PsiElement getReturnStatementParent(@NotNull PsiReturnStatement returnStatement) {
return PsiTreeUtil.getParentOfType(returnStatement, PsiFile.class, PsiClassInitializer.class,
PsiLambdaExpression.class, PsiMethod.class);
}
@Nullable
static HighlightInfo checkReturnStatementType(@NotNull PsiReturnStatement statement, @NotNull PsiElement parent) {
if (parent instanceof PsiCodeFragment || parent instanceof PsiLambdaExpression) {
return null;
}
PsiMethod method = ObjectUtils.tryCast(parent, PsiMethod.class);
String description;
HighlightInfo errorResult = null;
if (method == null && lambda != null) {
//todo check return statements type inside lambda
}
else if (method == null && !(parent instanceof ServerPageFile)) {
if (method == null && !(parent instanceof ServerPageFile)) {
description = JavaErrorMessages.message("return.outside.method");
errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create();
}
@@ -563,7 +552,10 @@ public class HighlightUtil extends HighlightUtilBase {
description = JavaErrorMessages.message("return.from.void.method");
errorResult =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(statement).descriptionAndTooltip(description).create();
registerReturnValueFixes(errorResult, method, statement, valueType);
if (method != null && valueType != null && method.getBody() != null) {
QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createDeleteReturnFix(method, statement, returnValue));
QuickFixAction.registerQuickFixAction(errorResult, QUICK_FIX_FACTORY.createMethodReturnFix(method, valueType, true));
}
}
else {
TextRange textRange = statement.getTextRange();
@@ -593,27 +585,96 @@ public class HighlightUtil extends HighlightUtilBase {
return errorResult;
}
private static boolean isValidConstructor(@NotNull PsiMethod method) {
PsiClass aClass = method.getContainingClass();
if (aClass == null) return false;
return method.getName().equals(aClass.getName());
@Nullable
static PsiType determineReturnType(@NotNull PsiMethod method) {
PsiManager manager = method.getManager();
PsiReturnStatement[] returnStatements = PsiUtil.findReturnStatements(method);
if (returnStatements.length == 0) return PsiType.VOID;
PsiType expectedType = null;
for (PsiReturnStatement returnStatement : returnStatements) {
ReturnModel returnModel = ReturnModel.create(returnStatement);
if (returnModel == null) return null;
expectedType = lub(expectedType, returnModel.myLeastType, returnModel.myType, method, manager);
}
return expectedType;
}
private static void registerReturnValueFixes(@Nullable HighlightInfo info,
@Nullable PsiMethod method,
@NotNull PsiReturnStatement returnStatement,
@Nullable PsiType returnValueType) {
boolean canCreateFixes = method != null && returnValueType != null && (!method.isConstructor() || isValidConstructor(method));
if (!canCreateFixes) return;
static void registerReturnTypeFixes(@NotNull HighlightInfo info, @NotNull PsiMethod method, @NotNull PsiType expectedReturnType) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMethodReturnFix(method, expectedReturnType, true, true));
}
PsiCodeBlock codeBlock = method.getBody();
if (codeBlock == null) return;
PsiExpression returnValue = returnStatement.getReturnValue();
if (returnValue != null) {
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createDeleteReturnFix(method, returnStatement, returnValue));
@Contract("null, _, _, _, _ -> param3")
@NotNull
static PsiType lub(@Nullable PsiType currentType,
@NotNull PsiType leastValueType,
@NotNull PsiType valueType,
@NotNull PsiMethod method,
@NotNull PsiManager manager) {
if (currentType == null || PsiType.VOID.equals(currentType)) return valueType;
if (currentType == valueType) return currentType;
if (TypeConversionUtil.isPrimitiveAndNotNull(valueType)) {
if (TypeConversionUtil.isPrimitiveAndNotNull(currentType)) {
int r1 = TypeConversionUtil.getTypeRank(currentType);
int r2 = TypeConversionUtil.getTypeRank(leastValueType);
return r1 >= r2 ? currentType : valueType;
}
PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(currentType);
if (unboxedType != null && unboxedType.equals(valueType)) return currentType;
valueType = ((PsiPrimitiveType)valueType).getBoxedType(method);
}
if (TypeConversionUtil.isPrimitiveAndNotNull(currentType)) {
currentType = ((PsiPrimitiveType)currentType).getBoxedType(method);
}
return Objects.requireNonNull(GenericsUtil.getLeastUpperBound(currentType, valueType, manager));
}
static class ReturnModel {
final PsiReturnStatement myStatement;
final PsiType myType;
final PsiType myLeastType;
@Contract(pure = true)
private ReturnModel(@NotNull PsiReturnStatement statement, @NotNull PsiType type) {
myStatement = statement;
myType = myLeastType = type;
}
@Contract(pure = true)
private ReturnModel(@NotNull PsiReturnStatement statement, @NotNull PsiType type, @NotNull PsiType leastType) {
myStatement = statement;
myType = type;
myLeastType = leastType;
}
@Nullable
private static ReturnModel create(@NotNull PsiReturnStatement statement) {
PsiExpression value = statement.getReturnValue();
if (value == null) return new ReturnModel(statement, PsiType.VOID);
if (ExpressionUtils.nonStructuralChildren(value).anyMatch(c -> c instanceof PsiFunctionalExpression)) return null;
PsiType type = RefactoringChangeUtil.getTypeByExpression(value);
if (type == null || type instanceof PsiClassType && ((PsiClassType)type).resolve() == null) return null;
return new ReturnModel(statement, type, getLeastValueType(value, type));
}
@NotNull
private static PsiType getLeastValueType(@NotNull PsiExpression returnValue, @NotNull PsiType type) {
if (type instanceof PsiPrimitiveType) {
int rank = TypeConversionUtil.getTypeRank(type);
if (rank < TypeConversionUtil.BYTE_RANK || rank > TypeConversionUtil.INT_RANK) return type;
PsiConstantEvaluationHelper evaluator = JavaPsiFacade.getInstance(returnValue.getProject()).getConstantEvaluationHelper();
Object res = evaluator.computeConstantExpression(returnValue);
if (res instanceof Number) {
long value = ((Number)res).longValue();
if (-128 <= value && value <= 127) return PsiType.BYTE;
if (-32768 <= value && value <= 32767) return PsiType.SHORT;
if (0 <= value && value <= 0xFFFF) return PsiType.CHAR;
}
}
return type;
}
if (method.isConstructor()) return;
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createMethodReturnFix(method, returnValueType, true));
}
@NotNull

View File

@@ -84,6 +84,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
};
private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<>();
private final Set<PsiClass> myOverrideEquivalentMethodsVisitedClasses = new THashSet<>();
private final Map<PsiMethod, PsiType> myExpectedReturnTypes = new HashMap<>();
private static class Holder {
private static final boolean CHECK_ELEMENT_LEVEL = ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isInternal();
@@ -191,6 +192,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myHolder = null;
myDuplicateMethods.clear();
myOverrideEquivalentMethodsVisitedClasses.clear();
myExpectedReturnTypes.clear();
}
return success;
@@ -669,10 +671,12 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
else if (parent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)parent;
if (method.isConstructor()) {
myHolder.add(HighlightMethodUtil.checkConstructorName(method));
}
else if (method.getBody() != null) {
myHolder.add(HighlightMethodUtil.checkReturnType(method));
HighlightInfo info = HighlightMethodUtil.checkConstructorName(method);
if (info != null) {
PsiType expectedType = myExpectedReturnTypes.computeIfAbsent(method, HighlightUtil::determineReturnType);
if (expectedType != null) HighlightUtil.registerReturnTypeFixes(info, method, expectedType);
}
myHolder.add(info);
}
myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme));
final PsiClass aClass = method.getContainingClass();
@@ -1593,7 +1597,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
if (!myHolder.hasErrorResults()) {
try {
myHolder.add(HighlightUtil.checkReturnStatementType(statement));
PsiElement parent = HighlightUtil.getReturnStatementParent(statement);
HighlightInfo info = parent != null ? HighlightUtil.checkReturnStatementType(statement, parent) : null;
if (info != null && parent instanceof PsiMethod) {
PsiMethod method = (PsiMethod)parent;
PsiType expectedType = myExpectedReturnTypes.computeIfAbsent(method, HighlightUtil::determineReturnType);
if (expectedType != null && !PsiType.VOID.equals(expectedType)) HighlightUtil.registerReturnTypeFixes(info, method, expectedType);
}
myHolder.add(info);
}
catch (IndexNotReadyException ignore) { }
}

View File

@@ -60,6 +60,10 @@ public class MethodReturnTypeFix extends LocalQuickFixAndIntentionActionOnPsiEle
private final String myName;
private final String myCanonicalText;
public MethodReturnTypeFix(@NotNull PsiMethod method, @NotNull PsiType returnType, boolean fixWholeHierarchy) {
this(method, returnType, fixWholeHierarchy, false);
}
public MethodReturnTypeFix(@NotNull PsiMethod method, @NotNull PsiType returnType, boolean fixWholeHierarchy, boolean suggestSuperTypes) {
super(method);
myReturnTypePointer = SmartTypePointerManager.getInstance(method.getProject()).createSmartTypePointer(returnType);

View File

@@ -81,7 +81,7 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
public LocalQuickFixAndIntentionActionOnPsiElement createMethodReturnFix(@NotNull PsiMethod method,
@NotNull PsiType toReturn,
boolean fixWholeHierarchy) {
return new MethodReturnTypeFix(method, toReturn, fixWholeHierarchy, false);
return new MethodReturnTypeFix(method, toReturn, fixWholeHierarchy);
}
@NotNull

View File

@@ -164,7 +164,6 @@ cannot.resolve.method=Cannot resolve method ''{0}''
missing.method.body=Missing method body, or declare abstract
abstract.method.in.non.abstract.class=Abstract method in non-abstract class
missing.return.type=Invalid method declaration; return type required
invalid.return.type=Invalid return type
duplicate.method=''{0}'' is already defined in ''{1}''
constructor.call.must.be.first.statement=Call to ''{0}'' must be first statement in constructor body
direct.abstract.method.access=Abstract method ''{0}'' cannot be accessed directly

View File

@@ -1,6 +1,6 @@
class C {
<error descr="Illegal type: 'void'">void</error>[] <error descr="Invalid return type">m1</error>() { }
<error descr="Illegal type: 'void'">void</error> <error descr="Invalid return type">m2</error>()[] { }
<error descr="Illegal type: 'void'">void</error>[] m1() { }
<error descr="Illegal type: 'void'">void</error> m2()[] { }
void m3(<error descr="Illegal type: 'void'">void</error> p) {}
{

View File

@@ -6,7 +6,7 @@ interface ii {}
int <error descr="Invalid return type">f1</error>() throws Exception {
int f1() throws Exception {
<error descr="Missing return statement">}</error>
Object f2(int i) throws Exception {
@@ -217,7 +217,7 @@ interface ii {}
int <error descr="Invalid return type">f1</error>() throws Exception {
int f1() throws Exception {
<error descr="Missing return statement">}</error>
Object f2(int i) throws Exception {
@@ -421,7 +421,7 @@ interface ii {}
int <error descr="Invalid return type">f1</error>() throws Exception {
int f1() throws Exception {
<error descr="Missing return statement">}</error>
Object f2(int i) throws Exception {
@@ -626,7 +626,7 @@ interface ii {}
int <error descr="Invalid return type">f1</error>() throws Exception {
int f1() throws Exception {
<error descr="Missing return statement">}</error>
Object f2(int i) throws Exception {
@@ -829,7 +829,7 @@ interface ii {}
int <error descr="Invalid return type">f1</error>() throws Exception {
int f1() throws Exception {
<error descr="Missing return statement">}</error>
Object f2(int i) throws Exception {

View File

@@ -1,12 +1,12 @@
class s {
void <error descr="Invalid return type">f</error>() {
void f() {
<error descr="Cannot return a value from a method with void result type">return 0;</error>
}
void f2() {
return;
}
int <error descr="Invalid return type">f3</error>() {
int f3() {
<error descr="Missing return value">return;</error>
}
int f4() {

View File

@@ -1071,7 +1071,7 @@ public abstract class ClassLoader
return parent;
}
static ClassLoader <error descr="Invalid return type">createSystemClassLoader</error>(URL[] urls, ClassLoader parent)
static ClassLoader createSystemClassLoader(URL[] urls, ClassLoader parent)
{
return
new <error descr="Cannot resolve symbol 'URLClassLoader'">URLClassLoader</error>(urls, parent)

View File

@@ -6,7 +6,7 @@ class Test {
<warning descr="Unchecked call to 'isAssignableFrom(Class<?>)' as a member of raw type 'java.lang.Class'">foo.isAssignableFrom</warning>(Object.class);
}
public List<String> <error descr="Invalid return type">transform</error>(List<List<String>> result) {
public List<String> transform(List<List<String>> result) {
<error descr="Incompatible types. Found: 'java.util.List<java.util.List<java.lang.String>>', required: 'java.util.List<java.lang.String>'">return result;</error>
}
}

View File

@@ -2,7 +2,7 @@ class Test {
public <T> T doStuff() {
return null;
}
public boolean <error descr="Invalid return type">test</error>() {
public boolean test() {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'boolean'">return doStuff();</error>
}

View File

@@ -9,7 +9,7 @@ public class WrongGenerics {
}
@SuppressWarnings("unchecked")
<T> Set<Foo<? extends T>> <error descr="Invalid return type">bar</error>(Set<Foo<? extends T>> foo) {
<T> Set<Foo<? extends T>> bar(Set<Foo<? extends T>> foo) {
return <error descr="Inconvertible types; cannot cast 'java.util.Set<Foo<? extends T>>' to 'java.util.Set<Foo<?>>'">(Set<Foo<?>>) foo</error>;
}

View File

@@ -1,5 +1,5 @@
class Bug {
static A <error descr="Invalid return type">test</error>(A[] as) {
static A test(A[] as) {
for (<error descr="Incompatible types. Found: 'Bug.B', required: 'Bug.A'">B b</error> : as) {
<error descr="Incompatible types. Found: 'Bug.B', required: 'Bug.A'">return b;</error>
}

View File

@@ -12,7 +12,7 @@ class B<S> extends A<S> {
<error descr="'foo(T, S)' in 'A' clashes with 'foo(Object, Object)' in 'B'; both methods have same erasure, yet neither overrides the other">class C extends B<String></error> {
@Override
<T> T <error descr="Invalid return type">foo</error>(T x, String y) {
<T> T foo(T x, String y) {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'T'">return super.foo(x, y);</error>
}
}

View File

@@ -16,7 +16,7 @@ class LimitedPool<T> {
void cleanup(T t);
}
public T <error descr="Invalid return type">alloc</error>() {
public T alloc() {
if (index >= capacity) return factory.create();
if (storage[index] == null) {

View File

@@ -76,7 +76,7 @@ class d {
}
class e {
String <error descr="Invalid return type">foo</error> () {
String foo () {
MyList myList = new MyList();
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return myList.get(0);</error>
}
@@ -128,7 +128,7 @@ class A111<T> {
return v;
}
String <error descr="Invalid return type">g</error>(A111 a) {
String g(A111 a) {
//noinspection unchecked
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return a.f("");</error>
}
@@ -151,7 +151,7 @@ class A11<T> extends A1 {
class Test1<X> {
X x;
java.util.ArrayList<Number> foo = new java.util.ArrayList<Number>();
public static Number <error descr="Invalid return type">foo</error>() {
public static Number foo() {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.Number'">return new Test1().foo.get(0);</error>
}
}

View File

@@ -4,7 +4,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
class Test {
public static <Om> List<Om> <error descr="Invalid return type">sort</error>(Comparator comp, Stream<Om> stream) {
public static <Om> List<Om> sort(Comparator comp, Stream<Om> stream) {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.util.List<Om>'">return stream.sorted(comp).collect(Collectors.toList());</error>
}

View File

@@ -1,5 +1,5 @@
class Foo<T extends Enum> {
public T <error descr="Invalid return type">bar</error>(Class<? extends T> type, String str) {
public T bar(Class<? extends T> type, String str) {
return <error descr="Incompatible types: Enum is not convertible to T">Enum.valueOf(type, str);</error>
}
}

View File

@@ -12,7 +12,7 @@ class B<S> extends A<S> {
<error descr="'foo(T, S)' in 'A' clashes with 'foo(Object, Object)' in 'B'; both methods have same erasure, yet neither overrides the other">class C extends B<String></error> {
@Override
<T> T <error descr="Invalid return type">foo</error>(T x, String y) {
<T> T foo(T x, String y) {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'T'">return super.foo(x, y);</error>
}
}

View File

@@ -16,7 +16,7 @@ class LimitedPool<T> {
void cleanup(T t);
}
public T <error descr="Invalid return type">alloc</error>() {
public T alloc() {
if (index >= capacity) return factory.create();
if (storage[index] == null) {

View File

@@ -87,7 +87,7 @@ class d {
}
class e {
String <error descr="Invalid return type">foo</error> () {
String foo () {
MyList myList = new MyList();
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return myList.get(0);</error>
}
@@ -139,7 +139,7 @@ class A111<T> {
return v;
}
String <error descr="Invalid return type">g</error>(A111 a) {
String g(A111 a) {
//noinspection unchecked
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">return a.f("");</error>
}
@@ -162,7 +162,7 @@ class A11<T> extends A1 {
class Test1<X> {
X x;
java.util.ArrayList<Number> foo = new java.util.ArrayList<Number>();
public static Number <error descr="Invalid return type">foo</error>() {
public static Number foo() {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.Number'">return new Test1().foo.get(0);</error>
}
}

View File

@@ -3,7 +3,7 @@ abstract class Group {
public Group() {
}
public <T extends Category> T <error descr="Invalid return type">get</error>(Key<T> key) {
public <T extends Category> T get(Key<T> key) {
return <error descr="Incompatible types: Category is not convertible to T">getCategory(key);</error>
}

View File

@@ -1,6 +1,6 @@
class Outer<T> {
class Inner { }
Foo<Outer.Inner> <error descr="Invalid return type">m</error>(Foo<Outer<Integer>.Inner> foo) {
Foo<Outer.Inner> m(Foo<Outer<Integer>.Inner> foo) {
<error descr="Incompatible types. Found: 'Foo<Outer<java.lang.Integer>.Inner>', required: 'Foo<Outer.Inner>'">return foo;</error>
}
}

View File

@@ -6,7 +6,7 @@ class Test {
return list.stream().flatMap(List::stream).collect(Collectors.toList());
}
private static List<Object> <error descr="Invalid return type">test1</error>(List<List> list) {
private static List<Object> test1(List<List> list) {
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.util.List<java.lang.Object>'">return list.stream().flatMap(l -> l.stream()).collect(Collectors.toList());</error>
}
}

View File

@@ -26,7 +26,7 @@ public class ConcurrentCollectors {
}
static class Test3 {
static <T, K, D, M1 extends Map<K, D>> C<T, M1> <error descr="Invalid return type">groupingBy</error>(F<M1> f,
static <T, K, D, M1 extends Map<K, D>> C<T, M1> groupingBy(F<M1> f,
C<T, D> c,
BiConsumer<M1, T> consumer) {
return new CImpl<error descr="Cannot infer arguments"><></error>(f, consumer, arg(c.getOp()));

View File

@@ -11,7 +11,7 @@ interface Foo<T> {
}
class Bar {
Foo<List<String>> <error descr="Invalid return type">transform</error>(final Foo<? extends String> foo) {
Foo<List<String>> transform(final Foo<? extends String> foo) {
<error descr="Incompatible types. Found: 'Foo<? extends java.util.List<? extends java.lang.String>>', required: 'Foo<java.util.List<java.lang.String>>'">return foo
.map(v2 -> tuple(v2))
.onClose();</error>

View File

@@ -3,7 +3,7 @@ import java.util.Map;
import java.util.stream.Collectors;
class MyTest {
static Map<String, Meeting> <error descr="Invalid return type">getMeetingsById</error>(List<Meeting> meetings){
static Map<String, Meeting> getMeetingsById(List<Meeting> meetings){
return <error descr="Incompatible types. Found: 'java.util.Map<java.lang.String,java.util.List<Meeting>>', required: 'java.util.Map<java.lang.String,Meeting>'">meetings.stream()
.collect(Collectors.groupingBy(Meeting::getId));</error>
}

View File

@@ -2,8 +2,8 @@
class Test {
void <caret>m(boolean b) {
if (b) return null;
void m(boolean b) {
if (b) return n<caret>ull;
return 42;
}

View File

@@ -2,8 +2,8 @@
class Test {
void <caret>m() {
return 42;
void m() {
return 4<caret>2;
}
}

View File

@@ -2,7 +2,7 @@
class Test {
int <caret>m() {
}
int m() {
}<caret>
}

View File

@@ -3,8 +3,8 @@ import java.util.*;
class Test {
void <caret>m(boolean b) {
if (b) return new ArrayList<>();
void m(boolean b) {
if (b) <caret>return new ArrayList<>();
return new LinkedList<>();
}

View File

@@ -39,7 +39,7 @@ interface I2 extends I1 {
class A implements I1 {
@Override
public Object <error descr="Invalid return type">foo</error>() {
public Object foo() {
// returns something
<error descr="Missing return statement">}</error>
}

View File

@@ -1,6 +1,6 @@
class A{
String <error descr="Invalid return type">toHex</error>(int i) {<error descr="Missing return statement">}</error>
String <error descr="Invalid return type">toHex</error>(short i) {<error descr="Missing return statement">}</error>
String toHex(int i) {<error descr="Missing return statement">}</error>
String toHex(short i) {<error descr="Missing return statement">}</error>
void f(){
String result = toHex((short)'i');

View File

@@ -88,7 +88,7 @@ public class LightAdvHighlightingPerformanceTest extends LightDaemonAnalyzerTest
public void testAClassLoader() {
List<HighlightInfo> errors = doTest(800);
if (93 != errors.size()) {
if (92 != errors.size()) {
doTest(getFilePath("_hl"), false, false);
fail("Actual: " + errors.size());
}

View File

@@ -64,7 +64,7 @@ public class DataProviderReturnTypeInspection extends AbstractBaseJavaLocalInspe
String[] applicableReturnTypes = supportOneDimensional ? KNOWN_WITH_ONE_DIMENSIONAL_RETURN_TYPES : KNOWN_RETURN_TYPES;
for (String typeText : applicableReturnTypes) {
fixes.add(new MethodReturnTypeFix(method, elementFactory.createTypeFromText(typeText, method), false, false));
fixes.add(new MethodReturnTypeFix(method, elementFactory.createTypeFromText(typeText, method), false));
}
return fixes.toArray(LocalQuickFix.EMPTY_ARRAY);