Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, 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 serialization.summarize_ast; | |
| 6 | |
| 7 import 'package:analyzer/analyzer.dart'; | |
| 8 import 'package:analyzer/src/generated/ast.dart'; | |
|
Brian Wilkerson
2016/01/19 17:53:44
nit: After this weekend, this library is now empty
Paul Berry
2016/01/19 18:21:48
Done.
| |
| 9 import 'package:analyzer/src/generated/scanner.dart'; | |
| 10 import 'package:analyzer/src/summary/format.dart'; | |
| 11 import 'package:analyzer/src/summary/public_namespace_computer.dart'; | |
| 12 | |
| 13 /** | |
| 14 * Serialize all the declarations in [compilationUnit] to an unlinked summary. | |
| 15 */ | |
| 16 UnlinkedUnitBuilder serializeAstUnlinked(CompilationUnit compilationUnit) { | |
| 17 return new _SummarizeAstVisitor().serializeCompilationUnit(compilationUnit); | |
| 18 } | |
| 19 | |
| 20 /** | |
| 21 * An [_OtherScopedEntity] is a [_ScopedEntity] that does not refer to a type | |
| 22 * parameter. Since we don't need to track any special information about these | |
| 23 * types of scoped entities, it is a singleton class. | |
| 24 */ | |
| 25 class _OtherScopedEntity extends _ScopedEntity { | |
| 26 static final _OtherScopedEntity _instance = new _OtherScopedEntity._(); | |
| 27 | |
| 28 factory _OtherScopedEntity() => _instance; | |
| 29 | |
| 30 _OtherScopedEntity._(); | |
| 31 } | |
| 32 | |
| 33 /** | |
| 34 * A [_Scope] represents a set of name/value pairs defined locally within a | |
| 35 * limited span of a compilation unit. (Note that the spec also uses the term | |
| 36 * "scope" to refer to the set of names defined at top level within a | |
| 37 * compilation unit, but we do not use [_Scope] for that purpose). | |
| 38 */ | |
| 39 class _Scope { | |
| 40 /** | |
| 41 * Names defined in this scope, and their meanings. | |
| 42 */ | |
| 43 Map<String, _ScopedEntity> _definedNames = <String, _ScopedEntity>{}; | |
| 44 | |
| 45 /** | |
| 46 * Look up the meaning associated with the given [name], and return it. If | |
| 47 * [name] is not defined in this scope, return `null`. | |
| 48 */ | |
| 49 _ScopedEntity operator [](String name) => _definedNames[name]; | |
| 50 | |
| 51 /** | |
| 52 * Let the given [name] refer to [entity] within this scope. | |
| 53 */ | |
| 54 void operator []=(String name, _ScopedEntity entity) { | |
| 55 _definedNames[name] = entity; | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 /** | |
| 60 * Base class for entities that can live inside a scope. | |
| 61 */ | |
| 62 abstract class _ScopedEntity {} | |
| 63 | |
| 64 /** | |
| 65 * A [_ScopedTypeParameter] is a [_ScopedEntity] that refers to a type | |
| 66 * parameter of a class, typedef, or executable. | |
| 67 */ | |
| 68 class _ScopedTypeParameter extends _ScopedEntity { | |
| 69 /** | |
| 70 * Index of the type parameter within this scope. Since summaries use De | |
| 71 * Bruijn indices to refer to type parameters, which count upwards from the | |
| 72 * innermost bound name, the last type parameter in the scope has an index of | |
| 73 * 1, and each preceding type parameter has the next higher index. | |
| 74 */ | |
| 75 final int index; | |
| 76 | |
| 77 _ScopedTypeParameter(this.index); | |
| 78 } | |
| 79 | |
| 80 /** | |
| 81 * Visitor used to create a summary from an AST. | |
| 82 */ | |
| 83 class _SummarizeAstVisitor extends SimpleAstVisitor { | |
| 84 /** | |
| 85 * List of objects which should be written to [UnlinkedUnit.classes]. | |
| 86 */ | |
| 87 final List<UnlinkedClassBuilder> classes = <UnlinkedClassBuilder>[]; | |
| 88 | |
| 89 /** | |
| 90 * List of objects which should be written to [UnlinkedUnit.enums]. | |
| 91 */ | |
| 92 final List<UnlinkedEnumBuilder> enums = <UnlinkedEnumBuilder>[]; | |
| 93 | |
| 94 /** | |
| 95 * List of objects which should be written to [UnlinkedUnit.executables] | |
| 96 * or [UnlinkedClass.executables]. | |
| 97 */ | |
| 98 List<UnlinkedExecutableBuilder> executables = <UnlinkedExecutableBuilder>[]; | |
|
Brian Wilkerson
2016/01/19 17:53:44
Seems strange that some lists are 'final' and some
Paul Berry
2016/01/19 18:21:48
`setters` and `variables` were the only lists that
| |
| 99 | |
| 100 /** | |
| 101 * List of objects which should be written to [UnlinkedUnit.exports]. | |
| 102 */ | |
| 103 List<UnlinkedExportNonPublicBuilder> exports = | |
| 104 <UnlinkedExportNonPublicBuilder>[]; | |
| 105 | |
| 106 /** | |
| 107 * List of objects which should be written to [UnlinkedUnit.parts]. | |
| 108 */ | |
| 109 List<UnlinkedPartBuilder> parts = <UnlinkedPartBuilder>[]; | |
| 110 | |
| 111 /** | |
| 112 * List of objects which should be written to [UnlinkedUnit.typedefs]. | |
| 113 */ | |
| 114 final List<UnlinkedTypedefBuilder> typedefs = <UnlinkedTypedefBuilder>[]; | |
| 115 | |
| 116 /** | |
| 117 * List of objects which should be written to [UnlinkedUnit.variables] or | |
| 118 * [UnlinkedClass.fields]. | |
| 119 */ | |
| 120 List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[]; | |
| 121 | |
| 122 /** | |
| 123 * The unlinked portion of the "imports table". This is the list of objects | |
| 124 * which should be written to [UnlinkedUnit.imports]. | |
| 125 */ | |
| 126 final List<UnlinkedImportBuilder> unlinkedImports = <UnlinkedImportBuilder>[]; | |
| 127 | |
| 128 /** | |
| 129 * The unlinked portion of the "references table". This is the list of | |
| 130 * objects which should be written to [UnlinkedUnit.references]. | |
| 131 */ | |
| 132 final List<UnlinkedReferenceBuilder> unlinkedReferences = | |
| 133 <UnlinkedReferenceBuilder>[new UnlinkedReferenceBuilder()]; | |
| 134 | |
| 135 /** | |
| 136 * The [ClassDeclaration] currently being summarized, or `null` if we are not | |
| 137 * currently visiting a [ClassDeclaration]. | |
| 138 */ | |
| 139 ClassDeclaration currentClassDeclaration; | |
| 140 | |
| 141 /** | |
| 142 * Map associating names used as prefixes in this compilation unit with their | |
| 143 * associated indices into [UnlinkedUnit.references]. | |
| 144 */ | |
| 145 final Map<String, int> prefixIndices = <String, int>{}; | |
| 146 | |
| 147 /** | |
| 148 * List of [_Scope]s currently in effect. This is used to resolve type names | |
| 149 * to type parameters within classes, typedefs, and executables. | |
| 150 */ | |
| 151 final List<_Scope> scopes = <_Scope>[]; | |
| 152 | |
| 153 /** | |
| 154 * True if 'dart:core' has been explicitly imported. | |
| 155 */ | |
| 156 bool hasCoreBeenImported = false; | |
| 157 | |
| 158 /** | |
| 159 * Names referenced by this compilation unit. Structured as a map from | |
| 160 * prefix index to (map from name to reference table index), where "prefix | |
| 161 * index" means the index into [UnlinkedUnit.references] of the prefix (or | |
| 162 * `null` if there is no prefix), and "reference table index" means the index | |
| 163 * into [UnlinkedUnit.references] for the name itself. | |
| 164 */ | |
| 165 final Map<int, Map<String, int>> nameToReference = <int, Map<String, int>>{}; | |
| 166 | |
| 167 /** | |
| 168 * If the library has a library directive, the library name derived from it. | |
| 169 * Otherwise `null`. | |
| 170 */ | |
| 171 String libraryName; | |
| 172 | |
| 173 /** | |
| 174 * If the library has a library directive, the offset of the library name. | |
| 175 * Otherwise `null`. | |
| 176 */ | |
| 177 int libraryNameOffset; | |
| 178 | |
| 179 /** | |
| 180 * If the library has a library directive, the length of the library name, as | |
| 181 * it appears in the source file. Otherwise `null`. | |
| 182 */ | |
| 183 int libraryNameLength; | |
| 184 | |
| 185 /** | |
| 186 * If the library has a library directive, the documentation comment for it | |
| 187 * (if any). Othrwise `null`. | |
| 188 */ | |
| 189 UnlinkedDocumentationCommentBuilder libraryDocumentationComment; | |
| 190 | |
| 191 /** | |
| 192 * Build a [_Scope] object containing the names defined within the body of a | |
| 193 * class declaration. | |
| 194 */ | |
| 195 _Scope buildClassMemberScope(NodeList<ClassMember> members) { | |
| 196 _Scope scope = new _Scope(); | |
| 197 for (ClassMember member in members) { | |
| 198 // TODO(paulbery): consider replacing these if-tests with dynamic method | |
| 199 // dispatch. | |
| 200 if (member is MethodDeclaration) { | |
| 201 if (member.isSetter || member.isOperator) { | |
| 202 // We don't have to handle setters or operators because the only | |
| 203 // thing we look up is type names. | |
| 204 } else { | |
| 205 scope[member.name.name] = new _OtherScopedEntity(); | |
| 206 } | |
| 207 } else if (member is FieldDeclaration) { | |
| 208 for (VariableDeclaration field in member.fields.variables) { | |
| 209 // A field declaration introduces two names, one with a trailing `=`. | |
| 210 // We don't have to worry about the one with a trailing `=` because | |
| 211 // the only thing we look up is type names. | |
| 212 scope[field.name.name] = new _OtherScopedEntity(); | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 return scope; | |
| 217 } | |
| 218 | |
| 219 /** | |
| 220 * Try to find a field with the given [name] in the current class declaration | |
| 221 * and return its type. If no field is found, or there isn't a current | |
| 222 * class declaration, return null. | |
| 223 */ | |
| 224 TypeName getFieldType(String name) { | |
| 225 if (currentClassDeclaration == null) { | |
| 226 return null; | |
| 227 } | |
| 228 for (ClassMember member in currentClassDeclaration.members) { | |
| 229 if (member is FieldDeclaration) { | |
| 230 for (VariableDeclaration variable in member.fields.variables) { | |
| 231 if (variable.name.name == name) { | |
| 232 return member.fields.type; | |
| 233 } | |
| 234 } | |
| 235 } | |
| 236 } | |
| 237 return null; | |
| 238 } | |
| 239 | |
| 240 /** | |
| 241 * Serialize a [ClassDeclaration] or [ClassTypeAlias] into an [UnlinkedClass] | |
| 242 * and store the result in [classes]. | |
| 243 */ | |
| 244 void serializeClass( | |
| 245 Token abstractKeyword, | |
| 246 String name, | |
| 247 int nameOffset, | |
| 248 TypeParameterList typeParameters, | |
| 249 TypeName superclass, | |
| 250 WithClause withClause, | |
| 251 ImplementsClause implementsClause, | |
| 252 NodeList<ClassMember> members, | |
| 253 bool isMixinApplication, | |
| 254 Comment documentationComment) { | |
| 255 int oldScopesLength = scopes.length; | |
| 256 List<UnlinkedExecutableBuilder> oldExecutables = executables; | |
| 257 executables = <UnlinkedExecutableBuilder>[]; | |
| 258 List<UnlinkedVariableBuilder> oldVariables = variables; | |
| 259 variables = <UnlinkedVariableBuilder>[]; | |
| 260 _TypeParameterScope typeParameterScope = new _TypeParameterScope(); | |
| 261 scopes.add(typeParameterScope); | |
| 262 UnlinkedClassBuilder b = new UnlinkedClassBuilder(); | |
| 263 b.name = name; | |
| 264 b.nameOffset = nameOffset; | |
| 265 b.isMixinApplication = isMixinApplication; | |
| 266 b.typeParameters = | |
| 267 serializeTypeParameters(typeParameters, typeParameterScope); | |
| 268 if (superclass != null) { | |
| 269 b.supertype = serializeTypeName(superclass); | |
| 270 } | |
| 271 if (withClause != null) { | |
| 272 b.mixins = withClause.mixinTypes.map(serializeTypeName).toList(); | |
| 273 } | |
| 274 if (implementsClause != null) { | |
| 275 b.interfaces = | |
| 276 implementsClause.interfaces.map(serializeTypeName).toList(); | |
| 277 } | |
| 278 if (members != null) { | |
| 279 scopes.add(buildClassMemberScope(members)); | |
| 280 for (ClassMember member in members) { | |
| 281 member.accept(this); | |
| 282 } | |
| 283 scopes.removeLast(); | |
| 284 } | |
| 285 b.executables = executables; | |
| 286 b.fields = variables; | |
| 287 b.isAbstract = abstractKeyword != null; | |
| 288 b.documentationComment = serializeDocumentation(documentationComment); | |
| 289 classes.add(b); | |
| 290 scopes.removeLast(); | |
| 291 assert(scopes.length == oldScopesLength); | |
| 292 executables = oldExecutables; | |
| 293 variables = oldVariables; | |
| 294 } | |
| 295 | |
| 296 /** | |
| 297 * Serialize a [Combinator] into an [UnlinkedCombinator]. | |
| 298 */ | |
| 299 UnlinkedCombinatorBuilder serializeCombinator(Combinator combinator) { | |
| 300 UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder(); | |
| 301 if (combinator is ShowCombinator) { | |
| 302 b.shows = | |
| 303 combinator.shownNames.map((SimpleIdentifier id) => id.name).toList(); | |
| 304 } else if (combinator is HideCombinator) { | |
| 305 b.hides = | |
| 306 combinator.hiddenNames.map((SimpleIdentifier id) => id.name).toList(); | |
| 307 } else { | |
| 308 throw new StateError( | |
| 309 'Unexpected combinator type: ${combinator.runtimeType}'); | |
| 310 } | |
| 311 return b; | |
| 312 } | |
| 313 | |
| 314 /** | |
| 315 * Main entry point for serializing an AST. | |
| 316 */ | |
| 317 UnlinkedUnitBuilder serializeCompilationUnit( | |
| 318 CompilationUnit compilationUnit) { | |
| 319 compilationUnit.directives.accept(this); | |
| 320 if (!hasCoreBeenImported) { | |
| 321 unlinkedImports.add(new UnlinkedImportBuilder(isImplicit: true)); | |
| 322 } | |
| 323 compilationUnit.declarations.accept(this); | |
| 324 UnlinkedUnitBuilder b = new UnlinkedUnitBuilder(); | |
| 325 b.libraryName = libraryName; | |
| 326 b.libraryNameOffset = libraryNameOffset; | |
| 327 b.libraryNameLength = libraryNameLength; | |
| 328 b.libraryDocumentationComment = libraryDocumentationComment; | |
| 329 b.classes = classes; | |
| 330 b.enums = enums; | |
| 331 b.executables = executables; | |
| 332 b.exports = exports; | |
| 333 b.imports = unlinkedImports; | |
| 334 b.parts = parts; | |
| 335 b.references = unlinkedReferences; | |
| 336 b.typedefs = typedefs; | |
| 337 b.variables = variables; | |
| 338 b.publicNamespace = computePublicNamespace(compilationUnit); | |
| 339 return b; | |
| 340 } | |
| 341 | |
| 342 /** | |
| 343 * Serialize a [Comment] node into an [UnlinkedDocumentationComment] object. | |
| 344 */ | |
| 345 UnlinkedDocumentationCommentBuilder serializeDocumentation( | |
| 346 Comment documentationComment) { | |
| 347 if (documentationComment == null) { | |
| 348 return null; | |
| 349 } | |
| 350 String text = documentationComment.tokens | |
| 351 .map((Token t) => t.toString()) | |
| 352 .join() | |
| 353 .replaceAll('\r\n', '\n'); | |
| 354 return new UnlinkedDocumentationCommentBuilder( | |
| 355 text: text, | |
| 356 offset: documentationComment.offset, | |
| 357 length: documentationComment.length); | |
| 358 } | |
| 359 | |
| 360 /** | |
| 361 * Serialize a [FunctionDeclaration] or [MethodDeclaration] into an | |
| 362 * [UnlinkedExecutable]. | |
| 363 */ | |
| 364 UnlinkedExecutableBuilder serializeExecutable( | |
| 365 SimpleIdentifier name, | |
| 366 bool isGetter, | |
| 367 bool isSetter, | |
| 368 TypeName returnType, | |
| 369 FormalParameterList formalParameters, | |
| 370 FunctionBody body, | |
| 371 bool isTopLevel, | |
| 372 bool isStatic, | |
| 373 Comment documentationComment, | |
| 374 TypeParameterList typeParameters, | |
| 375 bool isExternal) { | |
| 376 int oldScopesLength = scopes.length; | |
| 377 _TypeParameterScope typeParameterScope = new _TypeParameterScope(); | |
| 378 scopes.add(typeParameterScope); | |
| 379 UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(); | |
| 380 String nameString = name.name; | |
| 381 if (isGetter) { | |
| 382 b.kind = UnlinkedExecutableKind.getter; | |
| 383 } else if (isSetter) { | |
| 384 b.kind = UnlinkedExecutableKind.setter; | |
| 385 nameString = '$nameString='; | |
| 386 } else { | |
| 387 b.kind = UnlinkedExecutableKind.functionOrMethod; | |
| 388 } | |
| 389 b.isAbstract = body is EmptyFunctionBody; | |
| 390 b.name = nameString; | |
| 391 b.nameOffset = name.offset; | |
| 392 b.typeParameters = | |
| 393 serializeTypeParameters(typeParameters, typeParameterScope); | |
| 394 if (!isTopLevel) { | |
| 395 b.isStatic = isStatic; | |
| 396 } | |
| 397 b.returnType = serializeTypeName(returnType, allowVoid: true); | |
| 398 b.hasImplicitReturnType = returnType == null; | |
| 399 b.isExternal = isExternal; | |
| 400 if (formalParameters != null) { | |
| 401 b.parameters = formalParameters.parameters | |
| 402 .map((FormalParameter p) => p.accept(this)) | |
| 403 .toList(); | |
| 404 } | |
| 405 b.documentationComment = serializeDocumentation(documentationComment); | |
| 406 scopes.removeLast(); | |
| 407 assert(scopes.length == oldScopesLength); | |
| 408 return b; | |
| 409 } | |
| 410 | |
| 411 /** | |
| 412 * Serialize the return type and parameters of a function-typed formal | |
| 413 * parameter and store them in [b]. | |
| 414 */ | |
| 415 void serializeFunctionTypedParameterDetails(UnlinkedParamBuilder b, | |
| 416 TypeName returnType, FormalParameterList parameters) { | |
| 417 UnlinkedTypeRefBuilder serializedReturnType = | |
| 418 serializeTypeName(returnType, allowVoid: true); | |
| 419 if (serializedReturnType != null) { | |
| 420 b.type = serializedReturnType; | |
| 421 } | |
| 422 b.parameters = parameters.parameters | |
| 423 .map((FormalParameter p) => p.accept(this)) | |
| 424 .toList(); | |
| 425 } | |
| 426 | |
| 427 /** | |
| 428 * Serialize a [FieldFormalParameter], [FunctionTypedFormalParameter], or | |
| 429 * [SimpleFormalParameter] into an [UnlinkedParam]. | |
| 430 */ | |
| 431 UnlinkedParamBuilder serializeParameter(NormalFormalParameter node) { | |
| 432 UnlinkedParamBuilder b = new UnlinkedParamBuilder(); | |
| 433 b.name = node.identifier.name; | |
| 434 b.nameOffset = node.identifier.offset; | |
| 435 switch (node.kind) { | |
| 436 case ParameterKind.REQUIRED: | |
| 437 b.kind = UnlinkedParamKind.required; | |
| 438 break; | |
| 439 case ParameterKind.POSITIONAL: | |
| 440 b.kind = UnlinkedParamKind.positional; | |
| 441 break; | |
| 442 case ParameterKind.NAMED: | |
| 443 b.kind = UnlinkedParamKind.named; | |
| 444 break; | |
| 445 default: | |
| 446 throw new StateError('Unexpected parameter kind: ${node.kind}'); | |
| 447 } | |
| 448 return b; | |
| 449 } | |
| 450 | |
| 451 /** | |
| 452 * Serialize a reference to a top level name declared elsewhere, by adding an | |
| 453 * entry to the references table if necessary. If [prefixIndex] is not null, | |
| 454 * the reference is associated with the prefix having the given index in the | |
| 455 * references table. | |
| 456 */ | |
| 457 int serializeReference(int prefixIndex, String name) => nameToReference | |
| 458 .putIfAbsent(prefixIndex, () => <String, int>{}) | |
| 459 .putIfAbsent(name, () { | |
| 460 assert(name != 'dynamic'); | |
| 461 int index = unlinkedReferences.length; | |
| 462 unlinkedReferences.add(new UnlinkedReferenceBuilder( | |
| 463 prefixReference: prefixIndex, name: name)); | |
| 464 return index; | |
| 465 }); | |
| 466 | |
| 467 /** | |
| 468 * Serialize a type name (which might be defined in a nested scope, at top | |
| 469 * level within this library, or at top level within an imported library) to | |
| 470 * an [UnlinkedTypeRef]. Note that this method does the right thing if the | |
| 471 * name doesn't refer to an entity other than a type (e.g. a class member). | |
| 472 */ | |
| 473 UnlinkedTypeRefBuilder serializeTypeName(TypeName node, | |
| 474 {bool allowVoid: false}) { | |
| 475 UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder(); | |
| 476 if (node != null) { | |
| 477 Identifier identifier = node.name; | |
| 478 if (identifier is SimpleIdentifier) { | |
| 479 String name = identifier.name; | |
| 480 int indexOffset = 0; | |
| 481 for (int i = scopes.length - 1; i >= 0; i--) { | |
| 482 _Scope scope = scopes[i]; | |
| 483 _ScopedEntity entity = scope[name]; | |
| 484 if (entity != null) { | |
| 485 if (entity is _ScopedTypeParameter) { | |
| 486 b.paramReference = indexOffset + entity.index; | |
| 487 return b; | |
| 488 } else { | |
| 489 // None of the other things that can be declared in local scopes | |
| 490 // are types, so this is an error and should be treated as a | |
| 491 // reference to `dynamic`. | |
| 492 return b; | |
| 493 } | |
| 494 } | |
| 495 if (scope is _TypeParameterScope) { | |
| 496 indexOffset += scope.length; | |
| 497 } | |
| 498 } | |
| 499 if (allowVoid && name == 'void') { | |
| 500 return null; | |
| 501 } | |
| 502 if (name != 'dynamic') { | |
| 503 b.reference = serializeReference(null, name); | |
| 504 } | |
| 505 } else if (identifier is PrefixedIdentifier) { | |
| 506 int prefixIndex = prefixIndices.putIfAbsent(identifier.prefix.name, | |
| 507 () => serializeReference(null, identifier.prefix.name)); | |
| 508 b.reference = | |
| 509 serializeReference(prefixIndex, identifier.identifier.name); | |
| 510 } else { | |
| 511 throw new StateError( | |
| 512 'Unexpected identifier type: ${identifier.runtimeType}'); | |
| 513 } | |
| 514 if (node.typeArguments != null && | |
| 515 node.typeArguments.arguments.any(isNotDynamic)) { | |
| 516 b.typeArguments = | |
| 517 node.typeArguments.arguments.map(serializeTypeName).toList(); | |
| 518 } | |
| 519 } | |
| 520 return b; | |
| 521 } | |
| 522 | |
| 523 /** | |
| 524 * Serialize the given [typeParameters] into a list of [UnlinkedTypeParam]s, | |
| 525 * and also store them in [typeParameterScope]. | |
| 526 */ | |
| 527 List<UnlinkedTypeParamBuilder> serializeTypeParameters( | |
| 528 TypeParameterList typeParameters, | |
| 529 _TypeParameterScope typeParameterScope) { | |
| 530 if (typeParameters != null) { | |
| 531 for (int i = 0; i < typeParameters.typeParameters.length; i++) { | |
| 532 TypeParameter typeParameter = typeParameters.typeParameters[i]; | |
| 533 typeParameterScope[typeParameter.name.name] = | |
| 534 new _ScopedTypeParameter(typeParameters.typeParameters.length - i); | |
| 535 } | |
| 536 return typeParameters.typeParameters.map(visitTypeParameter).toList(); | |
| 537 } | |
| 538 return const <UnlinkedTypeParamBuilder>[]; | |
| 539 } | |
| 540 | |
| 541 /** | |
| 542 * Serialize the given [variables] into [UnlinkedVariable]s, and store them | |
| 543 * in [this.variables]. | |
| 544 */ | |
| 545 void serializeVariables(VariableDeclarationList variables, bool isStatic, | |
| 546 Comment documentationComment) { | |
| 547 for (VariableDeclaration variable in variables.variables) { | |
| 548 UnlinkedVariableBuilder b = new UnlinkedVariableBuilder(); | |
| 549 b.isFinal = variables.isFinal; | |
| 550 b.isConst = variables.isConst; | |
| 551 b.isStatic = isStatic; | |
| 552 b.name = variable.name.name; | |
| 553 b.nameOffset = variable.name.offset; | |
| 554 b.type = serializeTypeName(variables.type); | |
| 555 b.hasImplicitType = variables.type == null; | |
| 556 b.documentationComment = serializeDocumentation(documentationComment); | |
| 557 this.variables.add(b); | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 @override | |
| 562 void visitClassDeclaration(ClassDeclaration node) { | |
| 563 currentClassDeclaration = node; | |
| 564 TypeName superclass = | |
| 565 node.extendsClause == null ? null : node.extendsClause.superclass; | |
| 566 serializeClass( | |
| 567 node.abstractKeyword, | |
| 568 node.name.name, | |
| 569 node.name.offset, | |
| 570 node.typeParameters, | |
| 571 superclass, | |
| 572 node.withClause, | |
| 573 node.implementsClause, | |
| 574 node.members, | |
| 575 false, | |
| 576 node.documentationComment); | |
| 577 currentClassDeclaration = null; | |
| 578 } | |
| 579 | |
| 580 @override | |
| 581 void visitClassTypeAlias(ClassTypeAlias node) { | |
| 582 serializeClass( | |
| 583 node.abstractKeyword, | |
| 584 node.name.name, | |
| 585 node.name.offset, | |
| 586 node.typeParameters, | |
| 587 node.superclass, | |
| 588 node.withClause, | |
| 589 node.implementsClause, | |
| 590 null, | |
| 591 true, | |
| 592 node.documentationComment); | |
| 593 } | |
| 594 | |
| 595 @override | |
| 596 void visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 597 UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder(); | |
| 598 if (node.name != null) { | |
| 599 b.name = node.name.name; | |
| 600 b.nameOffset = node.name.offset; | |
| 601 } else { | |
| 602 b.nameOffset = node.returnType.offset; | |
| 603 } | |
| 604 b.parameters = node.parameters.parameters | |
| 605 .map((FormalParameter p) => p.accept(this)) | |
| 606 .toList(); | |
| 607 b.kind = UnlinkedExecutableKind.constructor; | |
| 608 b.isFactory = node.factoryKeyword != null; | |
| 609 b.isConst = node.constKeyword != null; | |
| 610 b.isExternal = node.externalKeyword != null; | |
| 611 b.documentationComment = serializeDocumentation(node.documentationComment); | |
| 612 executables.add(b); | |
| 613 } | |
| 614 | |
| 615 @override | |
| 616 UnlinkedParamBuilder visitDefaultFormalParameter( | |
| 617 DefaultFormalParameter node) { | |
| 618 return node.parameter.accept(this); | |
| 619 } | |
| 620 | |
| 621 @override | |
| 622 void visitEnumDeclaration(EnumDeclaration node) { | |
| 623 UnlinkedEnumBuilder b = new UnlinkedEnumBuilder(); | |
| 624 b.name = node.name.name; | |
| 625 b.nameOffset = node.name.offset; | |
| 626 b.values = node.constants | |
| 627 .map((EnumConstantDeclaration value) => new UnlinkedEnumValueBuilder( | |
| 628 name: value.name.name, nameOffset: value.name.offset)) | |
| 629 .toList(); | |
| 630 b.documentationComment = serializeDocumentation(node.documentationComment); | |
| 631 enums.add(b); | |
| 632 } | |
| 633 | |
| 634 @override | |
| 635 void visitExportDirective(ExportDirective node) { | |
| 636 UnlinkedExportNonPublicBuilder b = new UnlinkedExportNonPublicBuilder( | |
| 637 uriOffset: node.uri.offset, uriEnd: node.uri.end, offset: node.offset); | |
| 638 exports.add(b); | |
| 639 } | |
| 640 | |
| 641 @override | |
| 642 void visitFieldDeclaration(FieldDeclaration node) { | |
| 643 serializeVariables( | |
| 644 node.fields, node.staticKeyword != null, node.documentationComment); | |
| 645 } | |
| 646 | |
| 647 @override | |
| 648 UnlinkedParamBuilder visitFieldFormalParameter(FieldFormalParameter node) { | |
| 649 UnlinkedParamBuilder b = serializeParameter(node); | |
| 650 b.isInitializingFormal = true; | |
| 651 if (node.type == null && node.parameters == null) { | |
| 652 b.hasImplicitType = true; | |
| 653 } else { | |
| 654 b.isFunctionTyped = node.parameters != null; | |
| 655 if (node.parameters != null) { | |
| 656 serializeFunctionTypedParameterDetails(b, node.type, node.parameters); | |
| 657 } else { | |
| 658 TypeName typeName = node.type; | |
| 659 if (typeName == null) { | |
| 660 typeName = getFieldType(node.identifier.name); | |
| 661 } | |
| 662 b.type = serializeTypeName(typeName); | |
| 663 } | |
| 664 } | |
| 665 return b; | |
| 666 } | |
| 667 | |
| 668 @override | |
| 669 void visitFunctionDeclaration(FunctionDeclaration node) { | |
| 670 executables.add(serializeExecutable( | |
| 671 node.name, | |
| 672 node.isGetter, | |
| 673 node.isSetter, | |
| 674 node.returnType, | |
| 675 node.functionExpression.parameters, | |
| 676 node.functionExpression.body, | |
| 677 true, | |
| 678 false, | |
| 679 node.documentationComment, | |
| 680 node.functionExpression.typeParameters, | |
| 681 node.externalKeyword != null)); | |
| 682 } | |
| 683 | |
| 684 @override | |
| 685 void visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 686 int oldScopesLength = scopes.length; | |
| 687 _TypeParameterScope typeParameterScope = new _TypeParameterScope(); | |
| 688 scopes.add(typeParameterScope); | |
| 689 UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder(); | |
| 690 b.name = node.name.name; | |
| 691 b.nameOffset = node.name.offset; | |
| 692 b.typeParameters = | |
| 693 serializeTypeParameters(node.typeParameters, typeParameterScope); | |
| 694 UnlinkedTypeRefBuilder serializedReturnType = | |
| 695 serializeTypeName(node.returnType, allowVoid: true); | |
| 696 if (serializedReturnType != null) { | |
| 697 b.returnType = serializedReturnType; | |
| 698 } | |
| 699 b.parameters = node.parameters.parameters | |
| 700 .map((FormalParameter p) => p.accept(this)) | |
| 701 .toList(); | |
| 702 b.documentationComment = serializeDocumentation(node.documentationComment); | |
| 703 typedefs.add(b); | |
| 704 scopes.removeLast(); | |
| 705 assert(scopes.length == oldScopesLength); | |
| 706 } | |
| 707 | |
| 708 @override | |
| 709 UnlinkedParamBuilder visitFunctionTypedFormalParameter( | |
| 710 FunctionTypedFormalParameter node) { | |
| 711 UnlinkedParamBuilder b = serializeParameter(node); | |
| 712 b.isFunctionTyped = true; | |
| 713 serializeFunctionTypedParameterDetails(b, node.returnType, node.parameters); | |
| 714 return b; | |
| 715 } | |
| 716 | |
| 717 @override | |
| 718 void visitImportDirective(ImportDirective node) { | |
| 719 UnlinkedImportBuilder b = new UnlinkedImportBuilder(); | |
| 720 if (node.uri.stringValue == 'dart:core') { | |
| 721 hasCoreBeenImported = true; | |
| 722 } | |
| 723 b.offset = node.offset; | |
| 724 b.combinators = node.combinators.map(serializeCombinator).toList(); | |
| 725 if (node.prefix != null) { | |
| 726 b.prefixReference = serializeReference(null, node.prefix.name); | |
| 727 b.prefixOffset = node.prefix.offset; | |
| 728 } | |
| 729 b.isDeferred = node.deferredKeyword != null; | |
| 730 b.uri = node.uri.stringValue; | |
| 731 b.uriOffset = node.uri.offset; | |
| 732 b.uriEnd = node.uri.end; | |
| 733 unlinkedImports.add(b); | |
| 734 } | |
| 735 | |
| 736 @override | |
| 737 void visitLibraryDirective(LibraryDirective node) { | |
| 738 libraryName = | |
| 739 node.name.components.map((SimpleIdentifier id) => id.name).join('.'); | |
| 740 libraryNameOffset = node.name.offset; | |
| 741 libraryNameLength = node.name.length; | |
| 742 libraryDocumentationComment = | |
| 743 serializeDocumentation(node.documentationComment); | |
| 744 } | |
| 745 | |
| 746 @override | |
| 747 void visitMethodDeclaration(MethodDeclaration node) { | |
| 748 executables.add(serializeExecutable( | |
| 749 node.name, | |
| 750 node.isGetter, | |
| 751 node.isSetter, | |
| 752 node.returnType, | |
| 753 node.parameters, | |
| 754 node.body, | |
| 755 false, | |
| 756 node.isStatic, | |
| 757 node.documentationComment, | |
| 758 node.typeParameters, | |
| 759 node.externalKeyword != null)); | |
| 760 } | |
| 761 | |
| 762 @override | |
| 763 void visitPartDirective(PartDirective node) { | |
| 764 parts.add(new UnlinkedPartBuilder( | |
| 765 uriOffset: node.uri.offset, uriEnd: node.uri.end)); | |
| 766 } | |
| 767 | |
| 768 @override | |
| 769 void visitPartOfDirective(PartOfDirective node) {} | |
| 770 | |
| 771 @override | |
| 772 UnlinkedParamBuilder visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 773 UnlinkedParamBuilder b = serializeParameter(node); | |
| 774 b.type = serializeTypeName(node.type); | |
| 775 b.hasImplicitType = node.type == null; | |
| 776 return b; | |
| 777 } | |
| 778 | |
| 779 @override | |
| 780 void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 781 serializeVariables(node.variables, false, node.documentationComment); | |
| 782 } | |
| 783 | |
| 784 @override | |
| 785 UnlinkedTypeParamBuilder visitTypeParameter(TypeParameter node) { | |
| 786 UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder(); | |
| 787 b.name = node.name.name; | |
| 788 b.nameOffset = node.name.offset; | |
| 789 if (node.bound != null) { | |
| 790 b.bound = serializeTypeName(node.bound); | |
| 791 } | |
| 792 return b; | |
| 793 } | |
| 794 | |
| 795 /** | |
| 796 * Helper method to determine if a given [typeName] refers to `dynamic`. | |
| 797 */ | |
| 798 static bool isNotDynamic(TypeName typeName) { | |
| 799 Identifier name = typeName.name; | |
| 800 return !(name is SimpleIdentifier && name.name == 'dynamic'); | |
| 801 } | |
| 802 } | |
| 803 | |
| 804 /** | |
| 805 * A [_TypeParameterScope] is a [_Scope] which defines [_ScopedTypeParameter]s. | |
| 806 */ | |
| 807 class _TypeParameterScope extends _Scope { | |
| 808 /** | |
| 809 * Get the number of [_ScopedTypeParameter]s defined in this | |
| 810 * [_TypeParameterScope]. | |
| 811 */ | |
| 812 int get length => _definedNames.length; | |
| 813 } | |
| OLD | NEW |