|
54 | 54 |
|
55 | 55 | import java.util.ArrayList; |
56 | 56 | import java.util.Arrays; |
| 57 | +import java.util.Collection; |
57 | 58 | import java.util.Comparator; |
58 | 59 | import java.util.HashMap; |
59 | 60 | import java.util.HashSet; |
| 61 | +import java.util.Iterator; |
| 62 | +import java.util.LinkedHashMap; |
60 | 63 | import java.util.List; |
61 | 64 | import java.util.Map; |
62 | 65 | import java.util.Set; |
@@ -2307,91 +2310,88 @@ public void detectWrapperResource() { |
2307 | 2310 | } |
2308 | 2311 |
|
2309 | 2312 | protected MethodBinding [] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidBindingException { |
2310 | | - |
2311 | 2313 | if (!isInterface() || !isValidBinding()) { |
2312 | 2314 | throw new InvalidBindingException("Not a functional interface"); //$NON-NLS-1$ |
2313 | 2315 | } |
2314 | 2316 |
|
2315 | | - MethodBinding [] methods = methods(); |
2316 | | - MethodBinding [] contracts = new MethodBinding[0]; |
2317 | | - int contractsCount = 0; |
2318 | | - int contractsLength = 0; |
| 2317 | + MethodBinding [] methods = methods(); // All methods defined by THIS interface |
| 2318 | + Map<String, List<MethodBinding>> contractsBySelector = new LinkedHashMap<>(); |
2319 | 2319 |
|
| 2320 | + // Fill List of contracts by name with all methods of super interfaces |
2320 | 2321 | ReferenceBinding [] superInterfaces = superInterfaces(); |
2321 | 2322 | for (ReferenceBinding superInterface : superInterfaces) { |
2322 | 2323 | // filterDefaultMethods=false => keep default methods needed to filter out any abstract methods they may override: |
2323 | 2324 | MethodBinding [] superInterfaceContracts = superInterface.getInterfaceAbstractContracts(scope, replaceWildcards, false); |
2324 | 2325 | final int superInterfaceContractsLength = superInterfaceContracts == null ? 0 : superInterfaceContracts.length; |
2325 | 2326 | if (superInterfaceContractsLength == 0) continue; |
2326 | | - if (contractsLength < contractsCount + superInterfaceContractsLength) { |
2327 | | - System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength = contractsCount + superInterfaceContractsLength], 0, contractsCount); |
| 2327 | + for (MethodBinding superInterfaceContract : superInterfaceContracts) { |
| 2328 | + if (superInterfaceContract == null) { |
| 2329 | + continue; |
| 2330 | + } |
| 2331 | + contractsBySelector.computeIfAbsent(String.valueOf(superInterfaceContract.selector), key -> new ArrayList<>()).add(superInterfaceContract); |
2328 | 2332 | } |
2329 | | - System.arraycopy(superInterfaceContracts, 0, contracts, contractsCount, superInterfaceContractsLength); |
2330 | | - contractsCount += superInterfaceContractsLength; |
2331 | 2333 | } |
2332 | 2334 |
|
2333 | 2335 | LookupEnvironment environment = scope.environment(); |
2334 | | - for (int i = 0, length = methods == null ? 0 : methods.length; i < length; i++) { |
2335 | | - final MethodBinding method = methods[i]; |
2336 | | - if (method == null || method.isStatic() || method.redeclaresPublicObjectMethod(scope) || method.isPrivate()) |
2337 | | - continue; |
2338 | | - if (!method.isValidBinding()) |
2339 | | - throw new InvalidBindingException("Not a functional interface"); //$NON-NLS-1$ |
2340 | | - for (int j = 0; j < contractsCount;) { |
2341 | | - if ( contracts[j] != null && MethodVerifier.doesMethodOverride(method, contracts[j], environment)) { |
2342 | | - contractsCount--; |
2343 | | - // abstract method from super type overridden by present interface ==> contracts[j] = null; |
2344 | | - if (j < contractsCount) { |
2345 | | - System.arraycopy(contracts, j+1, contracts, j, contractsCount - j); |
2346 | | - continue; |
| 2336 | + if (methods != null) { |
| 2337 | + for (final MethodBinding method : methods) { |
| 2338 | + if (method == null || method.isStatic() || method.redeclaresPublicObjectMethod(scope) || method.isPrivate()) |
| 2339 | + continue; |
| 2340 | + if (!method.isValidBinding()) |
| 2341 | + throw new InvalidBindingException("Not a functional interface"); //$NON-NLS-1$ |
| 2342 | + List<MethodBinding> contractsOfSelector = contractsBySelector.computeIfAbsent(String.valueOf(method.selector), key -> new ArrayList<>()); |
| 2343 | + Iterator<MethodBinding> iterator = contractsOfSelector.iterator(); |
| 2344 | + |
| 2345 | + // Does 'method' override any super interface method? |
| 2346 | + while (iterator.hasNext()) { |
| 2347 | + MethodBinding superInterfaceContract = iterator.next(); |
| 2348 | + |
| 2349 | + if (MethodVerifier.doesMethodOverride(method, superInterfaceContract, environment)) { |
| 2350 | + iterator.remove(); |
2347 | 2351 | } |
2348 | 2352 | } |
2349 | | - j++; |
2350 | | - } |
2351 | | - if (filterDefaultMethods && method.isDefaultMethod()) |
2352 | | - continue; // skip default method itself |
2353 | | - if (contractsCount == contractsLength) { |
2354 | | - System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsLength += 16], 0, contractsCount); |
2355 | | - } |
2356 | | - if(environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { |
2357 | | - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(method, scope); |
| 2353 | + if (filterDefaultMethods && method.isDefaultMethod()) |
| 2354 | + continue; // skip default method itself |
| 2355 | + if(environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { |
| 2356 | + ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(method, scope); |
| 2357 | + } |
| 2358 | + contractsOfSelector.add(method); |
2358 | 2359 | } |
2359 | | - contracts[contractsCount++] = method; |
2360 | 2360 | } |
| 2361 | + |
2361 | 2362 | // check mutual overriding of inherited methods (i.e., not from current type): |
2362 | | - for (int i = 0; i < contractsCount; i++) { |
2363 | | - MethodBinding contractI = contracts[i]; |
2364 | | - if (TypeBinding.equalsEquals(contractI.declaringClass, this)) |
2365 | | - continue; |
2366 | | - for (int j = 0; j < contractsCount; j++) { |
2367 | | - MethodBinding contractJ = contracts[j]; |
2368 | | - if (i == j || TypeBinding.equalsEquals(contractJ.declaringClass, this)) |
| 2363 | + for (List<MethodBinding> contractList : contractsBySelector.values()) { |
| 2364 | + for (int i = 0; i < contractList.size(); ++i) { |
| 2365 | + MethodBinding contractI = contractList.get(i); |
| 2366 | + |
| 2367 | + if (TypeBinding.equalsEquals(contractI.declaringClass, this)) { |
2369 | 2368 | continue; |
2370 | | - if (contractI == contractJ || MethodVerifier.doesMethodOverride(contractI, contractJ, environment)) { |
2371 | | - contractsCount--; |
2372 | | - // abstract method from one super type overridden by other super interface ==> contracts[j] = null; |
2373 | | - if (j < contractsCount) { |
2374 | | - System.arraycopy(contracts, j+1, contracts, j, contractsCount - j); |
| 2369 | + } |
| 2370 | + |
| 2371 | + for (int j = 0; j < contractList.size(); ++j) { |
| 2372 | + MethodBinding contractJ = contractList.get(j); |
| 2373 | + |
| 2374 | + if (i == j || TypeBinding.equalsEquals(contractJ.declaringClass, this)) { |
| 2375 | + continue; |
| 2376 | + } |
| 2377 | + |
| 2378 | + if (contractI == contractJ || MethodVerifier.doesMethodOverride(contractI, contractJ, environment)) { |
| 2379 | + contractList.remove(j); |
| 2380 | + |
| 2381 | + --j; |
| 2382 | + if (j < i) { |
| 2383 | + --i; |
| 2384 | + } |
2375 | 2385 | } |
2376 | | - j--; |
2377 | | - if (j < i) |
2378 | | - i--; |
2379 | | - continue; |
2380 | 2386 | } |
2381 | | - } |
2382 | | - if (filterDefaultMethods && contractI.isDefaultMethod()) { |
2383 | | - contractsCount--; |
2384 | | - // remove default method after it has eliminated any matching abstract methods from contracts |
2385 | | - if (i < contractsCount) { |
2386 | | - System.arraycopy(contracts, i+1, contracts, i, contractsCount - i); |
| 2387 | + |
| 2388 | + if (filterDefaultMethods && contractI.isDefaultMethod()) { |
| 2389 | + contractList.remove(i); |
| 2390 | + --i; |
2387 | 2391 | } |
2388 | | - i--; |
2389 | 2392 | } |
2390 | 2393 | } |
2391 | | - if (contractsCount < contractsLength) { |
2392 | | - System.arraycopy(contracts, 0, contracts = new MethodBinding[contractsCount], 0, contractsCount); |
2393 | | - } |
2394 | | - return contracts; |
| 2394 | + return contractsBySelector.values().stream().flatMap(Collection::stream).toArray(MethodBinding[]::new); |
2395 | 2395 | } |
2396 | 2396 | @Override |
2397 | 2397 | public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcards) { |
|
0 commit comments