Files
Paul Berry afcfbbeba8 Migrate developer experience packages to new constructor decl syntax.
(Part of https://github.com/dart-lang/sdk/issues/63288)

This change migrates the packages owned by the developer experience
team to use the new constructor declaration syntax, described in
https://github.com/dart-lang/language/blob/main/accepted/future-releases/primary-constructors/feature-specification.md#abbreviations-of-in-body-constructor-declarations.

This change was performed in an automated fashion, by (a) bumping the
packages' SDK constraints to `3.13.0-0`, (b) enabling the lints
`unnecessary_type_name_in_constructor` and
`unnecessary_const_in_enum_constructor`, (c) fixing the resulting lint
failures using `dart fix`, and then (d) reformatting the affected
files.

To ease code review, I've reverted unrelated formatting changes.

Since this change requires bumping SDK constaints to `3.13.0-0`, it
was only performed on packages that are *not* published on
pub. (Packages that *are* published on pub should remain on lower
language versions until at least after the stable version of 3.13 is
released, so that we don't block users on the stable channel from
receiving updates to those packages.)

Change-Id: Ibb4daebafd239da58251e838ea6a3f336a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/505046
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com>
2026-05-27 14:52:58 -07:00

255 lines
8.1 KiB
Dart

// Copyright (c) 2014, 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.
/// Tools for Java code generation.
library;
import 'package:analyzer_utilities/html_dom.dart' as dom;
import 'package:analyzer_utilities/tools.dart';
import 'api.dart';
import 'from_html.dart';
import 'to_html.dart';
/// Create a [GeneratedFile] that creates Java code and outputs it to [path].
/// [path] uses Posix-style path separators regardless of the OS.
GeneratedFile javaGeneratedFile(
String path,
CodegenJavaVisitor Function(Api api) createVisitor,
) {
return GeneratedFile(path, (pkgRoot) async {
var visitor = createVisitor(readApi(pkgRoot));
return visitor.collectCode(visitor.visitApi);
});
}
/// Iterate through the values in [map] in the order of increasing keys.
Iterable<String> _valuesSortedByKey(Map<String, String> map) {
var entries = map.entries.toList();
entries.sort((a, b) => a.key.compareTo(b.key));
return entries.map((e) => e.value);
}
/// Common code for all Java code generation.
class CodegenJavaVisitor extends HierarchicalApiVisitor with CodeGenerator {
/// Variable names which must be changed in order to avoid conflict with
/// reserved words in Java.
static const Map<String, String> _variableRenames = {'default': 'defaultSdk'};
/// Type references in the spec that are named something else in Java.
static const Map<String, String> _typeRenames = {
'bool': 'boolean',
'double': 'double',
'int': 'int',
'AvailableSuggestionRelevanceTag': 'String',
'ExecutionContextId': 'String',
'FilePath': 'String',
'DebugContextId': 'String',
'object': 'Object',
'Override': 'OverrideMember',
};
_CodegenJavaState _state = _CodegenJavaState();
/// Visitor used to produce doc comments.
final ToHtmlVisitor toHtmlVisitor;
new(super.api) : toHtmlVisitor = ToHtmlVisitor(api);
/// Create a constructor, using [callback] to create its contents.
void constructor(String name, void Function() callback) {
_state.constructors[name] = collectCode(callback);
}
/// Get the name of the consumer class for responses to this request.
String consumerName(Request request) {
return camelJoin([request.method, 'consumer'], doCapitalize: true);
}
/// Return true iff the passed [TypeDecl] will represent an array in Java.
bool isArray(TypeDecl type) {
return type is TypeList && isPrimitive(type.itemType);
}
/// Return true iff the passed [TypeDecl] is a type declared in the
/// spec_input.
bool isDeclaredInSpec(TypeDecl type) {
// TypeReference resolvedType = super.resolveTypeReferenceChain(type);
// if(resolvedType is TypeObject) {
// return true;
// }
if (type is TypeReference) {
return api.types.containsKey(type.typeName) && javaType(type) != 'String';
}
return false;
}
/// Return true iff the passed [TypeDecl] will represent an array in Java.
bool isList(TypeDecl type) {
return type is TypeList && !isPrimitive(type.itemType);
}
/// Return true iff the passed [TypeDecl] will represent a Map in type.
bool isMap(TypeDecl type) {
return type is TypeMap;
}
/// Return true iff the passed [TypeDecl] will be represented as Object in
/// Java.
bool isObject(TypeDecl type) {
var typeStr = javaType(type);
return typeStr == 'Object';
}
/// Return true iff the passed [TypeDecl] will represent a primitive Java
/// type.
bool isPrimitive(TypeDecl type) {
if (type is TypeReference) {
var typeStr = javaType(type);
return typeStr == 'boolean' ||
typeStr == 'double' ||
typeStr == 'int' ||
typeStr == 'long';
}
return false;
}
/// Convenience method for subclasses for calling docComment.
void javadocComment(List<dom.Node> docs) {
docComment(docs);
}
/// Return a Java type for the given [TypeObjectField].
String javaFieldType(TypeObjectField field) {
return javaType(field.type, field.optional);
}
/// Return a suitable representation of [name] as the name of a Java variable.
String javaName(String name) {
return _variableRenames[name] ?? name;
}
/// Convert the given [TypeDecl] to a Java type.
String javaType(TypeDecl type, [bool optional = false]) {
if (type is TypeReference) {
var resolvedType = resolveTypeReferenceChain(type) as TypeReference;
var typeName = resolvedType.typeName;
var renameTo = _typeRenames[typeName];
if (renameTo != null) {
typeName = renameTo;
if (optional) {
if (typeName == 'boolean') {
typeName = 'Boolean';
} else if (typeName == 'double') {
typeName = 'Double';
} else if (typeName == 'int') {
typeName = 'Integer';
}
}
}
return typeName;
} else if (type is TypeList) {
if (isPrimitive(type.itemType)) {
return '${javaType(type.itemType)}[]';
} else {
return 'List<${javaType(type.itemType)}>';
}
} else if (type is TypeMap) {
return 'Map<${javaType(type.keyType)}, ${javaType(type.valueType)}>';
} else if (type is TypeUnion) {
return 'Object';
} else {
throw Exception("Can't make type buildable");
}
}
/// Execute [callback], collecting any methods that are output using
/// [privateMethod] or [publicMethod], and insert the class (with methods
/// sorted). [header] is the part of the class declaration before the
/// opening brace.
void makeClass(String header, void Function() callback) {
var oldState = _state;
try {
_state = _CodegenJavaState();
callback();
writeln('$header {');
indent(() {
// fields
var allFields = _state.publicFields.values.toList();
allFields.addAll(_state.privateFields.values.toList());
for (var field in allFields) {
writeln();
write(field);
}
// constructors
var allConstructors = _state.constructors.values.toList();
for (var constructor in allConstructors) {
writeln();
write(constructor);
}
// methods (ordered by method name)
var allMethods = _valuesSortedByKey(_state.publicMethods).toList();
allMethods.addAll(_valuesSortedByKey(_state.privateMethods));
for (var method in allMethods) {
writeln();
write(method);
}
writeln();
});
writeln('}');
} finally {
_state = oldState;
}
}
/// Create a private field, using [callback] to create its contents.
void privateField(String fieldName, void Function() callback) {
_state.privateFields[fieldName] = collectCode(callback);
}
/// Create a private method, using [callback] to create its contents.
void privateMethod(String methodName, void Function() callback) {
_state.privateMethods[methodName] = collectCode(callback);
}
/// Create a public field, using [callback] to create its contents.
void publicField(String fieldName, void Function() callback) {
_state.publicFields[fieldName] = collectCode(callback);
}
/// Create a public method, using [callback] to create its contents.
void publicMethod(String methodName, void Function() callback) {
_state.publicMethods[methodName] = collectCode(callback);
}
@override
TypeDecl resolveTypeReferenceChain(TypeDecl type) {
var typeDecl = super.resolveTypeReferenceChain(type);
if (typeDecl is TypeEnum) {
return TypeReference('String', null);
}
return type;
}
}
/// State used by [CodegenJavaVisitor].
class _CodegenJavaState {
/// Temporary storage for public methods.
Map<String, String> publicMethods = <String, String>{};
/// Temporary storage for private methods.
Map<String, String> privateMethods = <String, String>{};
/// Temporary storage for public fields.
Map<String, String> publicFields = <String, String>{};
/// Temporary storage for private fields.
Map<String, String> privateFields = <String, String>{};
/// Temporary storage for constructors.
Map<String, String> constructors = <String, String>{};
}