changeset 38:2e8d8c4675db

7902161 : Discover simple getters, setters, throwers and delegators Reviewed-by: afedorch
author shurailine
date Wed, 16 May 2018 11:41:39 -0700
parents b7fab35801d1
children c92eeb0e0400
files plugins/simple_methods_anc/README.md plugins/simple_methods_anc/build.xml plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Delegators.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/EmptyMethods.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Getters.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Scanner.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Setters.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Throwers.java plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Utils.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/DelegatorsTest.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/EmptyMethodsTest.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/GettersTest.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/MainTest.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/SettersTest.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/TestUtils.java plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/ThrowersTest.java
diffstat 16 files changed, 1414 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/README.md	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,56 @@
+# Synopsis
+
+This repository contains source code for a tool which is capable of detecting **"simple methods"** in Java bytecode.
+
+A **"simple method"**, with the exception of empty methods, is a method which contains some **"simple code"** followed by a specific set of Java bytecode instructions as explained below.
+
+**"Simple code"**, then, is a code consisting of Java bytecode instructions which only bring values on stack and have no other side effect: loading field values, parameter values, constants, etc. You may see precise list of instructions in `openjdk.jcov.filter.simplemethods.Utils.SIMPLE_INSTRUCTIONS` field in the source.
+
+Next types of "simple methods" are supported:
+ * simple **getters**. A "simple code" followed by a return statement
+ * simple **setters**. A "simple code" followed by setting a field
+ * simple **delegators**. A "simple code" followed by a method call
+ * simple **throwers**. A "simple code" followed by a throw statement
+ * **empty methods**. Methods with empty bodies.
+
+# Command line syntax
+```
+java -classpath jcov.jar:SimpleMethods.jar openjdk.jcov.filter.simplemethods.Scanner --usage
+
+java -classpath jcov.jar:SimpleMethods.jar openjdk.jcov.filter.simplemethods.Scanner [--include|-i <include patern>] [--exclude|-e <exclude pattern>] \
+[--getters <output file name>] [--setters <output file name>] [--delegators <output file name>] [--throwers <output file name>] [--empty <output file name>] \
+jrt:/ | jar:file:/<jar file> | file:/<class hierarchy>
+
+    Options
+        --include - what classes to scan for simple methods.
+        --exclude - what classes to exclude from scanning.
+    Next options specify file names where to collect this or that type of methods. Only those which specified are detected. At least one kind of methods should be requested. Please consult the source code for exact details.
+        --getters - methods which are just returning a value.
+        --setters - methods which are just setting a field.
+        --delegators - methods which are just calling another method.
+        --throwers - methods which are just throwing an exception.
+        --empty - methods with an empty body.
+
+    Parameters define where to look for classes which are to be scanned.
+        jrt:/ - scan JDK classes
+        jar:file:/ - scan a jar file
+        file:/ - scan a directory containing compiled classes.
+```
+# Building
+```
+ant jar
+```
+
+To build, a `jcov.jar` is required. The `jcov.jar` should contain ASM of version 6.0 or newer.
+
+Build requires JDK 9.0 or newer.
+
+# Testing
+
+To run tests, TestNG is required. TestNG must be specified by `testng.classpath` property:
+```
+ant -Dtestng.classpath=<testng.jar>:<jcommander.jar> test
+```
+
+# Author
+Alexander (Shura) Ilin (alexandre.iline@oracle.com)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/build.xml	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+  This code is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License version 2 only, as
+  published by the Free Software Foundation.  Oracle designates this
+  particular file as subject to the "Classpath" exception as provided
+  by Oracle in the LICENSE file that accompanied this code.
+
+  This code is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  version 2 for more details (a copy is included in the LICENSE file that
+  accompanied this code).
+
+  You should have received a copy of the GNU General Public License version
+  2 along with this work; if not, write to the Free Software Foundation,
+  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+  or visit www.oracle.com if you need additional information or have any
+  questions.
+-->
+<project name="SimpleMethodsANCFilter" default="jar" basedir=".">
+  <!-- set global properties for this build -->
+  <property name="src" location="src"/>
+  <property name="test" location="test"/>
+  <property name="build" location="build"/>
+  <property name="classes" location="${build}/classes"/>
+  <property name="test.classes" location="${build}/tests"/>
+  <property name="test.jar" location="${build}/tests.jar"/>
+  <property name="jar" location="${build}/SimpleMethods.jar"/>
+  <property name="test.results" location="${build}/test_results"/>
+  <property name="jcov.jar" location="../../JCOV_BUILD/jcov_3.0/jcov.jar"/>
+
+  <target name="compile">
+    <available file="${jcov.jar}" property="jcov-jar-exists"/>
+    <fail unless="jcov-jar-exists" message="There is no ${jcov.jar}"/>
+    <mkdir dir="${classes}"/>
+    <javac srcdir="${src}" classpath="${jcov.jar}" destdir="${classes}"/>
+  </target>
+
+  <target name="jar" depends="compile">
+    <jar jarfile="${jar}" basedir="${classes}"/>
+  </target>
+
+  <target name="clean">
+    <delete dir="${build}"/>
+  </target>
+
+  <target name="compile-test">
+    <fail unless="testng.classpath" message="Please specify testng.classpath"/>
+    <mkdir dir="${test.classes}"/>
+    <javac srcdir="${test}" classpath="${classes}:${jcov.jar}:${testng.classpath}" destdir="${test.classes}"/>
+  </target>
+
+  <target name="test" depends="compile,compile-test">
+    <taskdef resource="testngtasks" classpath="${testng.classpath}"/>
+    <mkdir dir="${test.results}"/>
+    <jar jarfile="${test.jar}" basedir="${test.classes}"/>
+    <propertyset id="test.bytecode">
+      <propertyref name="test.classes"/>
+      <propertyref name="test.jar"/>
+    </propertyset>
+    <testng classpath="${classes}:${jcov.jar}:${test.classes}:${testng.classpath}" outputDir="${test.results}">
+      <classfileset dir="${test.classes}" includes="**/*.class"/>
+      <propertyset refid="test.bytecode"/>
+    </testng>
+  </target>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Delegators.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.InvokeDynamicInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.function.BiPredicate;
+
+import static java.util.Arrays.binarySearch;
+import static openjdk.jcov.filter.simplemethods.Utils.isInvokeInstruction;
+import static openjdk.jcov.filter.simplemethods.Utils.isReturnInstruction;
+import static openjdk.jcov.filter.simplemethods.Utils.isSimpleInstruction;
+
+public class Delegators implements BiPredicate<ClassNode, MethodNode> {
+
+    private final boolean sameNameDelegationOnly;
+
+    public Delegators(boolean sameNameDelegationOnly) {
+        this.sameNameDelegationOnly = sameNameDelegationOnly;
+    }
+
+    public Delegators() {
+        this(false);
+    }
+
+    /**
+     * Identifies simple delegation. A simple delegator is a method obtaining any number of values with a "simple" code
+     * and then calling a method with the obtained values.
+     * @see Utils#isSimpleInstruction(int)
+     */
+    @Override
+    public boolean test(ClassNode clazz, MethodNode m) {
+        int index = 0;
+        int opCode = -1;
+        //skip all instructions allowed to get values
+        for(; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //that should be an invocation instruction
+        if(!isInvokeInstruction(opCode)) {
+            return false;
+        }
+        if(sameNameDelegationOnly) {
+            //check name
+            AbstractInsnNode node = m.instructions.get(index);
+            String name;
+            if (node instanceof MethodInsnNode) {
+                name = ((MethodInsnNode) node).name;
+            } else if (node instanceof InvokeDynamicInsnNode) {
+                name = ((InvokeDynamicInsnNode) node).name;
+            } else {
+                throw new IllegalStateException("Unknown node type: " + node.getClass().getName());
+            }
+            if(!m.name.equals(name)) {
+                return false;
+            }
+        }
+        //scroll to next instruction
+        for(index++; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                break;
+            }
+        }
+        //that should be a return instruction
+        return isReturnInstruction(opCode);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/EmptyMethods.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.function.BiPredicate;
+
+import static org.objectweb.asm.Opcodes.RETURN;
+
+public class EmptyMethods implements BiPredicate<ClassNode, MethodNode> {
+    @Override
+    public boolean test(ClassNode node, MethodNode m) {
+        int index = 0;
+        int opCode = -1;
+        //skip all instructions allowed to get values
+        for(; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!Utils.isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //that should be a return
+        return opCode == RETURN;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Getters.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.function.BiPredicate;
+
+import static org.objectweb.asm.Opcodes.RETURN;
+
+public class Getters implements BiPredicate<ClassNode, MethodNode> {
+    /**
+     * Identifies simple getters. A simple getter is a method obtaining a value with a "simple" code and returning it.
+     * @see Utils#isSimpleInstruction(int)
+     */
+    @Override
+    public boolean test(ClassNode clazz, MethodNode m) {
+        int index = 0;
+        int opCode = -1;
+        //skip all instructions allowed to get values
+        for(; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!Utils.isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //that should be a return instruction, but returning a value
+        return Utils.isReturnInstruction(opCode) && opCode != RETURN;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Scanner.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import com.sun.tdk.jcov.util.Utils;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.BiPredicate;
+
+import static java.util.stream.Collectors.joining;
+
+public class Scanner {
+    private static String USAGE =
+            "java -classpath jcov.jar:SimpleMethods.jar " + Scanner.class.getName() + " --usage\n" +
+                    "\n" +
+                    "java -classpath jcov.jar:SimpleMethods.jar " + Scanner.class.getName() +
+                    " [--include|-i <include patern>] [--exclude|-e <exclude pattern>] \\\n" +
+                    "[--getters <output file name>] " +
+                    "[--setters <output file name>] " +
+                    "[--delegators <output file name>] " +
+                    "[--throwers <output file name>] " +
+                    "[--empty <output file name>] \\\n" +
+                    "jrt:/ | jar:file:/<jar file> | file:/<class hierarchy>\n" +
+                    "\n" +
+                    "    Options\n" +
+                    "        --include - what classes to scan for simple methods.\n" +
+                    "        --exclude - what classes to exclude from scanning.\n" +
+                    "    Next options specify file names where to collect this or that type of methods. " +
+                    "Only those which specified are detected. At least one kind of methods should be requested. " +
+                    "Please consult the source code for exact details.\n" +
+                    "        --getters - methods which are just returning a value.\n" +
+                    "        --setters - methods which are just setting a field.\n" +
+                    "        --delegators - methods which are just calling another method.\n" +
+                    "        --throwers - methods which are just throwing an exception.\n" +
+                    "        --empty - methods with an empty body.\n" +
+                    "\n" +
+                    "    Parameters define where to look for classes which are to be scanned.\n" +
+                    "        jrt:/ - scan JDK classes\n" +
+                    "        jar:file:/ - scan a jar file\n" +
+                    "        file:/ - scan a directory containing compiled classes.";
+
+    private Utils.Pattern[] includes;
+    private Utils.Pattern[] excludes;
+    private final List<Filter> filters = new ArrayList<>();
+    private final List<URI> filesystems = new ArrayList<>();
+
+    public static void main(String[] args) throws IOException, URISyntaxException {
+        if (args.length == 1 && args[0].equals("--usage")) {
+            usage();
+            return;
+        }
+        Scanner scanner = new Scanner();
+        final List<Utils.Pattern> class_includes = new ArrayList<>();
+        final List<Utils.Pattern> class_excludes = new ArrayList<>();
+        for (int i = 0; i < args.length; i++) {
+            switch (args[i]) {
+                case "--include":
+                case "-i":
+                    i++;
+                    class_includes.add(new Utils.Pattern(args[i], true, false));
+                    break;
+                case "--exclude":
+                case "-e":
+                    i++;
+                    class_excludes.add(new Utils.Pattern(args[i], false, false));
+                    break;
+                default:
+                    //the only other options allowed are -<filter name>
+                    //see usage
+                    if (args[i].startsWith("--")) {
+                        Filter filter = Filter.get(args[i].substring(2));
+                        scanner.filters.add(filter);
+                        i++;
+                        filter.setOutputFile(args[i]);
+                    } else {
+                        try {
+                            scanner.filesystems.add(new URI(args[i]));
+                        } catch (URISyntaxException e) {
+                            usage();
+                            throw e;
+                        }
+                    }
+            }
+        }
+        if (scanner.filters.size() == 0) {
+            usage();
+            String filtersList =
+                    Arrays.stream(Filter.values()).map(f -> "--" + f.name()).collect(joining(","));
+            throw new IllegalArgumentException("One or more of " + filtersList + " options must be specified");
+        }
+        scanner.includes = class_includes.toArray(new Utils.Pattern[0]);
+        scanner.excludes = class_excludes.toArray(new Utils.Pattern[0]);
+        scanner.run();
+    }
+
+    private static void usage() {
+        System.out.println(USAGE);
+    }
+
+    public void run() throws IOException {
+        try {
+            for (Filter f : filters) {
+                f.openFile();
+            }
+            for (URI uri : filesystems) {
+                FileSystem fs;
+                Iterator<Path> roots;
+                String scheme = uri.getScheme();
+                if(scheme == null) {
+                    throw new IllegalStateException("No scheme in " + uri.toString());
+                }
+                switch (scheme) {
+                    case "jrt":
+                        fs = FileSystems.getFileSystem(uri);
+                        roots = Files.newDirectoryStream(fs.getPath("./modules")).iterator();
+                        break;
+                    case "jar":
+                        fs = FileSystems.newFileSystem(uri, new HashMap<>());
+                        roots = fs.getRootDirectories().iterator();
+                        break;
+                    case "file":
+                        fs = FileSystems.getDefault();
+                        roots = List.of(fs.getPath(uri.getPath())).iterator();
+                        break;
+                    default:
+                        throw new RuntimeException("TRI not supported: " + uri.toString());
+                }
+                while (roots.hasNext()) {
+                    Path root = roots.next();
+                    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                        @Override
+                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                            if (file.toString().endsWith(".class")) {
+                                visitClass(root, file);
+                            }
+                            return FileVisitResult.CONTINUE;
+                        }
+                    });
+                }
+            }
+        } finally {
+            for (Filter f : filters) {
+                f.closeFile();
+            }
+        }
+    }
+
+    private void visitClass(Path root, Path file) throws IOException {
+        try (InputStream in = Files.newInputStream(file)) {
+            ClassReader reader;
+            reader = new ClassReader(in);
+            if (included(reader.getClassName())) {
+                ClassNode clazz = new ClassNode();
+                reader.accept(clazz, 0);
+                for (Object methodObject : clazz.methods) {
+                    MethodNode method = (MethodNode) methodObject;
+                    for (Filter f : filters) {
+                        if (f.filter.test(clazz, method)) {
+                            f.add(clazz.name + "#" + method.name + method.desc);
+                        }
+                    }
+                }
+            }
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Exception while parsing file " + file + " from " + root, e);
+        }
+    }
+
+    private boolean included(String clazz) {
+        return  Utils.accept(includes, null, "/" + clazz, null) &&
+                Utils.accept(excludes, null, "/" + clazz, null);
+    }
+
+    enum Filter {
+        getters("simple getter", new Getters()),
+        setters("simple setter", new Setters()),
+        delegators("simple delegator", new Delegators()),
+        throwers("simple thrower", new Throwers()),
+        empty("empty methods", new EmptyMethods());
+        private String description;
+        private BiPredicate<ClassNode, MethodNode> filter;
+        private String outputFile;
+        private BufferedWriter output;
+
+        Filter(String description, BiPredicate<ClassNode, MethodNode> filter) {
+            this.description = description;
+            this.filter = filter;
+        }
+
+        public void setOutputFile(String outputFile) {
+            this.outputFile = outputFile;
+        }
+
+        public void openFile() throws IOException {
+            output = Files.newBufferedWriter(Paths.get(outputFile));
+            output.write("#" + description);
+            output.newLine();
+            output.flush();
+        }
+
+        public void closeFile() throws IOException {
+            if (outputFile != null) {
+                output.flush();
+                output.close();
+            }
+        }
+
+        public void add(String s) throws IOException {
+            output.write(s);
+            output.newLine();
+            output.flush();
+        }
+
+        static Filter get(String name) {
+            for(Filter f : values()) {
+                if(f.name().equals(name)) {
+                    return f;
+                }
+            }
+            throw new RuntimeException("Unknown filter: " + name);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Setters.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.function.BiPredicate;
+
+import static org.objectweb.asm.Opcodes.PUTFIELD;
+import static org.objectweb.asm.Opcodes.PUTSTATIC;
+import static org.objectweb.asm.Opcodes.RETURN;
+
+/**
+ * Identifies simple setters. A simple setter is a method obtaining a value with a "simple" code and
+ * assigning a field with it.
+ * @see Utils#isSimpleInstruction(int)
+ */
+public class Setters implements BiPredicate<ClassNode, MethodNode> {
+    @Override
+    public boolean test(ClassNode clazz, MethodNode m) {
+        int index = 0;
+        int opCode = -1;
+        //skip all instructions allowed to get values
+        for(; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!Utils.isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //that should be an instruction setting a field
+        if(opCode != PUTFIELD && opCode != PUTSTATIC) {
+            return false;
+        }
+        //find next
+        for(index++; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!Utils.isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //and that should be a return
+        return opCode == RETURN;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Throwers.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.util.function.BiPredicate;
+
+public class Throwers implements BiPredicate<ClassNode, MethodNode> {
+    @Override
+    public boolean test(ClassNode cnode, MethodNode m) {
+        int index = 0;
+        int opCode = -1;
+        //find first instruction
+        for(; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                    break;
+            }
+        }
+        //should be NEW
+        if(opCode != Opcodes.NEW) {
+            return false;
+        }
+        //next is DUP
+        index++;
+        opCode = m.instructions.get(index).getOpcode();
+        if(opCode != Opcodes.DUP) {
+            return false;
+        }
+        //some more simple code
+        for(index++; index < m.instructions.size(); index++) {
+            opCode = m.instructions.get(index).getOpcode();
+            if(opCode >=0) {
+                if (!Utils.isSimpleInstruction(opCode)) {
+                    break;
+                }
+            }
+        }
+        //should be a constructor
+        if(opCode != Opcodes.INVOKESPECIAL) {
+            return false;
+        }
+        AbstractInsnNode node = m.instructions.get(index);
+        if(!(node instanceof MethodInsnNode)) {
+            return false;
+        }
+        if(!((MethodInsnNode)node).name.equals("<init>")) {
+            return false;
+        }
+        index++;
+        opCode = m.instructions.get(index).getOpcode();
+        return opCode == Opcodes.ATHROW;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/src/openjdk/jcov/filter/simplemethods/Utils.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import java.util.Arrays;
+
+import static org.objectweb.asm.Opcodes.*;
+
+public class Utils {
+    private final static int[] SIMPLE_INSTRUCTIONS = new int[]{DUP, LDC,
+            BALOAD, CALOAD, AALOAD, DALOAD, FALOAD, IALOAD, SALOAD,
+            ACONST_NULL,
+            ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, ICONST_M1,
+            LCONST_0, LCONST_1,
+            FCONST_0, FCONST_1, FCONST_2,
+            DCONST_0, DCONST_1,
+            ALOAD, ILOAD, FLOAD, LLOAD, DLOAD,
+            GETFIELD, GETSTATIC,
+            BIPUSH, SIPUSH};
+    private final static int[] INVOKE_INSTRUCTIONS = new int[]{INVOKEVIRTUAL, INVOKEINTERFACE, INVOKESTATIC,
+            INVOKEDYNAMIC, INVOKESPECIAL};
+    private final static int[] RETURN_INSTRUCTIONS = new int[]{RETURN, ARETURN, IRETURN, FRETURN, LRETURN, DRETURN};
+
+    static {
+        Arrays.sort(SIMPLE_INSTRUCTIONS);
+        Arrays.sort(INVOKE_INSTRUCTIONS);
+        Arrays.sort(RETURN_INSTRUCTIONS);
+    }
+
+    /**
+     * An instruction is called "simple" if its only effect is to bring values onto the stack from stack, variables, fields, constants, etc.
+     * @param opCode
+     * @return
+     */
+    public static boolean isSimpleInstruction(int opCode) {
+        return Arrays.binarySearch(SIMPLE_INSTRUCTIONS, opCode) >= 0;
+    }
+    public static boolean isReturnInstruction(int opCode) {
+        return Arrays.binarySearch(RETURN_INSTRUCTIONS, opCode) >= 0;
+    }
+    public static boolean isInvokeInstruction(int opCode) {
+        return Arrays.binarySearch(INVOKE_INSTRUCTIONS, opCode) >= 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/DelegatorsTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+import static org.testng.Assert.assertEquals;
+
+public class DelegatorsTest {
+
+    Delegators any_name_delegator;
+    Delegators same_name_delegator;
+    ClassNode cls;
+
+    @BeforeTest
+    public void init() throws IOException {
+        any_name_delegator = new Delegators();
+        same_name_delegator = new Delegators(true);
+        cls = TestUtils.findTestClass(this.getClass());
+    }
+
+    @DataProvider(name = "cases")
+    public Object[][] cases() {
+        return new Object[][] {
+                {same_name_delegator, "foo(Ljava/lang/String;I)I", false, "Simple getter"},
+                {same_name_delegator, "foo(I)I", true, "Using constants or parameters"},
+                {same_name_delegator, "foo(J)I", true, "Using fields"},
+                {same_name_delegator, "foo(Z)I", false, "Having condition"},
+                {same_name_delegator, "foo(F)I", false, "Calling other methods"},
+                {same_name_delegator, "bar(I)I", false, "Different method"},
+                {any_name_delegator, "bar(I)I", true, "Different method"},
+                {any_name_delegator, "empty()V", false, "Empty"}
+        };
+    }
+    @Test(dataProvider = "cases")
+    public void test(Delegators delegator, String method, boolean result, String description) throws IOException {
+        assertEquals(delegator.test(cls, TestUtils.findTestMethod(cls, method)), result, description);
+    }
+
+    //test data
+    int aField = 0;
+    static String aStaticField = null;
+
+    int foo(String i, int j) {return j;}
+
+    int foo(int j) {
+        return foo("", j);
+    }
+
+    int foo(long s) {
+        return foo(aStaticField, aField);
+    }
+
+    int foo(boolean s) {
+        if(s)
+            return foo(1);
+        else
+            return foo(0);
+    }
+
+    int foo(float s) {
+        foo(null, 0);
+        return foo(null, 1);
+    }
+
+    int bar(int j) {
+        return foo(null, j);
+    }
+
+    void empty() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/EmptyMethodsTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+import static org.testng.Assert.assertEquals;
+
+public class EmptyMethodsTest {
+
+    EmptyMethods tested;
+    ClassNode cls;
+
+    @BeforeTest
+    public void init() throws IOException {
+        tested = new EmptyMethods();
+        cls = TestUtils.findTestClass(this.getClass());
+    }
+
+    @DataProvider(name = "cases")
+    public Object[][] cases() {
+        return new Object[][] {
+                {"empty()V", true, "Empty"},
+                {"get()I", false, "A getter"},
+                {"init()V", false, "init()"}
+        };
+    }
+    @Test(dataProvider = "cases")
+    public void test(String method, boolean result, String description) {
+        assertEquals(tested.test(cls, TestUtils.findTestMethod(cls, method)), result, description);
+    }
+
+    //test data
+    void empty() {
+        //doing nothing
+    }
+    int get(){return 0;}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/GettersTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+import static openjdk.jcov.filter.simplemethods.TestUtils.findTestMethod;
+import static org.testng.Assert.assertEquals;
+
+public class GettersTest {
+
+    Getters tested;
+    ClassNode cls;
+
+    @BeforeTest
+    public void init() throws IOException {
+        tested = new Getters();
+        cls = TestUtils.findTestClass(this.getClass());
+    }
+
+    @DataProvider(name = "cases")
+    public Object[][] cases() {
+        return new Object[][] {
+                {"getField()I", true, "A getter"},
+                {"getConstant()Ljava/lang/Object;", true, "A constant getter"},
+                {"getObjectField()Ljava/lang/String;", true, "An object getter"},
+                {"getStaticConstant()I", true, "A constant getter using LDC"},
+                {"getStaticField()Ljava/lang/Object;", true, "A static getter"},
+                {"getFieldToString()Ljava/lang/String;", false, "Returning toString() of a field"},
+                {"getOtherField()J", true, "A getter for other field object"},
+                {"empty()V", false, "Empty"}
+        };
+    }
+    @Test(dataProvider = "cases")
+    public void test(String method, boolean result, String description) {
+        assertEquals(tested.test(cls, findTestMethod(cls, method)), result, description);
+    }
+
+    //test data
+    int aField;
+    String anObjectField;
+    static Object aStaticField;
+    static final int CONSTANT=7532957;
+
+    class Other {
+        long aField;
+    }
+
+    Other other;
+
+    int getField() {
+        return aField;
+    }
+
+    Object getConstant() {
+        return null;
+    }
+
+    int getStaticConstant() {
+        return CONSTANT;
+    }
+
+    long getOtherField() {
+        return other.aField;
+    }
+
+    String getObjectField() {
+        return anObjectField;
+    }
+
+    String getFieldToString() {
+        return anObjectField.toString();
+    }
+
+    static Object getStaticField() {
+        return aStaticField;
+    }
+
+    void empty() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/MainTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+
+public class MainTest {
+
+    @Test
+    public void testJRTFS() throws IOException, URISyntaxException {
+        Path getters = Files.createTempFile("getters", ".lst");
+        System.out.println("testJRTFS output file: " + getters.toAbsolutePath().toString());
+        Scanner.main(new String[]{
+                "--getters", getters.toAbsolutePath().toString(),
+                "--include", "java.util",
+                "jrt:/"
+        });
+        assertTrue(Files.lines(getters).anyMatch(l -> l.equals("java/util/ArrayList#size()I")));
+        assertTrue(Files.lines(getters).noneMatch(l -> l.equals("java/io/File#getPath()Ljava/lang/String;")));
+        Files.delete(getters);
+    }
+
+    @Test
+    public void testJRTFSNoJavaUtil() throws IOException, URISyntaxException {
+        Path getters = Files.createTempFile("throwers", ".lst");
+        System.out.println("testJRTFSNoJavaUtil output file: " + getters.toAbsolutePath().toString());
+        Scanner.main(new String[]{
+                "--throwers", getters.toAbsolutePath().toString(),
+                "--exclude", "java.util",
+                "jrt:/"
+        });
+        assertTrue(Files.lines(getters).noneMatch(l -> l.equals("java/util/AbstractList#add(ILjava/lang/Object;)V")));
+        assertTrue(Files.lines(getters).anyMatch("java/io/InputStream#reset()V"::equals));
+        Files.delete(getters);
+    }
+
+    @Test
+    public void testDir() throws IOException, URISyntaxException {
+        String dir = System.getProperty("test.classes");
+        Path delegators = Files.createTempFile("delegators", ".lst");
+        System.out.println("testDir output file: " + delegators.toAbsolutePath().toString());
+        Scanner.main(new String[]{
+                "--delegators", delegators.toAbsolutePath().toString(),
+                "file://" + dir
+        });
+        assertTrue(Files.lines(delegators).anyMatch(l ->
+                l.equals(DelegatorsTest.class.getName().replace('.', '/') + "#foo(I)I")));
+        Files.delete(delegators);
+    }
+
+    @Test
+    public void testJAR() throws IOException, URISyntaxException {
+        String jar = System.getProperty("test.jar");
+        Path setters = Files.createTempFile("setters", ".lst");
+        System.out.println("testJAR output file: " + setters.toAbsolutePath().toString());
+        Scanner.main(new String[]{
+                "--setters", setters.toAbsolutePath().toString(),
+                "jar:file:" + jar});
+        assertTrue(Files.lines(setters).anyMatch(l ->
+                l.equals(SettersTest.class.getName().replace('.', '/') + "#setField(I)V")));
+    }
+
+    @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "Unknown filter.*")
+    public void testWrongFilter() throws IOException, URISyntaxException {
+            Scanner.main(new String[]{
+                    "--a-non-existing-filter", "a_file",
+                    "file:///a/path"});
+    }
+
+    public void testNoFilter() throws IOException, URISyntaxException {
+        try {
+            Scanner.main(new String[]{
+                    "file:///a/path"});
+            fail("No RuntimeException when no filters specified");
+        } catch (RuntimeException e) {
+            assertTrue(Arrays.stream(Scanner.Filter.values()).map(f -> "--" + f.name())
+                    .allMatch(f -> e.getMessage().contains(f)), "Incorrect error message: " + e.getMessage());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/SettersTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+import static org.testng.Assert.assertEquals;
+
+public class SettersTest {
+
+    Setters tested;
+    ClassNode cls;
+
+    @BeforeTest
+    public void init() throws IOException {
+        tested = new Setters();
+        cls = TestUtils.findTestClass(this.getClass());
+    }
+
+    @DataProvider(name = "cases")
+    public Object[][] cases() {
+        return new Object[][] {
+                {"setObjectField(Ljava/lang/String;)V", true, "An object setter"},
+                {"setFieldToToString(Ljava/lang/Object;)V", false, "Assigning toString() to a field"},
+                {"setField(I)V", true, "A setter"},
+                {"setStaticField(Ljava/lang/Object;)V", true, "A static setter"},
+                {"setOtherField(J)V", true, "A setter for other field object"},
+                {"empty()V", false, "Empty"}
+        };
+    }
+    @Test(dataProvider = "cases")
+    public void test(String method, boolean result, String description) {
+        assertEquals(tested.test(cls, TestUtils.findTestMethod(cls, method)), result, description);
+    }
+
+    //test data
+    int aField;
+    String anObjectField;
+    static Object aStaticField;
+
+    class Other {
+        long aField;
+    }
+
+    Other other;
+
+    void setField(int v) { aField = v; }
+
+    void setOtherField(long v) {
+        other.aField = v;
+    }
+
+    void setObjectField(String v) {
+        anObjectField = v;
+    }
+
+    void setFieldToToString(Object v) {
+        anObjectField = v.toString();
+    }
+
+    static void setStaticField(Object v) {
+        aStaticField = v;
+    }
+
+    void empty() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/TestUtils.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.MethodNode;
+
+import java.io.IOException;
+
+public class TestUtils {
+    static ClassNode findTestClass(Class cls) throws IOException {
+        ClassNode result = new ClassNode();
+        ClassReader reader = new ClassReader(cls.getClassLoader().
+                getResourceAsStream(cls.getName().replace('.','/') + ".class"));
+        reader.accept(result, 0);
+        return result;
+    }
+
+    static MethodNode findTestMethod(ClassNode cls, String methodSig)  {
+        for(Object mo: cls.methods) {
+            MethodNode m = (MethodNode) mo;
+            if((m.name + m.desc).equals(methodSig)) {
+                return m;
+            }
+        }
+        throw new IllegalStateException("Method does not exist: " + methodSig + " in class " + cls.name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/simple_methods_anc/test/openjdk/jcov/filter/simplemethods/ThrowersTest.java	Wed May 16 11:41:39 2018 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package openjdk.jcov.filter.simplemethods;
+
+import org.objectweb.asm.tree.ClassNode;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+import static openjdk.jcov.filter.simplemethods.TestUtils.findTestMethod;
+import static org.testng.Assert.assertEquals;
+
+public class ThrowersTest {
+
+    Throwers tested;
+    ClassNode cls;
+
+    @BeforeTest
+    public void init() throws IOException {
+        tested = new Throwers();
+        cls = TestUtils.findTestClass(this.getClass());
+    }
+
+    @DataProvider(name = "cases")
+    public Object[][] cases() {
+        return new Object[][] {
+                {"notImplemented()V", true, "A thrower"},
+                {"compoundMessage()V", false, "A thrower with a computed message"},
+                {"empty()V", false, "Empty"}
+        };
+    }
+    @Test(dataProvider = "cases")
+    public void test(String method, boolean result, String description) {
+        assertEquals(tested.test(cls, findTestMethod(cls, method)), result, description);
+    }
+
+    //test data
+    String message = "not ";
+    void empty() {}
+    void notImplemented(){throw new RuntimeException(message);}
+    void compoundMessage(){throw new RuntimeException(message + "implemented");}
+}