Skip to content

Commit

Permalink
Create a stricter version of the BanUnresolvedType conformance config.
Browse files Browse the repository at this point in the history
This version warns for any AST node that resolves to a forwardDeclared type
instead of only GETPROP nodes. When using OTI, allow using this stricter
conformance config as the way to avoid forward declared types instead of
dropping all forward declares.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=172761296
  • Loading branch information
blickly authored and lauraharker committed Oct 19, 2017
1 parent f59c589 commit 2baef98
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 11 deletions.
5 changes: 3 additions & 2 deletions src/com/google/javascript/jscomp/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -1527,9 +1527,10 @@ public JSTypeRegistry getTypeRegistry() {

@Override
void forwardDeclareType(String typeName) {
if (options.allowUnfulfilledForwardDeclarations()) {
forwardDeclaredTypes.add(typeName);
if (options.dropForwardDeclarations()) {
return;
}
forwardDeclaredTypes.add(typeName);
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions src/com/google/javascript/jscomp/CompilerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ public boolean allowIjsInputs() {
return incrementalCheckMode != IncrementalCheckMode.OFF;
}

public boolean allowUnfulfilledForwardDeclarations() {
return incrementalCheckMode == IncrementalCheckMode.OFF;
public boolean dropForwardDeclarations() {
return incrementalCheckMode == IncrementalCheckMode.CHECK_IJS && useNewTypeInference;
}

private Config.JsDocParsing parseJsDocDocumentation = Config.JsDocParsing.TYPES_ONLY;
Expand Down
19 changes: 18 additions & 1 deletion src/com/google/javascript/jscomp/ConformanceRules.java
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ protected ConformanceResult checkConformance(NodeTraversal t, Node n) {
return ConformanceResult.CONFORMANCE;
}

private boolean conforms(TypeI type) {
private static boolean conforms(TypeI type) {
if (type.isUnionType()) {
// unwrap union types which might contain unresolved type name
// references for example {Foo|undefined}
Expand All @@ -1381,6 +1381,23 @@ private boolean conforms(TypeI type) {
}
}

/** Ban any use of unresolved forward-declared types */
public static final class StrictBanUnresolvedType extends AbstractTypeRestrictionRule {
public StrictBanUnresolvedType(AbstractCompiler compiler, Requirement requirement)
throws InvalidRequirementSpec {
super(compiler, requirement);
}

@Override
protected ConformanceResult checkConformance(NodeTraversal t, Node n) {
TypeI type = n.getTypeI();
if (type != null && !BanUnresolvedType.conforms(type) && !isTypeImmediatelyTightened(n)) {
return ConformanceResult.VIOLATION;
}
return ConformanceResult.CONFORMANCE;
}
}


/**
* Banned global var declarations.
Expand Down
7 changes: 4 additions & 3 deletions src/com/google/javascript/jscomp/ConvertToTypedInterface.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ class ConvertToTypedInterface implements CompilerPass {

private static final ImmutableSet<String> CALLS_TO_PRESERVE =
ImmutableSet.of(
"goog.provide",
"goog.define",
"goog.require",
"goog.forwardDeclare",
"goog.module",
"goog.module.declareLegacyNamespace");
"goog.module.declareLegacyNamespace",
"goog.provide",
"goog.require");

private final AbstractCompiler compiler;

Expand Down
34 changes: 34 additions & 0 deletions test/com/google/javascript/jscomp/CheckConformanceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1530,6 +1530,40 @@ public void testCustomBanUnresolvedType() {
"}"));
}

public void testCustomStrictBanUnresolvedType() {
configuration =
"requirement: {\n"
+ " type: CUSTOM\n"
+ " java_class: 'com.google.javascript.jscomp.ConformanceRules$StrictBanUnresolvedType'\n"
+ " error_message: 'StrictBanUnresolvedType Message'\n"
+ "}";

// NTI doesn't model unresolved types separately from unknown, so this check always results
// in conformance.
// TODO(b/67899666): Implement similar functionality in NTI for preventing uses of forward
// declared types by implementing support for resolving forward declarations to a new
// "unusable type" instead of to unknown.
this.mode = TypeInferenceMode.OTI_ONLY;
testWarning(
"goog.forwardDeclare('Foo'); /** @param {Foo} a */ var f = function(a) {}",
CheckConformance.CONFORMANCE_VIOLATION,
"Violation: StrictBanUnresolvedType Message");

testWarning(
new String[] {
"goog.forwardDeclare('Foo'); /** @param {!Foo} a */ var f;",
"f(5);",
},
TypeValidator.TYPE_MISMATCH_WARNING);

testWarning(
new String[] {
"goog.forwardDeclare('Foo'); /** @return {!Foo} */ var f;",
"f();",
},
CheckConformance.CONFORMANCE_VIOLATION);
}

public void testMergeRequirements() {
Compiler compiler = createCompiler();
ConformanceConfig.Builder builder = ConformanceConfig.newBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -954,9 +954,8 @@ public void testDontRemoveGoogModuleContents() {
}

public void testDontPreserveUnknownTypeDeclarations() {
test(
"goog.forwardDeclare('MyType'); /** @type {MyType} */ var x;",
"/** @type {MyType} */ var x;");
testSame(
"goog.forwardDeclare('MyType'); /** @type {MyType} */ var x;");

test(
"goog.addDependency('zzz.js', ['MyType'], []); /** @type {MyType} */ var x;",
Expand Down

0 comments on commit 2baef98

Please sign in to comment.