This repository has been archived on 2023-06-18. You can view files and clone it, but cannot push or open issues or pull requests.
ima02/resources/defects4j-checkout-closure-1f/test/com/google/javascript/jscomp/CheckAccessControlsTest.java

839 lines
29 KiB
Java
Raw Permalink Normal View History

2023-04-25 11:33:41 +00:00
/*
* Copyright 2008 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import static com.google.javascript.jscomp.CheckAccessControls.BAD_PRIVATE_GLOBAL_ACCESS;
import static com.google.javascript.jscomp.CheckAccessControls.BAD_PRIVATE_PROPERTY_ACCESS;
import static com.google.javascript.jscomp.CheckAccessControls.BAD_PROTECTED_PROPERTY_ACCESS;
import static com.google.javascript.jscomp.CheckAccessControls.CONST_PROPERTY_DELETED;
import static com.google.javascript.jscomp.CheckAccessControls.CONST_PROPERTY_REASSIGNED_VALUE;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_CLASS;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_CLASS_REASON;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_NAME;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_NAME_REASON;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_PROP;
import static com.google.javascript.jscomp.CheckAccessControls.DEPRECATED_PROP_REASON;
import static com.google.javascript.jscomp.CheckAccessControls.EXTEND_FINAL_CLASS;
import static com.google.javascript.jscomp.CheckAccessControls.PRIVATE_OVERRIDE;
import static com.google.javascript.jscomp.CheckAccessControls.VISIBILITY_MISMATCH;
/**
* Tests for {@link CheckAccessControls}.
*
* @author nicksantos@google.com (Nick Santos)
*/
public class CheckAccessControlsTest extends CompilerTestCase {
public CheckAccessControlsTest() {
super(CompilerTypeTestCase.DEFAULT_EXTERNS);
parseTypeInfo = true;
enableTypeCheck(CheckLevel.WARNING);
}
@Override
protected CompilerPass getProcessor(final Compiler compiler) {
return new CheckAccessControls(compiler);
}
@Override
protected CompilerOptions getOptions() {
CompilerOptions options = super.getOptions();
options.setWarningLevel(DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.ERROR);
options.setWarningLevel(DiagnosticGroups.CONSTANT_PROPERTY,
CheckLevel.ERROR);
return options;
}
/**
* Tests that the given JavaScript code has a @deprecated marker
* somewhere in it which raises an error. Also tests that the
* deprecated marker works with a message. The JavaScript should
* have a JsDoc of the form "@deprecated %s\n".
*
* @param js The JavaScript code to parse and test.
* @param reason A simple deprecation reason string, used for testing
* the addition of a deprecation reason to the @deprecated tag.
* @param error The deprecation error expected when no reason is given.
* @param errorWithMessage The deprecation error expected when a reason
* message is given.
*/
private void testDep(String js, String reason,
DiagnosticType error,
DiagnosticType errorWithMessage) {
// Test without a reason.
test(String.format(js, ""), null, error);
// Test with a reason.
test(String.format(js, reason), null, errorWithMessage, null, reason);
}
public void testDeprecatedFunction() {
testDep("/** @deprecated %s */ function f() {} function g() { f(); }",
"Some Reason",
DEPRECATED_NAME, DEPRECATED_NAME_REASON);
}
public void testWarningOnDeprecatedConstVariable() {
testDep("/** @deprecated %s */ var f = 4; function g() { alert(f); }",
"Another reason",
DEPRECATED_NAME, DEPRECATED_NAME_REASON);
}
public void testThatNumbersArentDeprecated() {
testSame("/** @deprecated */ var f = 4; var h = 3; " +
"function g() { alert(h); }");
}
public void testDeprecatedFunctionVariable() {
testDep("/** @deprecated %s */ var f = function() {}; " +
"function g() { f(); }", "I like g...",
DEPRECATED_NAME, DEPRECATED_NAME_REASON);
}
public void testNoWarningInGlobalScope() {
testSame("var goog = {}; goog.makeSingleton = function(x) {};" +
"/** @deprecated */ function f() {} goog.makeSingleton(f);");
}
public void testNoWarningInGlobalScopeForCall() {
testDep("/** @deprecated %s */ function f() {} f();",
"Some global scope", DEPRECATED_NAME, DEPRECATED_NAME_REASON);
}
public void testNoWarningInDeprecatedFunction() {
testSame("/** @deprecated */ function f() {} " +
"/** @deprecated */ function g() { f(); }");
}
public void testWarningInNormalClass() {
testDep("/** @deprecated %s */ function f() {}" +
"/** @constructor */ var Foo = function() {}; " +
"Foo.prototype.bar = function() { f(); }",
"FooBar", DEPRECATED_NAME, DEPRECATED_NAME_REASON);
}
public void testWarningForProperty1() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.bar = 3;" +
"Foo.prototype.baz = function() { alert((new Foo()).bar); };",
"A property is bad",
DEPRECATED_PROP, DEPRECATED_PROP_REASON);
}
public void testWarningForProperty2() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.bar = 3;" +
"Foo.prototype.baz = function() { alert(this.bar); };",
"Zee prop, it is deprecated!",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForDeprecatedClass() {
testDep("/** @constructor \n* @deprecated %s */ function Foo() {} " +
"function f() { new Foo(); }",
"Use the class 'Bar'",
DEPRECATED_CLASS,
DEPRECATED_CLASS_REASON);
}
public void testNoWarningForDeprecatedClassInstance() {
testSame("/** @constructor \n * @deprecated */ function Foo() {} " +
"/** @param {Foo} x */ function f(x) { return x; }");
}
public void testWarningForDeprecatedSuperClass() {
testDep("/** @constructor \n * @deprecated %s */ function Foo() {} " +
"/** @constructor \n * @extends {Foo} */ function SubFoo() {}" +
"function f() { new SubFoo(); }",
"Superclass to the rescue!",
DEPRECATED_CLASS,
DEPRECATED_CLASS_REASON);
}
public void testWarningForDeprecatedSuperClass2() {
testDep("/** @constructor \n * @deprecated %s */ function Foo() {} " +
"var namespace = {}; " +
"/** @constructor \n * @extends {Foo} */ " +
"namespace.SubFoo = function() {}; " +
"function f() { new namespace.SubFoo(); }",
"Its only weakness is Kryptoclass",
DEPRECATED_CLASS,
DEPRECATED_CLASS_REASON);
}
public void testWarningForPrototypeProperty() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.bar = 3;" +
"Foo.prototype.baz = function() { alert(Foo.prototype.bar); };",
"It is now in production, use that model...",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testNoWarningForNumbers() {
testSame("/** @constructor */ function Foo() {}" +
"/** @deprecated */ Foo.prototype.bar = 3;" +
"Foo.prototype.baz = function() { alert(3); };");
}
public void testWarningForMethod1() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.bar = function() {};" +
"Foo.prototype.baz = function() { this.bar(); };",
"There is a madness to this method",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForMethod2() {
testDep("/** @constructor */ function Foo() {} " +
"/** @deprecated %s */ Foo.prototype.bar; " +
"Foo.prototype.baz = function() { this.bar(); };",
"Stop the ringing!",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testNoWarningInDeprecatedClass() {
testSame("/** @deprecated */ function f() {} " +
"/** @constructor \n * @deprecated */ " +
"var Foo = function() {}; " +
"Foo.prototype.bar = function() { f(); }");
}
public void testNoWarningInDeprecatedClass2() {
testSame("/** @deprecated */ function f() {} " +
"/** @constructor \n * @deprecated */ " +
"var Foo = function() {}; " +
"Foo.bar = function() { f(); }");
}
public void testNoWarningInDeprecatedStaticMethod() {
testSame("/** @deprecated */ function f() {} " +
"/** @constructor */ " +
"var Foo = function() {}; " +
"/** @deprecated */ Foo.bar = function() { f(); }");
}
public void testWarningInStaticMethod() {
testDep("/** @deprecated %s */ function f() {} " +
"/** @constructor */ " +
"var Foo = function() {}; " +
"Foo.bar = function() { f(); }",
"crazy!",
DEPRECATED_NAME,
DEPRECATED_NAME_REASON);
}
public void testDeprecatedObjLitKey() {
testDep("var f = {}; /** @deprecated %s */ f.foo = 3; " +
"function g() { return f.foo; }",
"It is literally not used anymore",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForSubclassMethod() {
testDep("/** @constructor */ function Foo() {}" +
"Foo.prototype.bar = function() {};" +
"/** @constructor \n * @extends {Foo} */ function SubFoo() {}" +
"/** @deprecated %s */ SubFoo.prototype.bar = function() {};" +
"function f() { (new SubFoo()).bar(); };",
"I have a parent class!",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForSuperClassWithDeprecatedSubclassMethod() {
testSame("/** @constructor */ function Foo() {}" +
"Foo.prototype.bar = function() {};" +
"/** @constructor \n * @extends {Foo} */ function SubFoo() {}" +
"/** @deprecated \n * @override */ SubFoo.prototype.bar = " +
"function() {};" +
"function f() { (new Foo()).bar(); };");
}
public void testWarningForSuperclassMethod() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.bar = function() {};" +
"/** @constructor \n * @extends {Foo} */ function SubFoo() {}" +
"SubFoo.prototype.bar = function() {};" +
"function f() { (new SubFoo()).bar(); };",
"I have a child class!",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForSuperclassMethod2() {
testDep("/** @constructor */ function Foo() {}" +
"/** @deprecated %s \n* @protected */" +
"Foo.prototype.bar = function() {};" +
"/** @constructor \n * @extends {Foo} */ function SubFoo() {}" +
"/** @protected */SubFoo.prototype.bar = function() {};" +
"function f() { (new SubFoo()).bar(); };",
"I have another child class...",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForBind() {
testDep("/** @deprecated %s */ Function.prototype.bind = function() {};" +
"(function() {}).bind();",
"I'm bound to this method...",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testWarningForDeprecatedClassInGlobalScope() {
testDep("/** @constructor \n * @deprecated %s */ var Foo = function() {};" +
"new Foo();",
"I'm a very worldly object!",
DEPRECATED_CLASS,
DEPRECATED_CLASS_REASON);
}
public void testNoWarningForPrototypeCopying() {
testSame("/** @constructor */ var Foo = function() {};" +
"Foo.prototype.bar = function() {};" +
"/** @deprecated */ Foo.prototype.baz = Foo.prototype.bar;" +
"(new Foo()).bar();");
}
public void testNoWarningOnDeprecatedPrototype() {
// This used to cause an NPE.
testSame("/** @constructor */ var Foo = function() {};" +
"/** @deprecated */ Foo.prototype = {};" +
"Foo.prototype.bar = function() {};");
}
public void testPrivateAccessForNames() {
testSame("/** @private */ function foo_() {}; foo_();");
test(new String[] {
"/** @private */ function foo_() {};",
"foo_();"
}, null, BAD_PRIVATE_GLOBAL_ACCESS);
}
public void testPrivateAccessForProperties1() {
testSame("/** @constructor */ function Foo() {}" +
"/** @private */ Foo.prototype.bar_ = function() {};" +
"Foo.prototype.baz = function() { this.bar_(); }; (new Foo).bar_();");
}
public void testPrivateAccessForProperties2() {
testSame(new String[] {
"/** @constructor */ function Foo() {}",
"/** @private */ Foo.prototype.bar_ = function() {};" +
"Foo.prototype.baz = function() { this.bar_(); }; (new Foo).bar_();"
});
}
public void testPrivateAccessForProperties3() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @private */ Foo.prototype.bar_ = function() {}; (new Foo).bar_();",
"Foo.prototype.baz = function() { this.bar_(); };"
});
}
public void testPrivateAccessForProperties4() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @private */ Foo.prototype.bar_ = function() {};",
"Foo.prototype['baz'] = function() { (new Foo()).bar_(); };"
});
}
public void testNoPrivateAccessForProperties1() {
test(new String[] {
"/** @constructor */ function Foo() {} (new Foo).bar_();",
"/** @private */ Foo.prototype.bar_ = function() {};" +
"Foo.prototype.baz = function() { this.bar_(); };"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties2() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};" +
"Foo.prototype.baz = function() { this.bar_(); };",
"(new Foo).bar_();"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties3() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};",
"/** @constructor */ function OtherFoo() { (new Foo).bar_(); }"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties4() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() { this.bar_(); }"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties5() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {};" +
"SubFoo.prototype.baz = function() { this.bar_(); }"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties6() {
// Overriding a private property with a non-private property
// in a different file causes problems.
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {};" +
"SubFoo.prototype.bar_ = function() {};"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties7() {
// It's OK to override a private property with a non-private property
// in the same file, but you'll get yelled at when you try to use it.
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @private */ Foo.prototype.bar_ = function() {};" +
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {};" +
"SubFoo.prototype.bar_ = function() {};",
"SubFoo.prototype.baz = function() { this.bar_(); }"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testNoPrivateAccessForProperties8() {
test(new String[] {
"/** @constructor */ function Foo() { /** @private */ this.bar_ = 3; }",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() { /** @private */ this.bar_ = 3; };"
}, null, PRIVATE_OVERRIDE);
}
public void testProtectedAccessForProperties1() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @protected */ Foo.prototype.bar = function() {};" +
"(new Foo).bar();",
"Foo.prototype.baz = function() { this.bar(); };"
});
}
public void testProtectedAccessForProperties2() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @protected */ Foo.prototype.bar = function() {};" +
"(new Foo).bar();",
"/** @constructor \n * @extends {Foo} */" +
"function SubFoo() { this.bar(); }"
});
}
public void testProtectedAccessForProperties3() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @protected */ Foo.prototype.bar = function() {};" +
"(new Foo).bar();",
"/** @constructor \n * @extends {Foo} */" +
"function SubFoo() { }" +
"SubFoo.baz = function() { (new Foo).bar(); }"
});
}
public void testProtectedAccessForProperties4() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @protected */ Foo.bar = function() {};",
"/** @constructor \n * @extends {Foo} */" +
"function SubFoo() { Foo.bar(); }"
});
}
public void testProtectedAccessForProperties5() {
testSame(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @protected */ Foo.prototype.bar = function() {};" +
"(new Foo).bar();",
"/** @constructor \n * @extends {Foo} */" +
"var SubFoo = function() { this.bar(); }"
});
}
public void testProtectedAccessForProperties6() {
testSame(new String[] {
"var goog = {};" +
"/** @constructor */ goog.Foo = function() {};" +
"/** @protected */ goog.Foo.prototype.bar = function() {};",
"/** @constructor \n * @extends {goog.Foo} */" +
"goog.SubFoo = function() { this.bar(); };"
});
}
public void testNoProtectedAccessForProperties1() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @protected */ Foo.prototype.bar = function() {};",
"(new Foo).bar();"
}, null, BAD_PROTECTED_PROPERTY_ACCESS);
}
public void testNoProtectedAccessForProperties2() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @protected */ Foo.prototype.bar = function() {};",
"/** @constructor */ function OtherFoo() { (new Foo).bar(); }"
}, null, BAD_PROTECTED_PROPERTY_ACCESS);
}
public void testNoProtectedAccessForProperties3() {
test(new String[] {
"/** @constructor */ function Foo() {} " +
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @protected */ SubFoo.prototype.bar = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubberFoo() { (new SubFoo).bar(); }"
}, null, BAD_PROTECTED_PROPERTY_ACCESS);
}
public void testNoProtectedAccessForProperties4() {
test(new String[] {
"/** @constructor */ function Foo() { (new SubFoo).bar(); } ",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @protected */ SubFoo.prototype.bar = function() {};",
}, null, BAD_PROTECTED_PROPERTY_ACCESS);
}
public void testNoProtectedAccessForProperties5() {
test(new String[] {
"var goog = {};" +
"/** @constructor */ goog.Foo = function() {};" +
"/** @protected */ goog.Foo.prototype.bar = function() {};",
"/** @constructor */" +
"goog.NotASubFoo = function() { (new goog.Foo).bar(); };"
}, null, BAD_PROTECTED_PROPERTY_ACCESS);
}
public void testNoExceptionsWithBadConstructors1() {
testSame(new String[] {
"function Foo() { (new SubFoo).bar(); } " +
"/** @constructor */ function SubFoo() {}" +
"/** @protected */ SubFoo.prototype.bar = function() {};"
});
}
public void testNoExceptionsWithBadConstructors2() {
testSame(new String[] {
"/** @constructor */ function Foo() {} " +
"Foo.prototype.bar = function() {};" +
"/** @constructor */" +
"function SubFoo() {}" +
"/** @protected */ " +
"SubFoo.prototype.bar = function() { (new Foo).bar(); };"
});
}
public void testGoodOverrideOfProtectedProperty() {
testSame(new String[] {
"/** @constructor */ function Foo() { } " +
"/** @protected */ Foo.prototype.bar = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @inheritDoc */ SubFoo.prototype.bar = function() {};",
});
}
public void testBadOverrideOfProtectedProperty() {
test(new String[] {
"/** @constructor */ function Foo() { } " +
"/** @protected */ Foo.prototype.bar = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @private */ SubFoo.prototype.bar = function() {};",
}, null, VISIBILITY_MISMATCH);
}
public void testBadOverrideOfPrivateProperty() {
test(new String[] {
"/** @constructor */ function Foo() { } " +
"/** @private */ Foo.prototype.bar = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @protected */ SubFoo.prototype.bar = function() {};",
}, null, PRIVATE_OVERRIDE);
testSame(new String[] {
"/** @constructor */ function Foo() { } " +
"/** @private */ Foo.prototype.bar = function() {};",
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {}" +
"/** @override \n *@suppress{visibility} */\n" +
" SubFoo.prototype.bar = function() {};",
});
}
public void testAccessOfStaticMethodOnPrivateConstructor() {
testSame(new String[] {
"/** @constructor \n * @private */ function Foo() { } " +
"Foo.create = function() { return new Foo(); };",
"Foo.create()",
});
}
public void testAccessOfStaticMethodOnPrivateQualifiedConstructor() {
testSame(new String[] {
"var goog = {};" +
"/** @constructor \n * @private */ goog.Foo = function() { }; " +
"goog.Foo.create = function() { return new goog.Foo(); };",
"goog.Foo.create()",
});
}
public void testInstanceofOfPrivateConstructor() {
testSame(new String[] {
"var goog = {};" +
"/** @constructor \n * @private */ goog.Foo = function() { }; " +
"goog.Foo.create = function() { return new goog.Foo(); };",
"goog instanceof goog.Foo",
});
}
public void testOkAssignmentOfDeprecatedProperty() {
testSame(
"/** @constructor */ function Foo() {" +
" /** @deprecated */ this.bar = 3;" +
"}");
}
public void testBadReadOfDeprecatedProperty() {
testDep(
"/** @constructor */ function Foo() {" +
" /** @deprecated %s */ this.bar = 3;" +
" this.baz = this.bar;" +
"}",
"GRR",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testAutoboxedDeprecatedProperty() {
test(
"", // no externs
"/** @constructor */ function String() {}" +
"/** @deprecated %s */ String.prototype.length;" +
"function f() { return 'x'.length; }",
"GRR",
DEPRECATED_PROP_REASON,
null);
}
public void testAutoboxedPrivateProperty() {
test(
"/** @constructor */ function String() {}" +
"/** @private */ String.prototype.length;", // externs
"function f() { return 'x'.length; }",
"", // output
BAD_PRIVATE_PROPERTY_ACCESS,
null);
}
public void testNullableDeprecatedProperty() {
testDep(
"/** @constructor */ function Foo() {}" +
"/** @deprecated %s */ Foo.prototype.length;" +
"/** @param {?Foo} x */ function f(x) { return x.length; }",
"GRR",
DEPRECATED_PROP,
DEPRECATED_PROP_REASON);
}
public void testNullablePrivateProperty() {
test(new String[] {
"/** @constructor */ function Foo() {}" +
"/** @private */ Foo.prototype.length;",
"/** @param {?Foo} x */ function f(x) { return x.length; }"
}, null, BAD_PRIVATE_PROPERTY_ACCESS);
}
public void testConstantProperty1() {
test("/** @constructor */ function A() {" +
"/** @const */ this.bar = 3;}" +
"/** @constructor */ function B() {" +
"/** @const */ this.bar = 3;this.bar += 4;}",
null, CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty2() {
test("/** @constructor */ function Foo() {}" +
"/** @const */ Foo.prototype.prop = 2;" +
"var foo = new Foo();" +
"foo.prop = 3;",
null , CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty3() {
testSame("var o = { /** @const */ x: 1 };" +
"o.x = 2;");
}
public void testConstantProperty4() {
test("/** @constructor */ function cat(name) {}" +
"/** @const */ cat.test = 1;" +
"cat.test *= 2;",
null, CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty5() {
test("/** @constructor */ function Foo() { this.prop = 1;}" +
"/** @const */ Foo.prototype.prop;" +
"Foo.prototype.prop = 2",
null , CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty6() {
test("/** @constructor */ function Foo() { this.prop = 1;}" +
"/** @const */ Foo.prototype.prop = 2;",
null , CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty7() {
testSame("/** @constructor */ function Foo() {} " +
"Foo.prototype.bar_ = function() {};" +
"/** @constructor \n * @extends {Foo} */ " +
"function SubFoo() {};" +
"/** @const */ /** @override */ SubFoo.prototype.bar_ = function() {};" +
"SubFoo.prototype.baz = function() { this.bar_(); }");
}
public void testConstantProperty8() {
testSame("var o = { /** @const */ x: 1 };" +
"var y = o.x;");
}
public void testConstantProperty9() {
testSame("/** @constructor */ function A() {" +
"/** @const */ this.bar = 3;}" +
"/** @constructor */ function B() {" +
"this.bar = 4;}");
}
public void testConstantProperty10() {
testSame("/** @constructor */ function Foo() { this.prop = 1;}" +
"/** @const */ Foo.prototype.prop;");
}
public void testConstantProperty11() {
test("/** @constructor */ function Foo() {}" +
"/** @const */ Foo.prototype.bar;" +
"/**\n" +
" * @constructor\n" +
" * @extends {Foo}\n" +
" */ function SubFoo() { this.bar = 5; this.bar = 6; }",
null , CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty12() {
testSame("/** @constructor */ function Foo() {}" +
"/** @const */ Foo.prototype.bar;" +
"/**\n" +
" * @constructor\n" +
" * @extends {Foo}\n" +
" */ function SubFoo() { this.bar = 5; }" +
"/**\n" +
" * @constructor\n" +
" * @extends {Foo}\n" +
" */ function SubFoo2() { this.bar = 5; }");
}
public void testConstantProperty13() {
test("/** @constructor */ function Foo() {}" +
"/** @const */ Foo.prototype.bar;" +
"/**\n" +
" * @constructor\n" +
" * @extends {Foo}\n" +
" */ function SubFoo() { this.bar = 5; }" +
"/**\n" +
" * @constructor\n" +
" * @extends {SubFoo}\n" +
" */ function SubSubFoo() { this.bar = 5; }",
null , CONST_PROPERTY_REASSIGNED_VALUE);
}
public void testConstantProperty14() {
test("/** @constructor */ function Foo() {" +
"/** @const */ this.bar = 3; delete this.bar; }",
null, CONST_PROPERTY_DELETED);
}
public void testSuppressConstantProperty() {
testSame("/** @constructor */ function A() {" +
"/** @const */ this.bar = 3;}" +
"/**\n" +
" * @suppress {constantProperty}\n" +
" * @constructor\n" +
" */ function B() {" +
"/** @const */ this.bar = 3;this.bar += 4;}");
}
public void testSuppressConstantProperty2() {
testSame("/** @constructor */ function A() {" +
"/** @const */ this.bar = 3;}" +
"/**\n" +
" * @suppress {const}\n" +
" * @constructor\n" +
" */ function B() {" +
"/** @const */ this.bar = 3;this.bar += 4;}");
}
public void testFinalClassCannotBeSubclassed() {
test(
"/**\n"
+ " * @constructor\n"
+ " * @const\n"
+ " */ Foo = function() {};\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {Foo}\n*"
+ " */ Bar = function() {};",
null, EXTEND_FINAL_CLASS);
test(
"/**\n"
+ " * @constructor\n"
+ " * @const\n"
+ " */ function Foo() {};\n"
+ "/**\n"
+ " * @constructor\n"
+ " * @extends {Foo}\n*"
+ " */ function Bar() {};",
null, EXTEND_FINAL_CLASS);
}
}