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

Side by Side Diff: pkg/analyzer/tool/summary/generate.dart

Issue 1691923002: Make summary format stable when adding getters to idl. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 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
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 /** 5 /**
6 * This file contains code to generate serialization/deserialization logic for 6 * This file contains code to generate serialization/deserialization logic for
7 * summaries based on an "IDL" description of the summary format (written in 7 * summaries based on an "IDL" description of the summary format (written in
8 * stylized Dart). 8 * stylized Dart).
9 * 9 *
10 * For each class in the "IDL" input, two corresponding classes are generated: 10 * For each class in the "IDL" input, two corresponding classes are generated:
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 * Semantic model of the "IDL" input file. 75 * Semantic model of the "IDL" input file.
76 */ 76 */
77 idlModel.Idl _idl; 77 idlModel.Idl _idl;
78 78
79 /** 79 /**
80 * Perform basic sanity checking of the IDL (over and above that done by 80 * Perform basic sanity checking of the IDL (over and above that done by
81 * [extractIdl]). 81 * [extractIdl]).
82 */ 82 */
83 void checkIdl() { 83 void checkIdl() {
84 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { 84 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) {
85 Map<int, String> idsUsed = <int, String>{};
85 for (idlModel.FieldDeclaration field in cls.fields) { 86 for (idlModel.FieldDeclaration field in cls.fields) {
86 String fieldName = field.name; 87 String fieldName = field.name;
87 idlModel.FieldType type = field.type; 88 idlModel.FieldType type = field.type;
88 if (type.isList) { 89 if (type.isList) {
89 if (_idl.classes.containsKey(type.typeName)) { 90 if (_idl.classes.containsKey(type.typeName)) {
90 // List of classes is ok 91 // List of classes is ok
91 } else if (_idl.enums.containsKey(type.typeName)) { 92 } else if (_idl.enums.containsKey(type.typeName)) {
92 // List of enums is ok 93 // List of enums is ok
93 } else if (type.typeName == 'int') { 94 } else if (type.typeName == 'int') {
94 // List of ints is ok 95 // List of ints is ok
95 } else if (type.typeName == 'double') { 96 } else if (type.typeName == 'double') {
96 // List of doubles is ok 97 // List of doubles is ok
97 } else if (type.typeName == 'String') { 98 } else if (type.typeName == 'String') {
98 // List of strings is ok 99 // List of strings is ok
99 } else { 100 } else {
100 throw new Exception( 101 throw new Exception(
101 '$name.$fieldName: illegal type (list of ${type.typeName})'); 102 '$name.$fieldName: illegal type (list of ${type.typeName})');
102 } 103 }
103 } 104 }
105 if (idsUsed.containsKey(field.id)) {
106 throw new Exception('$name.$fieldName: id ${field.id} already used by'
107 ' ${idsUsed[field.id]}');
108 }
109 idsUsed[field.id] = fieldName;
110 }
111 for (int i = 0; i < idsUsed.length; i++) {
112 if (!idsUsed.containsKey(i)) {
113 throw new Exception('$name: no field uses id $i');
114 }
104 } 115 }
105 }); 116 });
106 } 117 }
107 118
108 /** 119 /**
109 * Generate a string representing the Dart type which should be used to 120 * Generate a string representing the Dart type which should be used to
110 * represent [type] when deserialized. 121 * represent [type] when deserialized.
111 */ 122 */
112 String dartType(idlModel.FieldType type) { 123 String dartType(idlModel.FieldType type) {
113 String baseType = idlPrefix(type.typeName); 124 String baseType = idlPrefix(type.typeName);
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel); 197 new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel);
187 _idl.classes[cls.name] = cls; 198 _idl.classes[cls.name] = cls;
188 String expectedBase = 'base.SummaryClass'; 199 String expectedBase = 'base.SummaryClass';
189 if (decl.extendsClause == null || 200 if (decl.extendsClause == null ||
190 decl.extendsClause.superclass.name.name != expectedBase) { 201 decl.extendsClause.superclass.name.name != expectedBase) {
191 throw new Exception( 202 throw new Exception(
192 'Class `${cls.name}` needs to extend `$expectedBase`'); 203 'Class `${cls.name}` needs to extend `$expectedBase`');
193 } 204 }
194 for (ClassMember classMember in decl.members) { 205 for (ClassMember classMember in decl.members) {
195 if (classMember is MethodDeclaration && classMember.isGetter) { 206 if (classMember is MethodDeclaration && classMember.isGetter) {
207 String desc = '${cls.name}.${classMember.name.name}';
196 TypeName type = classMember.returnType; 208 TypeName type = classMember.returnType;
197 if (type == null) { 209 if (type == null) {
198 throw new Exception('Class member needs a type: $classMember'); 210 throw new Exception('Class member needs a type: $desc');
199 } 211 }
200 bool isList = false; 212 bool isList = false;
201 if (type.name.name == 'List' && 213 if (type.name.name == 'List' &&
202 type.typeArguments != null && 214 type.typeArguments != null &&
203 type.typeArguments.arguments.length == 1) { 215 type.typeArguments.arguments.length == 1) {
204 isList = true; 216 isList = true;
205 type = type.typeArguments.arguments[0]; 217 type = type.typeArguments.arguments[0];
206 } 218 }
207 if (type.typeArguments != null) { 219 if (type.typeArguments != null) {
208 throw new Exception('Cannot handle type arguments in `$type`'); 220 throw new Exception('Cannot handle type arguments in `$type`');
209 } 221 }
222 int id;
223 for (Annotation annotation in classMember.metadata) {
224 if (annotation.name.name == 'Id') {
225 if (id != null) {
226 throw new Exception(
227 'Duplicate @id annotation ($classMember)');
228 }
229 if (annotation.arguments.arguments.length != 1) {
230 throw new Exception(
231 '@Id must be passed exactly one argument ($desc)');
232 }
233 Expression expression = annotation.arguments.arguments[0];
234 if (expression is IntegerLiteral) {
235 id = expression.value;
236 } else {
237 throw new Exception(
238 '@Id parameter must be an integer literal ($desc)');
239 }
240 }
241 }
242 if (id == null) {
243 throw new Exception('Missing @id annotation ($desc)');
244 }
210 String doc = _getNodeDoc(lineInfo, classMember); 245 String doc = _getNodeDoc(lineInfo, classMember);
211 idlModel.FieldType fieldType = 246 idlModel.FieldType fieldType =
212 new idlModel.FieldType(type.name.name, isList); 247 new idlModel.FieldType(type.name.name, isList);
213 cls.fields.add(new idlModel.FieldDeclaration( 248 cls.fields.add(new idlModel.FieldDeclaration(
214 doc, classMember.name.name, fieldType)); 249 doc, classMember.name.name, fieldType, id));
215 } else if (classMember is ConstructorDeclaration && 250 } else if (classMember is ConstructorDeclaration &&
216 classMember.name.name == 'fromBuffer') { 251 classMember.name.name == 'fromBuffer') {
217 // Ignore `fromBuffer` declarations; they simply forward to the 252 // Ignore `fromBuffer` declarations; they simply forward to the
218 // read functions generated by [_generateReadFunction]. 253 // read functions generated by [_generateReadFunction].
219 } else { 254 } else {
220 throw new Exception('Unexpected class member `$classMember`'); 255 throw new Exception('Unexpected class member `$classMember`');
221 } 256 }
222 } 257 }
223 } else if (decl is EnumDeclaration) { 258 } else if (decl is EnumDeclaration) {
224 String doc = _getNodeDoc(lineInfo, decl); 259 String doc = _getNodeDoc(lineInfo, decl);
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 out('return fbBuilder.finish(finish(fbBuilder));'); 432 out('return fbBuilder.finish(finish(fbBuilder));');
398 }); 433 });
399 out('}'); 434 out('}');
400 } 435 }
401 out(); 436 out();
402 out('fb.Offset finish(fb.Builder fbBuilder) {'); 437 out('fb.Offset finish(fb.Builder fbBuilder) {');
403 indent(() { 438 indent(() {
404 out('assert(!_finished);'); 439 out('assert(!_finished);');
405 out('_finished = true;'); 440 out('_finished = true;');
406 // Write objects and remember Offset(s). 441 // Write objects and remember Offset(s).
407 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) { 442 for (idlModel.FieldDeclaration field in cls.fields) {
408 idlModel.FieldType fieldType = field.type; 443 idlModel.FieldType fieldType = field.type;
409 String offsetName = 'offset_' + field.name; 444 String offsetName = 'offset_' + field.name;
410 if (fieldType.isList || 445 if (fieldType.isList ||
411 fieldType.typeName == 'String' || 446 fieldType.typeName == 'String' ||
412 _idl.classes.containsKey(fieldType.typeName)) { 447 _idl.classes.containsKey(fieldType.typeName)) {
413 out('fb.Offset $offsetName;'); 448 out('fb.Offset $offsetName;');
414 } 449 }
415 }); 450 }
416 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) { 451 for (idlModel.FieldDeclaration field in cls.fields) {
417 idlModel.FieldType fieldType = field.type; 452 idlModel.FieldType fieldType = field.type;
418 String valueName = '_' + field.name; 453 String valueName = '_' + field.name;
419 String offsetName = 'offset_' + field.name; 454 String offsetName = 'offset_' + field.name;
420 String condition; 455 String condition;
421 String writeCode; 456 String writeCode;
422 if (fieldType.isList) { 457 if (fieldType.isList) {
423 condition = ' || $valueName.isEmpty'; 458 condition = ' || $valueName.isEmpty';
424 if (_idl.classes.containsKey(fieldType.typeName)) { 459 if (_idl.classes.containsKey(fieldType.typeName)) {
425 String itemCode = 'b.finish(fbBuilder)'; 460 String itemCode = 'b.finish(fbBuilder)';
426 String listCode = '$valueName.map((b) => $itemCode).toList()'; 461 String listCode = '$valueName.map((b) => $itemCode).toList()';
(...skipping 23 matching lines...) Expand all
450 if (condition == null) { 485 if (condition == null) {
451 out('if ($valueName != null) {'); 486 out('if ($valueName != null) {');
452 } else { 487 } else {
453 out('if (!($valueName == null$condition)) {'); 488 out('if (!($valueName == null$condition)) {');
454 } 489 }
455 indent(() { 490 indent(() {
456 out(writeCode); 491 out(writeCode);
457 }); 492 });
458 out('}'); 493 out('}');
459 } 494 }
460 }); 495 }
461 // Write the table. 496 // Write the table.
462 out('fbBuilder.startTable();'); 497 out('fbBuilder.startTable();');
463 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) { 498 for (idlModel.FieldDeclaration field in cls.fields) {
499 int index = field.id;
464 idlModel.FieldType fieldType = field.type; 500 idlModel.FieldType fieldType = field.type;
465 String valueName = '_' + field.name; 501 String valueName = '_' + field.name;
466 String condition = '$valueName != null'; 502 String condition = '$valueName != null';
467 String writeCode; 503 String writeCode;
468 if (fieldType.isList || 504 if (fieldType.isList ||
469 fieldType.typeName == 'String' || 505 fieldType.typeName == 'String' ||
470 _idl.classes.containsKey(fieldType.typeName)) { 506 _idl.classes.containsKey(fieldType.typeName)) {
471 String offsetName = 'offset_' + field.name; 507 String offsetName = 'offset_' + field.name;
472 condition = '$offsetName != null'; 508 condition = '$offsetName != null';
473 writeCode = 'fbBuilder.addOffset($index, $offsetName);'; 509 writeCode = 'fbBuilder.addOffset($index, $offsetName);';
474 } else if (fieldType.typeName == 'bool') { 510 } else if (fieldType.typeName == 'bool') {
475 condition = '$valueName == true'; 511 condition = '$valueName == true';
476 writeCode = 'fbBuilder.addBool($index, true);'; 512 writeCode = 'fbBuilder.addBool($index, true);';
477 } else if (fieldType.typeName == 'int') { 513 } else if (fieldType.typeName == 'int') {
478 condition += ' && $valueName != ${defaultValue(fieldType, true)}'; 514 condition += ' && $valueName != ${defaultValue(fieldType, true)}';
479 writeCode = 'fbBuilder.addUint32($index, $valueName);'; 515 writeCode = 'fbBuilder.addUint32($index, $valueName);';
480 } else if (_idl.enums.containsKey(fieldType.typeName)) { 516 } else if (_idl.enums.containsKey(fieldType.typeName)) {
481 condition += ' && $valueName != ${defaultValue(fieldType, true)}'; 517 condition += ' && $valueName != ${defaultValue(fieldType, true)}';
482 writeCode = 'fbBuilder.addUint32($index, $valueName.index);'; 518 writeCode = 'fbBuilder.addUint32($index, $valueName.index);';
483 } 519 }
484 if (writeCode == null) { 520 if (writeCode == null) {
485 throw new UnimplementedError('Writing type ${fieldType.typeName}'); 521 throw new UnimplementedError('Writing type ${fieldType.typeName}');
486 } 522 }
487 out('if ($condition) {'); 523 out('if ($condition) {');
488 indent(() { 524 indent(() {
489 out(writeCode); 525 out(writeCode);
490 }); 526 });
491 out('}'); 527 out('}');
492 }); 528 }
493 out('return fbBuilder.endTable();'); 529 out('return fbBuilder.endTable();');
494 }); 530 });
495 out('}'); 531 out('}');
496 }); 532 });
497 out('}'); 533 out('}');
498 } 534 }
499 535
500 void _generateEnumReader(idlModel.EnumDeclaration enm) { 536 void _generateEnumReader(idlModel.EnumDeclaration enm) {
501 String name = enm.name; 537 String name = enm.name;
502 String readerName = '_${name}Reader'; 538 String readerName = '_${name}Reader';
(...skipping 26 matching lines...) Expand all
529 out(); 565 out();
530 out('$implName(this._bp);'); 566 out('$implName(this._bp);');
531 out(); 567 out();
532 // Write cache fields. 568 // Write cache fields.
533 for (idlModel.FieldDeclaration field in cls.fields) { 569 for (idlModel.FieldDeclaration field in cls.fields) {
534 String returnType = dartType(field.type); 570 String returnType = dartType(field.type);
535 String fieldName = field.name; 571 String fieldName = field.name;
536 out('$returnType _$fieldName;'); 572 out('$returnType _$fieldName;');
537 } 573 }
538 // Write getters. 574 // Write getters.
539 cls.fields.asMap().forEach((index, field) { 575 for (idlModel.FieldDeclaration field in cls.fields) {
576 int index = field.id;
540 String fieldName = field.name; 577 String fieldName = field.name;
541 idlModel.FieldType type = field.type; 578 idlModel.FieldType type = field.type;
542 String typeName = type.typeName; 579 String typeName = type.typeName;
543 // Prepare "readCode" + "def" 580 // Prepare "readCode" + "def"
544 String readCode; 581 String readCode;
545 String def = defaultValue(type, false); 582 String def = defaultValue(type, false);
546 if (type.isList) { 583 if (type.isList) {
547 if (typeName == 'int') { 584 if (typeName == 'int') {
548 String itemCode = 'const fb.Uint32Reader()'; 585 String itemCode = 'const fb.Uint32Reader()';
549 readCode = 'const fb.ListReader<int>($itemCode)'; 586 readCode = 'const fb.ListReader<int>($itemCode)';
(...skipping 26 matching lines...) Expand all
576 out(); 613 out();
577 out('@override'); 614 out('@override');
578 String returnType = dartType(type); 615 String returnType = dartType(type);
579 out('$returnType get $fieldName {'); 616 out('$returnType get $fieldName {');
580 indent(() { 617 indent(() {
581 String readExpr = '$readCode.vTableGet(_bp, $index, $def)'; 618 String readExpr = '$readCode.vTableGet(_bp, $index, $def)';
582 out('_$fieldName ??= $readExpr;'); 619 out('_$fieldName ??= $readExpr;');
583 out('return _$fieldName;'); 620 out('return _$fieldName;');
584 }); 621 });
585 out('}'); 622 out('}');
586 }); 623 }
587 }); 624 });
588 out('}'); 625 out('}');
589 } 626 }
590 627
591 void _generateMixin(idlModel.ClassDeclaration cls) { 628 void _generateMixin(idlModel.ClassDeclaration cls) {
592 String name = cls.name; 629 String name = cls.name;
593 String mixinName = '_${name}Mixin'; 630 String mixinName = '_${name}Mixin';
594 out('abstract class $mixinName implements ${idlPrefix(name)} {'); 631 out('abstract class $mixinName implements ${idlPrefix(name)} {');
595 indent(() { 632 indent(() {
596 // Write toMap(). 633 // Write toMap().
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 return token.lexeme.split('\n').map((String line) { 684 return token.lexeme.split('\n').map((String line) {
648 if (line.startsWith(indent)) { 685 if (line.startsWith(indent)) {
649 line = line.substring(indent.length); 686 line = line.substring(indent.length);
650 } 687 }
651 return line; 688 return line;
652 }).join('\n'); 689 }).join('\n');
653 } 690 }
654 return null; 691 return null;
655 } 692 }
656 } 693 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698