| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.test.message_kind_helper; | 5 library dart2js.test.message_kind_helper; |
| 6 | 6 |
| 7 import 'package:expect/expect.dart'; | 7 import 'package:expect/expect.dart'; |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 | 9 |
| 10 import 'package:compiler/src/dart2jslib.dart' show | 10 import 'package:compiler/src/dart2jslib.dart' show |
| 11 Compiler, | 11 Compiler, |
| 12 MessageKind; | 12 MessageKind, |
| 13 MessageTemplate; |
| 13 import 'package:compiler/src/dart_backend/dart_backend.dart' show | 14 import 'package:compiler/src/dart_backend/dart_backend.dart' show |
| 14 DartBackend; | 15 DartBackend; |
| 15 import 'package:compiler/src/old_to_new_api.dart' show | 16 import 'package:compiler/src/old_to_new_api.dart' show |
| 16 LegacyCompilerDiagnostics; | 17 LegacyCompilerDiagnostics; |
| 17 | 18 |
| 18 import 'memory_compiler.dart'; | 19 import 'memory_compiler.dart'; |
| 19 | 20 |
| 20 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]'; | 21 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]'; |
| 21 | 22 |
| 22 /// Most examples generate a single diagnostic. | 23 /// Most examples generate a single diagnostic. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 45 ]); | 46 ]); |
| 46 | 47 |
| 47 /// Most messages can be tested without causing a fatal error. Add an exception | 48 /// Most messages can be tested without causing a fatal error. Add an exception |
| 48 /// here if a fatal error is unavoidable and leads to pending classes. | 49 /// here if a fatal error is unavoidable and leads to pending classes. |
| 49 /// Try to avoid adding exceptions here; a fatal error causes the compiler to | 50 /// Try to avoid adding exceptions here; a fatal error causes the compiler to |
| 50 /// stop before analyzing all input, and it isn't safe to reuse it. | 51 /// stop before analyzing all input, and it isn't safe to reuse it. |
| 51 final Set<MessageKind> kindsWithPendingClasses = new Set<MessageKind>.from([ | 52 final Set<MessageKind> kindsWithPendingClasses = new Set<MessageKind>.from([ |
| 52 // If you add something here, please file a *new* bug report. | 53 // If you add something here, please file a *new* bug report. |
| 53 ]); | 54 ]); |
| 54 | 55 |
| 55 Future<Compiler> check(MessageKind kind, Compiler cachedCompiler) { | 56 Future<Compiler> check(MessageTemplate template, Compiler cachedCompiler) { |
| 56 Expect.isNotNull(kind.howToFix); | 57 Expect.isNotNull(template.howToFix); |
| 57 Expect.isFalse(kind.examples.isEmpty); | 58 Expect.isFalse(template.examples.isEmpty); |
| 58 | 59 |
| 59 return Future.forEach(kind.examples, (example) { | 60 return Future.forEach(template.examples, (example) { |
| 60 if (example is String) { | 61 if (example is String) { |
| 61 example = {'main.dart': example}; | 62 example = {'main.dart': example}; |
| 62 } else { | 63 } else { |
| 63 Expect.isTrue(example is Map, | 64 Expect.isTrue(example is Map, |
| 64 "Example must be either a String or a Map."); | 65 "Example must be either a String or a Map."); |
| 65 Expect.isTrue(example.containsKey('main.dart'), | 66 Expect.isTrue(example.containsKey('main.dart'), |
| 66 "Example map must contain a 'main.dart' entry."); | 67 "Example map must contain a 'main.dart' entry."); |
| 67 } | 68 } |
| 68 List<String> messages = <String>[]; | 69 List<String> messages = <String>[]; |
| 69 void collect(Uri uri, int begin, int end, String message, kind) { | 70 void collect(Uri uri, int begin, int end, String message, kind) { |
| 70 if (kind.name == 'verbose info' || kind.name == 'info') { | 71 if (kind.name == 'verbose info' || kind.name == 'info') { |
| 71 return; | 72 return; |
| 72 } | 73 } |
| 73 messages.add(message); | 74 messages.add(message); |
| 74 } | 75 } |
| 75 | 76 |
| 76 bool oldBackendIsDart; | 77 bool oldBackendIsDart; |
| 77 if (cachedCompiler != null) { | 78 if (cachedCompiler != null) { |
| 78 oldBackendIsDart = cachedCompiler.backend is DartBackend; | 79 oldBackendIsDart = cachedCompiler.backend is DartBackend; |
| 79 } | 80 } |
| 80 bool newBackendIsDart = kind.options.contains('--output-type=dart'); | 81 bool newBackendIsDart = template.options.contains('--output-type=dart'); |
| 81 | 82 |
| 82 Compiler compiler = compilerFor( | 83 Compiler compiler = compilerFor( |
| 83 example, | 84 example, |
| 84 diagnosticHandler: new LegacyCompilerDiagnostics(collect), | 85 diagnosticHandler: new LegacyCompilerDiagnostics(collect), |
| 85 options: ['--analyze-only', | 86 options: ['--analyze-only', |
| 86 '--enable-experimental-mirrors']..addAll(kind.options), | 87 '--enable-experimental-mirrors']..addAll(template.options), |
| 87 cachedCompiler: | 88 cachedCompiler: |
| 88 // TODO(johnniwinther): Remove this restriction when constant | 89 // TODO(johnniwinther): Remove this restriction when constant |
| 89 // values can be computed directly from the expressions. | 90 // values can be computed directly from the expressions. |
| 90 oldBackendIsDart == newBackendIsDart ? cachedCompiler : null); | 91 oldBackendIsDart == newBackendIsDart ? cachedCompiler : null); |
| 91 | 92 |
| 92 return compiler.run(Uri.parse('memory:main.dart')).then((_) { | 93 return compiler.run(Uri.parse('memory:main.dart')).then((_) { |
| 93 | 94 |
| 94 Expect.isFalse(messages.isEmpty, 'No messages in """$example"""'); | 95 Expect.isFalse(messages.isEmpty, 'No messages in """$example"""'); |
| 95 | 96 |
| 96 String expectedText = !kind.hasHowToFix | 97 String expectedText = !template.hasHowToFix |
| 97 ? kind.template : '${kind.template}\n${kind.howToFix}'; | 98 ? template.template : '${template.template}\n${template.howToFix}'; |
| 98 String pattern = expectedText.replaceAllMapped( | 99 String pattern = expectedText.replaceAllMapped( |
| 99 new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}'); | 100 new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}'); |
| 100 pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*'); | 101 pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*'); |
| 101 | 102 |
| 102 // TODO(johnniwinther): Extend MessageKind to contain information on | 103 // TODO(johnniwinther): Extend MessageKind to contain information on |
| 103 // where info messages are expected. | 104 // where info messages are expected. |
| 104 bool messageFound = false; | 105 bool messageFound = false; |
| 105 List unexpectedMessages = []; | 106 List unexpectedMessages = []; |
| 106 for (String message in messages) { | 107 for (String message in messages) { |
| 107 if (!messageFound && new RegExp('^$pattern\$').hasMatch(message)) { | 108 if (!messageFound && new RegExp('^$pattern\$').hasMatch(message)) { |
| 108 messageFound = true; | 109 messageFound = true; |
| 109 } else { | 110 } else { |
| 110 unexpectedMessages.add(message); | 111 unexpectedMessages.add(message); |
| 111 } | 112 } |
| 112 } | 113 } |
| 113 Expect.isTrue(messageFound, '"$pattern" does not match any in $messages'); | 114 Expect.isTrue(messageFound, '"$pattern" does not match any in $messages'); |
| 114 Expect.isFalse(compiler.hasCrashed); | 115 Expect.isFalse(compiler.hasCrashed); |
| 115 if (!unexpectedMessages.isEmpty) { | 116 if (!unexpectedMessages.isEmpty) { |
| 116 for (String message in unexpectedMessages) { | 117 for (String message in unexpectedMessages) { |
| 117 print("Unexpected message: $message"); | 118 print("Unexpected message: $message"); |
| 118 } | 119 } |
| 119 if (!kindsWithExtraMessages.contains(kind)) { | 120 if (!kindsWithExtraMessages.contains(template.kind)) { |
| 120 // Try changing the error reporting logic before adding an exception | 121 // Try changing the error reporting logic before adding an exception |
| 121 // to [kindsWithExtraMessages]. | 122 // to [kindsWithExtraMessages]. |
| 122 throw 'Unexpected messages found.'; | 123 throw 'Unexpected messages found.'; |
| 123 } | 124 } |
| 124 } | 125 } |
| 125 | 126 |
| 126 bool pendingStuff = false; | 127 bool pendingStuff = false; |
| 127 for (var e in compiler.resolver.pendingClassesToBePostProcessed) { | 128 for (var e in compiler.resolver.pendingClassesToBePostProcessed) { |
| 128 pendingStuff = true; | 129 pendingStuff = true; |
| 129 compiler.reportInfo( | 130 compiler.reportInfo( |
| 130 e, MessageKind.GENERIC, | 131 e, MessageKind.GENERIC, |
| 131 {'text': 'Pending class to be post-processed.'}); | 132 {'text': 'Pending class to be post-processed.'}); |
| 132 } | 133 } |
| 133 for (var e in compiler.resolver.pendingClassesToBeResolved) { | 134 for (var e in compiler.resolver.pendingClassesToBeResolved) { |
| 134 pendingStuff = true; | 135 pendingStuff = true; |
| 135 compiler.reportInfo( | 136 compiler.reportInfo( |
| 136 e, MessageKind.GENERIC, | 137 e, MessageKind.GENERIC, |
| 137 {'text': 'Pending class to be resolved.'}); | 138 {'text': 'Pending class to be resolved.'}); |
| 138 } | 139 } |
| 139 Expect.isTrue(!pendingStuff || kindsWithPendingClasses.contains(kind)); | 140 Expect.isTrue(!pendingStuff || |
| 141 kindsWithPendingClasses.contains(template)); |
| 140 | 142 |
| 141 if (!pendingStuff) { | 143 if (!pendingStuff) { |
| 142 // If there is pending stuff, or the compiler was cancelled, we | 144 // If there is pending stuff, or the compiler was cancelled, we |
| 143 // shouldn't reuse the compiler. | 145 // shouldn't reuse the compiler. |
| 144 cachedCompiler = compiler; | 146 cachedCompiler = compiler; |
| 145 } | 147 } |
| 146 }); | 148 }); |
| 147 }).then((_) => cachedCompiler); | 149 }).then((_) => cachedCompiler); |
| 148 } | 150 } |
| OLD | NEW |