Index: pkg/analyzer/lib/src/generated/element.dart |
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart |
index 5c83632fc8c3d77664787cbba4c0a23f9984fd9b..166fc822188b0287e39d96d809bfa60750d6c9b8 100644 |
--- a/pkg/analyzer/lib/src/generated/element.dart |
+++ b/pkg/analyzer/lib/src/generated/element.dart |
@@ -4667,17 +4667,7 @@ class FieldMember extends VariableMember implements FieldElement { |
* @return the field element that will return the correctly substituted types |
*/ |
static FieldElement from(FieldElement baseField, InterfaceType definingType) { |
- if (baseField == null || definingType.typeArguments.length == 0) { |
- return baseField; |
- } |
- DartType baseType = baseField.type; |
- if (baseType == null) { |
- return baseField; |
- } |
- List<DartType> argumentTypes = definingType.typeArguments; |
- List<DartType> parameterTypes = definingType.element.type.typeArguments; |
- DartType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); |
- if (baseType == substitutedType) { |
+ if (!_isChangedByTypeSubstitution(baseField, definingType)) { |
return baseField; |
} |
// TODO(brianwilkerson) Consider caching the substituted type in the instance. It would use more |
@@ -4686,6 +4676,39 @@ class FieldMember extends VariableMember implements FieldElement { |
} |
/** |
+ * Determine whether the given field's type is changed when type parameters from the defining |
+ * type's declaration are replaced with the actual type arguments from the defining type. |
+ * |
+ * @param baseField the base field |
+ * @param definingType the type defining the parameters and arguments to be used in the |
+ * substitution |
+ * @return true if the type is changed by type substitution. |
+ */ |
+ static bool _isChangedByTypeSubstitution(FieldElement baseField, InterfaceType definingType) { |
+ List<DartType> argumentTypes = definingType.typeArguments; |
+ if (baseField != null && argumentTypes.length != 0) { |
+ DartType baseType = baseField.type; |
+ List<DartType> parameterTypes = definingType.element.type.typeArguments; |
+ if (baseType != null) { |
+ DartType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); |
+ if (baseType != substitutedType) { |
+ return true; |
+ } |
+ } |
+ // If the field has a propagated type, then we need to check whether the propagated type |
+ // needs substitution. |
+ DartType basePropagatedType = baseField.propagatedType; |
+ if (basePropagatedType != null) { |
+ DartType substitutedPropagatedType = basePropagatedType.substitute2(argumentTypes, parameterTypes); |
+ if (basePropagatedType != substitutedPropagatedType) { |
+ return true; |
+ } |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ /** |
* Initialize a newly created element to represent a field of the given parameterized type. |
* |
* @param baseElement the element on which the parameterized element was created |
@@ -4715,6 +4738,15 @@ class FieldMember extends VariableMember implements FieldElement { |
bool get isStatic => baseElement.isStatic; |
@override |
+ String toString() { |
+ JavaStringBuilder builder = new JavaStringBuilder(); |
+ builder.append(type); |
+ builder.append(" "); |
+ builder.append(displayName); |
+ return builder.toString(); |
+ } |
+ |
+ @override |
InterfaceType get definingType => super.definingType as InterfaceType; |
} |
@@ -7413,14 +7445,21 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType { |
* Combination of [AngularTagSelectorElementImpl] and [HasAttributeSelectorElementImpl]. |
*/ |
class IsTagHasAttributeSelectorElementImpl extends AngularSelectorElementImpl { |
- final String tagName; |
+ String _tagName; |
- final String attributeName; |
+ String _attributeName; |
- IsTagHasAttributeSelectorElementImpl(this.tagName, this.attributeName) : super(null, -1); |
+ IsTagHasAttributeSelectorElementImpl(String tagName, String attributeName) : super("${tagName}[${attributeName}]", -1) { |
+ this._tagName = tagName; |
+ this._attributeName = attributeName; |
+ } |
@override |
- bool apply(XmlTagNode node) => node.tag == tagName && node.getAttribute(attributeName) != null; |
+ bool apply(XmlTagNode node) => node.tag == _tagName && node.getAttribute(_attributeName) != null; |
+ |
+ String get attributeName => _attributeName; |
+ |
+ String get tagName => _tagName; |
} |
/** |
@@ -9900,14 +9939,7 @@ class PropertyAccessorMember extends ExecutableMember implements PropertyAccesso |
* @return the property accessor element that will return the correctly substituted types |
*/ |
static PropertyAccessorElement from(PropertyAccessorElement baseAccessor, InterfaceType definingType) { |
- if (baseAccessor == null || definingType.typeArguments.length == 0) { |
- return baseAccessor; |
- } |
- FunctionType baseType = baseAccessor.type; |
- List<DartType> argumentTypes = definingType.typeArguments; |
- List<DartType> parameterTypes = definingType.element.type.typeArguments; |
- FunctionType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); |
- if (baseType == substitutedType) { |
+ if (!_isChangedByTypeSubstitution(baseAccessor, definingType)) { |
return baseAccessor; |
} |
// TODO(brianwilkerson) Consider caching the substituted type in the instance. It would use more |
@@ -9916,6 +9948,40 @@ class PropertyAccessorMember extends ExecutableMember implements PropertyAccesso |
} |
/** |
+ * Determine whether the given property accessor's type is changed when type parameters from the |
+ * defining type's declaration are replaced with the actual type arguments from the defining type. |
+ * |
+ * @param baseAccessor the base property accessor |
+ * @param definingType the type defining the parameters and arguments to be used in the |
+ * substitution |
+ * @return true if the type is changed by type substitution. |
+ */ |
+ static bool _isChangedByTypeSubstitution(PropertyAccessorElement baseAccessor, InterfaceType definingType) { |
+ List<DartType> argumentTypes = definingType.typeArguments; |
+ if (baseAccessor != null && argumentTypes.length != 0) { |
+ FunctionType baseType = baseAccessor.type; |
+ List<DartType> parameterTypes = definingType.element.type.typeArguments; |
+ FunctionType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); |
+ if (baseType != substitutedType) { |
+ return true; |
+ } |
+ // If this property accessor is based on a field, that field might have a propagated type. |
+ // In which case we need to check whether the propagated type of the field needs substitution. |
+ PropertyInducingElement field = baseAccessor.variable; |
+ if (!field.isSynthetic) { |
+ DartType baseFieldType = field.propagatedType; |
+ if (baseFieldType != null) { |
+ DartType substitutedFieldType = baseFieldType.substitute2(argumentTypes, parameterTypes); |
+ if (baseFieldType != substitutedFieldType) { |
+ return true; |
+ } |
+ } |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ /** |
* Initialize a newly created element to represent a property accessor of the given parameterized |
* type. |
* |