blob: e13057be0ed8eb6edb00a1c8b4165a290c20bc02 [file] [log] [blame]
// Copyright (c) 2023, 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 'dart:convert' show jsonEncode;
import '../constants/values.dart';
import '../serialization/serialization.dart';
class ResourceIdentifier {
static const String tag = 'resource-identifier';
/// Name of the class or method that is a resource identifier.
final String name;
/// When the class or method is defined.
final Uri uri;
/// Location of the resource identifer instance. This is `null` for constant
/// resource identifiers. For other resource identifer instances this is the
/// call site to the constructor or method.
final ResourceIdentifierLocation? location;
/// True if some argument is missing from [arguments] because it is not a
/// constant.
final bool nonconstant;
/// JSON encoded map from class field names or function parameter positions to
/// primitive values for arguments that are constant.
// TODO(sra): Consider holding as a map with ConstantValue values.
final String arguments;
ResourceIdentifier(
this.name, this.uri, this.location, this.nonconstant, this.arguments);
factory ResourceIdentifier.readFromDataSource(DataSourceReader source) {
source.begin(tag);
String name = source.readString();
Uri uri = source.readUri();
bool hasLocation = source.readBool();
ResourceIdentifierLocation? location = hasLocation
? ResourceIdentifierLocation.readFromDataSource(source)
: null;
bool nonconstant = source.readBool();
String arguments = source.readString();
source.end(tag);
return ResourceIdentifier(name, uri, location, nonconstant, arguments);
}
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeString(name);
sink.writeUri(uri);
if (location == null) {
sink.writeBool(false);
} else {
sink.writeBool(true);
location!.writeToDataSink(sink);
}
sink.writeBool(nonconstant);
sink.writeString(arguments);
sink.end(tag);
}
@override
bool operator ==(Object other) =>
other is ResourceIdentifier &&
name == other.name &&
uri == other.uri &&
location == other.location &&
arguments == other.arguments;
@override
int get hashCode => Object.hash(name, uri, location, arguments);
@override
String toString() {
return 'ResourceIdentifier($name @ $uri, $location, $arguments)';
}
}
class ResourceIdentifierLocation {
final Uri uri;
final int? line;
final int? column;
ResourceIdentifierLocation._(this.uri, this.line, this.column);
factory ResourceIdentifierLocation.readFromDataSource(
DataSourceReader source) {
final uri = source.readUri();
final line = source.readIntOrNull();
final column = source.readIntOrNull();
return ResourceIdentifierLocation._(uri, line, column);
}
void writeToDataSink(DataSinkWriter sink) {
sink.writeUri(uri);
sink.writeIntOrNull(line);
sink.writeIntOrNull(column);
}
@override
bool operator ==(Object other) =>
other is ResourceIdentifierLocation &&
uri == other.uri &&
line == other.line &&
column == other.column;
@override
late int hashCode = Object.hash(uri, line, column);
@override
String toString() => 'ResourceIdentifierLocation($uri:$line:$column)';
}
class ResourceIdentifierBuilder {
final String name;
final Uri uri;
bool _nonconstant = false;
ResourceIdentifierLocation? _location;
final Map<String, Object?> _arguments = {};
ResourceIdentifierBuilder(this.name, this.uri);
ResourceIdentifier finish() {
return ResourceIdentifier(
name, uri, _location, _nonconstant, jsonEncode(_arguments));
}
void add(String argumentName, ConstantValue? constant) {
if (constant != null) {
final value = _findValue(constant);
if (!identical(value, _unknown)) {
_arguments[argumentName] = value;
return;
}
}
_nonconstant = true;
}
void addLocation(Uri uri, int? line, int? column) {
_location = ResourceIdentifierLocation._(uri, line, column);
}
Object? _findValue(ConstantValue constant) {
if (constant is IntConstantValue) {
final value = constant.intValue;
return value.isValidInt ? value.toInt() : _unknown;
}
if (constant is StringConstantValue) return constant.stringValue;
if (constant is BoolConstantValue) return constant.boolValue;
if (constant is DoubleConstantValue) return constant.doubleValue;
if (constant is NullConstantValue) return null;
return _unknown;
}
static final Object _unknown = Object();
}