| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library fletchc.incremental.scope_information_visitor; | |
| 6 | |
| 7 import 'package:compiler/src/elements/modelx.dart' as modelx; | |
| 8 | |
| 9 import 'package:compiler/src/elements/visitor.dart' show | |
| 10 ElementVisitor; | |
| 11 | |
| 12 import 'package:compiler/src/compiler.dart' show | |
| 13 Compiler; | |
| 14 | |
| 15 import 'package:compiler/src/elements/elements.dart' show | |
| 16 AbstractFieldElement, | |
| 17 ClassElement, | |
| 18 CompilationUnitElement, | |
| 19 Element, | |
| 20 ElementCategory, | |
| 21 FunctionElement, | |
| 22 LibraryElement, | |
| 23 MemberElement, | |
| 24 ScopeContainerElement; | |
| 25 | |
| 26 import 'package:compiler/src/dart_types.dart' show | |
| 27 DartType; | |
| 28 | |
| 29 /** | |
| 30 * Serializes scope information about an element. This is accomplished by | |
| 31 * calling the [serialize] method on each element. Some elements need special | |
| 32 * treatment, as their enclosing scope must also be serialized. | |
| 33 */ | |
| 34 class ScopeInformationVisitor extends ElementVisitor/* <void> */ { | |
| 35 // TODO(ahe): Include function parameters and local variables. | |
| 36 | |
| 37 final Compiler compiler; | |
| 38 final Element currentElement; | |
| 39 final int position; | |
| 40 final StringBuffer buffer = new StringBuffer(); | |
| 41 int indentationLevel = 0; | |
| 42 ClassElement currentClass; | |
| 43 | |
| 44 bool sortMembers = false; | |
| 45 | |
| 46 bool ignoreImports = false; | |
| 47 | |
| 48 ScopeInformationVisitor(this.compiler, this.currentElement, this.position); | |
| 49 | |
| 50 String get indentation => ' ' * indentationLevel; | |
| 51 | |
| 52 StringBuffer get indented => buffer..write(indentation); | |
| 53 | |
| 54 void visitElement(Element e) { | |
| 55 serialize(e, omitEnclosing: false); | |
| 56 } | |
| 57 | |
| 58 void visitLibraryElement(LibraryElement e, _) { | |
| 59 bool isFirst = true; | |
| 60 forEach(Element member) { | |
| 61 if (!isFirst) { | |
| 62 buffer.write(','); | |
| 63 } | |
| 64 buffer.write('\n'); | |
| 65 indented; | |
| 66 serialize(member); | |
| 67 isFirst = false; | |
| 68 } | |
| 69 serialize( | |
| 70 e, | |
| 71 // TODO(ahe): We omit the import scope if there is no current | |
| 72 // class. That's wrong. | |
| 73 omitEnclosing: ignoreImports || currentClass == null, | |
| 74 name: e.libraryName, | |
| 75 serializeEnclosing: () { | |
| 76 // The enclosing scope of a library is a scope which contains all the | |
| 77 // imported names. | |
| 78 isFirst = true; | |
| 79 buffer.write('{\n'); | |
| 80 indentationLevel++; | |
| 81 indented.write('"kind": "imports",\n'); | |
| 82 indented.write('"members": ['); | |
| 83 indentationLevel++; | |
| 84 sortElements(importScope(e).importScope.values).forEach(forEach); | |
| 85 indentationLevel--; | |
| 86 buffer.write('\n'); | |
| 87 indented.write('],\n'); | |
| 88 // The enclosing scope of the imported names scope is the superclass | |
| 89 // scope of the current class. | |
| 90 indented.write('"enclosing": '); | |
| 91 serializeClassSide( | |
| 92 currentClass.superclass, isStatic: false, includeSuper: true); | |
| 93 buffer.write('\n'); | |
| 94 indentationLevel--; | |
| 95 indented.write('}'); | |
| 96 }, | |
| 97 serializeMembers: () { | |
| 98 isFirst = true; | |
| 99 sortElements(localScope(e).values).forEach(forEach); | |
| 100 }); | |
| 101 } | |
| 102 | |
| 103 void visitClassElement(ClassElement e, _) { | |
| 104 currentClass = e; | |
| 105 serializeClassSide(e, isStatic: true); | |
| 106 } | |
| 107 | |
| 108 /// Serializes one of the "sides" a class. The sides of a class are "instance | |
| 109 /// side" and "class side". These terms are from Smalltalk. The instance side | |
| 110 /// is all the local instance members of the class (the members of the | |
| 111 /// mixin), and the class side is the equivalent for static members and | |
| 112 /// constructors. | |
| 113 /// The scope chain is ordered so that the "class side" is searched before | |
| 114 /// the "instance side". | |
| 115 void serializeClassSide( | |
| 116 ClassElement e, | |
| 117 {bool isStatic: false, | |
| 118 bool omitEnclosing: false, | |
| 119 bool includeSuper: false}) { | |
| 120 e.ensureResolved(compiler.resolution); | |
| 121 bool isFirst = true; | |
| 122 var serializeEnclosing; | |
| 123 String kind; | |
| 124 if (isStatic) { | |
| 125 kind = 'class side'; | |
| 126 serializeEnclosing = () { | |
| 127 serializeClassSide(e, isStatic: false, omitEnclosing: omitEnclosing); | |
| 128 }; | |
| 129 } else { | |
| 130 kind = 'instance side'; | |
| 131 } | |
| 132 if (includeSuper) { | |
| 133 assert(!omitEnclosing && !isStatic); | |
| 134 if (e.superclass == null) { | |
| 135 omitEnclosing = true; | |
| 136 } else { | |
| 137 // Members of the superclass are represented as a separate scope. | |
| 138 serializeEnclosing = () { | |
| 139 serializeClassSide( | |
| 140 e.superclass, isStatic: false, omitEnclosing: false, | |
| 141 includeSuper: true); | |
| 142 }; | |
| 143 } | |
| 144 } | |
| 145 serialize( | |
| 146 e, omitEnclosing: omitEnclosing, serializeEnclosing: serializeEnclosing, | |
| 147 kind: kind, serializeMembers: () { | |
| 148 localMembersSorted(e).forEach((Element member) { | |
| 149 // Filter out members that don't belong to this "side". | |
| 150 if (member.isConstructor) { | |
| 151 // In dart2js, some constructors aren't static, but that isn't | |
| 152 // convenient here. | |
| 153 if (!isStatic) return; | |
| 154 } else if (member.isStatic != isStatic) { | |
| 155 return; | |
| 156 } | |
| 157 if (!isFirst) { | |
| 158 buffer.write(','); | |
| 159 } | |
| 160 buffer.write('\n'); | |
| 161 indented; | |
| 162 serialize(member); | |
| 163 isFirst = false; | |
| 164 }); | |
| 165 }); | |
| 166 } | |
| 167 | |
| 168 void visitScopeContainerElement(ScopeContainerElement e) { | |
| 169 bool isFirst = true; | |
| 170 serialize(e, omitEnclosing: false, serializeMembers: () { | |
| 171 localMembersSorted(e).forEach((Element member) { | |
| 172 if (!isFirst) { | |
| 173 buffer.write(','); | |
| 174 } | |
| 175 buffer.write('\n'); | |
| 176 indented; | |
| 177 serialize(member); | |
| 178 isFirst = false; | |
| 179 }); | |
| 180 }); | |
| 181 } | |
| 182 | |
| 183 void visitCompilationUnitElement(CompilationUnitElement e, _) { | |
| 184 e.library.accept(this, _); | |
| 185 } | |
| 186 | |
| 187 void visitAbstractFieldElement(AbstractFieldElement e, _) { | |
| 188 throw new UnsupportedError('AbstractFieldElement cannot be serialized.'); | |
| 189 } | |
| 190 | |
| 191 void serialize( | |
| 192 Element element, | |
| 193 {bool omitEnclosing: true, | |
| 194 void serializeMembers(), | |
| 195 void serializeEnclosing(), | |
| 196 String kind, | |
| 197 String name}) { | |
| 198 if (element.isAbstractField) { | |
| 199 AbstractFieldElement field = element; | |
| 200 FunctionElement getter = field.getter; | |
| 201 FunctionElement setter = field.setter; | |
| 202 if (getter != null) { | |
| 203 serialize( | |
| 204 getter, | |
| 205 omitEnclosing: omitEnclosing, | |
| 206 serializeMembers: serializeMembers, | |
| 207 serializeEnclosing: serializeEnclosing, | |
| 208 kind: kind, | |
| 209 name: name); | |
| 210 } | |
| 211 if (setter != null) { | |
| 212 if (getter != null) { | |
| 213 buffer.write(',\n'); | |
| 214 indented; | |
| 215 } | |
| 216 serialize( | |
| 217 getter, | |
| 218 omitEnclosing: omitEnclosing, | |
| 219 serializeMembers: serializeMembers, | |
| 220 serializeEnclosing: serializeEnclosing, | |
| 221 kind: kind, | |
| 222 name: name); | |
| 223 } | |
| 224 return; | |
| 225 } | |
| 226 DartType type; | |
| 227 int category = element.kind.category; | |
| 228 if (category == ElementCategory.FUNCTION || | |
| 229 category == ElementCategory.VARIABLE || | |
| 230 element.isConstructor) { | |
| 231 type = (element as MemberElement).type; | |
| 232 } | |
| 233 if (name == null) { | |
| 234 name = element.name; | |
| 235 } | |
| 236 if (kind == null) { | |
| 237 kind = '${element.kind}'; | |
| 238 } | |
| 239 buffer.write('{\n'); | |
| 240 indentationLevel++; | |
| 241 if (name != '') { | |
| 242 indented | |
| 243 ..write('"name": "') | |
| 244 ..write(name) | |
| 245 ..write('",\n'); | |
| 246 } | |
| 247 indented | |
| 248 ..write('"kind": "') | |
| 249 ..write(kind) | |
| 250 ..write('"'); | |
| 251 if (type != null) { | |
| 252 buffer.write(',\n'); | |
| 253 indented | |
| 254 ..write('"type": "') | |
| 255 ..write(type) | |
| 256 ..write('"'); | |
| 257 } | |
| 258 if (serializeMembers != null) { | |
| 259 buffer.write(',\n'); | |
| 260 indented.write('"members": ['); | |
| 261 indentationLevel++; | |
| 262 serializeMembers(); | |
| 263 indentationLevel--; | |
| 264 buffer.write('\n'); | |
| 265 indented.write(']'); | |
| 266 } | |
| 267 if (!omitEnclosing) { | |
| 268 buffer.write(',\n'); | |
| 269 indented.write('"enclosing": '); | |
| 270 if (serializeEnclosing != null) { | |
| 271 serializeEnclosing(); | |
| 272 } else { | |
| 273 element.enclosingElement.accept(this, null); | |
| 274 } | |
| 275 } | |
| 276 indentationLevel--; | |
| 277 buffer.write('\n'); | |
| 278 indented.write('}'); | |
| 279 } | |
| 280 | |
| 281 List<Element> localMembersSorted(ScopeContainerElement element) { | |
| 282 List<Element> result = <Element>[]; | |
| 283 element.forEachLocalMember((Element member) { | |
| 284 result.add(member); | |
| 285 }); | |
| 286 return sortElements(result); | |
| 287 } | |
| 288 | |
| 289 List<Element> sortElements(Iterable<Element> elements) { | |
| 290 List<Element> result = new List<Element>.from(elements); | |
| 291 if (sortMembers) { | |
| 292 result.sort((Element a, Element b) => a.name.compareTo(b.name)); | |
| 293 } | |
| 294 return result; | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 modelx.ScopeX localScope(modelx.LibraryElementX element) => element.localScope; | |
| 299 | |
| 300 modelx.ImportScope importScope(modelx.LibraryElementX element) { | |
| 301 return element.importScope; | |
| 302 } | |
| OLD | NEW |