1683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti/*
2683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Copyright 2016 Federico Tomassetti
3683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
4683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Licensed under the Apache License, Version 2.0 (the "License");
5683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * you may not use this file except in compliance with the License.
6683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * You may obtain a copy of the License at
7683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
8683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * http://www.apache.org/licenses/LICENSE-2.0
9683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti *
10683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * Unless required by applicable law or agreed to in writing, software
11683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * distributed under the License is distributed on an "AS IS" BASIS,
12683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * See the License for the specific language governing permissions and
14683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti * limitations under the License.
15683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti */
16683012de2a3a28358e848f8b145d462eb8b322baFederico Tomassetti
179c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettipackage com.github.javaparser.symbolsolver.resolution;
18d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti
19223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassettiimport com.github.javaparser.resolution.MethodAmbiguityException;
205d8d0cb7947efcf2282f7d056302dd905f348532Federico Tomassettiimport com.github.javaparser.resolution.MethodUsage;
21e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassettiimport com.github.javaparser.resolution.declarations.*;
22e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassettiimport com.github.javaparser.resolution.types.*;
239c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.core.resolution.Context;
2416720991418fda8f29abd4888fd1a5969f99d259malte_langkabelimport com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserAnonymousClassDeclaration;
259c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration;
269c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserEnumDeclaration;
279c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserInterfaceDeclaration;
289c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration;
299c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javassistmodel.JavassistClassDeclaration;
30c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoideimport com.github.javaparser.symbolsolver.javassistmodel.JavassistEnumDeclaration;
319c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.javassistmodel.JavassistInterfaceDeclaration;
321e7780e554428a10c73de88ca64e5933b2291593Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
339c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
34cb5ffb7fdd56f1b768d25da330fa3b29ecb74eafFederico Tomassettiimport com.github.javaparser.symbolsolver.model.typesystem.*;
359c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
36c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoideimport com.github.javaparser.symbolsolver.reflectionmodel.ReflectionEnumDeclaration;
379c53c2cbc607ea694438ade8630be0c155a33162Federico Tomassettiimport com.github.javaparser.symbolsolver.reflectionmodel.ReflectionInterfaceDeclaration;
38630eb94d43670f2080c7273584d49c0b0d4162f1Federico Tomassetti
39cb5ffb7fdd56f1b768d25da330fa3b29ecb74eafFederico Tomassettiimport java.util.*;
40cb5ffb7fdd56f1b768d25da330fa3b29ecb74eafFederico Tomassettiimport java.util.stream.Collectors;
41cb5ffb7fdd56f1b768d25da330fa3b29ecb74eafFederico Tomassetti
42a7803cf050435e3162f7fdde83fb9692a891e92eFederico Tomassetti/**
43a7803cf050435e3162f7fdde83fb9692a891e92eFederico Tomassetti * @author Federico Tomassetti
44a7803cf050435e3162f7fdde83fb9692a891e92eFederico Tomassetti */
45d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassettipublic class MethodResolutionLogic {
46d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti
47e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static List<ResolvedType> groupVariadicParamValues(List<ResolvedType> argumentsTypes, int startVariadic, ResolvedType variadicType) {
48e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        List<ResolvedType> res = new ArrayList<>(argumentsTypes.subList(0, startVariadic));
49e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        List<ResolvedType> variadicValues = argumentsTypes.subList(startVariadic, argumentsTypes.size());
50e709c28d4c7d8aa5f4ae1a76c2ca746c244e496fayman abdelghany        if (variadicValues.isEmpty()) {
51ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti            // TODO if there are no variadic values we should default to the bound of the formal type
52ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti            res.add(variadicType);
53ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        } else {
54e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType componentType = findCommonType(variadicValues);
55e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            res.add(new ResolvedArrayType(componentType));
56ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        }
57ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        return res;
58ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti    }
59ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti
60e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static ResolvedType findCommonType(List<ResolvedType> variadicValues) {
61e709c28d4c7d8aa5f4ae1a76c2ca746c244e496fayman abdelghany        if (variadicValues.isEmpty()) {
62ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti            throw new IllegalArgumentException();
63ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        }
64ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        // TODO implement this decently
65ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        return variadicValues.get(0);
66ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti    }
67ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti
68e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    public static boolean isApplicable(ResolvedMethodDeclaration method, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
6988db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti        return isApplicable(method, name, argumentsTypes, typeSolver, false);
70c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti    }
71c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti
72e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static boolean isApplicable(ResolvedMethodDeclaration method, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver, boolean withWildcardTolerance) {
73d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        if (!method.getName().equals(name)) {
74d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti            return false;
75d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        }
76ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        if (method.hasVariadicParameter()) {
77b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti            int pos = method.getNumberOfParams() - 1;
78b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti            if (method.getNumberOfParams() == argumentsTypes.size()) {
79ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                // check if the last value is directly assignable as an array
80e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedType expectedType = method.getLastParam().getType();
81e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedType actualType = argumentsTypes.get(pos);
82ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                if (!expectedType.isAssignableBy(actualType)) {
83e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    for (ResolvedTypeParameterDeclaration tp : method.getTypeParameters()) {
84ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                        expectedType = replaceTypeParam(expectedType, tp, typeSolver);
85ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                    }
86ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                    if (!expectedType.isAssignableBy(actualType)) {
87051dbd94c17c4f142d3fe9e8fbd03c29d09ace54Federico Tomassetti                        if (actualType.isArray() && expectedType.isAssignableBy(actualType.asArrayType().getComponentType())) {
8888db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti                            argumentsTypes.set(pos, actualType.asArrayType().getComponentType());
89b20f28d6034a54108c056947c631c360fa079138Federico Tomassetti                        } else {
9088db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti                            argumentsTypes = groupVariadicParamValues(argumentsTypes, pos, method.getLastParam().getType());
91b20f28d6034a54108c056947c631c360fa079138Federico Tomassetti                        }
92ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                    }
93ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti                } // else it is already assignable, nothing to do
94ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti            } else {
95c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                if (pos > argumentsTypes.size()) {
96c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                  return false;
97c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                }
9888db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti                argumentsTypes = groupVariadicParamValues(argumentsTypes, pos, method.getLastParam().getType());
99ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti            }
100ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        }
101ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti
102b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti        if (method.getNumberOfParams() != argumentsTypes.size()) {
103d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti            return false;
104d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        }
105e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        Map<String, ResolvedType> matchedParameters = new HashMap<>();
106c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti        boolean needForWildCardTolerance = false;
107b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti        for (int i = 0; i < method.getNumberOfParams(); i++) {
108e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedType = method.getParam(i).getType();
109e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType actualType = argumentsTypes.get(i);
11069e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti            if ((expectedType.isTypeVariable() && !(expectedType.isWildcard())) && expectedType.asTypeParameter().declaredOnMethod()) {
1116e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti                matchedParameters.put(expectedType.asTypeParameter().getName(), actualType);
1126e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti                continue;
1136e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti            }
114e3e4b88ee821fdcec76aa3c940cb4b4f466bc2cdFederico Tomassetti            boolean isAssignableWithoutSubstitution = expectedType.isAssignableBy(actualType) ||
115e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    (method.getParam(i).isVariadic() && new ResolvedArrayType(expectedType).isAssignableBy(actualType));
1163337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            if (!isAssignableWithoutSubstitution && expectedType.isReferenceType() && actualType.isReferenceType()) {
1173337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                isAssignableWithoutSubstitution = isAssignableMatchTypeParameters(
118051dbd94c17c4f142d3fe9e8fbd03c29d09ace54Federico Tomassetti                        expectedType.asReferenceType(),
119051dbd94c17c4f142d3fe9e8fbd03c29d09ace54Federico Tomassetti                        actualType.asReferenceType(),
1203337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                        matchedParameters);
1213337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            }
122558fc9b4f808d718b9b266071078752ba68d4203Federico Tomassetti            if (!isAssignableWithoutSubstitution) {
123e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                List<ResolvedTypeParameterDeclaration> typeParameters = method.getTypeParameters();
124e2cc24a4f5a54a058c1d9ba971b7c8aa0a445601malte_langkabel                typeParameters.addAll(method.declaringType().getTypeParameters());
125e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                for (ResolvedTypeParameterDeclaration tp : typeParameters) {
126eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                    expectedType = replaceTypeParam(expectedType, tp, typeSolver);
127558fc9b4f808d718b9b266071078752ba68d4203Federico Tomassetti                }
128f821be8dfe72fcd3f4e14f75420617b87ddb8689Federico Tomassetti
1290b419e87200878fe13db395a415efc4d1338cef2Federico Tomassetti                if (!expectedType.isAssignableBy(actualType)) {
130c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti                    if (actualType.isWildcard() && withWildcardTolerance && !expectedType.isPrimitive()) {
131c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti                        needForWildCardTolerance = true;
132c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti                        continue;
133c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti                    }
134b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti                    if (method.hasVariadicParameter() && i == method.getNumberOfParams() - 1) {
135e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                        if (new ResolvedArrayType(expectedType).isAssignableBy(actualType)) {
136b20f28d6034a54108c056947c631c360fa079138Federico Tomassetti                            continue;
137b20f28d6034a54108c056947c631c360fa079138Federico Tomassetti                        }
138b20f28d6034a54108c056947c631c360fa079138Federico Tomassetti                    }
139558fc9b4f808d718b9b266071078752ba68d4203Federico Tomassetti                    return false;
140558fc9b4f808d718b9b266071078752ba68d4203Federico Tomassetti                }
141d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti            }
142d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        }
143c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti        return !withWildcardTolerance || needForWildCardTolerance;
144d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti    }
145d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti
146e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    public static boolean isAssignableMatchTypeParameters(ResolvedType expected, ResolvedType actual,
147e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                                                          Map<String, ResolvedType> matchedParameters) {
14869e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti        if (expected.isReferenceType() && actual.isReferenceType()) {
14969e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti            return isAssignableMatchTypeParameters(expected.asReferenceType(), actual.asReferenceType(), matchedParameters);
15069e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti        } else if (expected.isTypeVariable()) {
15169e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti            matchedParameters.put(expected.asTypeParameter().getName(), actual);
15269e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti            return true;
15369e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti        } else {
1541e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti            throw new UnsupportedOperationException(expected.getClass().getCanonicalName() + " " + actual.getClass().getCanonicalName());
15569e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti        }
15669e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti    }
15769e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti
158e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    public static boolean isAssignableMatchTypeParameters(ResolvedReferenceType expected, ResolvedReferenceType actual,
159e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                                                          Map<String, ResolvedType> matchedParameters) {
1603337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        if (actual.getQualifiedName().equals(expected.getQualifiedName())) {
1613337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            return isAssignableMatchTypeParametersMatchingQName(expected, actual, matchedParameters);
1623337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        } else {
163e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            List<ResolvedReferenceType> ancestors = actual.getAllAncestors();
164e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            for (ResolvedReferenceType ancestor : ancestors) {
1653337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                if (isAssignableMatchTypeParametersMatchingQName(expected, ancestor, matchedParameters)) {
1663337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                    return true;
1673337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                }
1683337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            }
1693337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        }
1703337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        return false;
1713337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti    }
1723337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti
173e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static boolean isAssignableMatchTypeParametersMatchingQName(ResolvedReferenceType expected, ResolvedReferenceType actual,
174e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                                                                        Map<String, ResolvedType> matchedParameters) {
1753337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti
1763337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        if (!expected.getQualifiedName().equals(actual.getQualifiedName())) {
1773337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            return false;
1783337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        }
17970f3e66c944670a818922f101162226ef604b263Federico Tomassetti        if (expected.typeParametersValues().size() != actual.typeParametersValues().size()) {
1803337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            throw new UnsupportedOperationException();
1813337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            //return true;
1823337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        }
18370f3e66c944670a818922f101162226ef604b263Federico Tomassetti        for (int i = 0; i < expected.typeParametersValues().size(); i++) {
184e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedParam = expected.typeParametersValues().get(i);
185e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType actualParam = actual.typeParametersValues().get(i);
18689fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop
18789fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop            // In the case of nested parameterizations eg. List<R> <-> List<Integer>
18889fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop            // we should peel off one layer and ensure R <-> Integer
18989fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop            if (expectedParam.isReferenceType() && actualParam.isReferenceType()){
190e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedReferenceType r1 = expectedParam.asReferenceType();
191e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedReferenceType r2 = actualParam.asReferenceType();
19289fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop
19389fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop                return isAssignableMatchTypeParametersMatchingQName(r1, r2, matchedParameters);
19489fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop            }
19589fe70d234005ccd9479e9c26f8c77d8eb35a6a7xdrop
1963337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            if (expectedParam.isTypeVariable()) {
1973337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                String expectedParamName = expectedParam.asTypeParameter().getName();
1983337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                if (!actualParam.isTypeVariable() || !actualParam.asTypeParameter().getName().equals(expectedParamName)) {
19904395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                    return matchTypeVariable(expectedParam.asTypeVariable(), actualParam, matchedParameters);
2003337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                }
2013337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            } else if (expectedParam.isReferenceType()) {
20204395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                if (actualParam.isTypeVariable()) {
20304395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                    return matchTypeVariable(actualParam.asTypeVariable(), expectedParam, matchedParameters);
204c7331319573681ed2251cce3c2ea82348ff4d7c6mlangkabel                } else if (!expectedParam.equals(actualParam)) {
2053337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                    return false;
2063337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti                }
20726c12a20f1206e2a1f63c46b6b41c304af8c7389Federico Tomassetti            } else if (expectedParam.isWildcard()) {
2081e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti                if (expectedParam.asWildcard().isExtends()) {
20969e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti                    return isAssignableMatchTypeParameters(expectedParam.asWildcard().getBoundedType(), actual, matchedParameters);
21069e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti                }
21169e724f5a168e148ea4479c872cfbf656fce8accFederico Tomassetti                // TODO verify super bound
21226c12a20f1206e2a1f63c46b6b41c304af8c7389Federico Tomassetti                return true;
2133337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            } else {
21426c12a20f1206e2a1f63c46b6b41c304af8c7389Federico Tomassetti                throw new UnsupportedOperationException(expectedParam.describe());
2153337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti            }
2163337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        }
2173337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti        return true;
2183337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti    }
2193337bf584f7ef47f4f56b81743ca0d83930763bfFederico Tomassetti
220e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static boolean matchTypeVariable(ResolvedTypeVariable typeVariable, ResolvedType type, Map<String, ResolvedType> matchedParameters) {
22104395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel        String typeParameterName = typeVariable.asTypeParameter().getName();
22204395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel        if (matchedParameters.containsKey(typeParameterName)) {
223e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType matchedParameter = matchedParameters.get(typeParameterName);
22404395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel            if (matchedParameter.isAssignableBy(type)) {
22504395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                return true;
22604395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel            } else if (type.isAssignableBy(matchedParameter)) {
22704395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                // update matchedParameters to contain the more general type
22804395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                matchedParameters.put(typeParameterName, type);
22904395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel                return true;
23004395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel            }
23104395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel            return false;
23204395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel        } else {
23304395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel            matchedParameters.put(typeParameterName, type);
23404395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel        }
23504395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel        return true;
23604395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel    }
23704395d51f29cecbf4d58f8e2e23d7fcbbb1c6d0dmlangkabel
2385d8d0cb7947efcf2282f7d056302dd905f348532Federico Tomassetti    public static ResolvedType replaceTypeParam(ResolvedType type, ResolvedTypeParameterDeclaration tp, TypeSolver typeSolver) {
23982eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti        if (type.isTypeVariable()) {
24082eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti            if (type.describe().equals(tp.getName())) {
241e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                List<ResolvedTypeParameterDeclaration.Bound> bounds = tp.getBounds();
242eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                if (bounds.size() > 1) {
243eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                    throw new UnsupportedOperationException();
24449719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti                } else if (bounds.size() == 1) {
245eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                    return bounds.get(0).getType();
246eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                } else {
24782eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti                    return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
248eec165d9e3ef0ab1d93f69a231964984a3379762Federico Tomassetti                }
249f821be8dfe72fcd3f4e14f75420617b87ddb8689Federico Tomassetti            }
25082eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti            return type;
25182eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti        } else if (type.isPrimitive()) {
25282eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti            return type;
25382eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti        } else if (type.isArray()) {
2545d8d0cb7947efcf2282f7d056302dd905f348532Federico Tomassetti            return new ResolvedArrayType(replaceTypeParam(type.asArrayType().getComponentType(), tp, typeSolver));
25582eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti        } else if (type.isReferenceType()) {
2565d8d0cb7947efcf2282f7d056302dd905f348532Federico Tomassetti            ResolvedReferenceType result = type.asReferenceType();
257bfed113b416d139de8c5fedb4e39da353e31d992Federico Tomassetti            result = result.transformTypeParameters(typeParam -> replaceTypeParam(typeParam, tp, typeSolver)).asReferenceType();
25881d24cde385d47abd15f9e81cf22ff0413ee5d14Federico Tomassetti            return result;
25982eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti        } else if (type.isWildcard()) {
26082eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti            if (type.describe().equals(tp.getName())) {
261e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                List<ResolvedTypeParameterDeclaration.Bound> bounds = tp.getBounds();
262fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                if (bounds.size() > 1) {
263fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                    throw new UnsupportedOperationException();
264fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                } else if (bounds.size() == 1) {
265fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                    return bounds.get(0).getType();
266fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                } else {
26782eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti                    return new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver);
268fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti                }
269fdf266d3432a99bc960ab57f1294046281148c79Federico Tomassetti            }
27082eb44707b620803d424188a1eb8708fcaf093cbFederico Tomassetti            return type;
271ead147279ca0b84d2f479a714943b20cd689e7c7Federico Tomassetti        } else {
2721e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti            throw new UnsupportedOperationException("Replacing " + type + ", param " + tp + " with " + type.getClass().getCanonicalName());
273f821be8dfe72fcd3f4e14f75420617b87ddb8689Federico Tomassetti        }
274f821be8dfe72fcd3f4e14f75420617b87ddb8689Federico Tomassetti    }
275f821be8dfe72fcd3f4e14f75420617b87ddb8689Federico Tomassetti
2765d8d0cb7947efcf2282f7d056302dd905f348532Federico Tomassetti    public static boolean isApplicable(MethodUsage method, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
27774026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        if (!method.getName().equals(name)) {
27874026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            return false;
27974026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
28074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        // TODO Consider varargs
28188db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti        if (method.getNoParams() != argumentsTypes.size()) {
28274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            return false;
28374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
28449719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti        for (int i = 0; i < method.getNoParams(); i++) {
285e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedType = method.getParamType(i);
286e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedTypeWithoutSubstitutions = expectedType;
287e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedTypeWithInference = method.getParamType(i);
288e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType actualType = argumentsTypes.get(i);
2891e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti
290e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            List<ResolvedTypeParameterDeclaration> typeParameters = method.getDeclaration().getTypeParameters();
29101f3fa874fcd280adfedc4b3807f0ce7e40535d2malte_langkabel            typeParameters.addAll(method.declaringType().getTypeParameters());
292acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
293acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (expectedType.describe().equals(actualType.describe())){
294acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                return true;
295acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
296acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
297e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            Map<ResolvedTypeParameterDeclaration, ResolvedType> derivedValues = new HashMap<>();
298acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            for (int j = 0; j < method.getParamTypes().size(); j++) {
299e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedParameterDeclaration parameter = method.getDeclaration().getParam(i);
300e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedType parameterType = parameter.getType();
301acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (parameter.isVariadic()) {
302acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    parameterType = parameterType.asArrayType().getComponentType();
303acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
304acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                inferTypes(argumentsTypes.get(j), parameterType, derivedValues);
305acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
306acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
307e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            for (Map.Entry<ResolvedTypeParameterDeclaration, ResolvedType> entry : derivedValues.entrySet()){
308e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                ResolvedTypeParameterDeclaration tp = entry.getKey();
309acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                expectedTypeWithInference = expectedTypeWithInference.replaceTypeVariables(tp, entry.getValue());
310acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
311acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
312e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            for (ResolvedTypeParameterDeclaration tp : typeParameters) {
313e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                if (tp.getBounds().isEmpty()) {
314631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                    //expectedType = expectedType.replaceTypeVariables(tp.getName(), new ReferenceTypeUsageImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
315e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    expectedType = expectedType.replaceTypeVariables(tp, ResolvedWildcard.extendsBound(new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver)));
316e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                } else if (tp.getBounds().size() == 1) {
317e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    ResolvedTypeParameterDeclaration.Bound bound = tp.getBounds().get(0);
318a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                    if (bound.isExtends()) {
319631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                        //expectedType = expectedType.replaceTypeVariables(tp.getName(), bound.getType());
320e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                        expectedType = expectedType.replaceTypeVariables(tp, ResolvedWildcard.extendsBound(bound.getType()));
321a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                    } else {
322631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                        //expectedType = expectedType.replaceTypeVariables(tp.getName(), new ReferenceTypeUsageImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
323e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                        expectedType = expectedType.replaceTypeVariables(tp, ResolvedWildcard.superBound(bound.getType()));
324454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                    }
325454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                } else {
326454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                    throw new UnsupportedOperationException();
327454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                }
328454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti            }
329e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType expectedType2 = expectedTypeWithoutSubstitutions;
330e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            for (ResolvedTypeParameterDeclaration tp : typeParameters) {
331e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                if (tp.getBounds().isEmpty()) {
332631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                    expectedType2 = expectedType2.replaceTypeVariables(tp, new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
333e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                } else if (tp.getBounds().size() == 1) {
334e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    ResolvedTypeParameterDeclaration.Bound bound = tp.getBounds().get(0);
335454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                    if (bound.isExtends()) {
336631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                        expectedType2 = expectedType2.replaceTypeVariables(tp, bound.getType());
337454904fe0cb3b15aa506e3f5fa8f0c9fb1313f61Federico Tomassetti                    } else {
338631896a1d2f34eed89c41cc717f463ebbd69e401Federico Tomassetti                        expectedType2 = expectedType2.replaceTypeVariables(tp, new ReferenceTypeImpl(typeSolver.solveType(Object.class.getCanonicalName()), typeSolver));
339a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                    }
340a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                } else {
341a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                    throw new UnsupportedOperationException();
342a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti                }
343a6849db3884e47909d2d97fcac0b057ab13d544bFederico Tomassetti            }
344bdb0b3525f68c94381a57016bd124db2252c4f74ayman abdelghany            if (!expectedType.isAssignableBy(actualType)
345bdb0b3525f68c94381a57016bd124db2252c4f74ayman abdelghany                    && !expectedType2.isAssignableBy(actualType)
346acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    && !expectedTypeWithInference.isAssignableBy(actualType)
347bdb0b3525f68c94381a57016bd124db2252c4f74ayman abdelghany                    && !expectedTypeWithoutSubstitutions.isAssignableBy(actualType)) {
3481e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti                return false;
34974026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            }
35074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
35174026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        return true;
35274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti    }
35374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti
354e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    private static List<ResolvedMethodDeclaration> getMethodsWithoutDuplicates(List<ResolvedMethodDeclaration> methods) {
355e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        Set<ResolvedMethodDeclaration> s = new TreeSet<>((m1, m2) -> {
356e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            if (m1 instanceof JavaParserMethodDeclaration && m2 instanceof JavaParserMethodDeclaration &&
357e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                    ((JavaParserMethodDeclaration) m1).getWrappedNode().equals(((JavaParserMethodDeclaration) m2).getWrappedNode())) {
358e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti                return 0;
359dfbc101bfbffe83d27776868495634b3e7a256e7malte_langkabel            }
360e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            return 1;
361dfbc101bfbffe83d27776868495634b3e7a256e7malte_langkabel        });
362dfbc101bfbffe83d27776868495634b3e7a256e7malte_langkabel        s.addAll(methods);
363e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        List<ResolvedMethodDeclaration> res = new ArrayList<>();
36437576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti        Set<String> usedSignatures = new HashSet<>();
365e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti        for (ResolvedMethodDeclaration md : methods) {
36637576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti            String signature = md.getQualifiedSignature();
36737576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti            if (!usedSignatures.contains(signature)) {
36837576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti                usedSignatures.add(signature);
36937576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti                res.add(md);
37037576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti            }
37137576d078d11264fec1a28bbffea400003160b6bFederico Tomassetti        }
372dfbc101bfbffe83d27776868495634b3e7a256e7malte_langkabel        return res;
373dfbc101bfbffe83d27776868495634b3e7a256e7malte_langkabel    }
3741e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti
375a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti    /**
376effd4c172ad6e4d60d68a749121a0960040edd63Federico Tomassetti     * @param methods        we expect the methods to be ordered such that inherited methods are later in the list
377a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti     * @param name
37888db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti     * @param argumentsTypes
379a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti     * @param typeSolver
380a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti     * @return
381a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti     */
382223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    public static SymbolReference<ResolvedMethodDeclaration> findMostApplicable(List<ResolvedMethodDeclaration> methods,
383223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                                                                String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
384223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti        SymbolReference<ResolvedMethodDeclaration> res = findMostApplicable(methods, name, argumentsTypes, typeSolver, false);
385c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti        if (res.isSolved()) {
386c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti            return res;
387c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti        }
38888db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti        return findMostApplicable(methods, name, argumentsTypes, typeSolver, true);
389c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti    }
390c48864ccaea00039c2f6a8390d21cffd3fbde054Federico Tomassetti
391223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    public static SymbolReference<ResolvedMethodDeclaration> findMostApplicable(List<ResolvedMethodDeclaration> methods,
392223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                                                                String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver, boolean wildcardTolerance) {
393223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti        List<ResolvedMethodDeclaration> applicableMethods = getMethodsWithoutDuplicates(methods).stream().filter((m) -> isApplicable(m, name, argumentsTypes, typeSolver, wildcardTolerance)).collect(Collectors.toList());
394d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        if (applicableMethods.isEmpty()) {
395e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            return SymbolReference.unsolved(ResolvedMethodDeclaration.class);
396d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        }
397acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
398936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide        if (applicableMethods.size() > 1) {
399936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide          List<Integer> nullParamIndexes = new ArrayList<>();
400936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide          for (int i = 0; i < argumentsTypes.size(); i++) {
401936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            if (argumentsTypes.get(i).isNull()) {
402936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide              nullParamIndexes.add(i);
403936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            }
404936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide          }
405936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide          if (!nullParamIndexes.isEmpty()) {
406936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            // remove method with array param if a non array exists and arg is null
407223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            Set<ResolvedMethodDeclaration> removeCandidates = new HashSet<>();
408936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            for (Integer nullParamIndex: nullParamIndexes) {
409223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti              for (ResolvedMethodDeclaration methDecl: applicableMethods) {
410936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide                if (methDecl.getParam(nullParamIndex.intValue()).getType().isArray()) {
411936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide                  removeCandidates.add(methDecl);
412936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide                }
413936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide              }
414936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            }
415936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            if (!removeCandidates.isEmpty() && removeCandidates.size() < applicableMethods.size()) {
416936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide              applicableMethods.removeAll(removeCandidates);
417936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide            }
418936b3bf34af0bbdfd804c9f69c7a52b654cf6e1eFred Lefévère-Laoide          }
419c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        }
420d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        if (applicableMethods.size() == 1) {
421d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti            return SymbolReference.solved(applicableMethods.get(0));
422d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        } else {
423223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedMethodDeclaration winningCandidate = applicableMethods.get(0);
424223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedMethodDeclaration other = null;
425c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide            boolean possibleAmbiguity = false;
42649719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti            for (int i = 1; i < applicableMethods.size(); i++) {
427c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                other = applicableMethods.get(i);
428acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (isMoreSpecific(winningCandidate, other, argumentsTypes, typeSolver)) {
429c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                    possibleAmbiguity = false;
430acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                } else if (isMoreSpecific(other, winningCandidate, argumentsTypes, typeSolver)) {
431c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                    possibleAmbiguity = false;
43227bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti                    winningCandidate = other;
43327bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti                } else {
434a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti                    if (winningCandidate.declaringType().getQualifiedName().equals(other.declaringType().getQualifiedName())) {
435c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                        possibleAmbiguity = true;
436a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti                    } else {
437a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti                        // we expect the methods to be ordered such that inherited methods are later in the list
438a7fa0c3db19bd74be9affdd624447251963b68afFederico Tomassetti                    }
43927bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti                }
44027bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            }
441c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide            if (possibleAmbiguity) {
442c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide              // pick the first exact match if it exists
443c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide              if (!isExactMatch(winningCandidate, argumentsTypes)) {
444c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                if (isExactMatch(other, argumentsTypes)) {
445c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                  winningCandidate = other;
446c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                } else {
447c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                  throw new MethodAmbiguityException("Ambiguous method call: cannot find a most applicable method: " + winningCandidate + ", " + other);
448c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide                }
449c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide              }
450c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide            }
45127bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            return SymbolReference.solved(winningCandidate);
45227bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti        }
45327bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti    }
45427bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti
455223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    protected static boolean isExactMatch(ResolvedMethodLikeDeclaration method, List<ResolvedType> argumentsTypes) {
456c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide      for (int i = 0; i < method.getNumberOfParams(); i++) {
457c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        if (!method.getParam(i).getType().equals(argumentsTypes.get(i))) {
458c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide          return false;
459c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        }
460c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide      }
461c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide      return true;
462c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide    }
463c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide
464223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    private static boolean isMoreSpecific(ResolvedMethodDeclaration methodA, ResolvedMethodDeclaration methodB,
465223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                          List<ResolvedType> argumentTypes, TypeSolver typeSolver) {
46627bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti        boolean oneMoreSpecificFound = false;
467b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti        if (methodA.getNumberOfParams() < methodB.getNumberOfParams()) {
4686e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti            return true;
4696e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti        }
470b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti        if (methodA.getNumberOfParams() > methodB.getNumberOfParams()) {
4716e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti            return false;
4726e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti        }
473b32947e8c85bc21fe533173f50d4a0a91036fdafFederico Tomassetti        for (int i = 0; i < methodA.getNumberOfParams(); i++) {
474223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedType tdA = methodA.getParam(i).getType();
475223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedType tdB = methodB.getParam(i).getType();
47627bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            // B is more specific
477adb02497ed443e836ae552e20bcb11ab8c1ab623Federico Tomassetti            if (tdB.isAssignableBy(tdA) && !tdA.isAssignableBy(tdB)) {
478590b94f8538d2c2fc3080c9b606bfaaacebcbde7Federico Tomassetti                oneMoreSpecificFound = true;
47927bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            }
48027bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            // A is more specific
481adb02497ed443e836ae552e20bcb11ab8c1ab623Federico Tomassetti            if (tdA.isAssignableBy(tdB) && !tdB.isAssignableBy(tdA)) {
482590b94f8538d2c2fc3080c9b606bfaaacebcbde7Federico Tomassetti                return false;
48327bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti            }
484acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
485acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
486acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (!oneMoreSpecificFound) {
487acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            int lastIndex = argumentTypes.size() - 1;
488acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
489acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (methodA.hasVariadicParameter() && !methodB.hasVariadicParameter()) {
490acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                // if the last argument is an array then m1 is more specific
491acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (argumentTypes.get(lastIndex).isArray()) {
492acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    return true;
493acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
494acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
495acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (!argumentTypes.get(lastIndex).isArray()) {
496acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    return false;
497acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
498acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
499acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (!methodA.hasVariadicParameter() && methodB.hasVariadicParameter()) {
500acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                // if the last argument is an array and m1 is not variadic then
501acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                // it is not more specific
502acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (argumentTypes.get(lastIndex).isArray()) {
503acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    return false;
504acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
505acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
506acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (!argumentTypes.get(lastIndex).isArray()) {
507acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    return true;
508acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
5096e654694b8d141fd5503b46f9e77b8763cfa9a81Federico Tomassetti            }
510d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti        }
511acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
51227bee3fd5da7ae397014a33e4365608f77d04485Federico Tomassetti        return oneMoreSpecificFound;
513d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti    }
514d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti
51574026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti    private static boolean isMoreSpecific(MethodUsage methodA, MethodUsage methodB, TypeSolver typeSolver) {
51674026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        boolean oneMoreSpecificFound = false;
51749719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti        for (int i = 0; i < methodA.getNoParams(); i++) {
518e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType tdA = methodA.getParamType(i);
519e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti            ResolvedType tdB = methodB.getParamType(i);
520fb07f9b8b66fdb7aed984f451267c8b02ec976c9Federico Tomassetti
521adb02497ed443e836ae552e20bcb11ab8c1ab623Federico Tomassetti            boolean aIsAssignableByB = tdA.isAssignableBy(tdB);
522adb02497ed443e836ae552e20bcb11ab8c1ab623Federico Tomassetti            boolean bIsAssignableByA = tdB.isAssignableBy(tdA);
523fb07f9b8b66fdb7aed984f451267c8b02ec976c9Federico Tomassetti
52474026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            // B is more specific
525fb07f9b8b66fdb7aed984f451267c8b02ec976c9Federico Tomassetti            if (bIsAssignableByA && !aIsAssignableByB) {
52674026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                oneMoreSpecificFound = true;
52774026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            }
52874026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            // A is more specific
529fb07f9b8b66fdb7aed984f451267c8b02ec976c9Federico Tomassetti            if (aIsAssignableByB && !bIsAssignableByA) {
53074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                return false;
53174026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            }
53274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
53374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        return oneMoreSpecificFound;
53474026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti    }
53574026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti
536e15d5a8aa84a34917e4ef47135dfc62e58ea7650Federico Tomassetti    public static Optional<MethodUsage> findMostApplicableUsage(List<MethodUsage> methods, String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
53788db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti        List<MethodUsage> applicableMethods = methods.stream().filter((m) -> isApplicable(m, name, argumentsTypes, typeSolver)).collect(Collectors.toList());
538acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
53974026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        if (applicableMethods.isEmpty()) {
54074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            return Optional.empty();
54174026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
54274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        if (applicableMethods.size() == 1) {
54374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            return Optional.of(applicableMethods.get(0));
54474026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        } else {
54574026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            MethodUsage winningCandidate = applicableMethods.get(0);
54649719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti            for (int i = 1; i < applicableMethods.size(); i++) {
54774026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                MethodUsage other = applicableMethods.get(i);
54874026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                if (isMoreSpecific(winningCandidate, other, typeSolver)) {
54974026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                    // nothing to do
55074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                } else if (isMoreSpecific(other, winningCandidate, typeSolver)) {
55174026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                    winningCandidate = other;
55274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                } else {
55374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                    if (winningCandidate.declaringType().getQualifiedName().equals(other.declaringType().getQualifiedName())) {
554283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti                        if (!areOverride(winningCandidate, other)) {
555283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti                            throw new MethodAmbiguityException("Ambiguous method call: cannot find a most applicable method: " + winningCandidate + ", " + other + ". First declared in " + winningCandidate.declaringType().getQualifiedName());
556283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti                        }
55774026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                    } else {
55874026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                        // we expect the methods to be ordered such that inherited methods are later in the list
559dc04a5a13190654977eb689d85be429b45cb0215Federico Tomassetti                        //throw new UnsupportedOperationException();
56074026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                    }
56174026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti                }
56274026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            }
56374026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti            return Optional.of(winningCandidate);
56474026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti        }
56574026e2be2b8b569f1b1644ecb09456c1729ecc1Federico Tomassetti    }
566283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti
567283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti    private static boolean areOverride(MethodUsage winningCandidate, MethodUsage other) {
568283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        if (!winningCandidate.getName().equals(other.getName())) {
569283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti            return false;
570283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        }
571283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        if (winningCandidate.getNoParams() != other.getNoParams()) {
572283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti            return false;
573283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        }
57449719b4acbe10e3714ceb4f7040acac34709f558Federico Tomassetti        for (int i = 0; i < winningCandidate.getNoParams(); i++) {
575283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti            if (!winningCandidate.getParamTypes().get(i).equals(other.getParamTypes().get(i))) {
576283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti                return false;
577283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti            }
578283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        }
579283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti        return true;
580283204dd5840cb11dd6c73dbbb196e80db79c9a4Federico Tomassetti    }
581656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti
582223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    public static SymbolReference<ResolvedMethodDeclaration> solveMethodInType(ResolvedTypeDeclaration typeDeclaration,
583223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                                                               String name, List<ResolvedType> argumentsTypes, TypeSolver typeSolver) {
584acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        return solveMethodInType(typeDeclaration, name, argumentsTypes, false, typeSolver);
585acdac6790f4424f8097b3aa6c888e825cac485f9xdrop    }
586acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
587acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        /**
588acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * Replace TypeDeclaration.solveMethod
589acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         *
590acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * @param typeDeclaration
591acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * @param name
592acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * @param argumentsTypes
593acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * @param staticOnly
594acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         * @return
595acdac6790f4424f8097b3aa6c888e825cac485f9xdrop         */
596223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    public static SymbolReference<ResolvedMethodDeclaration> solveMethodInType(ResolvedTypeDeclaration typeDeclaration,
597223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                                                               String name, List<ResolvedType> argumentsTypes, boolean staticOnly,
598223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti                                                                               TypeSolver typeSolver) {
599656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof JavaParserClassDeclaration) {
6001e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti            Context ctx = ((JavaParserClassDeclaration) typeDeclaration).getContext();
60117ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
602656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
603656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof JavaParserInterfaceDeclaration) {
6041e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti            Context ctx = ((JavaParserInterfaceDeclaration) typeDeclaration).getContext();
60517ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
606656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
607656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof JavaParserEnumDeclaration) {
60888db8b2a8b93bcc692cb8fd5085ba68b8bcf1968Federico Tomassetti            if (name.equals("values") && argumentsTypes.isEmpty()) {
609656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti                return SymbolReference.solved(new JavaParserEnumDeclaration.ValuesMethod((JavaParserEnumDeclaration) typeDeclaration, typeSolver));
610656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti            }
6111e7780e554428a10c73de88ca64e5933b2291593Federico Tomassetti            Context ctx = ((JavaParserEnumDeclaration) typeDeclaration).getContext();
61217ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
613656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
61416720991418fda8f29abd4888fd1a5969f99d259malte_langkabel        if (typeDeclaration instanceof JavaParserAnonymousClassDeclaration) {
61516720991418fda8f29abd4888fd1a5969f99d259malte_langkabel        	Context ctx = ((JavaParserAnonymousClassDeclaration) typeDeclaration).getContext();
61616720991418fda8f29abd4888fd1a5969f99d259malte_langkabel            return ctx.solveMethod(name, argumentsTypes, staticOnly, typeSolver);
61716720991418fda8f29abd4888fd1a5969f99d259malte_langkabel        }
618656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof ReflectionClassDeclaration) {
61917ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ((ReflectionClassDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
620656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
621656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof ReflectionInterfaceDeclaration) {
62217ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop          return ((ReflectionInterfaceDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
623c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        }
624c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide          if (typeDeclaration instanceof ReflectionEnumDeclaration) {
62517ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ((ReflectionEnumDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
626656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
627656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof JavassistInterfaceDeclaration) {
62817ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ((JavassistInterfaceDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
629656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
630656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        if (typeDeclaration instanceof JavassistClassDeclaration) {
63117ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop          return ((JavassistClassDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
632c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide        }
633c990d23490f5c4ac4322119b03d5951b63eef055Fred Lefévère-Laoide          if (typeDeclaration instanceof JavassistEnumDeclaration) {
63417ac5ada0476c72aa79a2e0c39311e90bfa0fe60xdrop            return ((JavassistEnumDeclaration) typeDeclaration).solveMethod(name, argumentsTypes, staticOnly);
635656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        }
636656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti        throw new UnsupportedOperationException(typeDeclaration.getClass().getCanonicalName());
637656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti    }
638656bb37a1dba87d61d24e69f2346f35dbc73d81dFederico Tomassetti
639223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti    private static void inferTypes(ResolvedType source, ResolvedType target, Map<ResolvedTypeParameterDeclaration, ResolvedType> mappings) {
640acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
641acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
642acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.equals(target)) {
643acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
644acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
645acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isReferenceType() && target.isReferenceType()) {
646223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedReferenceType sourceRefType = source.asReferenceType();
647223fc7650a7a3b89b43d81160f40326aaeaa98f1Federico Tomassetti            ResolvedReferenceType targetRefType = target.asReferenceType();
648acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (sourceRefType.getQualifiedName().equals(targetRefType.getQualifiedName())) {
649acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                if (!sourceRefType.isRawType() && !targetRefType.isRawType()) {
650acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    for (int i = 0; i < sourceRefType.typeParametersValues().size(); i++) {
651acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                        inferTypes(sourceRefType.typeParametersValues().get(i), targetRefType.typeParametersValues().get(i), mappings);
652acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                    }
653acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                }
654acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
655acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
656acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
657acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isReferenceType() && target.isWildcard()) {
658acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (target.asWildcard().isBounded()) {
659acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                inferTypes(source, target.asWildcard().getBoundedType(), mappings);
660acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                return;
661acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
662acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
663acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
664acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isWildcard() && target.isWildcard()) {
665acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
666acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
667acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isReferenceType() && target.isTypeVariable()) {
668acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            mappings.put(target.asTypeParameter(), source);
669acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
670acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
671acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
672acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isWildcard() && target.isReferenceType()){
673acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            if (source.asWildcard().isBounded()){
674acdac6790f4424f8097b3aa6c888e825cac485f9xdrop                inferTypes(source.asWildcard().getBoundedType(), target, mappings);
675acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            }
676acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
677acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
678acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
679acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isWildcard() && target.isTypeVariable()) {
680acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            mappings.put(target.asTypeParameter(), source);
681acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
682acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
683acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isTypeVariable() && target.isTypeVariable()) {
684acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            mappings.put(target.asTypeParameter(), source);
685acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
686acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
687acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isPrimitive() || target.isPrimitive()) {
688acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
689acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
690acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        if (source.isNull()) {
691acdac6790f4424f8097b3aa6c888e825cac485f9xdrop            return;
692acdac6790f4424f8097b3aa6c888e825cac485f9xdrop        }
693acdac6790f4424f8097b3aa6c888e825cac485f9xdrop    }
694acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
695acdac6790f4424f8097b3aa6c888e825cac485f9xdrop
696d420a496cd03b7e9b5c4cce5074d8a74da69f3cdFederico Tomassetti}
697