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