Erich Douglass | 1874abe | 2014-12-17 19:22:16 -0800 | [diff] [blame] | 1 | package org.robolectric.internal.bytecode; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 2 | |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 3 | import com.google.common.collect.ArrayListMultimap; |
| 4 | import com.google.common.collect.ImmutableList; |
| 5 | import com.google.common.collect.ImmutableListMultimap; |
Christian Williams | 9551151 | 2018-01-05 16:43:12 -0800 | [diff] [blame] | 6 | import com.google.common.collect.ImmutableMap; |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 7 | import java.lang.reflect.InvocationTargetException; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 8 | import java.util.Collections; |
| 9 | import java.util.HashMap; |
christianw | 0e4184c | 2019-03-06 13:32:35 -0800 | [diff] [blame] | 10 | import java.util.List; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 11 | import java.util.Map; |
Christian Williams | 851f2a9 | 2017-07-25 18:12:59 -0700 | [diff] [blame] | 12 | import java.util.Set; |
| 13 | import org.robolectric.annotation.Implements; |
| 14 | import org.robolectric.internal.ShadowProvider; |
Christian Williams | f5371b5 | 2020-03-06 11:19:38 -0800 | [diff] [blame] | 15 | import org.robolectric.sandbox.ShadowMatcher; |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 16 | import org.robolectric.shadow.api.ShadowPicker; |
Rex Hoffman | 9b76374 | 2022-11-15 20:26:41 +0000 | [diff] [blame] | 17 | import org.robolectric.util.Logger; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 18 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 19 | /** |
| 20 | * Maps from instrumented class to shadow class. |
| 21 | * |
| 22 | * We deal with class names rather than actual classes here, since a ShadowMap is built outside of |
| 23 | * any sandboxes, but instrumented and shadowed classes must be loaded through a |
| 24 | * {@link SandboxClassLoader}. We don't want to try to resolve those classes outside of a sandbox. |
| 25 | * |
| 26 | * Once constructed, instances are immutable. |
| 27 | */ |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 28 | @SuppressWarnings("NewApi") |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 29 | public class ShadowMap { |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 30 | |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 31 | static final ShadowMap EMPTY = new ShadowMap(ImmutableListMultimap.of(), ImmutableMap.of()); |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 32 | |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 33 | private final ImmutableListMultimap<String, String> defaultShadows; |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 34 | private final ImmutableMap<String, ShadowInfo> overriddenShadows; |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 35 | private final ImmutableMap<String, String> shadowPickers; |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 36 | |
brettchabot | 5725427 | 2019-02-13 01:49:27 -0800 | [diff] [blame] | 37 | @SuppressWarnings("AndroidJdkLibsChecker") |
christianw | 0e4184c | 2019-03-06 13:32:35 -0800 | [diff] [blame] | 38 | public static ShadowMap createFromShadowProviders(List<ShadowProvider> sortedProviders) { |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 39 | final ArrayListMultimap<String, String> shadowMap = ArrayListMultimap.create(); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 40 | final Map<String, String> shadowPickerMap = new HashMap<>(); |
brettchabot | 5725427 | 2019-02-13 01:49:27 -0800 | [diff] [blame] | 41 | |
Michael Hoisie | aab24ad | 2022-10-06 00:18:05 -0700 | [diff] [blame] | 42 | // These are sorted in descending order (higher priority providers are first). |
Rex Hoffman | 9b76374 | 2022-11-15 20:26:41 +0000 | [diff] [blame] | 43 | Logger.debug("Shadow providers: " + sortedProviders); |
brettchabot | 5725427 | 2019-02-13 01:49:27 -0800 | [diff] [blame] | 44 | for (ShadowProvider provider : sortedProviders) { |
Rex Hoffman | 9b76374 | 2022-11-15 20:26:41 +0000 | [diff] [blame] | 45 | Logger.debug("Shadow provider: " + provider.getClass().getName()); |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 46 | for (Map.Entry<String, String> entry : provider.getShadows()) { |
| 47 | shadowMap.put(entry.getKey(), entry.getValue()); |
| 48 | } |
Michael Hoisie | aab24ad | 2022-10-06 00:18:05 -0700 | [diff] [blame] | 49 | provider.getShadowPickerMap().forEach(shadowPickerMap::putIfAbsent); |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 50 | } |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 51 | return new ShadowMap( |
| 52 | ImmutableListMultimap.copyOf(shadowMap), |
| 53 | Collections.emptyMap(), |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 54 | ImmutableMap.copyOf(shadowPickerMap)); |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 55 | } |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 56 | |
christianw | 0e4184c | 2019-03-06 13:32:35 -0800 | [diff] [blame] | 57 | ShadowMap( |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 58 | ImmutableListMultimap<String, String> defaultShadows, |
christianw | 0e4184c | 2019-03-06 13:32:35 -0800 | [diff] [blame] | 59 | Map<String, ShadowInfo> overriddenShadows) { |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 60 | this(defaultShadows, overriddenShadows, Collections.emptyMap()); |
| 61 | } |
| 62 | |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 63 | private ShadowMap( |
| 64 | ImmutableListMultimap<String, String> defaultShadows, |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 65 | Map<String, ShadowInfo> overriddenShadows, |
| 66 | Map<String, String> shadowPickers) { |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 67 | this.defaultShadows = ImmutableListMultimap.copyOf(defaultShadows); |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 68 | this.overriddenShadows = ImmutableMap.copyOf(overriddenShadows); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 69 | this.shadowPickers = ImmutableMap.copyOf(shadowPickers); |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 70 | } |
| 71 | |
Christian Williams | f5371b5 | 2020-03-06 11:19:38 -0800 | [diff] [blame] | 72 | public ShadowInfo getShadowInfo(Class<?> clazz, ShadowMatcher shadowMatcher) { |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 73 | String instrumentedClassName = clazz.getName(); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 74 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 75 | ShadowInfo shadowInfo = overriddenShadows.get(instrumentedClassName); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 76 | if (shadowInfo == null) { |
| 77 | shadowInfo = checkShadowPickers(instrumentedClassName, clazz); |
christianw | 1caa33a | 2019-04-05 14:26:24 -0700 | [diff] [blame] | 78 | } else if (shadowInfo.hasShadowPicker()) { |
| 79 | shadowInfo = pickShadow(instrumentedClassName, clazz, shadowInfo); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 80 | } |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 81 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 82 | if (shadowInfo == null && clazz.getClassLoader() != null) { |
| 83 | try { |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 84 | final ImmutableList<String> shadowNames = defaultShadows.get(clazz.getCanonicalName()); |
| 85 | for (String shadowName : shadowNames) { |
| 86 | if (shadowName != null) { |
| 87 | Class<?> shadowClass = clazz.getClassLoader().loadClass(shadowName); |
| 88 | shadowInfo = obtainShadowInfo(shadowClass); |
| 89 | if (!shadowInfo.shadowedClassName.equals(instrumentedClassName)) { |
| 90 | // somehow we got the wrong shadow class? |
| 91 | shadowInfo = null; |
| 92 | } |
| 93 | if (shadowInfo != null && shadowMatcher.matches(shadowInfo)) { |
| 94 | return shadowInfo; |
| 95 | } |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 96 | } |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 97 | } |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 98 | } catch (ClassNotFoundException | IncompatibleClassChangeError e) { |
| 99 | return null; |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 100 | } |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 101 | } |
| 102 | |
Christian Williams | f5371b5 | 2020-03-06 11:19:38 -0800 | [diff] [blame] | 103 | if (shadowInfo != null && !shadowMatcher.matches(shadowInfo)) { |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 104 | return null; |
| 105 | } |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 106 | |
| 107 | return shadowInfo; |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 108 | } |
| 109 | |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 110 | // todo: some caching would probably be nice here... |
| 111 | private ShadowInfo checkShadowPickers(String instrumentedClassName, Class<?> clazz) { |
| 112 | String shadowPickerClassName = shadowPickers.get(instrumentedClassName); |
| 113 | if (shadowPickerClassName == null) { |
| 114 | return null; |
| 115 | } |
| 116 | |
christianw | 1caa33a | 2019-04-05 14:26:24 -0700 | [diff] [blame] | 117 | return pickShadow(instrumentedClassName, clazz, shadowPickerClassName); |
| 118 | } |
| 119 | |
| 120 | private ShadowInfo pickShadow(String instrumentedClassName, Class<?> clazz, |
| 121 | String shadowPickerClassName) { |
| 122 | ClassLoader sandboxClassLoader = clazz.getClassLoader(); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 123 | try { |
| 124 | Class<? extends ShadowPicker<?>> shadowPickerClass = |
christianw | 1caa33a | 2019-04-05 14:26:24 -0700 | [diff] [blame] | 125 | (Class<? extends ShadowPicker<?>>) sandboxClassLoader.loadClass(shadowPickerClassName); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 126 | ShadowPicker<?> shadowPicker = shadowPickerClass.getDeclaredConstructor().newInstance(); |
christianw | 23ea494 | 2018-08-16 11:53:35 -0700 | [diff] [blame] | 127 | Class<?> selectedShadowClass = shadowPicker.pickShadowClass(); |
| 128 | if (selectedShadowClass == null) { |
| 129 | return obtainShadowInfo(Object.class, true); |
| 130 | } |
| 131 | ShadowInfo shadowInfo = obtainShadowInfo(selectedShadowClass); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 132 | |
| 133 | if (!shadowInfo.shadowedClassName.equals(instrumentedClassName)) { |
| 134 | throw new IllegalArgumentException("Implemented class for " |
christianw | 23ea494 | 2018-08-16 11:53:35 -0700 | [diff] [blame] | 135 | + selectedShadowClass.getName() + " (" + shadowInfo.shadowedClassName + ") != " |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 136 | + instrumentedClassName); |
| 137 | } |
| 138 | |
| 139 | return shadowInfo; |
| 140 | } catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException |
| 141 | | IllegalAccessException | InstantiationException e) { |
| 142 | throw new RuntimeException("Failed to resolve shadow picker for " + instrumentedClassName, |
| 143 | e); |
| 144 | } |
| 145 | } |
| 146 | |
christianw | 1caa33a | 2019-04-05 14:26:24 -0700 | [diff] [blame] | 147 | private ShadowInfo pickShadow( |
| 148 | String instrumentedClassName, Class<?> clazz, ShadowInfo shadowInfo) { |
| 149 | return pickShadow(instrumentedClassName, clazz, shadowInfo.getShadowPickerClass().getName()); |
| 150 | } |
| 151 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 152 | public static ShadowInfo obtainShadowInfo(Class<?> clazz) { |
Christian Williams | 1375d8d | 2018-01-24 14:59:32 -0800 | [diff] [blame] | 153 | return obtainShadowInfo(clazz, false); |
| 154 | } |
| 155 | |
| 156 | static ShadowInfo obtainShadowInfo(Class<?> clazz, boolean mayBeNonShadow) { |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 157 | Implements annotation = clazz.getAnnotation(Implements.class); |
| 158 | if (annotation == null) { |
Christian Williams | 1375d8d | 2018-01-24 14:59:32 -0800 | [diff] [blame] | 159 | if (mayBeNonShadow) { |
| 160 | return null; |
| 161 | } else { |
| 162 | throw new IllegalArgumentException(clazz + " is not annotated with @Implements"); |
| 163 | } |
Erich Douglass | 9a8b34e | 2015-06-16 23:05:12 -0700 | [diff] [blame] | 164 | } |
| 165 | |
| 166 | String className = annotation.className(); |
| 167 | if (className.isEmpty()) { |
| 168 | className = annotation.value().getName(); |
| 169 | } |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 170 | return new ShadowInfo(className, clazz.getName(), annotation); |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 171 | } |
| 172 | |
Christian Williams | 07e61e0 | 2017-10-06 16:56:08 -0700 | [diff] [blame] | 173 | @SuppressWarnings("ReferenceEquality") |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 174 | public Set<String> getInvalidatedClasses(ShadowMap previous) { |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 175 | if (this == previous && shadowPickers.isEmpty()) return Collections.emptySet(); |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 176 | |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 177 | Map<String, ShadowInfo> invalidated = new HashMap<>(overriddenShadows); |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 178 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 179 | for (Map.Entry<String, ShadowInfo> entry : previous.overriddenShadows.entrySet()) { |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 180 | String className = entry.getKey(); |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 181 | ShadowInfo previousConfig = entry.getValue(); |
| 182 | ShadowInfo currentConfig = invalidated.get(className); |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 183 | if (currentConfig == null) { |
| 184 | invalidated.put(className, previousConfig); |
| 185 | } else if (previousConfig.equals(currentConfig)) { |
| 186 | invalidated.remove(className); |
| 187 | } |
| 188 | } |
| 189 | |
Christian Williams | 6b08d4a | 2019-02-01 13:50:07 -0800 | [diff] [blame] | 190 | return invalidated.keySet(); |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 191 | } |
| 192 | |
Christian Williams | 3f02445 | 2018-01-05 16:57:16 -0800 | [diff] [blame] | 193 | /** |
| 194 | * @deprecated do not use |
| 195 | */ |
| 196 | @Deprecated |
Alexander Blom | 1021315 | 2015-04-22 12:33:45 +0200 | [diff] [blame] | 197 | public static String convertToShadowName(String className) { |
| 198 | String shadowClassName = |
| 199 | "org.robolectric.shadows.Shadow" + className.substring(className.lastIndexOf(".") + 1); |
| 200 | shadowClassName = shadowClassName.replaceAll("\\$", "\\$Shadow"); |
| 201 | return shadowClassName; |
| 202 | } |
| 203 | |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 204 | public Builder newBuilder() { |
| 205 | return new Builder(this); |
| 206 | } |
| 207 | |
| 208 | @Override |
| 209 | public boolean equals(Object o) { |
| 210 | if (this == o) return true; |
jongerrish | faf97f2 | 2018-08-21 15:07:20 -0700 | [diff] [blame] | 211 | if (!(o instanceof ShadowMap)) return false; |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 212 | |
| 213 | ShadowMap shadowMap = (ShadowMap) o; |
| 214 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 215 | if (!overriddenShadows.equals(shadowMap.overriddenShadows)) return false; |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 216 | |
| 217 | return true; |
| 218 | } |
| 219 | |
| 220 | @Override |
| 221 | public int hashCode() { |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 222 | return overriddenShadows.hashCode(); |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | public static class Builder { |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 226 | private final ImmutableListMultimap<String, String> defaultShadows; |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 227 | private final Map<String, ShadowInfo> overriddenShadows; |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 228 | private final Map<String, String> shadowPickers; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 229 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 230 | public Builder () { |
Michael Hoisie | 7e005cf | 2022-05-24 10:47:07 -0700 | [diff] [blame] | 231 | defaultShadows = ImmutableListMultimap.of(); |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 232 | overriddenShadows = new HashMap<>(); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 233 | shadowPickers = new HashMap<>(); |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 234 | } |
| 235 | |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 236 | public Builder(ShadowMap shadowMap) { |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 237 | this.defaultShadows = shadowMap.defaultShadows; |
| 238 | this.overriddenShadows = new HashMap<>(shadowMap.overriddenShadows); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 239 | this.shadowPickers = new HashMap<>(shadowMap.shadowPickers); |
Christian Williams + Kiran Ryali | 4306d0d | 2013-04-05 13:20:17 -0700 | [diff] [blame] | 240 | } |
| 241 | |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 242 | public Builder addShadowClasses(Class<?>... shadowClasses) { |
| 243 | for (Class<?> shadowClass : shadowClasses) { |
| 244 | addShadowClass(shadowClass); |
| 245 | } |
| 246 | return this; |
Christian Williams + Kiran Ryali | 4306d0d | 2013-04-05 13:20:17 -0700 | [diff] [blame] | 247 | } |
| 248 | |
Christian Williams | d214ef0 | 2018-10-04 17:16:49 -0700 | [diff] [blame] | 249 | Builder addShadowClass(Class<?> shadowClass) { |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 250 | addShadowInfo(obtainShadowInfo(shadowClass)); |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 251 | return this; |
Christian Williams | 36d87d7 | 2013-03-13 18:25:54 -0700 | [diff] [blame] | 252 | } |
| 253 | |
Christian Williams | d214ef0 | 2018-10-04 17:16:49 -0700 | [diff] [blame] | 254 | Builder addShadowClass( |
jongerrish | faf97f2 | 2018-08-21 15:07:20 -0700 | [diff] [blame] | 255 | String realClassName, |
| 256 | String shadowClassName, |
| 257 | boolean callThroughByDefault, |
Christian Williams | f7e46ea | 2018-01-17 15:09:34 -0800 | [diff] [blame] | 258 | boolean looseSignatures) { |
jongerrish | faf97f2 | 2018-08-21 15:07:20 -0700 | [diff] [blame] | 259 | addShadowInfo( |
| 260 | new ShadowInfo( |
| 261 | realClassName, shadowClassName, callThroughByDefault, looseSignatures, -1, -1, null)); |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 262 | return this; |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 263 | } |
| 264 | |
Christian Williams | e71f919 | 2018-01-08 13:17:59 -0800 | [diff] [blame] | 265 | private void addShadowInfo(ShadowInfo shadowInfo) { |
| 266 | overriddenShadows.put(shadowInfo.shadowedClassName, shadowInfo); |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 267 | if (shadowInfo.hasShadowPicker()) { |
| 268 | shadowPickers |
| 269 | .put(shadowInfo.shadowedClassName, shadowInfo.getShadowPickerClass().getName()); |
| 270 | } |
Christian Williams | a1c4830 | 2013-03-18 14:44:04 -0700 | [diff] [blame] | 271 | } |
| 272 | |
Christian Williams | 0d4f5f6 | 2018-08-06 14:18:45 -0700 | [diff] [blame] | 273 | public ShadowMap build() { |
christianw | b15df5a | 2018-08-07 11:59:33 -0700 | [diff] [blame] | 274 | return new ShadowMap(defaultShadows, overriddenShadows, shadowPickers); |
Christian Williams | a1c4830 | 2013-03-18 14:44:04 -0700 | [diff] [blame] | 275 | } |
Christian Williams | 29a8359 | 2013-05-13 15:05:09 -0700 | [diff] [blame] | 276 | } |
Kiran Ryali + Christian Williams | 7be4d2b | 2013-03-01 18:10:16 -0800 | [diff] [blame] | 277 | } |