109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)package org.chromium.devtools.jsdoc;
209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
3197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.jscomp.Compiler;
4197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.jscomp.NodeTraversal;
5197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.jscomp.parsing.Config;
6197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.jscomp.parsing.Config.LanguageMode;
7197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.jscomp.parsing.ParserRunner;
8197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.rhino.ErrorReporter;
9197021e6b966cfb06891637935ef33fff06433d1Ben Murdochimport com.google.javascript.rhino.Node;
1009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
1109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import org.chromium.devtools.jsdoc.checks.ContextTrackingValidationCheck;
1209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
1309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.io.FileNotFoundException;
1409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.io.IOException;
1509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.nio.ByteBuffer;
1609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.nio.charset.StandardCharsets;
1709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.nio.file.FileSystems;
1809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.nio.file.Files;
1909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.util.ArrayList;
2009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.util.List;
2109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)import java.util.concurrent.Callable;
2209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
2309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)public class FileCheckerCallable implements Callable<ValidatorContext> {
2409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
2509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    private final String fileName;
2609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
2709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    public FileCheckerCallable(String fileName) {
2809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        this.fileName = fileName;
2909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
3009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
3109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    @Override
3209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    public ValidatorContext call() {
3309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        try {
3409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            ValidatorContext context = new ValidatorContext(readScriptText(), fileName);
3509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            ValidationCheckDispatcher dispatcher = new ValidationCheckDispatcher(context);
3609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            dispatcher.registerCheck(new ContextTrackingValidationCheck());
37197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            NodeTraversal.traverse(new Compiler(), parseScript(context), dispatcher);
3809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return context;
3909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        } catch (FileNotFoundException e) {
4009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            logError("File not found: " + fileName);
4109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        } catch (IOException e) {
4209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            logError("Failed to read file " + fileName);
4309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
4409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return null;
4509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
4609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
47197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    private String readScriptText() throws IOException {
4809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        byte[] encoded = Files.readAllBytes(FileSystems.getDefault().getPath(fileName));
4909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        String text = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(encoded)).toString();
50197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        return text;
5109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
5209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
53197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch    private static Node parseScript(final ValidatorContext context) {
54197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        Config config = ParserRunner.createConfig(true, LanguageMode.ECMASCRIPT5_STRICT, true);
55197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        ErrorReporter errorReporter = new ErrorReporter() {
56197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            @Override
57197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            public void warning(String message, String sourceName, int line, int lineOffset) {
58197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                // Ignore.
59197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            }
60197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
61197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            @Override
62197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            public void error(String message, String sourceName, int line, int lineOffset) {
63197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                logError("at " + sourceName + ":" + line + ":" + lineOffset);
64197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            }
65197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        };
66197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        try {
67197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            return ParserRunner.parse(
68197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch                    context.sourceFile, context.sourceFile.getCode(), config, errorReporter).ast;
69197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        } catch (IOException e) {
70197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            // Does not happen with preloaded files.
71197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch            return null;
72197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        }
7309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
7409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
7509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    private static void logError(String message) {
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        System.err.println("ERROR: " + message);
7709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
7809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
7909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    private static class ValidationCheckDispatcher extends DoDidVisitorAdapter {
8009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        private final List<ValidationCheck> checks = new ArrayList<>(2);
8109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        private final ValidatorContext context;
8209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
8309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        public ValidationCheckDispatcher(ValidatorContext context) {
8409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            this.context = context;
8509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
8609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
8709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        public void registerCheck(ValidationCheck check) {
8809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            check.setContext(context);
8909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            checks.add(check);
9009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
9109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
9209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        @Override
93197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        public void doVisit(Node node) {
9409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            for (DoDidNodeVisitor visitor : checks) {
9509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                visitor.doVisit(node);
9609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            }
9709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
9809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
9909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        @Override
100197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch        public void didVisit(Node node) {
10109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            for (ValidationCheck check : checks) {
10209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                check.didVisit(node);
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            }
10409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
10509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
10609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
107