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

Unified Diff: pkg/analysis_server/lib/src/utilities/change_builder_dart.dart

Issue 1110583002: Add utilities for creating SourceChanges (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add missed files Created 5 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a337db28d8d9d4332a6de3e198989abc4672a57d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -0,0 +1,412 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.utilities.change_builder_dart;
+
+import 'package:analysis_server/src/protocol.dart' hide ElementKind;
+import 'package:analysis_server/src/services/correction/name_suggestion.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analysis_server/src/utilities/change_builder_core.dart';
+import 'package:analysis_server/utilities/change_builder_core.dart';
+import 'package:analysis_server/utilities/change_builder_dart.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * A [ChangeBuilder] used to build changes in Dart files.
+ */
+class DartChangeBuilderImpl extends ChangeBuilderImpl
+ implements DartChangeBuilder {
+ /**
+ * The analysis context in which the files being edited were analyzed.
+ */
+ final AnalysisContext context;
+
+ /**
+ * Initialize a newly created change builder.
+ */
+ DartChangeBuilderImpl(this.context);
+
+ @override
+ DartFileEditBuilderImpl createFileEditBuilder(Source source, int fileStamp) {
+ return new DartFileEditBuilderImpl(this, source, fileStamp);
+ }
+}
+
+/**
+ * An [EditBuilder] used to build edits in Dart files.
+ */
+class DartEditBuilderImpl extends EditBuilderImpl implements DartEditBuilder {
+ /**
+ * The string used when writing the 'abstract' modifier.
+ */
+ static const String ABSTRACT_MODIFIER = 'abstract ';
Paul Berry 2015/05/04 16:00:29 Personally, I'm a little dubious about making stri
+
+ /**
+ * The string used when writing the 'const' modifier.
+ */
+ static const String CONST_MODIFIER = 'const ';
+
+ /**
+ * A utility class used to help build the source code.
+ */
+ final CorrectionUtils utils;
+
+// /**
+// * The string used when writing the 'final' modifier.
+// */
+// static const String FINAL_MODIFIER = 'final ';
+//
+// /**
+// * The string used when writing the 'static' modifier.
+// */
+// static const String STATIC_MODIFIER = 'static ';
+
+ /**
+ * Initialize a newly created builder to build a source edit.
+ */
+ DartEditBuilderImpl(
+ DartFileEditBuilderImpl sourceFileEditBuilder, int offset, int length)
+ : utils = sourceFileEditBuilder.utils,
+ super(sourceFileEditBuilder, offset, length);
+
+ DartFileEditBuilderImpl get dartFileEditBuilder => fileEditBuilder;
+
+ @override
+ void writeClassDeclaration(String name, {Iterator<DartType> interfaces,
+ bool isAbstract: false, void memberWriter(), Iterator<DartType> mixins, DartType superclass}) {
+ // TODO(brianwilkerson) Add support for type parameters
+ // Map<String, DartType>, List<TypeParameter>?
+ //
+ // TODO(brianwilkerson) Make additional optional parameters visible in the
+ // public API.
+ if (isAbstract) {
+ write(ABSTRACT_MODIFIER);
+ }
+ write('class ');
+ addLinkedEdit(DartEditBuilder.NAME_GROUP_ID, (LinkedEditBuilder builder) {
+ write(name);
+ });
+ if (superclass != null) {
Paul Berry 2015/05/04 16:00:29 Two things: 1. If superclass == null && mixins.is
+ write(' extends ');
+ writeType(superclass, groupName: DartEditBuilder.SUPERCLASS_GROUP_ID);
+ }
+ writeTypes(mixins, prefix: ' with ');
+ writeTypes(interfaces, prefix: ' implements ');
+ writeln(' {');
+ if (memberWriter != null) {
+ memberWriter();
+ }
+ write('}');
+ }
+
+ /**
+ * Write the code for a comma-separated list of [types], optionally prefixed
+ * by a [prefix]. If the list of [types] is `null` or does not return any
+ * types, then nothing will be written.
+ */
+ void writeTypes(Iterator<DartType> types, {String prefix}) {
+ if (types == null) {
+ return;
+ }
+ bool first = true;
+ while (types.moveNext()) {
+ if (first) {
+ if (prefix != null) {
+ write(prefix);
+ }
+ first = false;
+ } else {
+ write(', ');
+ }
+ writeType(types.current);
+ }
+ }
+
+ void writeConstructorDeclaration(ClassElement classElement,
+ {ArgumentList argumentList, SimpleIdentifier constructorName,
+ bool isConst: false}) {
+ // TODO(brianwilkerson) Clean up the API and add it to the public API.
+ //
+ // TODO(brianwilkerson) Support passing a list of final fields rather than
+ // an argument list.
+ if (isConst) {
+ write(CONST_MODIFIER);
+ }
+ write(classElement.name);
+ write('.');
+ if (constructorName != null) {
+ addLinkedEdit(DartEditBuilder.NAME_GROUP_ID, (LinkedEditBuilder builder) {
+ write(constructorName.name);
+ });
+ CompilationUnit unit = constructorName
+ .getAncestor((AstNode node) => node is CompilationUnit);
+ if (unit != null) {
+ CompilationUnitElement element = unit.element;
+ if (element != null) {
+ String referenceFile = element.source.fullName;
+ if (referenceFile == dartFileEditBuilder.fileEdit.file) {
+ dartFileEditBuilder.addLinkedPosition(constructorName.offset,
+ constructorName.length, DartEditBuilder.NAME_GROUP_ID);
+ }
+ }
+ }
+ }
+ if (argumentList != null) {
+ writeParametersMatchingArguments(argumentList);
+ } else {
+ write('()');
+ }
+ writeln(' {');
+ write(' }');
+ }
+
+ @override
+ void writeOverrideOfInheritedMember(ExecutableElement member) {
+ // prepare environment
+ String prefix = utils.getIndent(1);
+ // may be property
+ String prefix2 = utils.getIndent(2);
+ ElementKind elementKind = member.kind;
+ bool isGetter = elementKind == ElementKind.GETTER;
+ bool isSetter = elementKind == ElementKind.SETTER;
+ bool isMethod = elementKind == ElementKind.METHOD;
+ bool isOperator = isMethod && (member as MethodElement).isOperator;
+ write(prefix);
+ if (isGetter) {
+ writeln('// TODO: implement ${member.displayName}');
+ write(prefix);
+ }
+ // @override
+ writeln('@override');
+ write(prefix);
+ // return type
+ // REVIEW: Added groupId
+ bool shouldReturn = writeType(member.type.returnType,
+ groupName: DartEditBuilder.RETURN_TYPE_GROUP_ID);
+ write(' ');
+ if (isGetter) {
+ write('get ');
+ } else if (isSetter) {
+ write('set ');
+ } else if (isOperator) {
+ write('operator ');
+ }
+ // name
+ write(member.displayName);
+ // parameters + body
+ if (isGetter) {
+ writeln(' => null;');
+ } else {
+ List<ParameterElement> parameters = member.parameters;
+ writeParameters(parameters);
+ writeln(' {');
+ // TO-DO
+ write(prefix2);
+ writeln('// TODO: implement ${member.displayName}');
+ // REVIEW: Added return statement.
+ if (shouldReturn) {
+ write(prefix2);
+ writeln('return null;');
+ }
+ // close method
+ write(prefix);
+ writeln('}');
+ }
+ }
+
+ @override
+ void writeParameters(Iterable<ParameterElement> parameters) {
+ write('(');
+ bool sawNamed = false;
+ bool sawPositional = false;
+ for (int i = 0; i < parameters.length; i++) {
+ ParameterElement parameter = parameters.elementAt(i);
+ if (i > 0) {
+ write(', ');
+ }
+ // may be optional
+ ParameterKind parameterKind = parameter.parameterKind;
+ if (parameterKind == ParameterKind.NAMED) {
+ if (!sawNamed) {
+ write('{');
+ sawNamed = true;
+ }
+ }
+ if (parameterKind == ParameterKind.POSITIONAL) {
+ if (!sawPositional) {
+ write('[');
+ sawPositional = true;
+ }
+ }
+ // parameter
+ writeParameterSource(parameter.type, parameter.name);
+ // default value
+ String defaultCode = parameter.defaultValueCode;
+ if (defaultCode != null) {
+ if (sawPositional) {
+ write(' = ');
+ } else {
+ write(': ');
+ }
+ write(defaultCode);
+ }
+ }
+ // close parameters
+ if (sawNamed) {
+ write('}');
+ }
+ if (sawPositional) {
+ write(']');
+ }
+ write(')');
+ }
+
+ @override
+ void writeParametersMatchingArguments(ArgumentList arguments) {
+ Set<String> excluded = new Set();
+ bool namedFound = false;
+ write('(');
+ List<Expression> argumentList = arguments.arguments;
+ for (int i = 0; i < argumentList.length; i++) {
+ Expression argument = argumentList[i];
+ DartType type = argument.bestType;
+ List<String> suggestions =
+ _getParameterNameSuggestions(excluded, type, argument, i);
+ String favorite = suggestions[0];
+ // append separator
+ if (i > 0) {
+ write(', ');
+ }
+ if (argument is NamedExpression) {
+ if (!namedFound) {
+ namedFound = true;
+ write('[');
+ }
+ favorite = argument.name.label.name;
+ }
+ // append type name
+ writeType(type, addSupertypeProposals: true, groupName: 'TYPE$i');
+ write(' ');
+ // append parameter name
+ excluded.add(favorite);
+ addLinkedEdit('ARG$i', (LinkedEditBuilder builder) {
+ builder.write(favorite);
+ builder.addSuggestions(LinkedEditSuggestionKind.PARAMETER, suggestions);
+ });
+ }
+ if (namedFound) {
+ write(']');
+ }
+ write(')');
+ }
+
+ @override
+ void writeParameterSource(DartType type, String name) {
+ String parameterSource = utils.getParameterSource(
+ type, name, dartFileEditBuilder.librariesToImport);
+ write(parameterSource);
+ }
+
+ @override
+ bool writeType(DartType type, {bool addSupertypeProposals: false,
+ String groupName, bool required: false}) {
+ if (type != null && !type.isDynamic) {
+ String typeSource =
+ utils.getTypeSource(type, dartFileEditBuilder.librariesToImport);
+ if (groupName != null) {
+ addLinkedEdit(groupName, (LinkedEditBuilder builder) {
+ write(typeSource);
+ if (addSupertypeProposals) {
+ _addSuperTypeProposals(builder, type, new Set<DartType>());
+ }
+ });
+ } else {
+ write(typeSource);
+ }
+ return true;
+ } else if (required) {
+ write('var');
+ }
+ return false;
+ }
+
+ void _addSuperTypeProposals(
+ LinkedEditBuilder builder, DartType type, Set<DartType> alreadyAdded) {
+ if (type != null &&
+ type.element is ClassElement &&
+ alreadyAdded.add(type)) {
+ ClassElement element = type.element as ClassElement;
+ builder.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name);
+ _addSuperTypeProposals(builder, element.supertype, alreadyAdded);
+ for (InterfaceType interfaceType in element.interfaces) {
+ _addSuperTypeProposals(builder, interfaceType, alreadyAdded);
+ }
+ }
+ }
+
+ /**
+ * Return a list containing the suggested names for a parmeter with the given
+ * [type] whose value in one location is computed by the given [expression].
+ * The list will not contain any names in the set of [excluded] names. The
+ * [index] is the index of the argument, used to create a name if no better
+ * name could be created. The first name in the list will be the best name.
+ */
+ List<String> _getParameterNameSuggestions(
+ Set<String> excluded, DartType type, Expression expression, int index) {
+ List<String> suggestions =
+ getVariableNameSuggestionsForExpression(type, expression, excluded);
+ if (suggestions.length != 0) {
+ return suggestions;
+ }
+ return <String>['arg$index'];
+ }
+}
+
+/**
+ * A [FileEditBuilder] used to build edits for Dart files.
+ */
+class DartFileEditBuilderImpl extends FileEditBuilderImpl
+ implements DartFileEditBuilder {
+ /**
+ * The compilation unit to which the code will be added.
+ */
+ CompilationUnit unit;
+
+ /**
+ * A utility class used to help build the source code.
+ */
+ CorrectionUtils utils;
+
+ /**
+ * A set containing the elements of the libraries that need to be imported in
+ * order to make visible the names used in generated code.
+ */
+ Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
+
+ /**
+ * Initialize a newly created builder to build a source file edit within the
+ * change being built by the given [changeBuilder]. The file being edited has
+ * the given [source] and [timeStamp].
+ */
+ DartFileEditBuilderImpl(
+ DartChangeBuilderImpl changeBuilder, Source source, int timeStamp)
+ : super(changeBuilder, source, timeStamp) {
+ AnalysisContext context = changeBuilder.context;
+ List<Source> librariesContaining = context.getLibrariesContaining(source);
+ if (librariesContaining.length < 1) {
+ throw new StateError('Cannot build edits for ${source.fullName}');
+ }
+ unit = context.resolveCompilationUnit2(source, librariesContaining[0]);
+ utils = new CorrectionUtils(unit);
+ }
+
+ @override
+ DartEditBuilderImpl createEditBuilder(int offset, int length) {
+ return new DartEditBuilderImpl(this, offset, length);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698