blob: 9729bfd68cd3b265ad2e060890ccf63c07d36212 [file] [log] [blame]
// Copyright (c) 2020, 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.
import 'package:analysis_server/src/services/correction/fix/data_driven/value_extractor.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analyzer/dart/ast/ast.dart';
/// An object used to generate code to be inserted.
class CodeTemplate {
/// The kind of code that will be generated by this template.
final CodeTemplateKind kind;
/// The components of the template.
final List<TemplateComponent> components;
/// Initialize a newly generated code template with the given [kind] and
/// [components].
CodeTemplate(this.kind, this.components);
String generate(AstNode node, CorrectionUtils utils) {
var context = TemplateContext(node, utils);
var buffer = StringBuffer();
for (var component in components) {
component.appendTo(buffer, context);
}
return buffer.toString();
}
}
/// The kinds of code that can be generated by a template.
enum CodeTemplateKind {
expression,
statements,
}
/// An object used to compute some portion of a template.
abstract class TemplateComponent {
/// Append the text contributed by this component to the given [sink], using
/// the [context] to access needed information that isn't already known to
/// this component.
void appendTo(StringSink sink, TemplateContext context);
}
/// The context in which a template is being evaluated.
class TemplateContext {
/// The node in the AST that is being transformed.
final AstNode node;
/// The utilities used to help extract the code associated with various nodes.
final CorrectionUtils utils;
/// A table mapping variable names to the values of those variables after they
/// have been computed. Used to prevent computing the same value multiple
/// times.
final Map<ValueGenerator, String> _variableValues = {};
/// Initialize a newly created variable support.
TemplateContext(this.node, this.utils);
/// Return the value of the variable with the given [name].
String valueOf(ValueGenerator extractor) {
return _variableValues.putIfAbsent(extractor, () {
return extractor.from(this);
});
}
}
/// Literal text within a template.
class TemplateText extends TemplateComponent {
/// The literal text to be included in the resulting code.
final String text;
/// Initialize a newly create template text with the given [text].
TemplateText(this.text);
@override
void appendTo(StringSink sink, TemplateContext context) {
sink.write(text);
}
}
/// A reference to a variable within a template.
class TemplateVariable extends TemplateComponent {
/// The extractor used to compute the value of the variable.
final ValueGenerator extractor;
/// Initialize a newly created template variable with the given [name].
TemplateVariable(this.extractor);
@override
void appendTo(StringSink sink, TemplateContext context) {
sink.write(context.valueOf(extractor));
}
}