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