mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 19:21:30 +00:00
Reject deprecated language features.
Or rather, provide the following options which do: --reject-deprecated-language-features Reject deprecated language features. Without this option, the compiler will accept language features that are no longer valid according to The Dart Programming Language Specification, version 0.12, M1. --report-sdk-use-of-deprecated-language-features Report use of deprecated features in Dart platform libraries. Without this option, the compiler will silently accept use of deprecated language features from these libraries. The option --reject-deprecated-language-features controls if these usages are reported as errors or warnings. Review URL: https://codereview.chromium.org//11416004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@15007 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
42b89c9f77
commit
f5c804380f
|
@ -35,9 +35,14 @@ class Compiler extends leg.Compiler {
|
|||
emitJavaScript: !hasOption(options, '--output-type=dart'),
|
||||
disallowUnsafeEval: hasOption(options, '--disallow-unsafe-eval'),
|
||||
analyzeAll: hasOption(options, '--analyze-all'),
|
||||
rejectDeprecatedFeatures:
|
||||
hasOption(options, '--reject-deprecated-language-features'),
|
||||
checkDeprecationInSdk:
|
||||
hasOption(options,
|
||||
'--report-sdk-use-of-deprecated-language-features'),
|
||||
strips: getStrips(options),
|
||||
enableConcreteTypeInference:
|
||||
hasOption(options, '--enable-concrete-type-inference')) {
|
||||
hasOption(options, '--enable-concrete-type-inference')) {
|
||||
if (!libraryRoot.path.endsWith("/")) {
|
||||
throw new ArgumentError("libraryRoot must end with a /");
|
||||
}
|
||||
|
|
|
@ -113,6 +113,8 @@ abstract class Compiler implements DiagnosticListener {
|
|||
final bool enableConcreteTypeInference;
|
||||
final bool analyzeAll;
|
||||
final bool enableNativeLiveTypeAnalysis;
|
||||
final bool rejectDeprecatedFeatures;
|
||||
final bool checkDeprecationInSdk;
|
||||
|
||||
bool disableInlining = false;
|
||||
|
||||
|
@ -225,6 +227,8 @@ abstract class Compiler implements DiagnosticListener {
|
|||
bool generateSourceMap: true,
|
||||
bool disallowUnsafeEval: false,
|
||||
this.analyzeAll: false,
|
||||
this.rejectDeprecatedFeatures: false,
|
||||
this.checkDeprecationInSdk: false,
|
||||
List<String> strips: const []})
|
||||
: libraries = new Map<String, LibraryElement>(),
|
||||
progress = new Stopwatch() {
|
||||
|
@ -341,12 +345,10 @@ abstract class Compiler implements DiagnosticListener {
|
|||
try {
|
||||
runCompiler(uri);
|
||||
} on CompilerCancelledException catch (exception) {
|
||||
log(exception.toString());
|
||||
log('compilation failed');
|
||||
log('Error: $exception');
|
||||
return false;
|
||||
}
|
||||
tracer.close();
|
||||
log('compilation succeeded');
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -399,12 +401,11 @@ abstract class Compiler implements DiagnosticListener {
|
|||
LibraryElement scanBuiltinLibrary(String filename);
|
||||
|
||||
void initializeSpecialClasses() {
|
||||
bool coreLibValid = true;
|
||||
final List missingClasses = [];
|
||||
ClassElement lookupSpecialClass(SourceString name) {
|
||||
ClassElement result = coreLibrary.find(name);
|
||||
if (result == null) {
|
||||
log('core library class $name missing');
|
||||
coreLibValid = false;
|
||||
missingClasses.add(name.slowToString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -424,8 +425,8 @@ abstract class Compiler implements DiagnosticListener {
|
|||
dynamicClass = lookupSpecialClass(const SourceString('Dynamic_'));
|
||||
nullClass = lookupSpecialClass(const SourceString('Null'));
|
||||
types = new Types(this, dynamicClass);
|
||||
if (!coreLibValid) {
|
||||
cancel('core library does not contain required classes');
|
||||
if (!missingClasses.isEmpty) {
|
||||
cancel('core library does not contain required classes: $missingClasses');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,6 +768,21 @@ abstract class Compiler implements DiagnosticListener {
|
|||
reportDiagnostic(span, "$message", kind);
|
||||
}
|
||||
|
||||
void onDeprecatedFeature(Spannable span, String feature) {
|
||||
if (currentElement == null)
|
||||
throw new SpannableAssertionFailure(span, feature);
|
||||
if (!checkDeprecationInSdk &&
|
||||
currentElement.getLibrary().isPlatformLibrary) {
|
||||
return;
|
||||
}
|
||||
var kind = rejectDeprecatedFeatures
|
||||
? api.Diagnostic.ERROR : api.Diagnostic.WARNING;
|
||||
var message = rejectDeprecatedFeatures
|
||||
? MessageKind.DEPRECATED_FEATURE_ERROR.error([feature])
|
||||
: MessageKind.DEPRECATED_FEATURE_WARNING.error([feature]);
|
||||
reportMessage(spanFromSpannable(span), message, kind);
|
||||
}
|
||||
|
||||
void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind);
|
||||
|
||||
SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
|
||||
|
|
|
@ -165,6 +165,10 @@ void compile(List<String> argv) {
|
|||
new OptionHandler('--disallow-unsafe-eval', passThrough),
|
||||
new OptionHandler('--analyze-all', passThrough),
|
||||
new OptionHandler('--enable-native-live-type-analysis', passThrough),
|
||||
new OptionHandler('--reject-deprecated-language-features', passThrough),
|
||||
new OptionHandler('--report-sdk-use-of-deprecated-language-features',
|
||||
passThrough),
|
||||
|
||||
// The following two options must come last.
|
||||
new OptionHandler('-.*', (String argument) {
|
||||
helpAndFail('Error: Unknown option "$argument".');
|
||||
|
@ -418,7 +422,22 @@ be removed in a future version:
|
|||
Disables dynamic generation of code in the generated output. This is
|
||||
necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).
|
||||
This flag is not continuously tested. Please report breakages and we
|
||||
will fix them as soon as possible.''');
|
||||
will fix them as soon as possible.
|
||||
|
||||
--reject-deprecated-language-features
|
||||
Reject deprecated language features. Without this option, the
|
||||
compiler will accept language features that are no longer valid
|
||||
according to The Dart Programming Language Specification, version
|
||||
0.12, M1.
|
||||
|
||||
--report-sdk-use-of-deprecated-language-features
|
||||
Report use of deprecated features in Dart platform libraries.
|
||||
Without this option, the compiler will silently accept use of
|
||||
deprecated language features from these libraries. The option
|
||||
--reject-deprecated-language-features controls if these usages are
|
||||
reported as errors or warnings.
|
||||
|
||||
'''.trim());
|
||||
}
|
||||
|
||||
void helpAndExit(bool verbose) {
|
||||
|
|
|
@ -19,4 +19,6 @@ abstract class DiagnosticListener {
|
|||
SourceSpan spanFromNode(Node node, [Uri uri]);
|
||||
|
||||
void reportMessage(SourceSpan span, Diagnostic message, api.Diagnostic kind);
|
||||
|
||||
void onDeprecatedFeature(Spannable span, String feature);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
library org_dartlang_js_helper;
|
||||
library _js_helper;
|
||||
|
||||
import 'dart:collection';
|
||||
|
||||
|
|
|
@ -192,13 +192,16 @@ class NativeEnqueuerBase implements NativeEnqueuer {
|
|||
}
|
||||
|
||||
bool isNativeMethod(Element element) {
|
||||
if (!element.getLibrary().canUseNative) return false;
|
||||
// Native method?
|
||||
Node node = element.parseNode(compiler);
|
||||
if (node is! FunctionExpression) return false;
|
||||
node = node.body;
|
||||
Token token = node.getBeginToken();
|
||||
if (token.stringValue == 'native') return true;
|
||||
return false;
|
||||
return compiler.withCurrentElement(element, () {
|
||||
Node node = element.parseNode(compiler);
|
||||
if (node is! FunctionExpression) return false;
|
||||
node = node.body;
|
||||
Token token = node.getBeginToken();
|
||||
if (identical(token.stringValue, 'native')) return true;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void registerFieldLoad(Element field) {
|
||||
|
|
|
@ -1048,12 +1048,14 @@ class TypeResolver {
|
|||
if (send != null) {
|
||||
typeName = send.selector;
|
||||
}
|
||||
if (identical(typeName.source.stringValue, 'void')) {
|
||||
String stringValue = typeName.source.stringValue;
|
||||
if (identical(stringValue, 'void')) {
|
||||
return compiler.types.voidType.element;
|
||||
} else if (
|
||||
// TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support.
|
||||
identical(typeName.source.stringValue, 'Dynamic')
|
||||
|| identical(typeName.source.stringValue, 'dynamic')) {
|
||||
} else if (identical(stringValue, 'Dynamic')) {
|
||||
// TODO(aprelev@gmail.com): Remove deprecated Dynamic keyword support.
|
||||
compiler.onDeprecatedFeature(typeName, 'Dynamic');
|
||||
return compiler.dynamicClass;
|
||||
} else if (identical(stringValue, 'dynamic')) {
|
||||
return compiler.dynamicClass;
|
||||
} else if (send != null) {
|
||||
Element e = scope.lookup(send.receiver.asIdentifier().source);
|
||||
|
@ -2926,13 +2928,17 @@ class SignatureResolver extends CommonResolverVisitor<Element> {
|
|||
}
|
||||
} else {
|
||||
if (element.isGetter()) {
|
||||
if (!element.getLibrary().isPlatformLibrary) {
|
||||
// TODO(ahe): Remove the isPlatformLibrary check.
|
||||
if (!identical(formalParameters.getEndToken().next.stringValue, 'native')) {
|
||||
// TODO(ahe): Remove the check for native keyword.
|
||||
if (!identical(formalParameters.getEndToken().next.stringValue,
|
||||
// TODO(ahe): Remove the check for native keyword.
|
||||
'native')) {
|
||||
if (compiler.rejectDeprecatedFeatures &&
|
||||
// TODO(ahe): Remove isPlatformLibrary check.
|
||||
!element.getLibrary().isPlatformLibrary) {
|
||||
compiler.reportMessage(compiler.spanFromNode(formalParameters),
|
||||
MessageKind.EXTRA_FORMALS.error([]),
|
||||
Diagnostic.WARNING);
|
||||
Diagnostic.ERROR);
|
||||
} else {
|
||||
compiler.onDeprecatedFeature(formalParameters, 'getter parameters');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -605,6 +605,8 @@ class ParserError {
|
|||
toString() => reason;
|
||||
}
|
||||
|
||||
typedef int IdGenerator();
|
||||
|
||||
/**
|
||||
* A parser event listener designed to work with [PartialParser]. It
|
||||
* builds elements representing the top-level declarations found in
|
||||
|
@ -612,7 +614,7 @@ class ParserError {
|
|||
* [compilationUnitElement].
|
||||
*/
|
||||
class ElementListener extends Listener {
|
||||
Function idGenerator;
|
||||
final IdGenerator idGenerator;
|
||||
final DiagnosticListener listener;
|
||||
final CompilationUnitElement compilationUnitElement;
|
||||
final StringValidator stringValidator;
|
||||
|
@ -623,10 +625,9 @@ class ElementListener extends Listener {
|
|||
Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
|
||||
|
||||
ElementListener(DiagnosticListener listener,
|
||||
CompilationUnitElement this.compilationUnitElement,
|
||||
int idGenerator())
|
||||
this.compilationUnitElement,
|
||||
this.idGenerator)
|
||||
: this.listener = listener,
|
||||
this.idGenerator = idGenerator,
|
||||
stringValidator = new StringValidator(listener),
|
||||
interpolationScope = const Link<StringQuoting>();
|
||||
|
||||
|
@ -791,6 +792,7 @@ class ElementListener extends Listener {
|
|||
pushElement(new PartialClassElement(
|
||||
name.source, interfaceKeyword, endToken, compilationUnitElement, id));
|
||||
rejectBuiltInIdentifier(name);
|
||||
listener.onDeprecatedFeature(interfaceKeyword, 'interface declarations');
|
||||
}
|
||||
|
||||
void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
|
||||
|
@ -1005,8 +1007,9 @@ class ElementListener extends Listener {
|
|||
metadata = metadata.prepend(annotation);
|
||||
}
|
||||
|
||||
// TODO(ahe): Remove this method.
|
||||
void addScriptTag(ScriptTag tag) {
|
||||
// TODO(ahe): Remove this method.
|
||||
listener.onDeprecatedFeature(tag, '# tags');
|
||||
addLibraryTag(tag.toLibraryTag());
|
||||
}
|
||||
|
||||
|
@ -1338,6 +1341,9 @@ class NodeListener extends ElementListener {
|
|||
NodeList arguments = new NodeList.singleton(argument);
|
||||
pushNode(new Send(receiver, new Operator(token), arguments));
|
||||
}
|
||||
if (identical(tokenString, '===') || identical(tokenString, '!==')) {
|
||||
listener.onDeprecatedFeature(token, tokenString);
|
||||
}
|
||||
}
|
||||
|
||||
void beginCascade(Token token) {
|
||||
|
|
|
@ -21,7 +21,7 @@ class SpannableAssertionFailure {
|
|||
final String message;
|
||||
SpannableAssertionFailure(this.node, this.message);
|
||||
|
||||
String toString() => 'compiler crashed.';
|
||||
String toString() => 'Compiler crashed: $message.';
|
||||
}
|
||||
|
||||
/// Writes the characters of [iterator] on [buffer]. The characters
|
||||
|
|
|
@ -243,9 +243,20 @@ class MessageKind {
|
|||
static const MISSING_FORMALS = const MessageKind(
|
||||
"Error: Formal parameters are missing.");
|
||||
|
||||
// TODO(ahe): Change the message below when it becomes an error.
|
||||
static const EXTRA_FORMALS = const MessageKind(
|
||||
"Warning: Formal parameters will not be allowed here in M1.");
|
||||
"Error: Formal parameters are not allowed here.");
|
||||
|
||||
// TODO(ahe): This message is hard to localize. This is acceptable,
|
||||
// as it will be removed when we ship Dart version 1.0.
|
||||
static const DEPRECATED_FEATURE_WARNING = const MessageKind(
|
||||
"Warning: deprecated language feature, #{1}, "
|
||||
"will be removed in a future Dart milestone.");
|
||||
|
||||
// TODO(ahe): This message is hard to localize. This is acceptable,
|
||||
// as it will be removed when we ship Dart version 1.0.
|
||||
static const DEPRECATED_FEATURE_ERROR = const MessageKind(
|
||||
"Error: #{1} are not legal "
|
||||
"due to option --reject-deprecated-language-features.");
|
||||
|
||||
static const CONSTRUCTOR_WITH_RETURN_TYPE = const MessageKind(
|
||||
"Error: cannot have return type for constructor.");
|
||||
|
|
|
@ -21,11 +21,13 @@ import "mock_compiler.dart";
|
|||
import "parser_helper.dart";
|
||||
|
||||
String compile(String code, {String entry: 'main',
|
||||
String coreSource: DEFAULT_CORELIB,
|
||||
bool enableTypeAssertions: false,
|
||||
bool minify: false,
|
||||
bool analyzeAll: false}) {
|
||||
MockCompiler compiler =
|
||||
new MockCompiler(enableTypeAssertions: enableTypeAssertions,
|
||||
coreSource: coreSource,
|
||||
enableMinification: minify);
|
||||
compiler.parseScript(code);
|
||||
lego.Element element = compiler.mainApp.find(buildSourceString(entry));
|
||||
|
|
|
@ -66,8 +66,7 @@ const String DEFAULT_CORELIB = r'''
|
|||
class Object {}
|
||||
class Type {}
|
||||
class Function {}
|
||||
interface List default ListImplementation { List([length]);}
|
||||
class ListImplementation { factory List([length]) => null; }
|
||||
class List {}
|
||||
abstract class Map {}
|
||||
class Closure {}
|
||||
class Null {}
|
||||
|
|
|
@ -604,8 +604,8 @@ testClassHierarchy() {
|
|||
compiler.errors[0].message.kind);
|
||||
|
||||
compiler = new MockCompiler();
|
||||
compiler.parseScript("""interface A extends B {}
|
||||
interface B extends A {}
|
||||
compiler.parseScript("""abstract class A extends B {}
|
||||
abstract class B extends A {}
|
||||
class C implements A {}
|
||||
main() { return new C(); }""");
|
||||
mainElement = compiler.mainApp.find(MAIN);
|
||||
|
|
|
@ -124,7 +124,7 @@ testOperators() {
|
|||
analyze("{ bool b = (1 ${op} false); }", MessageKind.NOT_ASSIGNABLE);
|
||||
analyze("{ bool b = (true ${op} 2); }", MessageKind.NOT_ASSIGNABLE);
|
||||
}
|
||||
for (final op in ['>', '<', '<=', '>=', '==', '!=', '===', '!==']) {
|
||||
for (final op in ['>', '<', '<=', '>=', '==', '!=']) {
|
||||
analyze("{ bool b = 1 ${op} 2; }");
|
||||
analyze("{ int i = 1 ${op} 2; }", MessageKind.NOT_ASSIGNABLE);
|
||||
analyze("{ int i; bool b = (i = true) ${op} 2; }",
|
||||
|
|
|
@ -198,8 +198,30 @@ main(value) {
|
|||
REMOVED,
|
||||
];
|
||||
|
||||
// TODO(ahe): It would probably be better if this test used the real
|
||||
// core library sources, as its purpose is to detect failure to
|
||||
// optimize fixed-sized arrays.
|
||||
const String DEFAULT_CORELIB_WITH_LIST_INTERFACE = r'''
|
||||
print(var obj) {}
|
||||
abstract class num {}
|
||||
abstract class int extends num { }
|
||||
abstract class double extends num { }
|
||||
class bool {}
|
||||
class String {}
|
||||
class Object {}
|
||||
class Type {}
|
||||
class Function {}
|
||||
interface List default ListImplementation { List([length]);}
|
||||
class ListImplementation { factory List([length]) => null; }
|
||||
abstract class Map {}
|
||||
class Closure {}
|
||||
class Null {}
|
||||
class Dynamic_ {}
|
||||
bool identical(Object a, Object b) {}''';
|
||||
|
||||
expect(String code, int kind) {
|
||||
String generated = compile(code);
|
||||
String generated =
|
||||
compile(code, coreSource: DEFAULT_CORELIB_WITH_LIST_INTERFACE);
|
||||
switch (kind) {
|
||||
case REMOVED:
|
||||
Expect.isTrue(!generated.contains('ioore'));
|
||||
|
|
Loading…
Reference in a new issue