| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 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 | 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 computer.element; | 5 library computer.element; |
| 6 | 6 |
| 7 import 'package:analysis_server/src/constants.dart'; | |
| 8 import 'package:analysis_server/src/protocol2.dart'; | 7 import 'package:analysis_server/src/protocol2.dart'; |
| 9 import 'package:analyzer/src/generated/element.dart' as engine; | 8 import 'package:analyzer/src/generated/element.dart' as engine; |
| 10 import 'package:analyzer/src/generated/source.dart'; | |
| 11 import 'package:analyzer/src/generated/utilities_dart.dart' as engine; | 9 import 'package:analyzer/src/generated/utilities_dart.dart' as engine; |
| 12 | 10 |
| 13 | 11 |
| 14 /** | 12 /** |
| 15 * Returns a JSON correponding to the given Engine element. | 13 * Returns a JSON correponding to the given Engine element. |
| 16 */ | 14 */ |
| 17 Map<String, Object> engineElementToJson(engine.Element element) { | 15 Map<String, Object> engineElementToJson(engine.Element element) { |
| 18 return new Element.fromEngine(element).toJson(); | 16 return new Element.fromEngine(element).toJson(); |
| 19 } | 17 } |
| 20 | 18 |
| 21 | 19 |
| 22 /** | 20 Element elementFromEngine(engine.Element element) { |
| 23 * Information about an element. | 21 String name = element.displayName; |
| 24 */ | 22 String elementParameters = _getParametersString(element); |
| 25 class Element { | 23 String elementReturnType = _getReturnTypeString(element); |
| 26 static const List<Element> EMPTY_ARRAY = const <Element>[]; | 24 return new Element( |
| 27 | 25 new ElementKind.fromEngine(element.kind), |
| 28 static const int FLAG_ABSTRACT = 0x01; | 26 name, |
| 29 static const int FLAG_CONST = 0x02; | 27 Element.makeFlags(isPrivate: element.isPrivate, |
| 30 static const int FLAG_FINAL = 0x04; | 28 isDeprecated: element.isDeprecated, |
| 31 static const int FLAG_STATIC = 0x08; | |
| 32 static const int FLAG_PRIVATE = 0x10; | |
| 33 static const int FLAG_DEPRECATED = 0x20; | |
| 34 | |
| 35 /** | |
| 36 * The kind of the element. | |
| 37 */ | |
| 38 final ElementKind kind; | |
| 39 | |
| 40 /** | |
| 41 * The name of the element. This is typically used as the label in the outline
. | |
| 42 */ | |
| 43 final String name; | |
| 44 | |
| 45 /** | |
| 46 * The location of the element. | |
| 47 */ | |
| 48 final Location location; | |
| 49 | |
| 50 /** | |
| 51 * The parameter list for the element. | |
| 52 * If the element is not a method or function then `null`. | |
| 53 * If the element has zero parameters, then `()`. | |
| 54 */ | |
| 55 final String parameters; | |
| 56 | |
| 57 /** | |
| 58 * The return type of the element. | |
| 59 * If the element is not a method or function then `null`. | |
| 60 * If the element does not have a declared return type, then an empty string. | |
| 61 */ | |
| 62 final String returnType; | |
| 63 | |
| 64 final bool isAbstract; | |
| 65 final bool isConst; | |
| 66 final bool isFinal; | |
| 67 final bool isStatic; | |
| 68 final bool isPrivate; | |
| 69 final bool isDeprecated; | |
| 70 | |
| 71 Element(this.kind, this.name, this.location, this.isPrivate, | |
| 72 this.isDeprecated, {this.parameters, this.returnType, this.isAbstract: fal
se, | |
| 73 this.isConst: false, this.isFinal: false, this.isStatic: false}); | |
| 74 | |
| 75 factory Element.fromEngine(engine.Element element) { | |
| 76 String name = element.displayName; | |
| 77 String elementParameters = _getParametersString(element); | |
| 78 String elementReturnType = _getReturnTypeString(element); | |
| 79 return new Element( | |
| 80 new ElementKind.fromEngine(element.kind), | |
| 81 name, | |
| 82 new Location.fromElement(element), | |
| 83 element.isPrivate, | |
| 84 element.isDeprecated, | |
| 85 parameters: elementParameters, | |
| 86 returnType: elementReturnType, | |
| 87 isAbstract: _isAbstract(element), | 29 isAbstract: _isAbstract(element), |
| 88 isConst: _isConst(element), | 30 isConst: _isConst(element), |
| 89 isFinal: _isFinal(element), | 31 isFinal: _isFinal(element), |
| 90 isStatic: _isStatic(element)); | 32 isStatic: _isStatic(element)), |
| 91 } | 33 location: new Location.fromElement(element), |
| 34 parameters: elementParameters, |
| 35 returnType: elementReturnType); |
| 36 } |
| 92 | 37 |
| 93 factory Element.fromJson(Map<String, Object> map) { | 38 String _getParametersString(engine.Element element) { |
| 94 ElementKind kind = new ElementKind(map[KIND]); | 39 // TODO(scheglov) expose the corresponding feature from ExecutableElement |
| 95 int flags = map[FLAGS]; | 40 if (element is engine.ExecutableElement) { |
| 96 return new Element( | 41 var sb = new StringBuffer(); |
| 97 kind, | 42 String closeOptionalString = ''; |
| 98 map[NAME], | 43 for (var parameter in element.parameters) { |
| 99 new Location.fromJson(map[LOCATION]), | 44 if (sb.isNotEmpty) { |
| 100 _hasFlag(flags, FLAG_PRIVATE), | 45 sb.write(', '); |
| 101 _hasFlag(flags, FLAG_DEPRECATED), | 46 } |
| 102 parameters: map[PARAMETERS], | 47 if (closeOptionalString.isEmpty) { |
| 103 returnType: map[RETURN_TYPE], | 48 if (parameter.kind == engine.ParameterKind.NAMED) { |
| 104 isAbstract: _hasFlag(flags, FLAG_ABSTRACT), | 49 sb.write('{'); |
| 105 isConst: _hasFlag(flags, FLAG_CONST), | 50 closeOptionalString = '}'; |
| 106 isFinal: _hasFlag(flags, FLAG_FINAL), | 51 } |
| 107 isStatic: _hasFlag(flags, FLAG_STATIC)); | 52 if (parameter.kind == engine.ParameterKind.POSITIONAL) { |
| 108 } | 53 sb.write('['); |
| 109 | 54 closeOptionalString = ']'; |
| 110 int get flags { | 55 } |
| 111 int flags = 0; | 56 } |
| 112 if (isAbstract) flags |= FLAG_ABSTRACT; | 57 sb.write(parameter.toString()); |
| 113 if (isConst) flags |= FLAG_CONST; | |
| 114 if (isFinal) flags |= FLAG_FINAL; | |
| 115 if (isStatic) flags |= FLAG_STATIC; | |
| 116 if (isPrivate) flags |= FLAG_PRIVATE; | |
| 117 if (isDeprecated) flags |= FLAG_DEPRECATED; | |
| 118 return flags; | |
| 119 } | |
| 120 | |
| 121 Map<String, Object> toJson() { | |
| 122 Map<String, Object> json = { | |
| 123 KIND: kind.name, | |
| 124 NAME: name, | |
| 125 LOCATION: location.toJson(), | |
| 126 FLAGS: flags | |
| 127 }; | |
| 128 if (parameters != null) { | |
| 129 json[PARAMETERS] = parameters; | |
| 130 } | 58 } |
| 131 if (returnType != null) { | 59 sb.write(closeOptionalString); |
| 132 json[RETURN_TYPE] = returnType; | 60 return '(' + sb.toString() + ')'; |
| 133 } | 61 } else { |
| 134 return json; | 62 return null; |
| 135 } | |
| 136 | |
| 137 @override | |
| 138 String toString() => toJson().toString(); | |
| 139 | |
| 140 static Map<String, Object> asJson(Element element) { | |
| 141 return element.toJson(); | |
| 142 } | |
| 143 | |
| 144 static String _getParametersString(engine.Element element) { | |
| 145 // TODO(scheglov) expose the corresponding feature from ExecutableElement | |
| 146 if (element is engine.ExecutableElement) { | |
| 147 var sb = new StringBuffer(); | |
| 148 String closeOptionalString = ''; | |
| 149 for (var parameter in element.parameters) { | |
| 150 if (sb.isNotEmpty) { | |
| 151 sb.write(', '); | |
| 152 } | |
| 153 if (closeOptionalString.isEmpty) { | |
| 154 if (parameter.kind == engine.ParameterKind.NAMED) { | |
| 155 sb.write('{'); | |
| 156 closeOptionalString = '}'; | |
| 157 } | |
| 158 if (parameter.kind == engine.ParameterKind.POSITIONAL) { | |
| 159 sb.write('['); | |
| 160 closeOptionalString = ']'; | |
| 161 } | |
| 162 } | |
| 163 sb.write(parameter.toString()); | |
| 164 } | |
| 165 sb.write(closeOptionalString); | |
| 166 return '(' + sb.toString() + ')'; | |
| 167 } else { | |
| 168 return null; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 static String _getReturnTypeString(engine.Element element) { | |
| 173 if ((element is engine.ExecutableElement)) { | |
| 174 return element.returnType.toString(); | |
| 175 } else { | |
| 176 return null; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 static bool _hasFlag(int flags, int flag) => (flags & flag) != 0; | |
| 181 | |
| 182 static bool _isAbstract(engine.Element element) { | |
| 183 // TODO(scheglov) add isAbstract to Element API | |
| 184 if (element is engine.ClassElement) { | |
| 185 return element.isAbstract; | |
| 186 } | |
| 187 if (element is engine.MethodElement) { | |
| 188 return element.isAbstract; | |
| 189 } | |
| 190 if (element is engine.PropertyAccessorElement) { | |
| 191 return element.isAbstract; | |
| 192 } | |
| 193 return false; | |
| 194 } | |
| 195 | |
| 196 static bool _isConst(engine.Element element) { | |
| 197 // TODO(scheglov) add isConst to Element API | |
| 198 if (element is engine.ConstructorElement) { | |
| 199 return element.isConst; | |
| 200 } | |
| 201 if (element is engine.VariableElement) { | |
| 202 return element.isConst; | |
| 203 } | |
| 204 return false; | |
| 205 } | |
| 206 | |
| 207 static bool _isFinal(engine.Element element) { | |
| 208 // TODO(scheglov) add isFinal to Element API | |
| 209 if (element is engine.VariableElement) { | |
| 210 return element.isFinal; | |
| 211 } | |
| 212 return false; | |
| 213 } | |
| 214 | |
| 215 static bool _isStatic(engine.Element element) { | |
| 216 // TODO(scheglov) add isStatic to Element API | |
| 217 if (element is engine.ExecutableElement) { | |
| 218 return element.isStatic; | |
| 219 } | |
| 220 if (element is engine.PropertyInducingElement) { | |
| 221 return element.isStatic; | |
| 222 } | |
| 223 return false; | |
| 224 } | 63 } |
| 225 } | 64 } |
| 226 | 65 |
| 227 | 66 String _getReturnTypeString(engine.Element element) { |
| 228 /** | 67 if ((element is engine.ExecutableElement)) { |
| 229 * Information about a location. | 68 return element.returnType.toString(); |
| 230 */ | 69 } else { |
| 231 class Location { | 70 return null; |
| 232 final String file; | |
| 233 final int offset; | |
| 234 final int length; | |
| 235 final int startLine; | |
| 236 final int startColumn; | |
| 237 | |
| 238 Location(this.file, this.offset, this.length, this.startLine, | |
| 239 this.startColumn); | |
| 240 | |
| 241 factory Location.fromElement(engine.Element element) { | |
| 242 Source source = element.source; | |
| 243 LineInfo lineInfo = element.context.getLineInfo(source); | |
| 244 String name = element.displayName; | |
| 245 // prepare location | |
| 246 int offset = element.nameOffset; | |
| 247 int length = name != null ? name.length : 0; | |
| 248 LineInfo_Location lineLocation = lineInfo.getLocation(offset); | |
| 249 int startLine = lineLocation.lineNumber; | |
| 250 int startColumn = lineLocation.columnNumber; | |
| 251 if (element is engine.CompilationUnitElement) { | |
| 252 offset = 0; | |
| 253 length = 0; | |
| 254 startLine = 1; | |
| 255 startColumn = 1; | |
| 256 } | |
| 257 // done | |
| 258 return new Location( | |
| 259 source.fullName, | |
| 260 offset, | |
| 261 length, | |
| 262 startLine, | |
| 263 startColumn); | |
| 264 } | |
| 265 | |
| 266 factory Location.fromJson(Map<String, Object> map) { | |
| 267 return new Location( | |
| 268 map[FILE], | |
| 269 map[OFFSET], | |
| 270 map[LENGTH], | |
| 271 map[START_LINE], | |
| 272 map[START_COLUMN]); | |
| 273 } | |
| 274 | |
| 275 factory Location.fromOffset(engine.Element element, int offset, int length) { | |
| 276 Source source = element.source; | |
| 277 LineInfo lineInfo = element.context.getLineInfo(source); | |
| 278 // prepare location | |
| 279 LineInfo_Location lineLocation = lineInfo.getLocation(offset); | |
| 280 int startLine = lineLocation.lineNumber; | |
| 281 int startColumn = lineLocation.columnNumber; | |
| 282 // done | |
| 283 return new Location( | |
| 284 source.fullName, | |
| 285 offset, | |
| 286 length, | |
| 287 startLine, | |
| 288 startColumn); | |
| 289 } | |
| 290 | |
| 291 Map<String, Object> toJson() { | |
| 292 return { | |
| 293 FILE: file, | |
| 294 OFFSET: offset, | |
| 295 LENGTH: length, | |
| 296 START_LINE: startLine, | |
| 297 START_COLUMN: startColumn | |
| 298 }; | |
| 299 } | |
| 300 | |
| 301 @override | |
| 302 String toString() { | |
| 303 return 'Location(file=$file; offset=$offset; length=$length; ' | |
| 304 'startLine=$startLine; startColumn=$startColumn)'; | |
| 305 } | 71 } |
| 306 } | 72 } |
| 73 |
| 74 bool _isAbstract(engine.Element element) { |
| 75 // TODO(scheglov) add isAbstract to Element API |
| 76 if (element is engine.ClassElement) { |
| 77 return element.isAbstract; |
| 78 } |
| 79 if (element is engine.MethodElement) { |
| 80 return element.isAbstract; |
| 81 } |
| 82 if (element is engine.PropertyAccessorElement) { |
| 83 return element.isAbstract; |
| 84 } |
| 85 return false; |
| 86 } |
| 87 |
| 88 bool _isConst(engine.Element element) { |
| 89 // TODO(scheglov) add isConst to Element API |
| 90 if (element is engine.ConstructorElement) { |
| 91 return element.isConst; |
| 92 } |
| 93 if (element is engine.VariableElement) { |
| 94 return element.isConst; |
| 95 } |
| 96 return false; |
| 97 } |
| 98 |
| 99 bool _isFinal(engine.Element element) { |
| 100 // TODO(scheglov) add isFinal to Element API |
| 101 if (element is engine.VariableElement) { |
| 102 return element.isFinal; |
| 103 } |
| 104 return false; |
| 105 } |
| 106 |
| 107 bool _isStatic(engine.Element element) { |
| 108 // TODO(scheglov) add isStatic to Element API |
| 109 if (element is engine.ExecutableElement) { |
| 110 return element.isStatic; |
| 111 } |
| 112 if (element is engine.PropertyInducingElement) { |
| 113 return element.isStatic; |
| 114 } |
| 115 return false; |
| 116 } |
| OLD | NEW |