--- old/src/sample/nashorn/staticchecker.js 2020-04-15 18:54:33.000000000 +0530 +++ /dev/null 2020-04-15 18:54:33.000000000 +0530 @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// Usage: jjs --language=es6 staticchecker.js -- -// or jjs --language=es6 staticchecker.js -- -// default argument is the current directory - -if (arguments.length == 0) { - arguments[0] = "."; -} - -const File = Java.type("java.io.File"); -const file = new File(arguments[0]); -if (!file.exists()) { - print(arguments[0] + " is neither a file nor a directory"); - exit(1); -} - -// A simple static checker for javascript best practices. -// static checks performed are: -// -// * __proto__ magic property is bad (non-standard) -// * 'with' statements are bad -// * 'eval' calls are bad -// * 'delete foo' (scope variable delete) is bad -// * assignment to standard globals is bad (eg. Object = "hello") -// * assignment to property on standard prototype is bad (eg. String.prototype.foo = 45) -// * exception swallow (empty catch block in try-catch statements) - -const Files = Java.type("java.nio.file.Files"); -const EmptyStatementTree = Java.type("jdk.nashorn.api.tree.EmptyStatementTree"); -const IdentifierTree = Java.type("jdk.nashorn.api.tree.IdentifierTree"); -const MemberSelectTree = Java.type("jdk.nashorn.api.tree.MemberSelectTree"); -const Parser = Java.type("jdk.nashorn.api.tree.Parser"); -const SimpleTreeVisitor = Java.type("jdk.nashorn.api.tree.SimpleTreeVisitorES6"); -const Tree = Java.type("jdk.nashorn.api.tree.Tree"); - -const parser = Parser.create("-scripting", "--language=es6"); - -// capture standard global upfront -const globals = new Set(); -for (let name of Object.getOwnPropertyNames(this)) { - globals.add(name); -} - -const checkFile = function(file) { - print("Parsing " + file); - const ast = parser.parse(file, print); - if (!ast) { - print("FAILED to parse: " + file); - return; - } - - const checker = new (Java.extend(SimpleTreeVisitor)) { - lineMap: null, - - printWarning(node, msg) { - var pos = node.startPosition; - var line = this.lineMap.getLineNumber(pos); - var column = this.lineMap.getColumnNumber(pos); - print(`WARNING: ${msg} in ${file} @ ${line}:${column}`); - }, - - printWithWarning(node) { - this.printWarning(node, "'with' usage"); - }, - - printProtoWarning(node) { - this.printWarning(node, "__proto__ usage"); - }, - - printScopeDeleteWarning(node, varName) { - this.printWarning(node, `delete ${varName}`); - }, - - hasOnlyEmptyStats(stats) { - const itr = stats.iterator(); - while (itr.hasNext()) { - if (! (itr.next() instanceof EmptyStatementTree)) { - return false; - } - } - - return true; - }, - - checkProto(node, name) { - if (name == "__proto__") { - this.printProtoWarning(node); - } - }, - - checkAssignment(lhs) { - if (lhs instanceof IdentifierTree && globals.has(lhs.name)) { - this.printWarning(lhs, `assignment to standard global "${lhs.name}"`); - } else if (lhs instanceof MemberSelectTree) { - const expr = lhs.expression; - if (expr instanceof MemberSelectTree && - expr.expression instanceof IdentifierTree && - globals.has(expr.expression.name) && - "prototype" == expr.identifier) { - this.printWarning(lhs, - `property set "${expr.expression.name}.prototype.${lhs.identifier}"`); - } - } - }, - - visitAssignment(node, extra) { - this.checkAssignment(node.variable); - Java.super(checker).visitAssignment(node, extra); - }, - - visitCatch(node, extra) { - var stats = node.block.statements; - if (stats.empty || this.hasOnlyEmptyStats(stats)) { - this.printWarning(node, "exception swallow"); - } - Java.super(checker).visitCatch(node, extra); - }, - - visitCompilationUnit(node, extra) { - this.lineMap = node.lineMap; - Java.super(checker).visitCompilationUnit(node, extra); - }, - - visitFunctionCall(node, extra) { - var func = node.functionSelect; - if (func instanceof IdentifierTree && func.name == "eval") { - this.printWarning(node, "eval call found"); - } - Java.super(checker).visitFunctionCall(node, extra); - }, - - visitIdentifier(node, extra) { - this.checkProto(node, node.name); - Java.super(checker).visitIdentifier(node, extra); - }, - - visitMemberSelect(node, extra) { - this.checkProto(node, node.identifier); - Java.super(checker).visitMemberSelect(node, extra); - }, - - visitProperty(node, extra) { - this.checkProto(node, node.key); - Java.super(checker).visitProperty(node, extra); - }, - - visitUnary(node, extra) { - if (node.kind == Tree.Kind.DELETE && - node.expression instanceof IdentifierTree) { - this.printScopeDeleteWarning(node, node.expression.name); - } - Java.super(checker).visitUnary(node, extra); - }, - - visitWith(node, extra) { - this.printWithWarning(node); - Java.super(checker).visitWith(node, extra); - } - }; - - try { - ast.accept(checker, null); - } catch (e) { - print(e); - if (e.printStackTrace) e.printStackTrace(); - if (e.stack) print(e.stack); - } -} - -if (file.isDirectory()) { - Files.walk(file.toPath()) - .filter(function(p) Files.isRegularFile(p)) - .filter(function(p) p.toFile().name.endsWith('.js')) - .forEach(checkFile); -} else { - checkFile(file); -}