View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.expectations.state;
7   
8   import static mockit.internal.util.Utilities.getClassType;
9   
10  import edu.umd.cs.findbugs.annotations.NonNull;
11  import edu.umd.cs.findbugs.annotations.Nullable;
12  
13  import java.lang.reflect.Type;
14  import java.util.Iterator;
15  import java.util.Map;
16  import java.util.concurrent.ConcurrentHashMap;
17  
18  import mockit.asm.types.JavaType;
19  
20  public final class CascadingTypes {
21      @NonNull
22      private final Map<Type, MockedTypeCascade> mockedTypesToCascades;
23  
24      CascadingTypes() {
25          mockedTypesToCascades = new ConcurrentHashMap<>(4);
26      }
27  
28      public void add(boolean fromMockField, @NonNull Type mockedType) {
29          Class<?> mockedClass = getClassType(mockedType);
30          String mockedTypeDesc = JavaType.getInternalName(mockedClass);
31          add(mockedTypeDesc, fromMockField, mockedType);
32      }
33  
34      @NonNull
35      MockedTypeCascade add(@NonNull String mockedTypeDesc, boolean fromMockField, @NonNull Type mockedType) {
36          return mockedTypesToCascades.computeIfAbsent(mockedType,
37                  k -> new MockedTypeCascade(fromMockField, mockedType, mockedTypeDesc));
38      }
39  
40      @NonNull
41      MockedTypeCascade getCascade(@NonNull Type mockedType) {
42          return mockedTypesToCascades.get(mockedType);
43      }
44  
45      @Nullable
46      MockedTypeCascade getCascade(@NonNull String mockedTypeDesc, @Nullable Object mockInstance) {
47          if (mockedTypesToCascades.isEmpty()) {
48              return null;
49          }
50  
51          if (mockInstance != null) {
52              MockedTypeCascade cascade = findCascadeForInstance(mockInstance);
53  
54              if (cascade != null) {
55                  return cascade;
56              }
57          }
58  
59          for (MockedTypeCascade cascade : mockedTypesToCascades.values()) {
60              if (cascade.mockedTypeDesc.equals(mockedTypeDesc)) {
61                  return cascade;
62              }
63          }
64  
65          return null;
66      }
67  
68      @Nullable
69      private MockedTypeCascade findCascadeForInstance(@NonNull Object mockInstance) {
70          for (MockedTypeCascade cascade : mockedTypesToCascades.values()) {
71              if (cascade.hasInstance(mockInstance)) {
72                  return cascade;
73              }
74          }
75  
76          return null;
77      }
78  
79      void clearNonSharedCascadingTypes() {
80          if (!mockedTypesToCascades.isEmpty()) {
81              Iterator<MockedTypeCascade> itr = mockedTypesToCascades.values().iterator();
82  
83              while (itr.hasNext()) {
84                  MockedTypeCascade cascade = itr.next();
85  
86                  if (cascade.fromMockField) {
87                      cascade.discardCascadedMocks();
88                  } else {
89                      itr.remove();
90                  }
91              }
92          }
93      }
94  
95      public void clear() {
96          mockedTypesToCascades.clear();
97      }
98  
99      void addInstance(@NonNull Type mockedType, @NonNull Object cascadingInstance) {
100         MockedTypeCascade cascade = mockedTypesToCascades.get(mockedType);
101 
102         if (cascade != null) {
103             cascade.addInstance(cascadingInstance);
104         }
105     }
106 }