diff options
Diffstat (limited to 'sandbox/src/main/java/org/robolectric/internal/bytecode/NativeCallHandler.java')
-rw-r--r-- | sandbox/src/main/java/org/robolectric/internal/bytecode/NativeCallHandler.java | 137 |
1 files changed, 0 insertions, 137 deletions
diff --git a/sandbox/src/main/java/org/robolectric/internal/bytecode/NativeCallHandler.java b/sandbox/src/main/java/org/robolectric/internal/bytecode/NativeCallHandler.java deleted file mode 100644 index 89034d63f..000000000 --- a/sandbox/src/main/java/org/robolectric/internal/bytecode/NativeCallHandler.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.robolectric.internal.bytecode; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Set; -import java.util.TreeSet; -import javax.annotation.Nonnull; - -/** - * Handler for native calls instrumented by ClassInstrumentor. - * - * <p>Native Calls can either be instrumented as no-op calls (returning a default value or 0 or - * null) or throw an exception. This helper class helps maintain a list of exemptions to indicates - * which native calls should be no-op and never throw. - */ -public class NativeCallHandler { - - private final File exemptionsFile; - private final boolean writeExemptions; - private final boolean throwOnNatives; - private final Set<String> descriptors = new TreeSet<>(); - - /** - * Initializes the native calls handler. - * - * @param exemptionsFile The exemptions file to read from and/or to generate. - * @param writeExemptions When true, native calls are added to the exemption list. - * @param throwOnNatives Whether native calls should throw by default unless their signature is - * listed in the exemption list. When false, all native calls become no-op. - * @throws IOException if there's an issue reading an existing exemption list. - */ - public NativeCallHandler( - @Nonnull File exemptionsFile, boolean writeExemptions, boolean throwOnNatives) - throws IOException { - this.exemptionsFile = exemptionsFile; - this.writeExemptions = writeExemptions; - this.throwOnNatives = throwOnNatives; - - if (exemptionsFile.exists()) { - readExemptionsList(exemptionsFile); - } - } - - private String getExemptionFileName() { - return exemptionsFile.getName(); - } - - private void readExemptionsList(File exemptionsFile) throws IOException { - try (BufferedReader reader = - new BufferedReader(new FileReader(exemptionsFile.getPath(), UTF_8))) { - String line; - while ((line = reader.readLine()) != null) { - // Sanitize input. Ignore empty lines and commented lines starting with #. - line = sanitize(line.trim()); - if (line.isEmpty() || line.charAt(0) == '#') { - continue; - } - descriptors.add(line); - } - } - System.out.println( - "Loaded " + descriptors.size() + " exemptions from " + exemptionsFile.getPath()); - } - - public void writeExemptionsList() throws IOException { - try (BufferedWriter writer = - new BufferedWriter(new FileWriter(exemptionsFile.getPath(), UTF_8))) { - for (String descriptor : descriptors) { - writer.write(descriptor); - writer.write('\n'); - } - } - System.out.println( - "Wrote " + descriptors.size() + " exemptions to " + exemptionsFile.getPath()); - } - - /** - * Adds the method description to the native call exemption list if {@link #writeExemptions} is - * set. - */ - public void logNativeCall(@Nonnull String descriptor) { - if (!writeExemptions) { - return; - } - descriptors.add(sanitize(descriptor)); - } - - /** Returns whether the ClassInstrumentor should generate an exception or a no-op bytecode. */ - public boolean shouldThrow(@Nonnull String descriptor) { - return throwOnNatives && !descriptors.contains(sanitize(descriptor)); - } - - private String sanitize(String descriptor) { - // Post-processing of the exemptions files is made complicated by the presence of $ signs - // in the FQCN. Instead of escaping them, just replace them by another unused character - // that is not so sensitive to shell or make mangling. - return descriptor.replace('$', '^'); - } - - /** - * Returns the detailed message to be used by the ClassInstrumentor in the generated bytecode. - * - * @param descriptor The ASM descriptor as it should be written in the exemption file. - * @param className The fully qualified class name, used for the user description. - * @param methodName The method name, used for the user description. - */ - public String getExceptionMessage( - @Nonnull String descriptor, @Nonnull String className, @Nonnull String methodName) { - // The shadow message is merely a hint based on the last component of the FQCN, which is - // typically the pattern used for shadow classes. - String shadowHint = - "Shadow" + className.replaceAll("[^.]+\\.", "").replaceAll("\\$.*", "") + ".java"; - // The message below tries to educate the user that shadow overrides are not necessarily - // needed nor desired for trivial cases that are better covered by a no-op return operation. - return "Unexpected Robolectric native method call to '" - + className - + "#" - + methodName - + "()'.\n" - + "Option 1: If customizing this method is useful, add an implementation in " - + shadowHint - + ".\n" - + "Option 2: If this method just needs to trivially return 0 or null, please add an" - + " exemption entry for\n" - + " " - + sanitize(descriptor) - + "\n" - + "to exemption file " - + getExemptionFileName(); - } -} |