Skip to content

Commit

Permalink
Move the externs hoisting after file ordering.
Browse files Browse the repository at this point in the history
This allows externs to be sorted according to provides/requires

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=138003984
  • Loading branch information
blickly committed Nov 3, 2016
1 parent 1c8aec8 commit 670321a
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 24 deletions.
75 changes: 51 additions & 24 deletions src/com/google/javascript/jscomp/Compiler.java
Expand Up @@ -1587,8 +1587,7 @@ public Void call() throws Exception {
}

void orderInputs() {
hoistExterns();

hoistUnorderedExterns();
// Check if the sources need to be re-ordered.
boolean staleInputs = false;
if (options.dependencyOptions.needsManagement()) {
Expand All @@ -1601,9 +1600,7 @@ void orderInputs() {
}

try {
inputs =
(moduleGraph == null ? new JSModuleGraph(modules) : moduleGraph)
.manageDependencies(options.dependencyOptions, inputs);
inputs = getDegenerateModuleGraph().manageDependencies(options.dependencyOptions, inputs);
staleInputs = true;
} catch (MissingProvideException e) {
report(JSError.make(
Expand All @@ -1614,6 +1611,10 @@ void orderInputs() {
}
}

if (options.dependencyOptions.needsManagement() && options.allowGoogProvideInExterns()) {
hoistAllExterns();
}

hoistNoCompileFiles();

if (staleInputs) {
Expand All @@ -1622,46 +1623,72 @@ void orderInputs() {
}

/**
* Hoists inputs with the @externs annotation into the externs list.
* Hoists inputs with the @externs annotation and no provides or requires into the externs list.
*/
void hoistExterns() {
void hoistUnorderedExterns() {
boolean staleInputs = false;
for (CompilerInput input : inputs) {
if (!options.allowGoogProvideInExterns() && options.dependencyOptions.needsManagement()) {
if (options.dependencyOptions.needsManagement()) {
// If we're doing scanning dependency info anyway, use that
// information to skip sources that obviously aren't externs.
if (!input.getProvides().isEmpty() || !input.getRequires().isEmpty()) {
continue;
}
}

Node n = input.getAstRoot(this);

// Inputs can have a null AST on a parse error.
if (n == null) {
continue;
if (hoistIfExtern(input)) {
staleInputs = true;
}
}

JSDocInfo info = n.getJSDocInfo();
if (info != null && info.isExterns()) {
// If the input file is explicitly marked as an externs file, then
// assume the programmer made a mistake and throw it into
// the externs pile anyways.
externsRoot.addChildToBack(n);
input.setIsExtern(true);

input.getModule().remove(input);
if (staleInputs) {
repartitionInputs();
}
}

externs.add(input);
/**
* Hoists inputs with the @externs annotation into the externs list.
*/
void hoistAllExterns() {
boolean staleInputs = false;
for (CompilerInput input : inputs) {
if (hoistIfExtern(input)) {
staleInputs = true;
}
}

if (staleInputs) {
repartitionInputs();
}
}

/**
* Hoists a compiler input to externs if it contains the @externs annotation.
* Return whether or not the given input was hoisted.
*/
private boolean hoistIfExtern(CompilerInput input) {
Node n = input.getAstRoot(this);

// Inputs can have a null AST on a parse error.
if (n == null) {
return false;
}

JSDocInfo info = n.getJSDocInfo();
if (info != null && info.isExterns()) {
// If the input file is explicitly marked as an externs file, then
// assume the programmer made a mistake and throw it into
// the externs pile anyways.
externsRoot.addChildToBack(n);
input.setIsExtern(true);

input.getModule().remove(input);

externs.add(input);
return true;
}
return false;
}

/**
* Hoists inputs with the @nocompile annotation out of the inputs.
*/
Expand Down
44 changes: 44 additions & 0 deletions test/com/google/javascript/jscomp/CompilerTest.java
Expand Up @@ -918,6 +918,50 @@ public void testInputSerialization() throws Exception {
assertTrue(ast.isEquivalentTo(newInput.getAstRoot(compiler)));
}

public void testExternsDependencySorting() {
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode("leaf", "/** @externs */ goog.require('beer');"),
SourceFile.fromCode("beer", "/** @externs */ goog.provide('beer');\ngoog.require('hops');"),
SourceFile.fromCode("hops", "/** @externs */ goog.provide('hops');"));

CompilerOptions options = createNewFlagBasedOptions();
options.setIncrementalChecks(CompilerOptions.IncrementalCheckMode.CHECK_IJS);
options.dependencyOptions.setDependencySorting(true);

List<SourceFile> externs = ImmutableList.of();
Compiler compiler = new Compiler();
compiler.compile(externs, inputs, options);

assertThat(compiler.externsRoot.getChildCount()).isEqualTo(3);
assertExternIndex(compiler, 0, "hops");
assertExternIndex(compiler, 1, "beer");
assertExternIndex(compiler, 2, "leaf");
}

public void testExternsDependencyPruning() {
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode("unused", "/** @externs */ goog.provide('unused');"),
SourceFile.fromCode("moocher", "/** @externs */ goog.require('something');"),
SourceFile.fromCode("something", "/** @externs */ goog.provide('something');"));

CompilerOptions options = createNewFlagBasedOptions();
options.dependencyOptions.setDependencyPruning(true);
options.setIncrementalChecks(CompilerOptions.IncrementalCheckMode.CHECK_IJS);

List<SourceFile> externs = ImmutableList.of();
Compiler compiler = new Compiler();
compiler.compile(externs, inputs, options);

assertThat(compiler.externsRoot.getChildCount()).isEqualTo(2);
assertExternIndex(compiler, 0, "something");
assertExternIndex(compiler, 1, "moocher");
}

private void assertExternIndex(Compiler compiler, int index, String name) {
assertThat(compiler.externsRoot.getChildAtIndex(index))
.isSameAs(compiler.getInput(new InputId(name)).getAstRoot(compiler));
}

public void testEs6ModuleEntryPoint() throws Exception {
List<SourceFile> inputs = ImmutableList.of(
SourceFile.fromCode(
Expand Down

0 comments on commit 670321a

Please sign in to comment.