OLD | NEW |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'package:compiler/src/common.dart'; | 5 import 'package:compiler/src/common.dart'; |
6 import 'package:compiler/src/common_elements.dart'; | 6 import 'package:compiler/src/common_elements.dart'; |
7 import 'package:compiler/src/compiler.dart'; | 7 import 'package:compiler/src/compiler.dart'; |
8 import 'package:compiler/src/elements/elements.dart'; | 8 import 'package:compiler/src/elements/elements.dart'; |
9 import 'package:compiler/src/elements/entities.dart'; | 9 import 'package:compiler/src/elements/entities.dart'; |
10 import 'package:compiler/src/resolution/tree_elements.dart'; | 10 import 'package:compiler/src/resolution/tree_elements.dart'; |
11 import 'package:compiler/src/tree/nodes.dart'; | 11 import 'package:compiler/src/tree/nodes.dart'; |
12 import 'package:compiler/src/types/types.dart'; | |
13 import 'package:expect/expect.dart'; | 12 import 'package:expect/expect.dart'; |
14 | 13 |
15 import '../annotated_code_helper.dart'; | 14 import '../annotated_code_helper.dart'; |
16 import '../memory_compiler.dart'; | 15 import '../memory_compiler.dart'; |
17 import 'enumerator.dart'; | 16 import '../equivalence/id_equivalence.dart'; |
18 | 17 |
19 typedef void CheckMemberFunction( | 18 typedef void CheckMemberFunction( |
20 Compiler compiler, Map<Id, String> expectedMap, MemberElement member); | 19 Compiler compiler, Map<Id, String> expectedMap, MemberEntity member); |
21 | 20 |
22 /// Compiles the [annotatedCode] with the provided [options] and calls | 21 /// Compiles the [annotatedCode] with the provided [options] and calls |
23 /// [checkMember] for each member in the code providing the map from [Id] to | 22 /// [checkMember] for each member in the code providing the map from [Id] to |
24 /// annotation. Any [Id] left in the map will be reported as missing. | 23 /// annotation. Any [Id] left in the map will be reported as missing. |
25 checkCode(String annotatedCode, CheckMemberFunction checkMember, | 24 checkCode(String annotatedCode, CheckMemberFunction checkMember, |
26 {List<String> options: const <String>[]}) async { | 25 {List<String> options: const <String>[]}) async { |
27 AnnotatedCode code = | 26 AnnotatedCode code = |
28 new AnnotatedCode.fromText(annotatedCode, commentStart, commentEnd); | 27 new AnnotatedCode.fromText(annotatedCode, commentStart, commentEnd); |
29 Map<Id, String> expectedMap = computeExpectedMap(code); | 28 Map<Id, String> expectedMap = computeExpectedMap(code); |
30 Compiler compiler = compilerFor( | 29 Compiler compiler = compilerFor( |
31 memorySourceFiles: {'main.dart': code.sourceCode}, options: options); | 30 memorySourceFiles: {'main.dart': code.sourceCode}, options: options); |
32 compiler.stopAfterTypeInference = true; | 31 compiler.stopAfterTypeInference = true; |
33 Uri mainUri = Uri.parse('memory:main.dart'); | 32 Uri mainUri = Uri.parse('memory:main.dart'); |
34 await compiler.run(mainUri); | 33 await compiler.run(mainUri); |
35 LibraryElement mainApp = | 34 ElementEnvironment elementEnvironment = |
36 compiler.frontendStrategy.elementEnvironment.mainLibrary; | 35 compiler.backendClosedWorldForTesting.elementEnvironment; |
37 mainApp.forEachLocalMember((dynamic member) { | 36 LibraryEntity mainLibrary = elementEnvironment.mainLibrary; |
38 if (member.isClass) { | 37 elementEnvironment.forEachClass(mainLibrary, (ClassEntity cls) { |
39 member.forEachLocalMember((member) { | 38 elementEnvironment.forEachClassMember(cls, |
| 39 (ClassEntity declarer, MemberEntity member) { |
| 40 if (cls == declarer) { |
40 checkMember(compiler, expectedMap, member); | 41 checkMember(compiler, expectedMap, member); |
41 }); | 42 } |
42 } else if (member.isTypedef) { | 43 }); |
43 // Skip. | 44 }); |
44 } else { | 45 elementEnvironment.forEachLibraryMember(mainLibrary, (MemberEntity member) { |
45 checkMember(compiler, expectedMap, member); | 46 checkMember(compiler, expectedMap, member); |
46 } | |
47 }); | 47 }); |
48 expectedMap.forEach((Id id, String expected) { | 48 expectedMap.forEach((Id id, String expected) { |
49 reportHere( | 49 reportHere( |
50 compiler.reporter, | 50 compiler.reporter, |
51 computeSpannable(compiler.resolution.elementEnvironment, mainUri, id), | 51 computeSpannable(elementEnvironment, mainUri, id), |
52 'expected:${expected},actual:null'); | 52 'expected:${expected},actual:null'); |
53 }); | 53 }); |
54 Expect.isTrue(expectedMap.isEmpty, "Ids not found: $expectedMap."); | 54 Expect.isTrue(expectedMap.isEmpty, "Ids not found: $expectedMap."); |
55 } | 55 } |
56 | 56 |
57 void checkMemberAstTypeMasks( | |
58 Compiler compiler, Map<Id, String> expectedMap, MemberElement member) { | |
59 ResolvedAst resolvedAst = member.resolvedAst; | |
60 if (resolvedAst.kind != ResolvedAstKind.PARSED) return; | |
61 compiler.reporter.withCurrentElement(member.implementation, () { | |
62 new TypeMaskChecker(compiler.reporter, expectedMap, resolvedAst, | |
63 compiler.globalInference.results) | |
64 .check(); | |
65 }); | |
66 } | |
67 | |
68 Spannable computeSpannable( | 57 Spannable computeSpannable( |
69 ElementEnvironment elementEnvironment, Uri mainUri, Id id) { | 58 ElementEnvironment elementEnvironment, Uri mainUri, Id id) { |
70 if (id is NodeId) { | 59 if (id is NodeId) { |
71 return new SourceSpan(mainUri, id.value, id.value + 1); | 60 return new SourceSpan(mainUri, id.value, id.value + 1); |
72 } else if (id is ElementId) { | 61 } else if (id is ElementId) { |
73 LibraryEntity library = elementEnvironment.lookupLibrary(mainUri); | 62 LibraryEntity library = elementEnvironment.lookupLibrary(mainUri); |
74 if (id.className != null) { | 63 if (id.className != null) { |
75 ClassEntity cls = | 64 ClassEntity cls = |
76 elementEnvironment.lookupClass(library, id.className, required: true); | 65 elementEnvironment.lookupClass(library, id.className, required: true); |
77 return elementEnvironment.lookupClassMember(cls, id.memberName); | 66 return elementEnvironment.lookupClassMember(cls, id.memberName); |
(...skipping 16 matching lines...) Expand all Loading... |
94 expected = text; | 83 expected = text; |
95 } else { | 84 } else { |
96 id = new ElementId(text.substring(0, colonPos)); | 85 id = new ElementId(text.substring(0, colonPos)); |
97 expected = text.substring(colonPos + 1); | 86 expected = text.substring(colonPos + 1); |
98 } | 87 } |
99 map[id] = expected; | 88 map[id] = expected; |
100 } | 89 } |
101 return map; | 90 return map; |
102 } | 91 } |
103 | 92 |
104 class TypeMaskChecker extends Visitor with AstEnumeratorMixin { | 93 abstract class AbstractResolvedAstChecker extends Visitor |
| 94 with AstEnumeratorMixin { |
105 final DiagnosticReporter reporter; | 95 final DiagnosticReporter reporter; |
106 final Map<Id, String> expectedMap; | 96 final Map<Id, String> expectedMap; |
107 final ResolvedAst resolvedAst; | 97 final ResolvedAst resolvedAst; |
108 final GlobalTypeInferenceResults results; | |
109 final GlobalTypeInferenceElementResult result; | |
110 | 98 |
111 TypeMaskChecker( | 99 AbstractResolvedAstChecker(this.reporter, this.expectedMap, this.resolvedAst); |
112 this.reporter, this.expectedMap, this.resolvedAst, this.results) | |
113 : result = results.resultOfMember(resolvedAst.element as MemberElement); | |
114 | 100 |
115 TreeElements get elements => resolvedAst.elements; | 101 TreeElements get elements => resolvedAst.elements; |
116 | 102 |
117 void check() { | 103 void check() { |
118 resolvedAst.node.accept(this); | 104 resolvedAst.node.accept(this); |
119 } | 105 } |
120 | 106 |
121 visitNode(Node node) { | 107 visitNode(Node node) { |
122 node.visitChildren(this); | 108 node.visitChildren(this); |
123 } | 109 } |
124 | 110 |
125 void checkElement(AstElement element) { | 111 void checkElement(AstElement element) { |
126 ElementId id = computeElementId(element); | 112 ElementId id = computeElementId(element); |
127 GlobalTypeInferenceElementResult elementResult = | |
128 results.resultOfElement(element); | |
129 TypeMask value = | |
130 element.isFunction ? elementResult.returnType : elementResult.type; | |
131 String expected = annotationForId(id); | 113 String expected = annotationForId(id); |
| 114 String value = computeElementValue(element); |
132 checkValue(element, expected, value); | 115 checkValue(element, expected, value); |
133 } | 116 } |
134 | 117 |
| 118 String computeElementValue(AstElement element); |
| 119 |
135 String annotationForId(Id id) { | 120 String annotationForId(Id id) { |
136 if (id == null) return null; | 121 if (id == null) return null; |
137 return expectedMap.remove(id); | 122 return expectedMap.remove(id); |
138 } | 123 } |
139 | 124 |
140 void checkValue(Spannable spannable, String expected, TypeMask value) { | 125 void checkValue(Spannable spannable, String expected, String value) { |
141 if (value != null || expected != null) { | 126 if (value != null || expected != null) { |
142 String valueText = '$value'; | 127 if (value != expected) { |
143 if (valueText != expected) { | |
144 reportHere(reporter, spannable, 'expected:${expected},actual:${value}'); | 128 reportHere(reporter, spannable, 'expected:${expected},actual:${value}'); |
145 } | 129 } |
146 Expect.equals(expected, valueText); | 130 Expect.equals(expected, value); |
147 } | 131 } |
148 } | 132 } |
149 | 133 |
150 void checkSend(Send node) { | 134 void checkNode(Node node, AstElement element) { |
151 NodeId id = computeNodeId(node); | 135 NodeId id = computeNodeId(node, element); |
152 TypeMask value = result.typeOfSend(node); | |
153 String expected = annotationForId(id); | 136 String expected = annotationForId(id); |
| 137 String value = computeNodeValue(node, element); |
154 checkValue(node, expected, value); | 138 checkValue(node, expected, value); |
155 } | 139 } |
156 | 140 |
| 141 String computeNodeValue(Node node, [AstElement element]); |
| 142 |
157 visitVariableDefinitions(VariableDefinitions node) { | 143 visitVariableDefinitions(VariableDefinitions node) { |
158 for (Node child in node.definitions) { | 144 for (Node child in node.definitions) { |
159 AstElement element = elements[child]; | 145 AstElement element = elements[child]; |
160 if (element == null) { | 146 if (element == null) { |
161 reportHere(reporter, child, 'No element for variable.'); | 147 reportHere(reporter, child, 'No element for variable.'); |
162 } else if (!element.isLocal) { | 148 } else if (!element.isLocal) { |
163 checkElement(element); | 149 checkElement(element); |
| 150 } else { |
| 151 checkNode(child, element); |
164 } | 152 } |
165 } | 153 } |
166 visitNode(node); | 154 visitNode(node); |
167 } | 155 } |
168 | 156 |
169 visitFunctionExpression(FunctionExpression node) { | 157 visitFunctionExpression(FunctionExpression node) { |
170 AstElement element = elements.getFunctionDefinition(node); | 158 AstElement element = elements.getFunctionDefinition(node); |
171 checkElement(element); | 159 if (!element.isLocal) { |
| 160 checkElement(element); |
| 161 } else { |
| 162 checkNode(node, element); |
| 163 } |
172 visitNode(node); | 164 visitNode(node); |
173 } | 165 } |
174 | 166 |
175 visitSend(Send node) { | 167 visitSend(Send node) { |
176 checkSend(node); | 168 checkNode(node, null); |
177 visitNode(node); | 169 visitNode(node); |
178 } | 170 } |
179 | 171 |
180 visitSendSet(SendSet node) { | 172 visitSendSet(SendSet node) { |
181 checkSend(node); | 173 checkNode(node, null); |
182 visitNode(node); | 174 visitNode(node); |
183 } | 175 } |
184 } | 176 } |
OLD | NEW |