2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.siyeh.ig.naming;
18 import com.intellij.psi.*;
19 import com.intellij.psi.util.PsiSuperMethodUtil;
20 import com.siyeh.InspectionGadgetsBundle;
21 import com.siyeh.ig.BaseInspection;
22 import com.siyeh.ig.BaseInspectionVisitor;
23 import org.jetbrains.annotations.Nls;
24 import org.jetbrains.annotations.NotNull;
26 import java.util.Objects;
29 * @author Bas Leijdekkers
31 public class LambdaUnfriendlyMethodOverloadInspectionBase extends BaseInspection {
35 public String getDisplayName() {
36 return InspectionGadgetsBundle.message("lambda.unfriendly.method.overload.display.name");
41 protected String buildErrorString(Object... infos) {
42 final PsiMethod method = (PsiMethod)infos[0];
43 return InspectionGadgetsBundle.message(method.isConstructor()
44 ? "lambda.unfriendly.constructor.overload.problem.descriptor"
45 : "lambda.unfriendly.method.overload.problem.descriptor");
49 public BaseInspectionVisitor buildVisitor() {
50 return new LambdaUnfriendlyMethodOverloadVisitor();
53 private static class LambdaUnfriendlyMethodOverloadVisitor extends BaseInspectionVisitor {
56 public void visitMethod(PsiMethod method) {
57 super.visitMethod(method);
58 final PsiParameterList parameterList = method.getParameterList();
59 final int parametersCount = parameterList.getParametersCount();
60 if (parametersCount == 0) {
63 final PsiParameter[] parameters = parameterList.getParameters();
64 int functionalIndex = -1;
65 for (int i = 0; i < parameters.length; i++) {
66 final PsiParameter parameter = parameters[i];
67 if (LambdaUtil.isFunctionalType(parameter.getType())) {
72 if (functionalIndex < 0) {
75 final PsiClass containingClass = method.getContainingClass();
76 if (containingClass == null) {
79 final String name = method.getName();
80 for (PsiMethod sameNameMethod : containingClass.findMethodsByName(name, true)) {
81 if (method.equals(sameNameMethod) || PsiSuperMethodUtil.isSuperMethod(method, sameNameMethod)) {
84 final PsiParameterList otherParameterList = sameNameMethod.getParameterList();
85 if (parametersCount != otherParameterList.getParametersCount()) {
88 final PsiParameter[] otherParameters = otherParameterList.getParameters();
89 final PsiType otherFunctionalType = otherParameters[functionalIndex].getType();
90 final PsiType functionalType = parameters[functionalIndex].getType();
91 if (!areOtherParameterTypesConvertible(parameters, otherParameters, functionalIndex) ||
92 !LambdaUtil.isFunctionalType(otherFunctionalType) ||
93 Objects.equals(functionalType, otherFunctionalType)) {
97 if (areSameShapeFunctionalTypes(functionalType, otherFunctionalType)) {
98 registerMethodError(method, method);
104 private static boolean areSameShapeFunctionalTypes(PsiType one, PsiType two) {
105 final PsiMethod method1 = LambdaUtil.getFunctionalInterfaceMethod(one);
106 final PsiMethod method2 = LambdaUtil.getFunctionalInterfaceMethod(two);
107 if (method1 == null || method2 == null) {
110 final PsiType returnType1 = method1.getReturnType();
111 final PsiType returnType2 = method2.getReturnType();
112 if (PsiType.VOID.equals(returnType1) ^ PsiType.VOID.equals(returnType2)) {
115 return method1.getParameterList().getParametersCount() == method2.getParameterList().getParametersCount();
118 private static boolean areOtherParameterTypesConvertible(PsiParameter[] parameters, PsiParameter[] otherParameters, int notThisOne) {
119 for (int i = 0; i < parameters.length; i++) {
120 if (i == notThisOne) {
123 final PsiType type = parameters[i].getType();
124 final PsiType otherType = otherParameters[i].getType();
125 if (!type.isAssignableFrom(otherType) && !otherType.isAssignableFrom(type)) {