Skip to content

Commit

Permalink
Cache parsed library results. (#1307)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmorgan authored Apr 3, 2024
1 parent 25d356b commit ac1883c
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 79 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

# 8.9.2

- Improve build performance when there are lots of `built_value` classes.

# 8.9.1

- Fix for new warning about `operator==` param type.
Expand Down
16 changes: 11 additions & 5 deletions built_value_generator/lib/built_value_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:built_value_generator/src/enum_source_library.dart';
import 'package:built_value_generator/src/value_source_class.dart';
import 'package:built_value_generator/src/parsed_library_results.dart';
import 'package:built_value_generator/src/serializer_source_library.dart';
import 'package:built_value_generator/src/value_source_class.dart';
import 'package:source_gen/source_gen.dart';

/// Generator for Enum Class and Built Values.
Expand All @@ -18,14 +19,16 @@ class BuiltValueGenerator extends Generator {

@override
Future<String?> generate(LibraryReader library, BuildStep buildStep) async {
var parsedLibraryResults = ParsedLibraryResults();

// Workaround for https://github.com/google/built_value.dart/issues/941.
LibraryElement libraryElement;
var attempts = 0;
while (true) {
try {
libraryElement = await buildStep.resolver.libraryFor(
await buildStep.resolver.assetIdForElement(library.element));
libraryElement.session.getParsedLibraryByElement(libraryElement);
parsedLibraryResults.parsedLibraryResultOrThrowingMock(libraryElement);
break;
} catch (_) {
++attempts;
Expand All @@ -38,9 +41,11 @@ class BuiltValueGenerator extends Generator {

var result = StringBuffer();
try {
final enumCode = EnumSourceLibrary(libraryElement).generateCode();
final enumCode = EnumSourceLibrary(parsedLibraryResults, libraryElement)
.generateCode();
if (enumCode != null) result.writeln(enumCode);
final serializerSourceLibrary = SerializerSourceLibrary(libraryElement);
final serializerSourceLibrary =
SerializerSourceLibrary(parsedLibraryResults, libraryElement);
if (serializerSourceLibrary.needsBuiltJson ||
serializerSourceLibrary.hasSerializers) {
result.writeln(serializerSourceLibrary.generateCode());
Expand All @@ -64,7 +69,8 @@ class BuiltValueGenerator extends Generator {
for (var element in libraryElement.units.expand((unit) => unit.classes)) {
if (ValueSourceClass.needsBuiltValue(element)) {
try {
result.writeln(ValueSourceClass(element).generateCode());
result.writeln(
ValueSourceClass(parsedLibraryResults, element).generateCode());
} catch (e, st) {
result.writeln(_error(e));
log.severe('Error in BuiltValueGenerator for $element.', e, st);
Expand Down
19 changes: 0 additions & 19 deletions built_value_generator/lib/src/analyzer.dart

This file was deleted.

14 changes: 10 additions & 4 deletions built_value_generator/lib/src/dart_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:built_collection/built_collection.dart';
import 'package:built_value_generator/src/parsed_library_results.dart';
import 'package:built_value_generator/src/value_source_class.dart';

BuiltSet<String> _builtCollectionNames = BuiltSet<String>([
Expand All @@ -17,13 +18,18 @@ BuiltSet<String> _builtCollectionNames = BuiltSet<String>([
]);

class DartTypes {
static bool needsNestedBuilder(DartType type) {
return isInstantiableBuiltValue(type) || isBuiltCollection(type);
static bool needsNestedBuilder(
ParsedLibraryResults parsedLibraryResults, DartType type) {
return isInstantiableBuiltValue(parsedLibraryResults, type) ||
isBuiltCollection(type);
}

static bool isInstantiableBuiltValue(DartType type) {
static bool isInstantiableBuiltValue(
ParsedLibraryResults parsedLibraryResults, DartType type) {
return isBuiltValue(type) &&
ValueSourceClass(type.element as ClassElement).settings.instantiable;
ValueSourceClass(parsedLibraryResults, type.element as ClassElement)
.settings
.instantiable;
}

static bool isBuiltValue(DartType type) =>
Expand Down
13 changes: 8 additions & 5 deletions built_value_generator/lib/src/enum_source_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value_generator/src/analyzer.dart';
import 'package:built_value_generator/src/dart_types.dart';
import 'package:built_value_generator/src/enum_source_field.dart';
import 'package:built_value_generator/src/parsed_library_results.dart';
import 'package:built_value_generator/src/strings.dart';
import 'package:collection/collection.dart'
show IterableExtension, IterableNullableExtension;
Expand All @@ -21,16 +21,19 @@ part 'enum_source_class.g.dart';

abstract class EnumSourceClass
implements Built<EnumSourceClass, EnumSourceClassBuilder> {
ParsedLibraryResults get parsedLibraryResults;

InterfaceElement get element;

factory EnumSourceClass(
ParsedLibraryResult parsedLibrary, InterfaceElement element) =>
_$EnumSourceClass._(element: element);
factory EnumSourceClass(ParsedLibraryResults parsedLibraryResults,
InterfaceElement element) =>
_$EnumSourceClass._(
parsedLibraryResults: parsedLibraryResults, element: element);
EnumSourceClass._();

@memoized
ParsedLibraryResult get parsedLibrary =>
parsedLibraryResultOrThrowingMock(element.library);
parsedLibraryResults.parsedLibraryResultOrThrowingMock(element.library);

@memoized
String get name => element.name;
Expand Down
25 changes: 23 additions & 2 deletions built_value_generator/lib/src/enum_source_class.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions built_value_generator/lib/src/enum_source_library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,27 @@ import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value_generator/src/analyzer.dart';
import 'package:built_value_generator/src/enum_source_class.dart';
import 'package:built_value_generator/src/library_elements.dart';
import 'package:built_value_generator/src/parsed_library_results.dart';
import 'package:source_gen/source_gen.dart';

part 'enum_source_library.g.dart';

abstract class EnumSourceLibrary
implements Built<EnumSourceLibrary, EnumSourceLibraryBuilder> {
ParsedLibraryResults get parsedLibraryResults;
LibraryElement get element;

factory EnumSourceLibrary(LibraryElement element) =>
_$EnumSourceLibrary._(element: element);
factory EnumSourceLibrary(
ParsedLibraryResults parsedLibraryResults, LibraryElement element) =>
_$EnumSourceLibrary._(
parsedLibraryResults: parsedLibraryResults, element: element);
EnumSourceLibrary._();

@memoized
ParsedLibraryResult get parsedLibrary =>
parsedLibraryResultOrThrowingMock(element.library);
parsedLibraryResults.parsedLibraryResultOrThrowingMock(element.library);

@memoized
String get name => element.name;
Expand All @@ -42,7 +45,7 @@ abstract class EnumSourceLibrary

for (var classElement in LibraryElements.getClassElements(element)) {
if (EnumSourceClass.needsEnumClass(classElement)) {
result.add(EnumSourceClass(parsedLibrary, classElement));
result.add(EnumSourceClass(parsedLibraryResults, classElement));
}
}
return result.build();
Expand Down
25 changes: 23 additions & 2 deletions built_value_generator/lib/src/enum_source_library.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions built_value_generator/lib/src/parsed_library_results.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) 2021, Google Inc. 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:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';

/// Caches parsed library results across one generation.
///
/// Substitutes a "throwing mock" if no parsed library is available.
class ParsedLibraryResults {
final Map<Uri, ParsedLibraryResult> _results = {};

ParsedLibraryResult parsedLibraryResultOrThrowingMock(
LibraryElement element) {
var uri = element.source.uri;
return _results[uri] ??= _parsedLibraryResultOrThrowingMock(element);
}

ParsedLibraryResult _parsedLibraryResultOrThrowingMock(
LibraryElement element) {
var result = element.session.getParsedLibraryByElement(element);
if (result is ParsedLibraryResult) {
return result;
}
return _ParsedLibraryResultMock();
}
}

class _ParsedLibraryResultMock implements ParsedLibraryResult {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
Loading

0 comments on commit ac1883c

Please sign in to comment.