Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(343)

Side by Side Diff: pkg/compiler/lib/src/js_backend/no_such_method_registry.dart

Issue 1023673012: Emit diagnostics for bad NSM implementations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * Categorizes `noSuchMethod` implementations. 8 * Categorizes `noSuchMethod` implementations.
9 * 9 *
10 * If user code includes `noSuchMethod` implementations, type inference is 10 * If user code includes `noSuchMethod` implementations, type inference is
(...skipping 24 matching lines...) Expand all
35 * are in the same category as the superclass implementation. This covers a 35 * are in the same category as the superclass implementation. This covers a
36 * common case, where users implement `noSuchMethod` with these dummy 36 * common case, where users implement `noSuchMethod` with these dummy
37 * implementations to avoid warnings. 37 * implementations to avoid warnings.
38 */ 38 */
39 class NoSuchMethodRegistry { 39 class NoSuchMethodRegistry {
40 /// The implementations that fall into category A, described above. 40 /// The implementations that fall into category A, described above.
41 final Set<FunctionElement> defaultImpls = new Set<FunctionElement>(); 41 final Set<FunctionElement> defaultImpls = new Set<FunctionElement>();
42 /// The implementations that fall into category B, described above. 42 /// The implementations that fall into category B, described above.
43 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>(); 43 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
44 /// The implementations that fall into category C, described above. 44 /// The implementations that fall into category C, described above.
45 final Set<Element> otherImpls = new Set<Element>(); 45 final Set<FunctionElement> otherImpls = new Set<FunctionElement>();
46
47 /// The implementations that fall into category C1
48 final Set<FunctionElement> complexNoReturnImpls = new Set<FunctionElement>();
49 /// The implementations that fall into category C2
50 final Set<FunctionElement> complexReturningImpls = new Set<FunctionElement>();
46 51
47 /// The implementations that have not yet been categorized. 52 /// The implementations that have not yet been categorized.
48 final Set<Element> _uncategorizedImpls = new Set<Element>(); 53 final Set<FunctionElement> _uncategorizedImpls = new Set<FunctionElement>();
49 54
50 final JavaScriptBackend _backend; 55 final JavaScriptBackend _backend;
51 final Compiler _compiler; 56 final Compiler _compiler;
52 57
53 NoSuchMethodRegistry(JavaScriptBackend backend) 58 NoSuchMethodRegistry(JavaScriptBackend backend)
54 : this._backend = backend, 59 : this._backend = backend,
55 this._compiler = backend.compiler; 60 this._compiler = backend.compiler;
56 61
57 bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty; 62 bool get hasThrowingNoSuchMethod => throwingImpls.isNotEmpty;
58 bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty; 63 bool get hasComplexNoSuchMethod => otherImpls.isNotEmpty;
59 64
60 void registerNoSuchMethod(Element noSuchMethodElement) { 65 void registerNoSuchMethod(FunctionElement noSuchMethodElement) {
61 _uncategorizedImpls.add(noSuchMethodElement); 66 _uncategorizedImpls.add(noSuchMethodElement);
62 } 67 }
63 68
64 void onQueueEmpty() { 69 void onQueueEmpty() {
65 _uncategorizedImpls.forEach(_categorizeImpl); 70 _uncategorizedImpls.forEach(_categorizeImpl);
66 _uncategorizedImpls.clear(); 71 _uncategorizedImpls.clear();
67 } 72 }
68 73
74 /// Now that type inference is complete, split category C into two
75 /// subcategories: C1, those that have no return type, and C2, those
76 /// that have a return type.
77 void onInferenceComplete() {
78 otherImpls.forEach(_subcategorizeOther);
79 }
80
81 /// Emits a diagnostic
82 void emitDiagnostic() {
83 throwingImpls.forEach((e) {
84 if (!_hasForwardingSyntax(e)) {
85 _compiler.reportHint(e,
86 MessageKind.DIRECTLY_THROWING_NSM);
87 }
88 });
89 complexNoReturnImpls.forEach((e) {
90 if (!_hasForwardingSyntax(e)) {
91 _compiler.reportHint(e,
92 MessageKind.COMPLEX_THROWING_NSM);
93 }
94 });
95 complexReturningImpls.forEach((e) {
96 if (!_hasForwardingSyntax(e)) {
97 _compiler.reportHint(e,
98 MessageKind.COMPLEX_RETURNING_NSM);
99 }
100 });
101 }
102
69 /// Returns [true] if the given element is a complex [noSuchMethod] 103 /// Returns [true] if the given element is a complex [noSuchMethod]
70 /// implementation. An implementation is complex if it falls into 104 /// implementation. An implementation is complex if it falls into
71 /// category C, as described above. 105 /// category C, as described above.
72 bool isComplex(FunctionElement element) { 106 bool isComplex(FunctionElement element) {
73 assert(element.name == Compiler.NO_SUCH_METHOD); 107 assert(element.name == Compiler.NO_SUCH_METHOD);
74 return otherImpls.contains(element); 108 return otherImpls.contains(element);
75 } 109 }
76 110
77 NsmCategory _categorizeImpl(Element noSuchMethodElement) { 111 _subcategorizeOther(FunctionElement element) {
78 assert(noSuchMethodElement.name == Compiler.NO_SUCH_METHOD); 112 TypeMask returnType =
79 if (defaultImpls.contains(noSuchMethodElement)) { 113 _compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
114 if (returnType == const TypeMask.nonNullEmpty()) {
115 complexNoReturnImpls.add(element);
116 } else {
117 complexReturningImpls.add(element);
118 }
119 }
120
121 NsmCategory _categorizeImpl(FunctionElement element) {
122 assert(element.name == Compiler.NO_SUCH_METHOD);
123 if (defaultImpls.contains(element)) {
80 return NsmCategory.DEFAULT; 124 return NsmCategory.DEFAULT;
81 } 125 }
82 if (throwingImpls.contains(noSuchMethodElement)) { 126 if (throwingImpls.contains(element)) {
83 return NsmCategory.THROWING; 127 return NsmCategory.THROWING;
84 } 128 }
85 if (otherImpls.contains(noSuchMethodElement)) { 129 if (otherImpls.contains(element)) {
86 return NsmCategory.OTHER; 130 return NsmCategory.OTHER;
87 } 131 }
88 if (noSuchMethodElement is! FunctionElement || 132 if (!_compiler.noSuchMethodSelector.signatureApplies(element)) {
89 !_compiler.noSuchMethodSelector.signatureApplies(noSuchMethodElement)) { 133 otherImpls.add(element);
90 otherImpls.add(noSuchMethodElement);
91 return NsmCategory.OTHER; 134 return NsmCategory.OTHER;
92 } 135 }
93 FunctionElement noSuchMethodFunc = noSuchMethodElement as FunctionElement; 136 if (_isDefaultNoSuchMethodImplementation(element)) {
94 if (_isDefaultNoSuchMethodImplementation(noSuchMethodFunc)) { 137 defaultImpls.add(element);
95 defaultImpls.add(noSuchMethodFunc);
96 return NsmCategory.DEFAULT; 138 return NsmCategory.DEFAULT;
97 } else if (_hasForwardingSyntax(noSuchMethodFunc)) { 139 } else if (_hasForwardingSyntax(element)) {
98 // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);' 140 // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);'
99 // then it is in the same category as the super call. 141 // then it is in the same category as the super call.
100 Element superCall = noSuchMethodFunc.enclosingClass 142 Element superCall = element.enclosingClass
101 .lookupSuperSelector(_compiler.noSuchMethodSelector); 143 .lookupSuperSelector(_compiler.noSuchMethodSelector);
102 NsmCategory category = _categorizeImpl(superCall); 144 NsmCategory category = _categorizeImpl(superCall);
103 switch(category) { 145 switch(category) {
104 case NsmCategory.DEFAULT: 146 case NsmCategory.DEFAULT:
105 defaultImpls.add(noSuchMethodFunc); 147 defaultImpls.add(element);
106 break; 148 break;
107 case NsmCategory.THROWING: 149 case NsmCategory.THROWING:
108 throwingImpls.add(noSuchMethodFunc); 150 throwingImpls.add(element);
109 break; 151 break;
110 case NsmCategory.OTHER: 152 case NsmCategory.OTHER:
111 otherImpls.add(noSuchMethodFunc); 153 otherImpls.add(element);
112 break; 154 break;
113 } 155 }
114 return category; 156 return category;
115 } else if (_hasThrowingSyntax(noSuchMethodFunc)) { 157 } else if (_hasThrowingSyntax(element)) {
116 throwingImpls.add(noSuchMethodFunc); 158 throwingImpls.add(element);
117 return NsmCategory.THROWING; 159 return NsmCategory.THROWING;
118 } else { 160 } else {
119 otherImpls.add(noSuchMethodFunc); 161 otherImpls.add(element);
120 return NsmCategory.OTHER; 162 return NsmCategory.OTHER;
121 } 163 }
122 } 164 }
123 165
124 bool _isDefaultNoSuchMethodImplementation(Element element) { 166 bool _isDefaultNoSuchMethodImplementation(FunctionElement element) {
125 ClassElement classElement = element.enclosingClass; 167 ClassElement classElement = element.enclosingClass;
126 return classElement == _compiler.objectClass 168 return classElement == _compiler.objectClass
127 || classElement == _backend.jsInterceptorClass 169 || classElement == _backend.jsInterceptorClass
128 || classElement == _backend.jsNullClass; 170 || classElement == _backend.jsNullClass;
129 } 171 }
130 172
131 bool _hasForwardingSyntax(FunctionElement element) { 173 bool _hasForwardingSyntax(FunctionElement element) {
132 // At this point we know that this is signature-compatible with 174 // At this point we know that this is signature-compatible with
133 // Object.noSuchMethod, but it may have more than one argument as long as 175 // Object.noSuchMethod, but it may have more than one argument as long as
134 // it only has one required argument. 176 // it only has one required argument.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 if (body.statements.nodes.head is ExpressionStatement) { 216 if (body.statements.nodes.head is ExpressionStatement) {
175 ExpressionStatement stmt = body.statements.nodes.head; 217 ExpressionStatement stmt = body.statements.nodes.head;
176 return stmt.expression is Throw; 218 return stmt.expression is Throw;
177 } 219 }
178 } 220 }
179 return false; 221 return false;
180 } 222 }
181 } 223 }
182 224
183 enum NsmCategory { DEFAULT, THROWING, OTHER } 225 enum NsmCategory { DEFAULT, THROWING, OTHER }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698