private PropertySymbol AddPropertyToSymbolTable(PropertyInfo property, AggregateSymbol aggregate)
{
Name name;
bool isIndexer = property.GetIndexParameters() != null && property.GetIndexParameters().Length != 0;
if (isIndexer)
{
name = GetName(SpecialNames.Indexer);
}
else
{
name = GetName(property.Name);
}
PropertySymbol prop = _symbolTable.LookupSym(
name,
aggregate,
symbmask_t.MASK_PropertySymbol) as PropertySymbol;
// If we already had one, see if it matches.
if (prop != null)
{
PropertySymbol prevProp = null;
// We'll have multiple properties with the same name if we have indexers.
// In that case, we need to look at every indexer to see if we find one with
// the matching associated sym that we want.
while (prop != null)
{
if (prop.AssociatedPropertyInfo.IsEquivalentTo(property))
{
return prop;
}
prevProp = prop;
prop = _semanticChecker.SymbolLoader.LookupNextSym(prop, prop.parent, symbmask_t.MASK_PropertySymbol).AsPropertySymbol();
}
prop = prevProp;
if (isIndexer)
{
// We have an indexer for a different property info, so
// create a new symbol for it.
prop = null;
}
}
// If we already had a property but its associated info doesn't match,
// then we repurpose the property that we've found. This can happen
// in the case of generic instantiations.
//
// Note that this is a bit of a hack - the best way to fix this is
// by not depending on the instantiated properties at all, but rather depending
// on their non-instantiated generic form, which can be gotten from the
// parent's generic type definition's member. From there, we'll also need to
// keep track of the instantiation as we move along, so that when we need the
// associated property, we can instantiate it correctly.
//
// This seems far too heavyweight - since we know we will never bind to more
// than one property per payload, lets just blast it each time.
if (prop == null)
{
if (isIndexer)
{
prop = _semanticChecker.GetSymbolLoader().GetGlobalMiscSymFactory().CreateIndexer(name, aggregate, GetName(property.Name), null);
prop.Params = CreateParameterArray(null, property.GetIndexParameters());
}
else
{
prop = _symFactory.CreateProperty(GetName(property.Name), aggregate, null);
prop.Params = BSYMMGR.EmptyTypeArray();
}
}
prop.AssociatedPropertyInfo = property;
prop.isStatic = property.GetGetMethod(true) != null ? property.GetGetMethod(true).IsStatic : property.GetSetMethod(true).IsStatic;
prop.isParamArray = DoesMethodHaveParameterArray(property.GetIndexParameters());
prop.swtSlot = null;
prop.RetType = GetCTypeFromType(property.PropertyType);
prop.isOperator = isIndexer;
// Determine if its an override. We should always have an accessor, unless
// the metadata was bogus.
if (property.GetMethod != null || property.SetMethod != null)
{
MethodInfo accessor = property.GetMethod ?? property.SetMethod; // Must have at least one.
prop.isOverride = accessor.IsVirtual && accessor.IsHideBySig && accessor.GetRuntimeBaseDefinition() != accessor;
prop.isHideByName = !accessor.IsHideBySig;
}
SetParameterDataForMethProp(prop, property.GetIndexParameters());
// Get and set.
MethodInfo methGet = property.GetMethod;
MethodInfo methSet = property.SetMethod;
ACCESS access = ACCESS.ACC_PRIVATE;
if (methGet != null)
{
prop.methGet = AddMethodToSymbolTable(methGet, aggregate, MethodKindEnum.PropAccessor);
// If we have an indexed property, leave the method as a method we can call,
// and mark the property as bogus.
if (isIndexer || prop.methGet.Params.size == 0)
{
prop.methGet.SetProperty(prop);
}
else
{
prop.setBogus(true);
prop.methGet.SetMethKind(MethodKindEnum.Actual);
}
if (prop.methGet.GetAccess() > access)
{
access = prop.methGet.GetAccess();
}
}
if (methSet != null)
{
prop.methSet = AddMethodToSymbolTable(methSet, aggregate, MethodKindEnum.PropAccessor);
// If we have an indexed property, leave the method as a method we can call,
// and mark the property as bogus.
if (isIndexer || prop.methSet.Params.size == 1)
{
prop.methSet.SetProperty(prop);
}
else
{
prop.setBogus(true);
prop.methSet.SetMethKind(MethodKindEnum.Actual);
}
if (prop.methSet.GetAccess() > access)
{
access = prop.methSet.GetAccess();
}
}
// The access of the property is the least restrictive access of its getter/setter.
prop.SetAccess(access);
return prop;
}