Skip to content

Fix three little issues in mustachio codegen #2491

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions test/mustachio/builder_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Context<T> {
};

const _libraryFrontMatter = '''
@Renderer(#renderFoo, Context<Foo>(), visibleTypes: {Bar})
@Renderer(#renderFoo, Context<Foo>(), visibleTypes: {Bar, Baz})
library foo;
import 'package:mustachio/annotations.dart';
''';
Expand Down Expand Up @@ -73,15 +73,19 @@ $sourceLibraryContent
setUpAll(() async {
writer = InMemoryAssetWriter();
await testMustachioBuilder('''
abstract class FooBase {
abstract class FooBase2<T> {
T get generic;
}
abstract class FooBase<T extends Baz> extends FooBase2<T> {
Bar get bar;
}
class Foo extends FooBase {
abstract class Foo extends FooBase {
String s1 = "s1";
bool b1 = false;
List<int> l1 = [1, 2, 3];
}
class Bar {}
class Baz {}
''');
renderersLibrary = await resolveGeneratedLibrary(writer);
var rendererAsset = AssetId.parse('foo|lib/foo.renderers.dart');
Expand All @@ -92,11 +96,13 @@ class Bar {}
// The render function for Foo
expect(
generatedContent,
contains('String _render_FooBase(\n'
' FooBase context, List<MustachioNode> ast, Template template,'));
contains('String _render_FooBase<T extends Baz>(\n'
' FooBase<T> context, List<MustachioNode> ast, Template template,'));
// The renderer class for Foo
expect(generatedContent,
contains('class _Renderer_FooBase extends RendererBase<FooBase>'));
expect(
generatedContent,
contains(
'class _Renderer_FooBase<T extends Baz> extends RendererBase<FooBase<T>>'));
});

test('for Object', () {
Expand All @@ -121,6 +127,11 @@ class Bar {}
expect(renderersLibrary.getType('_Renderer_Bar'), isNotNull);
});

test('for a generic, bounded type found in a getter', () {
expect(renderersLibrary.getTopLevelFunction('_render_Baz'), isNotNull);
expect(renderersLibrary.getType('_Renderer_Baz'), isNotNull);
});

test('with a property map', () {
expect(
generatedContent,
Expand All @@ -130,7 +141,7 @@ class Bar {}

test('with a property map which references the superclass', () {
expect(generatedContent,
contains('..._Renderer_FooBase.propertyMap<CT_>(),'));
contains('..._Renderer_FooBase.propertyMap<Baz, CT_>(),'));
});

test('with a property map with a bool property', () {
Expand Down Expand Up @@ -203,6 +214,7 @@ class Bar {}
await testMustachioBuilder('''
class Foo {}
class Bar {}
class Baz {}
''', libraryFrontMatter: '''
@Renderer(#renderFoo, Context<Foo>())
@Renderer(#renderBar, Context<Bar>())
Expand All @@ -229,6 +241,7 @@ class FooBase<T> {}
class Foo<T> extends FooBase<T> {}
class BarBase<T> {}
class Bar<T> extends BarBase<int> {}
class Baz {}
''', libraryFrontMatter: '''
@Renderer(#renderFoo, Context<Foo>())
@Renderer(#renderBar, Context<Bar>())
Expand Down Expand Up @@ -275,6 +288,7 @@ import 'package:mustachio/annotations.dart';
await testMustachioBuilder('''
class Foo<T extends num> {}
class Bar {}
class Baz {}
''');
var renderersLibrary = await resolveGeneratedLibrary(writer);

Expand All @@ -295,13 +309,14 @@ class Bar {}
setUpAll(() async {
writer = InMemoryAssetWriter();
await testMustachioBuilder('''
class Foo {
abstract class Foo<T> {
static Static get static1 => Bar();
Private get _private1 => Bar();
void set setter1(Setter s);
Method method1(Method m);
}
class Bar {}
class Baz {}
class Static {}
class Private {}
class Setter {}
Expand Down
48 changes: 37 additions & 11 deletions tool/mustachio/codegen_runtime_renderer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,16 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>

specs.forEach(_addTypesForRendererSpec);

var builtRenderers = <ClassElement>{};

while (_typesToProcess.isNotEmpty) {
var info = _typesToProcess.removeFirst();

if (info.isFullRenderer) {
_buildRenderer(info);
var buildOnlyPublicFunction =
builtRenderers.contains(info._contextClass);
_buildRenderer(info, buildOnlyPublicFunction: buildOnlyPublicFunction);
builtRenderers.add(info._contextClass);
}
}

Expand Down Expand Up @@ -142,6 +147,18 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
if (property.isPrivate || property.isStatic || property.isSetter) return;
if (property.hasProtected || property.hasVisibleForTesting) return;
var type = property.type.returnType;
if (type is TypeParameterType) {
var bound = (type as TypeParameterType).bound;
if (bound == null || bound.isDynamic) {
// Don't add functions for a generic type, for example
// `List<E>.first` has type `E`, which we don't have a specific
// renderer for.
// TODO(srawlins): Find a solution for this. We can track all of the
// concrete types substituted for `E` for example.
return;
}
type = bound;
}
var isFullRenderer = _isVisibleToMustache(type.element);

if (_typeSystem.isAssignableTo(type, _typeProvider.iterableDynamicType)) {
Expand Down Expand Up @@ -170,9 +187,8 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>

/// Adds [type] to the [_typesToProcess] queue, if it is not already there.
void _addTypeToProcess(ClassElement element, {@required isFullRenderer}) {
var typeToProcess = _typesToProcess
.singleWhere((rs) => rs._contextClass == element, orElse: () => null);
if (typeToProcess == null) {
var types = _typesToProcess.where((rs) => rs._contextClass == element);
if (types.isEmpty) {
var rendererInfo = _RendererInfo(element,
isFullRenderer: isFullRenderer, public: _rendererClassesArePublic);
_typesToProcess.add(rendererInfo);
Expand All @@ -181,11 +197,14 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
_typeToRendererClassName[element] = rendererInfo._rendererClassName;
}
} else {
if (isFullRenderer && !typeToProcess.isFullRenderer) {
// This is the only case in which we update a type-to-render.
typeToProcess.isFullRenderer = true;
_typeToRenderFunctionName[element] = typeToProcess._renderFunctionName;
_typeToRendererClassName[element] = typeToProcess._rendererClassName;
for (var typeToProcess in types) {
if (isFullRenderer && !typeToProcess.isFullRenderer) {
// This is the only case in which we update a type-to-render.
typeToProcess.isFullRenderer = true;
_typeToRenderFunctionName[element] =
typeToProcess._renderFunctionName;
_typeToRendererClassName[element] = typeToProcess._rendererClassName;
}
}
}
}
Expand All @@ -201,14 +220,19 @@ String _simpleResolveErrorMessage(List<String> key, String type) =>
return _isVisibleToMustache(element.supertype.element);
}

/// Builds both the render function and the renderer class for [renderer].
/// Builds render functions and the renderer class for [renderer].
///
/// The function and the class are each written as Dart code to [_buffer].
///
/// If [renderer] also specifies a `publicApiFunctionName`, then a public API
/// function (which renders a context object using a template file at a path,
/// rather than an AST) is also written.
void _buildRenderer(_RendererInfo renderer) {
///
/// If [buildOnlyPublicFunction] is true, then the private render function and
/// renderer classes are not built, having been built for a different
/// [_RendererInfo].
void _buildRenderer(_RendererInfo renderer,
{@required bool buildOnlyPublicFunction}) {
var typeName = renderer._typeName;
var typeWithVariables = '$typeName${renderer._typeVariablesString}';

Expand All @@ -221,6 +245,8 @@ String ${renderer.publicApiFunctionName}${renderer._typeParametersString}(
''');
}

if (buildOnlyPublicFunction) return;

// Write out the render function.
_buffer.writeln('''
String ${renderer._renderFunctionName}${renderer._typeParametersString}(
Expand Down