Issue 41050. Get default values for fromEnvironment() from element model.
Bug: https://github.com/dart-lang/sdk/issues/41050 Change-Id: I8fee34a6b5816a725df4e4886fc85061ac4ec9b5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/139661 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
ae19e68377
commit
db5dc11b9b
@@ -418,41 +418,6 @@ class ConstantEvaluationEngine {
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate a call to fromEnvironment() on the bool, int, or String class.
|
||||
/// The [environmentValue] is the value fetched from the environment. The
|
||||
/// [builtInDefaultValue] is the value that should be used as the default if
|
||||
/// no "defaultValue" argument appears in [namedArgumentValues]. The
|
||||
/// [namedArgumentValues] are the values of the named parameters passed to
|
||||
/// fromEnvironment(). Return a [DartObjectImpl] object corresponding to the
|
||||
/// evaluated result.
|
||||
DartObjectImpl computeValueFromEnvironment(
|
||||
DartObject environmentValue,
|
||||
DartObjectImpl builtInDefaultValue,
|
||||
Map<String, DartObjectImpl> namedArgumentValues) {
|
||||
DartObjectImpl value = environmentValue as DartObjectImpl;
|
||||
if (value.isUnknown || value.isNull) {
|
||||
// The name either doesn't exist in the environment or we couldn't parse
|
||||
// the corresponding value.
|
||||
// If the code supplied an explicit default, use it.
|
||||
if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) {
|
||||
value = namedArgumentValues[_DEFAULT_VALUE_PARAM];
|
||||
} else if (value.isNull) {
|
||||
// The code didn't supply an explicit default.
|
||||
// The name exists in the environment but we couldn't parse the
|
||||
// corresponding value.
|
||||
// So use the built-in default value, because this is what the VM does.
|
||||
value = builtInDefaultValue;
|
||||
} else {
|
||||
// The code didn't supply an explicit default.
|
||||
// The name doesn't exist in the environment.
|
||||
// The VM would use the built-in default value, but we don't want to do
|
||||
// that for analysis because it's likely to lead to cascading errors.
|
||||
// So just leave [value] in the unknown state.
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
DartObjectImpl evaluateConstructorCall(
|
||||
AstNode node,
|
||||
List<Expression> arguments,
|
||||
@@ -527,43 +492,14 @@ class ConstantEvaluationEngine {
|
||||
String variableName =
|
||||
argumentCount < 1 ? null : argumentValues[0].toStringValue();
|
||||
if (definingClass == typeProvider.boolType) {
|
||||
DartObject valueFromEnvironment;
|
||||
valueFromEnvironment =
|
||||
_fromEnvironmentEvaluator.getBool(variableName);
|
||||
return computeValueFromEnvironment(
|
||||
valueFromEnvironment,
|
||||
DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.boolType,
|
||||
BoolState.FALSE_STATE,
|
||||
),
|
||||
namedValues,
|
||||
);
|
||||
return _fromEnvironmentEvaluator.getBool2(
|
||||
variableName, namedValues, constructor);
|
||||
} else if (definingClass == typeProvider.intType) {
|
||||
DartObject valueFromEnvironment;
|
||||
valueFromEnvironment = _fromEnvironmentEvaluator.getInt(variableName);
|
||||
return computeValueFromEnvironment(
|
||||
valueFromEnvironment,
|
||||
DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.nullType,
|
||||
NullState.NULL_STATE,
|
||||
),
|
||||
namedValues,
|
||||
);
|
||||
return _fromEnvironmentEvaluator.getInt2(
|
||||
variableName, namedValues, constructor);
|
||||
} else if (definingClass == typeProvider.stringType) {
|
||||
DartObject valueFromEnvironment;
|
||||
valueFromEnvironment =
|
||||
_fromEnvironmentEvaluator.getString(variableName);
|
||||
return computeValueFromEnvironment(
|
||||
valueFromEnvironment,
|
||||
DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.nullType,
|
||||
NullState.NULL_STATE,
|
||||
),
|
||||
namedValues,
|
||||
);
|
||||
return _fromEnvironmentEvaluator.getString2(
|
||||
variableName, namedValues, constructor);
|
||||
}
|
||||
} else if (constructor.name == "" &&
|
||||
definingClass == typeProvider.symbolType &&
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/dart/constant/value.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/generated/type_system.dart';
|
||||
|
||||
class FromEnvironmentEvaluator {
|
||||
/// Parameter to "fromEnvironment" methods that denotes the default value.
|
||||
static const String _defaultValue = 'defaultValue';
|
||||
|
||||
final TypeSystemImpl _typeSystem;
|
||||
final DeclaredVariables _declaredVariables;
|
||||
|
||||
@@ -17,6 +21,7 @@ class FromEnvironmentEvaluator {
|
||||
/// 'boolean' value. If the variable is not defined (or [name] is `null`), a
|
||||
/// DartObject representing "unknown" is returned. If the value cannot be
|
||||
/// parsed as a boolean, a DartObject representing 'null' is returned.
|
||||
@Deprecated("Clients don't need this functionality")
|
||||
DartObject getBool(String name) {
|
||||
String value = _declaredVariables.get(name);
|
||||
if (value == null) {
|
||||
@@ -46,10 +51,44 @@ class FromEnvironmentEvaluator {
|
||||
);
|
||||
}
|
||||
|
||||
/// Return the value of the variable with the given [name] interpreted as a
|
||||
/// 'boolean' value. If the variable is not defined, or the value cannot be
|
||||
/// parsed as a boolean, return the default value from [namedValues]. If no
|
||||
/// default value, return the default value of the default value from
|
||||
/// the [constructor], possibly a [DartObject] representing 'null'.
|
||||
DartObject getBool2(
|
||||
String name,
|
||||
Map<String, DartObjectImpl> namedValues,
|
||||
ConstructorElement constructor,
|
||||
) {
|
||||
var str = _declaredVariables.get(name);
|
||||
if (str == 'true') {
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.boolType,
|
||||
BoolState.TRUE_STATE,
|
||||
);
|
||||
}
|
||||
if (str == 'false') {
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.boolType,
|
||||
BoolState.FALSE_STATE,
|
||||
);
|
||||
}
|
||||
|
||||
if (namedValues.containsKey(_defaultValue)) {
|
||||
return namedValues[_defaultValue];
|
||||
}
|
||||
|
||||
return _defaultValueDefaultValue(constructor);
|
||||
}
|
||||
|
||||
/// Return the value of the variable with the given [name] interpreted as an
|
||||
/// integer value. If the variable is not defined (or [name] is `null`), a
|
||||
/// DartObject representing "unknown" is returned. If the value cannot be
|
||||
/// parsed as an integer, a DartObject representing 'null' is returned.
|
||||
@Deprecated("Clients don't need this functionality")
|
||||
DartObject getInt(String name) {
|
||||
String value = _declaredVariables.get(name);
|
||||
if (value == null) {
|
||||
@@ -76,11 +115,54 @@ class FromEnvironmentEvaluator {
|
||||
);
|
||||
}
|
||||
|
||||
/// Return the value of the variable with the given [name] interpreted as an
|
||||
/// integer value. If the variable is not defined, or the value cannot be
|
||||
/// parsed as an integer, return the default value from [namedValues]. If no
|
||||
/// default value, return the default value of the default value from
|
||||
/// the [constructor], possibly a [DartObject] representing 'null'.
|
||||
DartObject getInt2(
|
||||
String name,
|
||||
Map<String, DartObjectImpl> namedValues,
|
||||
ConstructorElement constructor,
|
||||
) {
|
||||
var str = _declaredVariables.get(name);
|
||||
if (str != null) {
|
||||
try {
|
||||
var value = int.parse(str);
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.intType,
|
||||
IntState(value),
|
||||
);
|
||||
} on FormatException {
|
||||
// fallthrough
|
||||
}
|
||||
}
|
||||
|
||||
if (namedValues.containsKey(_defaultValue)) {
|
||||
return namedValues[_defaultValue];
|
||||
}
|
||||
|
||||
var defaultDefault = _defaultValueDefaultValue(constructor);
|
||||
|
||||
// TODO(scheglov) Remove after https://github.com/dart-lang/sdk/issues/40678
|
||||
if (defaultDefault.isNull) {
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.intType,
|
||||
IntState.UNKNOWN_VALUE,
|
||||
);
|
||||
}
|
||||
|
||||
return defaultDefault;
|
||||
}
|
||||
|
||||
/// Return the value of the variable with the given [name] interpreted as a
|
||||
/// String value, or `null` if the variable is not defined. Return the value
|
||||
/// of the variable with the given name interpreted as a String value. If the
|
||||
/// variable is not defined (or [name] is `null`), a DartObject representing
|
||||
/// "unknown" is returned.
|
||||
@Deprecated("Clients don't need this functionality")
|
||||
DartObject getString(String name) {
|
||||
String value = _declaredVariables.get(name);
|
||||
if (value == null) {
|
||||
@@ -96,4 +178,51 @@ class FromEnvironmentEvaluator {
|
||||
StringState(value),
|
||||
);
|
||||
}
|
||||
|
||||
/// Return the value of the variable with the given [name] interpreted as a
|
||||
/// string value. If the variable is not defined, or the value cannot be
|
||||
/// parsed as a boolean, return the default value from [namedValues]. If no
|
||||
/// default value, return the default value of the default value from
|
||||
/// the [constructor], possibly a [DartObject] representing 'null'.
|
||||
DartObject getString2(
|
||||
String name,
|
||||
Map<String, DartObjectImpl> namedValues,
|
||||
ConstructorElement constructor,
|
||||
) {
|
||||
String str = _declaredVariables.get(name);
|
||||
if (str != null) {
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.stringType,
|
||||
StringState(str),
|
||||
);
|
||||
}
|
||||
|
||||
if (namedValues.containsKey(_defaultValue)) {
|
||||
return namedValues[_defaultValue];
|
||||
}
|
||||
|
||||
var defaultDefault = _defaultValueDefaultValue(constructor);
|
||||
|
||||
// TODO(scheglov) Remove after https://github.com/dart-lang/sdk/issues/40678
|
||||
if (defaultDefault.isNull) {
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.stringType,
|
||||
StringState.UNKNOWN_VALUE,
|
||||
);
|
||||
}
|
||||
|
||||
return defaultDefault;
|
||||
}
|
||||
|
||||
bool hasEnvironment(String name) {
|
||||
return _declaredVariables.get(name) != null;
|
||||
}
|
||||
|
||||
static DartObject _defaultValueDefaultValue(ConstructorElement constructor) {
|
||||
return constructor.parameters
|
||||
.singleWhere((parameter) => parameter.name == _defaultValue)
|
||||
.computeConstantValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
typeSystem = analysisContext.typeSystemLegacy;
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getBool_false() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -41,6 +42,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
expect(object.toBoolValue(), false);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getBool_invalid() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -52,6 +54,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getBool_true() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -63,6 +66,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
expect(object.toBoolValue(), true);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getBool_undefined() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -75,6 +79,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getInt_invalid() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -86,6 +91,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getInt_undefined() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -98,6 +104,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getInt_valid() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
@@ -109,6 +116,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
expect(object.toIntValue(), 23);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getString_defined() {
|
||||
String variableName = "var";
|
||||
String value = "value";
|
||||
@@ -121,6 +129,7 @@ class FromEnvironmentEvaluatorTest {
|
||||
expect(object.toStringValue(), value);
|
||||
}
|
||||
|
||||
@deprecated
|
||||
void test_getString_undefined() {
|
||||
String variableName = "var";
|
||||
var variables = FromEnvironmentEvaluator(
|
||||
|
||||
@@ -108,6 +108,76 @@ const c = true ? x : 0;
|
||||
expect(result, isNull);
|
||||
}
|
||||
|
||||
test_visitInstanceCreationExpression_bool_fromEnvironment() async {
|
||||
await resolveTestCode('''
|
||||
const a = bool.fromEnvironment('a');
|
||||
const b = bool.fromEnvironment('b', defaultValue: true);
|
||||
''');
|
||||
expect(
|
||||
_evaluateConstant('a'),
|
||||
_boolValue(false),
|
||||
);
|
||||
expect(
|
||||
_evaluateConstant('a', declaredVariables: {'a': 'true'}),
|
||||
_boolValue(true),
|
||||
);
|
||||
|
||||
expect(
|
||||
_evaluateConstant(
|
||||
'b',
|
||||
declaredVariables: {'b': 'bbb'},
|
||||
lexicalEnvironment: {'defaultValue': _boolValue(true)},
|
||||
),
|
||||
_boolValue(true),
|
||||
);
|
||||
}
|
||||
|
||||
test_visitInstanceCreationExpression_int_fromEnvironment() async {
|
||||
await resolveTestCode('''
|
||||
const a = int.fromEnvironment('a');
|
||||
const b = int.fromEnvironment('b', defaultValue: 42);
|
||||
''');
|
||||
expect(
|
||||
_evaluateConstant('a'),
|
||||
_intValue(0),
|
||||
);
|
||||
expect(
|
||||
_evaluateConstant('a', declaredVariables: {'a': '5'}),
|
||||
_intValue(5),
|
||||
);
|
||||
|
||||
expect(
|
||||
_evaluateConstant(
|
||||
'b',
|
||||
declaredVariables: {'b': 'bbb'},
|
||||
lexicalEnvironment: {'defaultValue': _intValue(42)},
|
||||
),
|
||||
_intValue(42),
|
||||
);
|
||||
}
|
||||
|
||||
test_visitInstanceCreationExpression_string_fromEnvironment() async {
|
||||
await resolveTestCode('''
|
||||
const a = String.fromEnvironment('a');
|
||||
''');
|
||||
expect(
|
||||
_evaluateConstant('a'),
|
||||
DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.stringType,
|
||||
StringState(''),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
_evaluateConstant('a', declaredVariables: {'a': 'test'}),
|
||||
DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.stringType,
|
||||
StringState('test'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
test_visitIntegerLiteral() async {
|
||||
await resolveTestCode('''
|
||||
const double d = 3;
|
||||
@@ -187,12 +257,38 @@ const b = 3;''');
|
||||
expect(result.type, typeProvider.intType);
|
||||
expect(result.toIntValue(), 3);
|
||||
}
|
||||
|
||||
DartObjectImpl _boolValue(bool value) {
|
||||
if (identical(value, false)) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.boolType,
|
||||
BoolState.FALSE_STATE,
|
||||
);
|
||||
} else if (identical(value, true)) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.boolType,
|
||||
BoolState.TRUE_STATE,
|
||||
);
|
||||
}
|
||||
fail("Invalid boolean value used in test");
|
||||
}
|
||||
|
||||
DartObjectImpl _intValue(int value) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
typeProvider.intType,
|
||||
IntState(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ConstantVisitorTestSupport extends DriverResolutionTest {
|
||||
DartObjectImpl _evaluateConstant(
|
||||
String name, {
|
||||
List<ErrorCode> errorCodes,
|
||||
Map<String, String> declaredVariables = const {},
|
||||
Map<String, DartObjectImpl> lexicalEnvironment,
|
||||
}) {
|
||||
var options = driver.analysisOptions as AnalysisOptionsImpl;
|
||||
@@ -210,7 +306,7 @@ class ConstantVisitorTestSupport extends DriverResolutionTest {
|
||||
ConstantVisitor(
|
||||
ConstantEvaluationEngine(
|
||||
typeProvider,
|
||||
DeclaredVariables(),
|
||||
DeclaredVariables.fromMap(declaredVariables),
|
||||
experimentStatus: options.experimentStatus,
|
||||
typeSystem: this.result.typeSystem,
|
||||
),
|
||||
|
||||
@@ -166,7 +166,7 @@ var x = const C(2);
|
||||
test_fromEnvironment_assertInitializer() async {
|
||||
await assertNoErrorsInCode('''
|
||||
class A {
|
||||
const A(int x) : assert(x > 5);
|
||||
const A(int x) : assert(x >= 0);
|
||||
}
|
||||
|
||||
main() {
|
||||
|
||||
Reference in New Issue
Block a user