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/commandline_options.dart'; | 10 import 'package:compiler/src/commandline_options.dart'; |
11 import 'package:compiler/src/compiler.dart' show | 11 import 'package:compiler/src/compiler.dart' show Compiler; |
12 Compiler; | 12 import 'package:compiler/src/diagnostics/messages.dart' |
13 import 'package:compiler/src/diagnostics/messages.dart' show | 13 show MessageKind, MessageTemplate; |
14 MessageKind, | 14 import 'package:compiler/compiler_new.dart' show Diagnostic; |
15 MessageTemplate; | |
16 import 'package:compiler/compiler_new.dart' show | |
17 Diagnostic; | |
18 | 15 |
19 import 'memory_compiler.dart'; | 16 import 'memory_compiler.dart'; |
20 | 17 |
21 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]'; | 18 const String ESCAPE_REGEXP = r'[[\]{}()*+?.\\^$|]'; |
22 | 19 |
23 /// Most examples generate a single diagnostic. | 20 /// Most examples generate a single diagnostic. |
24 /// Add an exception here if a single diagnostic cannot be produced. | 21 /// Add an exception here if a single diagnostic cannot be produced. |
25 /// However, consider that a single concise diagnostic is easier to understand, | 22 /// However, consider that a single concise diagnostic is easier to understand, |
26 /// so try to change error reporting logic before adding an exception. | 23 /// so try to change error reporting logic before adding an exception. |
27 final Set<MessageKind> kindsWithExtraMessages = new Set<MessageKind>.from([ | 24 final Set<MessageKind> kindsWithExtraMessages = new Set<MessageKind>.from([ |
28 // If you add something here, please file a *new* bug report. | 25 // If you add something here, please file a *new* bug report. |
29 // See http://dartbug.com/18361: | 26 // See http://dartbug.com/18361: |
30 MessageKind.CANNOT_EXTEND_MALFORMED, | 27 MessageKind.CANNOT_EXTEND_MALFORMED, |
31 MessageKind.CANNOT_IMPLEMENT_MALFORMED, | 28 MessageKind.CANNOT_IMPLEMENT_MALFORMED, |
32 MessageKind.CANNOT_MIXIN, | 29 MessageKind.CANNOT_MIXIN, |
33 MessageKind.CANNOT_MIXIN_MALFORMED, | 30 MessageKind.CANNOT_MIXIN_MALFORMED, |
34 MessageKind.CANNOT_INSTANTIATE_ENUM, | 31 MessageKind.CANNOT_INSTANTIATE_ENUM, |
35 MessageKind.CYCLIC_TYPEDEF_ONE, | 32 MessageKind.CYCLIC_TYPEDEF_ONE, |
36 MessageKind.DUPLICATE_DEFINITION, | 33 MessageKind.DUPLICATE_DEFINITION, |
37 MessageKind.EQUAL_MAP_ENTRY_KEY, | 34 MessageKind.EQUAL_MAP_ENTRY_KEY, |
38 MessageKind.FINAL_FUNCTION_TYPE_PARAMETER, | 35 MessageKind.FINAL_FUNCTION_TYPE_PARAMETER, |
39 MessageKind.FORMAL_DECLARED_CONST, | 36 MessageKind.FORMAL_DECLARED_CONST, |
40 MessageKind.FORMAL_DECLARED_STATIC, | 37 MessageKind.FORMAL_DECLARED_STATIC, |
41 MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT, | 38 MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT, |
42 MessageKind.HIDDEN_IMPLICIT_IMPORT, | 39 MessageKind.HIDDEN_IMPLICIT_IMPORT, |
43 MessageKind.HIDDEN_IMPORT, | 40 MessageKind.HIDDEN_IMPORT, |
44 MessageKind.INHERIT_GETTER_AND_METHOD, | 41 MessageKind.INHERIT_GETTER_AND_METHOD, |
45 MessageKind.UNIMPLEMENTED_METHOD, | 42 MessageKind.UNIMPLEMENTED_METHOD, |
46 MessageKind.UNIMPLEMENTED_METHOD_ONE, | 43 MessageKind.UNIMPLEMENTED_METHOD_ONE, |
47 MessageKind.VAR_FUNCTION_TYPE_PARAMETER, | 44 MessageKind.VAR_FUNCTION_TYPE_PARAMETER, |
48 ]); | 45 ]); |
49 | 46 |
50 /// Most messages can be tested without causing a fatal error. Add an exception | 47 /// Most messages can be tested without causing a fatal error. Add an exception |
51 /// here if a fatal error is unavoidable and leads to pending classes. | 48 /// here if a fatal error is unavoidable and leads to pending classes. |
52 /// Try to avoid adding exceptions here; a fatal error causes the compiler to | 49 /// Try to avoid adding exceptions here; a fatal error causes the compiler to |
53 /// stop before analyzing all input, and it isn't safe to reuse it. | 50 /// stop before analyzing all input, and it isn't safe to reuse it. |
54 final Set<MessageKind> kindsWithPendingClasses = new Set<MessageKind>.from([ | 51 final Set<MessageKind> kindsWithPendingClasses = new Set<MessageKind>.from([ |
55 // If you add something here, please file a *new* bug report. | 52 // If you add something here, please file a *new* bug report. |
56 ]); | 53 ]); |
57 | 54 |
58 Future<Compiler> check(MessageTemplate template, Compiler cachedCompiler) { | 55 Future<Compiler> check(MessageTemplate template, Compiler cachedCompiler) { |
59 Expect.isFalse(template.examples.isEmpty); | 56 Expect.isFalse(template.examples.isEmpty); |
60 | 57 |
61 return Future.forEach(template.examples, (example) { | 58 return Future.forEach(template.examples, (example) { |
62 if (example is String) { | 59 if (example is String) { |
63 example = {'main.dart': example}; | 60 example = {'main.dart': example}; |
64 } else { | 61 } else { |
65 Expect.isTrue(example is Map, | 62 Expect.isTrue( |
66 "Example must be either a String or a Map."); | 63 example is Map, "Example must be either a String or a Map."); |
67 Expect.isTrue(example.containsKey('main.dart'), | 64 Expect.isTrue(example.containsKey('main.dart'), |
68 "Example map must contain a 'main.dart' entry."); | 65 "Example map must contain a 'main.dart' entry."); |
69 } | 66 } |
70 DiagnosticCollector collector = new DiagnosticCollector(); | 67 DiagnosticCollector collector = new DiagnosticCollector(); |
71 | 68 |
72 Compiler compiler = compilerFor( | 69 Compiler compiler = compilerFor( |
73 memorySourceFiles: example, | 70 memorySourceFiles: example, |
74 diagnosticHandler: collector, | 71 diagnosticHandler: collector, |
75 options: [Flags.analyzeOnly, | 72 options: [Flags.analyzeOnly, Flags.enableExperimentalMirrors] |
76 Flags.enableExperimentalMirrors]..addAll(template.options), | 73 ..addAll(template.options), |
77 cachedCompiler: cachedCompiler); | 74 cachedCompiler: cachedCompiler); |
78 | 75 |
79 return compiler.run(Uri.parse('memory:main.dart')).then((_) { | 76 return compiler.run(Uri.parse('memory:main.dart')).then((_) { |
80 Iterable<CollectedMessage> messages = collector.filterMessagesByKinds( | 77 Iterable<CollectedMessage> messages = collector.filterMessagesByKinds([ |
81 [Diagnostic.ERROR, | 78 Diagnostic.ERROR, |
82 Diagnostic.WARNING, | 79 Diagnostic.WARNING, |
83 Diagnostic.HINT, | 80 Diagnostic.HINT, |
84 Diagnostic.CRASH]); | 81 Diagnostic.CRASH |
| 82 ]); |
85 | 83 |
86 Expect.isFalse(messages.isEmpty, 'No messages in """$example"""'); | 84 Expect.isFalse(messages.isEmpty, 'No messages in """$example"""'); |
87 | 85 |
88 String expectedText = !template.hasHowToFix | 86 String expectedText = !template.hasHowToFix |
89 ? template.template : '${template.template}\n${template.howToFix}'; | 87 ? template.template |
| 88 : '${template.template}\n${template.howToFix}'; |
90 String pattern = expectedText.replaceAllMapped( | 89 String pattern = expectedText.replaceAllMapped( |
91 new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}'); | 90 new RegExp(ESCAPE_REGEXP), (m) => '\\${m[0]}'); |
92 pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*'); | 91 pattern = pattern.replaceAll(new RegExp(r'#\\\{[^}]*\\\}'), '.*'); |
93 | 92 |
94 bool checkMessage(CollectedMessage message) { | 93 bool checkMessage(CollectedMessage message) { |
95 if (message.message.kind != MessageKind.GENERIC) { | 94 if (message.message.kind != MessageKind.GENERIC) { |
96 return message.message.kind == template.kind; | 95 return message.message.kind == template.kind; |
97 } else { | 96 } else { |
98 return new RegExp('^$pattern\$').hasMatch(message.text); | 97 return new RegExp('^$pattern\$').hasMatch(message.text); |
99 } | 98 } |
100 } | 99 } |
101 | 100 |
102 // TODO(johnniwinther): Extend MessageKind to contain information on | 101 // TODO(johnniwinther): Extend MessageKind to contain information on |
103 // where info messages are expected. | 102 // where info messages are expected. |
104 bool messageFound = false; | 103 bool messageFound = false; |
105 List unexpectedMessages = []; | 104 List unexpectedMessages = []; |
106 for (CollectedMessage message in messages) { | 105 for (CollectedMessage message in messages) { |
107 if (!messageFound && checkMessage(message)) { | 106 if (!messageFound && checkMessage(message)) { |
108 messageFound = true; | 107 messageFound = true; |
109 } else { | 108 } else { |
110 unexpectedMessages.add(message); | 109 unexpectedMessages.add(message); |
111 } | 110 } |
112 } | 111 } |
113 Expect.isTrue(messageFound, | 112 Expect.isTrue( |
| 113 messageFound, |
114 '${template.kind}} does not match any in\n ' | 114 '${template.kind}} does not match any in\n ' |
115 '${messages.join('\n ')}'); | 115 '${messages.join('\n ')}'); |
116 var reporter = compiler.reporter; | 116 var reporter = compiler.reporter; |
117 Expect.isFalse(reporter.hasCrashed); | 117 Expect.isFalse(reporter.hasCrashed); |
118 if (!unexpectedMessages.isEmpty) { | 118 if (!unexpectedMessages.isEmpty) { |
119 for (CollectedMessage message in unexpectedMessages) { | 119 for (CollectedMessage message in unexpectedMessages) { |
120 print("Unexpected message: $message"); | 120 print("Unexpected message: $message"); |
121 } | 121 } |
122 if (!kindsWithExtraMessages.contains(template.kind)) { | 122 if (!kindsWithExtraMessages.contains(template.kind)) { |
123 // Try changing the error reporting logic before adding an exception | 123 // Try changing the error reporting logic before adding an exception |
124 // to [kindsWithExtraMessages]. | 124 // to [kindsWithExtraMessages]. |
125 throw 'Unexpected messages found.'; | 125 throw 'Unexpected messages found.'; |
126 } | 126 } |
127 } | 127 } |
128 | 128 |
129 bool pendingStuff = false; | 129 bool pendingStuff = false; |
130 for (var e in compiler.resolver.pendingClassesToBePostProcessed) { | 130 for (var e in compiler.resolver.pendingClassesToBePostProcessed) { |
131 pendingStuff = true; | 131 pendingStuff = true; |
132 compiler.reporter.reportInfo( | 132 compiler.reporter.reportInfo(e, MessageKind.GENERIC, |
133 e, MessageKind.GENERIC, | |
134 {'text': 'Pending class to be post-processed.'}); | 133 {'text': 'Pending class to be post-processed.'}); |
135 } | 134 } |
136 for (var e in compiler.resolver.pendingClassesToBeResolved) { | 135 for (var e in compiler.resolver.pendingClassesToBeResolved) { |
137 pendingStuff = true; | 136 pendingStuff = true; |
138 compiler.reporter.reportInfo( | 137 compiler.reporter.reportInfo( |
139 e, MessageKind.GENERIC, | 138 e, MessageKind.GENERIC, {'text': 'Pending class to be resolved.'}); |
140 {'text': 'Pending class to be resolved.'}); | |
141 } | 139 } |
142 Expect.isTrue(!pendingStuff || | 140 Expect |
143 kindsWithPendingClasses.contains(template)); | 141 .isTrue(!pendingStuff || kindsWithPendingClasses.contains(template)); |
144 | 142 |
145 if (!pendingStuff) { | 143 if (!pendingStuff) { |
146 // If there is pending stuff, or the compiler was cancelled, we | 144 // If there is pending stuff, or the compiler was cancelled, we |
147 // shouldn't reuse the compiler. | 145 // shouldn't reuse the compiler. |
148 cachedCompiler = compiler; | 146 cachedCompiler = compiler; |
149 } | 147 } |
150 }); | 148 }); |
151 }).then((_) => cachedCompiler); | 149 }).then((_) => cachedCompiler); |
152 } | 150 } |
OLD | NEW |