diff --git a/src/com/google/javascript/jscomp/BranchCoverageInstrumentationCallback.java b/src/com/google/javascript/jscomp/BranchCoverageInstrumentationCallback.java index 1b3828b8003..16433babb03 100644 --- a/src/com/google/javascript/jscomp/BranchCoverageInstrumentationCallback.java +++ b/src/com/google/javascript/jscomp/BranchCoverageInstrumentationCallback.java @@ -51,8 +51,10 @@ public void visit(NodeTraversal traversal, Node node, Node parent) { if (node.isScript()) { if (instrumentationData.get(fileName) != null) { + Node toAddTo = + node.hasChildren() && node.getFirstChild().isModuleBody() ? node.getFirstChild() : node; // Add instrumentation code - node.addChildrenToFront(newHeaderNode(traversal, node).removeChildren()); + toAddTo.addChildrenToFront(newHeaderNode(traversal, toAddTo).removeChildren()); compiler.reportChangeToEnclosingScope(node); instrumentBranchCoverage(traversal, instrumentationData.get(fileName)); } diff --git a/src/com/google/javascript/jscomp/CoverageInstrumentationCallback.java b/src/com/google/javascript/jscomp/CoverageInstrumentationCallback.java index 437141c7f7b..df4f79d3b01 100644 --- a/src/com/google/javascript/jscomp/CoverageInstrumentationCallback.java +++ b/src/com/google/javascript/jscomp/CoverageInstrumentationCallback.java @@ -150,6 +150,9 @@ public void visit(NodeTraversal traversal, Node node, Node parent) { if (node.isScript()) { String fileName = getFileName(traversal); if (instrumentationData.get(fileName) != null) { + if (node.hasChildren() && node.getFirstChild().isModuleBody()) { + node = node.getFirstChild(); + } node.addChildrenToFront(newHeaderNode(traversal, node).removeChildren()); } traversal.reportCodeChange(); @@ -195,7 +198,7 @@ public void visit(NodeTraversal traversal, Node node, Node parent) { } // For any other statement, add instrumentation code just before it. - if (parent != null && NodeUtil.isStatementBlock(parent)) { + if (parent != null && NodeUtil.isStatementBlock(parent) && !node.isModuleBody()) { parent.addChildBefore( newInstrumentationNode(traversal, node), node); diff --git a/src/com/google/javascript/jscomp/CoverageInstrumentationPass.java b/src/com/google/javascript/jscomp/CoverageInstrumentationPass.java index 592e6564403..8994de0fc09 100644 --- a/src/com/google/javascript/jscomp/CoverageInstrumentationPass.java +++ b/src/com/google/javascript/jscomp/CoverageInstrumentationPass.java @@ -95,6 +95,11 @@ public void process(Node externsNode, Node rootNode) { } Node firstScript = rootNode.getFirstChild(); checkState(firstScript.isScript()); + // If any passes run after we need to preserve the MODULE_BODY structure of scripts - we can't + // just add to a script if it is a module. + if (firstScript.hasChildren() && firstScript.getFirstChild().isModuleBody()) { + firstScript = firstScript.getFirstChild(); + } addHeaderCode(firstScript); } } diff --git a/test/com/google/javascript/jscomp/CoverageInstrumentationPassTest.java b/test/com/google/javascript/jscomp/CoverageInstrumentationPassTest.java index ca542db802f..d4ad55a482b 100644 --- a/test/com/google/javascript/jscomp/CoverageInstrumentationPassTest.java +++ b/test/com/google/javascript/jscomp/CoverageInstrumentationPassTest.java @@ -25,14 +25,19 @@ @RunWith(JUnit4.class) public final class CoverageInstrumentationPassTest { - private CompilerOptions options(LanguageMode inMode) { + private CompilerOptions options(LanguageMode inMode, LanguageMode outMode, boolean coverageOnly) { CompilerOptions options = GoldenFileComparer.options(); options.setInstrumentForCoverage(true); + options.setInstrumentForCoverageOnly(coverageOnly); options.setLanguageIn(inMode); - options.setLanguageOut(LanguageMode.ECMASCRIPT5); + options.setLanguageOut(outMode); return options; } + private CompilerOptions options(LanguageMode inMode) { + return options(inMode, LanguageMode.ECMASCRIPT5, /* coverageOnly= */ false); + } + private CompilerOptions branchOptions(LanguageMode inMode) { CompilerOptions options = GoldenFileComparer.options(); options.setInstrumentForCoverage(true); @@ -152,4 +157,12 @@ public void testWhileLoopBranch() throws Exception { compareWhileLoopBranch(LanguageMode.ECMASCRIPT_2015); } + @Test + public void testEsModule() throws Exception { + GoldenFileComparer.compileAndCompare( + "CoverageInstrumentationPassTest/EsModuleGolden.jsdata", + options( + LanguageMode.ECMASCRIPT_NEXT, LanguageMode.ECMASCRIPT_NEXT, /* coverageOnly= */ true), + "CoverageInstrumentationPassTest/EsModule.jsdata"); + } } diff --git a/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModule.jsdata b/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModule.jsdata new file mode 100644 index 00000000000..f8c70d09007 --- /dev/null +++ b/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModule.jsdata @@ -0,0 +1,5 @@ +import * as foo from 'bar'; + +export function qux() { + console.log('baz'); +} \ No newline at end of file diff --git a/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModuleGolden.jsdata b/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModuleGolden.jsdata new file mode 100644 index 00000000000..65d1358a0cc --- /dev/null +++ b/test/com/google/javascript/jscomp/testdata/CoverageInstrumentationPassTest/EsModuleGolden.jsdata @@ -0,0 +1,19 @@ +'use strict'; +if (!self.window) { + self.window = self; + self.window.top = self; +} +var __jscov = window.top["__jscov"] || (window.top["__jscov"] = {"fileNames":[], "instrumentedLines":[], "executedLines":[]}); +var JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata = []; +__jscov["executedLines"].push(JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata); +__jscov["instrumentedLines"].push("0d"); +__jscov["fileNames"].push("CoverageInstrumentationPassTest/EsModule.jsdata"); +JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata[0] = true; +import*as foo from "bar"; +JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata[2] = true; +export function qux() { + JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata[2] = true; + JSCompiler_lcov_data_CoverageInstrumentationPassTest_EsModule_jsdata[3] = true; + console.log("baz"); +} +; \ No newline at end of file