Skip to content

Commit

Permalink
Runtime typechecking: Throw an exception if the log function the user…
Browse files Browse the repository at this point in the history
… passed is not a valid qualified name.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=174371775
  • Loading branch information
tbreisacher authored and brad4d committed Nov 3, 2017
1 parent aa022d2 commit 45d7209
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 14 deletions.
35 changes: 23 additions & 12 deletions src/com/google/javascript/jscomp/RuntimeTypeCheck.java
Expand Up @@ -16,6 +16,9 @@


package com.google.javascript.jscomp; package com.google.javascript.jscomp;


import static com.google.common.base.Preconditions.checkState;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.javascript.rhino.IR; import com.google.javascript.rhino.IR;
Expand Down Expand Up @@ -371,19 +374,27 @@ private Node createCheckerNode(JSType type) {


private void addBoilerplateCode() { private void addBoilerplateCode() {
Node newNode = compiler.ensureLibraryInjected("runtime_type_check", false); Node newNode = compiler.ensureLibraryInjected("runtime_type_check", false);
if (newNode != null && logFunction != null) { if (newNode != null) {
// Inject the custom log function. injectCustomLogFunction(newNode);
Node logOverride = IR.exprResult( }
IR.assign( }
NodeUtil.newQName(
compiler, @VisibleForTesting
"$jscomp.typecheck.log"), void injectCustomLogFunction(Node node) {
NodeUtil.newQName( if (logFunction == null) {
compiler, return;
logFunction)));
newNode.getParent().addChildAfter(logOverride, newNode);
compiler.reportChangeToEnclosingScope(newNode);
} }
checkState(
NodeUtil.isValidQualifiedName(compiler.getFeatureSet(), logFunction),
"%s is not a valid qualified name", logFunction);
Node logOverride =
IR.exprResult(
IR.assign(
NodeUtil.newQName(compiler, "$jscomp.typecheck.log"),
NodeUtil.newQName(compiler, logFunction)));
checkState(node.getParent().isScript(), node.getParent());
node.getParent().addChildAfter(logOverride, node);
compiler.reportChangeToEnclosingScope(node);
} }


private Node jsCode(String prop) { private Node jsCode(String prop) {
Expand Down
43 changes: 41 additions & 2 deletions test/com/google/javascript/jscomp/RuntimeTypeCheckTest.java
Expand Up @@ -18,11 +18,16 @@


import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;


import com.google.javascript.rhino.IR;
import com.google.javascript.rhino.Node;
import javax.annotation.Nullable;

/** /**
* Tests for {@link RuntimeTypeCheck}. * Tests for {@link RuntimeTypeCheck}.
* *
*/ */
public final class RuntimeTypeCheckTest extends CompilerTestCase { public final class RuntimeTypeCheckTest extends CompilerTestCase {
@Nullable private String logFunction = null;


public RuntimeTypeCheckTest() { public RuntimeTypeCheckTest() {
super("/** @const */ var undefined;"); super("/** @const */ var undefined;");
Expand Down Expand Up @@ -313,6 +318,40 @@ public void testFunctionType() {
testChecksSame("/** @type {!Function} */function f() {}"); testChecksSame("/** @type {!Function} */function f() {}");
} }


public void testInjectLogFunction_name() {
logFunction = "myLogFn";
Compiler compiler = createCompiler();
compiler.initOptions(getOptions());
Node testNode = IR.exprResult(IR.nullNode());
IR.script(testNode);
getProcessor(compiler).injectCustomLogFunction(testNode);
assertThat(compiler.toSource(testNode.getParent())).contains("$jscomp.typecheck.log=myLogFn");
}

public void testInjectLogFunction_qualifiedName() {
logFunction = "my.log.fn";
Compiler compiler = createCompiler();
compiler.initOptions(getOptions());
Node testNode = IR.exprResult(IR.nullNode());
IR.script(testNode);
getProcessor(compiler).injectCustomLogFunction(testNode);
assertThat(compiler.toSource(testNode.getParent())).contains("$jscomp.typecheck.log=my.log.fn");
}

public void testInvalidLogFunction() {
logFunction = "{}"; // Not a valid qualified name
Compiler compiler = createCompiler();
compiler.initOptions(getOptions());
Node testNode = IR.exprResult(IR.nullNode());
IR.script(testNode);
try {
getProcessor(compiler).injectCustomLogFunction(testNode);
fail("Expected an IllegalStateException");
} catch (IllegalStateException e) {
assertThat(e).hasMessageThat().contains("not a valid qualified name");
}
}

private void testChecks(String js, String expected) { private void testChecks(String js, String expected) {
test(js, expected); test(js, expected);
assertThat(getLastCompiler().injected).containsExactly("runtime_type_check"); assertThat(getLastCompiler().injected).containsExactly("runtime_type_check");
Expand All @@ -334,8 +373,8 @@ protected NoninjectingCompiler getLastCompiler() {
} }


@Override @Override
protected CompilerPass getProcessor(final Compiler compiler) { protected RuntimeTypeCheck getProcessor(final Compiler compiler) {
return new RuntimeTypeCheck(compiler, null); return new RuntimeTypeCheck(compiler, logFunction);
} }


@Override @Override
Expand Down

0 comments on commit 45d7209

Please sign in to comment.