1/*
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 *   - Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 *
11 *   - Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 *
15 *   - Neither the name of Oracle nor the names of its
16 *     contributors may be used to endorse or promote products derived
17 *     from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/**
33 * Nashorn project uses "final" modifier for method parameters
34 * (like 'val' of Scala). This tool finds method parameters that
35 * miss final modifier.
36 */
37
38// Usage: jjs -J-Djava.ext.dirs=<your_nashorn_jar_dir> find_nonfinals.js
39
40var Class = Java.type("java.lang.Class");
41var System = Java.type("java.lang.System");
42var Thread = Java.type("java.lang.Thread");
43var File = Java.type("java.io.File");
44var JarFile = Java.type("java.util.jar.JarFile");
45var Modifier = Java.type("java.lang.reflect.Modifier");
46
47// locate nashorn.jar from java.ext.dirs
48function findNashorn() {
49    var paths = System.getProperty("java.ext.dirs").split(File.pathSeparator);
50    for each (var p in paths) {
51        var nashorn = p + File.separator + "nashorn.jar";
52        if (new File(nashorn).exists()) {
53            return nashorn;
54        }
55    }
56}
57
58// analyze a single Class and print info on non-final parameters
59function analyzeClass(cls) {
60    var methods = cls.getDeclaredMethods();
61    for each (var method in methods) {
62        var methodModifiers = method.modifiers;
63        if (Modifier.isAbstract(methodModifiers) || Modifier.isNative(methodModifiers)) {
64            continue;
65        }
66        // this requires -parameters option when compiling java sources
67        var params = method.parameters;
68        for each (var p in params) {
69           var modifiers = p.modifiers;
70           if (!Modifier.isFinal(modifiers)) {
71               if (! method.name.startsWith("access$")) {
72                   print(method);
73                   print(" ->", p);
74               }
75           }
76        }
77    }
78}
79
80var jarFile = findNashorn();
81var ctxtLoader = Thread.currentThread().contextClassLoader;
82
83// load each class and use reflection to analyze each Class
84new JarFile(jarFile).stream().forEach(
85    function(entry) {
86        var name = entry.name;
87        if (name.endsWith(".class")) {
88            var clsName = name.substring(0, name.lastIndexOf('.class'));
89            clsName = clsName.replace(/\//g, '.');
90            try {
91                // don't initialize to avoid for possible initialization errors
92                var cls = Class.forName(clsName, false, ctxtLoader);
93                analyzeClass(cls);
94            } catch (e) {
95                // print exception and continue analysis for other classes
96                print("Failed to analyze " + clsName);
97                e.printStackTrace();
98            }
99        }
100    }
101)
102