Chromium Code Reviews| Index: pkg/analyzer/tool/summary/generate.dart |
| diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart |
| index 44ee7f4d3aa6204bab5dd4a52a035a62f786eeeb..3a377f95da13517f385706dc5dc16439f77aebaa 100644 |
| --- a/pkg/analyzer/tool/summary/generate.dart |
| +++ b/pkg/analyzer/tool/summary/generate.dart |
| @@ -54,10 +54,11 @@ final GeneratedFile target = |
| CharacterReader idlReader = new CharSequenceReader(idlText); |
| Scanner scanner = new Scanner(idlSource, idlReader, errorListener); |
| Token tokenStream = scanner.tokenize(); |
| + LineInfo lineInfo = new LineInfo(scanner.lineStarts); |
| Parser parser = new Parser(idlSource, new BooleanErrorListener()); |
| CompilationUnit idlParsed = parser.parseCompilationUnit(tokenStream); |
| _CodeGenerator codeGenerator = new _CodeGenerator(); |
| - codeGenerator.processCompilationUnit(idlParsed); |
| + codeGenerator.processCompilationUnit(lineInfo, idlParsed); |
| return codeGenerator._outBuffer.toString(); |
| }); |
| @@ -83,7 +84,9 @@ class _CodeGenerator { |
| */ |
| void checkIdl() { |
| _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| + idlModel.FieldType type = field.type; |
| if (type.isList) { |
| if (_idl.classes.containsKey(type.typeName)) { |
| // List of classes is ok |
| @@ -96,7 +99,7 @@ class _CodeGenerator { |
| '$name.$fieldName: illegal type (list of ${type.typeName})'); |
| } |
| } |
| - }); |
| + } |
| }); |
| } |
| @@ -154,7 +157,7 @@ class _CodeGenerator { |
| * Process the AST in [idlParsed] and store the resulting semantic model in |
| * [_idl]. Also perform some error checking. |
| */ |
| - void extractIdl(CompilationUnit idlParsed) { |
| + void extractIdl(LineInfo lineInfo, CompilationUnit idlParsed) { |
| _idl = new idlModel.Idl(); |
| for (CompilationUnitMember decl in idlParsed.declarations) { |
| if (decl is ClassDeclaration) { |
| @@ -165,9 +168,10 @@ class _CodeGenerator { |
| isTopLevel = true; |
| } |
| } |
| + String doc = _getNodeDoc(lineInfo, decl); |
| idlModel.ClassDeclaration cls = |
| - new idlModel.ClassDeclaration(isTopLevel); |
| - _idl.classes[decl.name.name] = cls; |
| + new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel); |
| + _idl.classes[cls.name] = cls; |
| for (ClassMember classMember in decl.members) { |
| if (classMember is FieldDeclaration) { |
| TypeName type = classMember.fields.type; |
| @@ -181,18 +185,23 @@ class _CodeGenerator { |
| if (type.typeArguments != null) { |
| throw new Exception('Cannot handle type arguments in `$type`'); |
| } |
| + String doc = _getNodeDoc(lineInfo, classMember); |
| idlModel.FieldType fieldType = |
| new idlModel.FieldType(type.name.name, isList); |
| for (VariableDeclaration field in classMember.fields.variables) { |
| - cls.fields[field.name.name] = fieldType; |
| + // TODO(scheglov) use actual documentation |
|
Paul Berry
2016/01/05 17:49:50
Can you clarify what this means? Isn't `doc` the
|
| + cls.fields.add(new idlModel.FieldDeclaration( |
| + doc, field.name.name, fieldType)); |
| } |
| } else { |
| throw new Exception('Unexpected class member `$classMember`'); |
| } |
| } |
| } else if (decl is EnumDeclaration) { |
| - idlModel.EnumDeclaration enm = new idlModel.EnumDeclaration(); |
| - _idl.enums[decl.name.name] = enm; |
| + String doc = _getNodeDoc(lineInfo, decl); |
| + idlModel.EnumDeclaration enm = |
| + new idlModel.EnumDeclaration(doc, decl.name.name); |
| + _idl.enums[enm.name] = enm; |
| for (EnumConstantDeclaration constDecl in decl.constants) { |
| enm.values.add(constDecl.name.name); |
| } |
| @@ -230,12 +239,18 @@ class _CodeGenerator { |
| } |
| } |
| + void outDoc(String documentation) { |
| + if (documentation != null) { |
| + documentation.split('\n').forEach(out); |
| + } |
| + } |
| + |
| /** |
| * Entry point to the code generator. Interpret the AST in [idlParsed], |
| * generate code, and output it to [_outBuffer]. |
| */ |
| - void processCompilationUnit(CompilationUnit idlParsed) { |
| - extractIdl(idlParsed); |
| + void processCompilationUnit(LineInfo lineInfo, CompilationUnit idlParsed) { |
| + extractIdl(lineInfo, idlParsed); |
| checkIdl(); |
| out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file'); |
| out('// for details. All rights reserved. Use of this source code is governed by a'); |
| @@ -250,6 +265,7 @@ class _CodeGenerator { |
| out("import 'base.dart' as base;"); |
| out(); |
| _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) { |
| + outDoc(enm.documentation); |
| out('enum $name {'); |
| indent(() { |
| for (String value in enm.values) { |
| @@ -260,16 +276,21 @@ class _CodeGenerator { |
| out(); |
| }); |
| _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { |
| + outDoc(cls.documentation); |
| out('class $name extends base.SummaryClass {'); |
| indent(() { |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| + idlModel.FieldType type = field.type; |
| out('${dartType(type)} _$fieldName;'); |
| - }); |
| + } |
| out(); |
| out('$name.fromJson(Map json)'); |
| indent(() { |
| List<String> initializers = <String>[]; |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| + idlModel.FieldType type = field.type; |
| String convert = 'json[${quoted(fieldName)}]'; |
| if (type.isList) { |
| if (type.typeName == 'int' || type.typeName == 'String') { |
| @@ -286,7 +307,7 @@ class _CodeGenerator { |
| '$convert == null ? null : ${type.typeName}.values[$convert]'; |
| } |
| initializers.add('_$fieldName = $convert'); |
| - }); |
| + } |
| for (int i = 0; i < initializers.length; i++) { |
| String prefix = i == 0 ? ': ' : ' '; |
| String suffix = i == initializers.length - 1 ? ';' : ','; |
| @@ -297,9 +318,10 @@ class _CodeGenerator { |
| out('@override'); |
| out('Map<String, Object> toMap() => {'); |
| indent(() { |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| out('${quoted(fieldName)}: $fieldName,'); |
| - }); |
| + } |
| }); |
| out('};'); |
| out(); |
| @@ -307,9 +329,15 @@ class _CodeGenerator { |
| out('$name.fromBuffer(List<int> buffer) : this.fromJson(JSON.decode(UTF8.decode(buffer)));'); |
| out(); |
| } |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + cls.fields.asMap().forEach((index, field) { |
| + String fieldName = field.name; |
| + idlModel.FieldType type = field.type; |
| + if (index != 0) { |
| + out(); |
| + } |
| String def = defaultValue(type); |
| String defaultSuffix = def == null ? '' : ' ?? $def'; |
| + outDoc(field.documentation); |
| out('${dartType(type)} get $fieldName => _$fieldName$defaultSuffix;'); |
| }); |
| }); |
| @@ -323,8 +351,11 @@ class _CodeGenerator { |
| out('bool _finished = false;'); |
| out(); |
| out('${name}Builder(base.BuilderContext context);'); |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| + idlModel.FieldType type = field.type; |
| out(); |
| + outDoc(field.documentation); |
| String conversion = '_value'; |
| String condition = ''; |
| if (type.isList) { |
| @@ -356,7 +387,7 @@ class _CodeGenerator { |
| out('}'); |
| }); |
| out('}'); |
| - }); |
| + } |
| if (cls.isTopLevel) { |
| out(); |
| out('List<int> toBuffer() => UTF8.encode(JSON.encode(finish()));'); |
| @@ -375,9 +406,10 @@ class _CodeGenerator { |
| out('${name}Builder encode$name(base.BuilderContext builderContext, {${builderParams.join(', ')}}) {'); |
| indent(() { |
| out('${name}Builder builder = new ${name}Builder(builderContext);'); |
| - cls.fields.forEach((String fieldName, idlModel.FieldType type) { |
| + for (idlModel.FieldDeclaration field in cls.fields) { |
| + String fieldName = field.name; |
| out('builder.$fieldName = $fieldName;'); |
| - }); |
| + } |
| out('return builder;'); |
| }); |
| out('}'); |
| @@ -391,4 +423,27 @@ class _CodeGenerator { |
| String quoted(String s) { |
| return JSON.encode(s); |
| } |
| + |
| + /** |
| + * Return the documentation text of the given [node], or `null` if the [node] |
| + * does not have a comment. Each line is `\n` separated. |
| + */ |
| + String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) { |
| + Comment comment = node.documentationComment; |
| + if (comment != null && |
| + comment.isDocumentation && |
| + comment.tokens.length == 1 && |
| + comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) { |
| + Token token = comment.tokens.first; |
| + int column = lineInfo.getLocation(token.offset).columnNumber; |
| + String indent = ' ' * (column - 1); |
| + return token.lexeme.split('\n').map((String line) { |
| + if (line.startsWith(indent)) { |
| + line = line.substring(indent.length); |
| + } |
| + return line; |
| + }).join('\n'); |
| + } |
| + return null; |
| + } |
| } |