1
2
3
4
5
6 package mockit.internal.capturing;
7
8 import static mockit.internal.util.GeneratedClasses.isExternallyGeneratedSubclass;
9 import static mockit.internal.util.GeneratedClasses.isGeneratedClass;
10
11 import edu.umd.cs.findbugs.annotations.NonNull;
12 import edu.umd.cs.findbugs.annotations.Nullable;
13
14 import java.security.ProtectionDomain;
15
16 import org.checkerframework.checker.index.qual.NonNegative;
17
18 final class CapturedType {
19 private static final ProtectionDomain JMOCKIT_DOMAIN = CapturedType.class.getProtectionDomain();
20
21 @NonNull
22 final Class<?> baseType;
23
24 CapturedType(@NonNull Class<?> baseType) {
25 this.baseType = baseType;
26 }
27
28 boolean isToBeCaptured(@NonNull Class<?> aClass) {
29 if (aClass == baseType || aClass.isArray() || !baseType.isAssignableFrom(aClass)
30 || extendsJMockitBaseType(aClass)) {
31 return false;
32 }
33
34 return !aClass.isInterface() && !isNotToBeCaptured(aClass.getProtectionDomain(), aClass.getName());
35 }
36
37 @SuppressWarnings("UnnecessaryFullyQualifiedName")
38 private static boolean extendsJMockitBaseType(@NonNull Class<?> aClass) {
39 return mockit.MockUp.class.isAssignableFrom(aClass) || mockit.Expectations.class.isAssignableFrom(aClass)
40 || mockit.Verifications.class.isAssignableFrom(aClass)
41 || mockit.Delegate.class.isAssignableFrom(aClass);
42 }
43
44 static boolean isNotToBeCaptured(@Nullable ProtectionDomain pd, @NonNull String classNameOrDesc) {
45 return pd == JMOCKIT_DOMAIN || classNameOrDesc.endsWith("Test")
46 || isNonEligibleInternalJDKClass(classNameOrDesc) || isNonEligibleStandardJavaClass(classNameOrDesc)
47 || isNonEligibleClassFromIDERuntime(classNameOrDesc)
48 || isNonEligibleClassFromThirdPartyLibrary(classNameOrDesc) || isGeneratedClass(classNameOrDesc)
49 || isExternallyGeneratedSubclass(classNameOrDesc);
50 }
51
52 private static boolean isNonEligibleInternalJDKClass(@NonNull String classNameOrDesc) {
53 return classNameOrDesc.startsWith("jdk/")
54 || classNameOrDesc.startsWith("sun") && !hasSubPackage(classNameOrDesc, 4, "management")
55 || classNameOrDesc.startsWith("com") && hasSubPackage(classNameOrDesc, 4, "sun")
56 && !hasSubPackages(classNameOrDesc, 8, "proxy org");
57 }
58
59 private static boolean isNonEligibleStandardJavaClass(@NonNull String classNameOrDesc) {
60 return classNameOrDesc.startsWith("java") && !hasSubPackage(classNameOrDesc, 10, "concurrent");
61 }
62
63 private static boolean isNonEligibleClassFromIDERuntime(@NonNull String classNameOrDesc) {
64 return classNameOrDesc.startsWith("com") && hasSubPackage(classNameOrDesc, 4, "intellij");
65 }
66
67 private static boolean isNonEligibleClassFromThirdPartyLibrary(@NonNull String classNameOrDesc) {
68 return classNameOrDesc.startsWith("junit") || classNameOrDesc.startsWith("org")
69 && hasSubPackages(classNameOrDesc, 4, "junit testng hamcrest gradle");
70 }
71
72 private static boolean hasSubPackage(@NonNull String nameOrDesc, @NonNegative int offset,
73 @NonNull String subPackage) {
74 return nameOrDesc.regionMatches(offset, subPackage, 0, subPackage.length());
75 }
76
77 private static boolean hasSubPackages(@NonNull String nameOrDesc, @NonNegative int offset,
78 @NonNull String subPackages) {
79 int subPackageStart = 0;
80 int subPackageEnd;
81
82 do {
83 subPackageEnd = subPackages.indexOf(' ', subPackageStart);
84 int subPackageLength = (subPackageEnd > 0 ? subPackageEnd : subPackages.length()) - subPackageStart;
85
86 if (nameOrDesc.regionMatches(offset, subPackages, subPackageStart, subPackageLength)) {
87 return true;
88 }
89
90 subPackageStart = subPackageEnd + 1;
91 } while (subPackageEnd > 0);
92
93 return false;
94 }
95 }