in src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs [55:399]
private SourcePropertySymbol(
SourceMemberContainerTypeSymbol containingType,
Binder bodyBinder,
BasePropertyDeclarationSyntax syntax,
string name,
Location location,
DiagnosticBag diagnostics)
{
// This has the value that IsIndexer will ultimately have, once we've populated the fields of this object.
bool isIndexer = syntax.Kind() == SyntaxKind.IndexerDeclaration;
var interfaceSpecifier = GetExplicitInterfaceSpecifier(syntax);
bool isExplicitInterfaceImplementation = (interfaceSpecifier != null);
_location = location;
_containingType = containingType;
_syntaxRef = syntax.GetReference();
_refKind = syntax.Type.GetRefKind();
SyntaxTokenList modifiers = syntax.Modifiers;
bodyBinder = bodyBinder.WithUnsafeRegionIfNecessary(modifiers);
bodyBinder = bodyBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this);
bool modifierErrors;
_modifiers = MakeModifiers(modifiers, isExplicitInterfaceImplementation, isIndexer, location, diagnostics, out modifierErrors);
this.CheckAccessibility(location, diagnostics);
this.CheckModifiers(location, isIndexer, diagnostics);
if (isIndexer && !isExplicitInterfaceImplementation)
{
// Evaluate the attributes immediately in case the IndexerNameAttribute has been applied.
// NOTE: we want IsExplicitInterfaceImplementation, IsOverride, Locations, and the syntax reference
// to be initialized before we pass this symbol to LoadCustomAttributes.
// CONSIDER: none of the information from this early binding pass is cached. Everything will
// be re-bound when someone calls GetAttributes. If this gets to be a problem, we could
// always use the real attribute bag of this symbol and modify LoadAndValidateAttributes to
// handle partially filled bags.
CustomAttributesBag<CSharpAttributeData> temp = null;
LoadAndValidateAttributes(OneOrMany.Create(this.CSharpSyntaxNode.AttributeLists), ref temp, earlyDecodingOnly: true);
if (temp != null)
{
Debug.Assert(temp.IsEarlyDecodedWellKnownAttributeDataComputed);
var propertyData = (PropertyEarlyWellKnownAttributeData)temp.EarlyDecodedWellKnownAttributeData;
if (propertyData != null)
{
_sourceName = propertyData.IndexerName;
}
}
}
string aliasQualifierOpt;
string memberName = ExplicitInterfaceHelpers.GetMemberNameAndInterfaceSymbol(bodyBinder, interfaceSpecifier, name, diagnostics, out _explicitInterfaceType, out aliasQualifierOpt);
_sourceName = _sourceName ?? memberName; //sourceName may have been set while loading attributes
_name = isIndexer ? ExplicitInterfaceHelpers.GetMemberName(WellKnownMemberNames.Indexer, _explicitInterfaceType, aliasQualifierOpt) : _sourceName;
_isExpressionBodied = false;
bool hasAccessorList = syntax.AccessorList != null;
var propertySyntax = syntax as PropertyDeclarationSyntax;
var arrowExpression = propertySyntax != null
? propertySyntax.ExpressionBody
: ((IndexerDeclarationSyntax)syntax).ExpressionBody;
bool hasExpressionBody = arrowExpression != null;
bool hasInitializer = !isIndexer && propertySyntax.Initializer != null;
bool notRegularProperty = (!IsAbstract && !IsExtern && !isIndexer && hasAccessorList);
AccessorDeclarationSyntax getSyntax = null;
AccessorDeclarationSyntax setSyntax = null;
if (hasAccessorList)
{
foreach (var accessor in syntax.AccessorList.Accessors)
{
switch (accessor.Kind())
{
case SyntaxKind.GetAccessorDeclaration:
if (getSyntax == null)
{
getSyntax = accessor;
}
else
{
diagnostics.Add(ErrorCode.ERR_DuplicateAccessor, accessor.Keyword.GetLocation());
}
break;
case SyntaxKind.SetAccessorDeclaration:
if (setSyntax == null)
{
setSyntax = accessor;
}
else
{
diagnostics.Add(ErrorCode.ERR_DuplicateAccessor, accessor.Keyword.GetLocation());
}
break;
case SyntaxKind.AddAccessorDeclaration:
case SyntaxKind.RemoveAccessorDeclaration:
diagnostics.Add(ErrorCode.ERR_GetOrSetExpected, accessor.Keyword.GetLocation());
continue;
case SyntaxKind.UnknownAccessorDeclaration:
// We don't need to report an error here as the parser will already have
// done that for us.
continue;
default:
throw ExceptionUtilities.UnexpectedValue(accessor.Kind());
}
if (accessor.Body != null || accessor.ExpressionBody != null)
{
notRegularProperty = false;
}
}
}
else
{
notRegularProperty = false;
}
if (hasInitializer)
{
CheckInitializer(notRegularProperty, location, diagnostics);
}
if (notRegularProperty || hasInitializer)
{
var hasGetSyntax = getSyntax != null;
_isAutoProperty = notRegularProperty && hasGetSyntax;
bool isReadOnly = hasGetSyntax && setSyntax == null;
if (_isAutoProperty && !isReadOnly && !IsStatic && ContainingType.IsReadOnly)
{
diagnostics.Add(ErrorCode.ERR_AutoPropsInRoStruct, location);
}
if (_isAutoProperty || hasInitializer)
{
if (_isAutoProperty)
{
//issue a diagnostic if the compiler generated attribute ctor is not found.
Binder.ReportUseSiteDiagnosticForSynthesizedAttribute(bodyBinder.Compilation,
WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor, diagnostics, syntax: syntax);
if (this._refKind != RefKind.None && !_containingType.IsInterface)
{
diagnostics.Add(ErrorCode.ERR_AutoPropertyCannotBeRefReturning, location, this);
}
}
string fieldName = GeneratedNames.MakeBackingFieldName(_sourceName);
_backingField = new SynthesizedBackingFieldSymbol(this,
fieldName,
isReadOnly,
this.IsStatic,
hasInitializer);
}
if (notRegularProperty)
{
Binder.CheckFeatureAvailability(
syntax,
isReadOnly ? MessageID.IDS_FeatureReadonlyAutoImplementedProperties : MessageID.IDS_FeatureAutoImplementedProperties,
diagnostics,
location);
}
}
PropertySymbol explicitlyImplementedProperty = null;
_customModifiers = CustomModifiersTuple.Empty;
// The runtime will not treat the accessors of this property as overrides or implementations
// of those of another property unless both the signatures and the custom modifiers match.
// Hence, in the case of overrides and *explicit* implementations, we need to copy the custom
// modifiers that are in the signatures of the overridden/implemented property accessors.
// (From source, we know that there can only be one overridden/implemented property, so there
// are no conflicts.) This is unnecessary for implicit implementations because, if the custom
// modifiers don't match, we'll insert bridge methods for the accessors (explicit implementations
// that delegate to the implicit implementations) with the correct custom modifiers
// (see SourceNamedTypeSymbol.ImplementInterfaceMember).
// Note: we're checking if the syntax indicates explicit implementation rather,
// than if explicitInterfaceType is null because we don't want to look for an
// overridden property if this is supposed to be an explicit implementation.
if (isExplicitInterfaceImplementation || this.IsOverride)
{
// Type and parameters for overrides and explicit implementations cannot be bound
// lazily since the property name depends on the metadata name of the base property,
// and the property name is required to add the property to the containing type, and
// the type and parameters are required to determine the override or implementation.
_lazyType = this.ComputeType(bodyBinder, syntax, diagnostics);
_lazyParameters = this.ComputeParameters(bodyBinder, syntax, diagnostics);
bool isOverride = false;
PropertySymbol overriddenOrImplementedProperty = null;
if (!isExplicitInterfaceImplementation)
{
// If this property is an override, we may need to copy custom modifiers from
// the overridden property (so that the runtime will recognize it as an override).
// We check for this case here, while we can still modify the parameters and
// return type without losing the appearance of immutability.
isOverride = true;
overriddenOrImplementedProperty = this.OverriddenProperty;
}
else
{
string interfacePropertyName = isIndexer ? WellKnownMemberNames.Indexer : name;
explicitlyImplementedProperty = this.FindExplicitlyImplementedProperty(_explicitInterfaceType, interfacePropertyName, interfaceSpecifier, diagnostics);
overriddenOrImplementedProperty = explicitlyImplementedProperty;
}
if ((object)overriddenOrImplementedProperty != null)
{
_customModifiers = CustomModifiersTuple.Create(overriddenOrImplementedProperty.TypeCustomModifiers,
_refKind != RefKind.None ? overriddenOrImplementedProperty.RefCustomModifiers : ImmutableArray<CustomModifier>.Empty);
TypeSymbol overriddenPropertyType = overriddenOrImplementedProperty.Type;
// We do an extra check before copying the type to handle the case where the overriding
// property (incorrectly) has a different type than the overridden property. In such cases,
// we want to retain the original (incorrect) type to avoid hiding the type given in source.
if (_lazyType.Equals(overriddenPropertyType, TypeCompareKind.IgnoreCustomModifiersAndArraySizesAndLowerBounds | TypeCompareKind.IgnoreDynamic))
{
_lazyType = CustomModifierUtils.CopyTypeCustomModifiers(overriddenPropertyType, _lazyType, this.ContainingAssembly);
}
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
}
}
else if (_refKind == RefKind.RefReadOnly)
{
var modifierType = bodyBinder.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_InAttribute, diagnostics, syntax.Type);
_customModifiers = CustomModifiersTuple.Create(
ImmutableArray<CustomModifier>.Empty,
ImmutableArray.Create(CSharpCustomModifier.CreateRequired(modifierType)));
}
if (!hasAccessorList)
{
if (hasExpressionBody)
{
_isExpressionBodied = true;
_getMethod = SourcePropertyAccessorSymbol.CreateAccessorSymbol(
containingType,
this,
_modifiers,
_sourceName,
arrowExpression,
explicitlyImplementedProperty,
aliasQualifierOpt,
diagnostics);
}
else
{
_getMethod = null;
}
_setMethod = null;
}
else
{
_getMethod = CreateAccessorSymbol(getSyntax, explicitlyImplementedProperty, aliasQualifierOpt, notRegularProperty, diagnostics);
_setMethod = CreateAccessorSymbol(setSyntax, explicitlyImplementedProperty, aliasQualifierOpt, notRegularProperty, diagnostics);
if ((getSyntax == null) || (setSyntax == null))
{
if ((getSyntax == null) && (setSyntax == null))
{
diagnostics.Add(ErrorCode.ERR_PropertyWithNoAccessors, location, this);
}
else if (_refKind != RefKind.None)
{
if (getSyntax == null)
{
diagnostics.Add(ErrorCode.ERR_RefPropertyMustHaveGetAccessor, location, this);
}
}
else if (notRegularProperty)
{
var accessor = _getMethod ?? _setMethod;
if (getSyntax == null)
{
diagnostics.Add(ErrorCode.ERR_AutoPropertyMustHaveGetAccessor, accessor.Locations[0], accessor);
}
}
}
// Check accessor accessibility is more restrictive than property accessibility.
CheckAccessibilityMoreRestrictive(_getMethod, diagnostics);
CheckAccessibilityMoreRestrictive(_setMethod, diagnostics);
if (((object)_getMethod != null) && ((object)_setMethod != null))
{
if (_refKind != RefKind.None)
{
diagnostics.Add(ErrorCode.ERR_RefPropertyCannotHaveSetAccessor, _setMethod.Locations[0], _setMethod);
}
else if ((_getMethod.LocalAccessibility != Accessibility.NotApplicable) &&
(_setMethod.LocalAccessibility != Accessibility.NotApplicable))
{
// Check accessibility is set on at most one accessor.
diagnostics.Add(ErrorCode.ERR_DuplicatePropertyAccessMods, location, this);
}
else if (this.IsAbstract)
{
// Check abstract property accessors are not private.
CheckAbstractPropertyAccessorNotPrivate(_getMethod, diagnostics);
CheckAbstractPropertyAccessorNotPrivate(_setMethod, diagnostics);
}
}
else
{
if (!this.IsOverride)
{
var accessor = _getMethod ?? _setMethod;
if ((object)accessor != null)
{
// Check accessibility is not set on the one accessor.
if (accessor.LocalAccessibility != Accessibility.NotApplicable)
{
diagnostics.Add(ErrorCode.ERR_AccessModMissingAccessor, location, this);
}
}
}
}
}
if ((object)explicitlyImplementedProperty != null)
{
CheckExplicitImplementationAccessor(this.GetMethod, explicitlyImplementedProperty.GetMethod, explicitlyImplementedProperty, diagnostics);
CheckExplicitImplementationAccessor(this.SetMethod, explicitlyImplementedProperty.SetMethod, explicitlyImplementedProperty, diagnostics);
}
_explicitInterfaceImplementations =
(object)explicitlyImplementedProperty == null ?
ImmutableArray<PropertySymbol>.Empty :
ImmutableArray.Create(explicitlyImplementedProperty);
// get-only auto property should not override settable properties
if (_isAutoProperty && (object)_setMethod == null && !this.IsReadOnly)
{
diagnostics.Add(ErrorCode.ERR_AutoPropertyMustOverrideSet, location, this);
}
CheckForBlockAndExpressionBody(
syntax.AccessorList, syntax.GetExpressionBodySyntax(), syntax, diagnostics);
}