Skip to content

Commit

Permalink
**** Merged from MCS ****
Browse files Browse the repository at this point in the history
svn path=/trunk/mcs/; revision=24299
  • Loading branch information
Martin Baulig committed Mar 18, 2004
1 parent f706238 commit 55ca6c7
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 95 deletions.
18 changes: 18 additions & 0 deletions mcs/gmcs/ChangeLog
@@ -1,3 +1,21 @@
2004-03-17 Ben Maurer <bmaurer@users.sourceforge.net>

* decl.cs (FindMemberToOverride): New method to find the correct
method or property to override in the base class.
* class.cs
- Make Method/Property use the above method to find the
version in the base class.
- Remove the InheritableMemberSignatureCompare as it is now
dead code.

This patch makes large code bases much faster to compile, as it is
O(n) rather than O(n^2) to do this validation.

Also, it fixes bug 52458 which is that nested classes are not
taken into account when finding the base class member.

Reviewed/Approved by Martin.

2004-03-17 Martin Baulig <martin@ximian.com>

* expression.cs (MemberAccess.DoResolve): Take the parent's number
Expand Down
121 changes: 26 additions & 95 deletions mcs/gmcs/class.cs
Expand Up @@ -2650,31 +2650,19 @@ protected override bool CheckBase (TypeContainer container)
Type ptype = container.TypeBuilder.BaseType;

// ptype is only null for System.Object while compiling corlib.
if (ptype != null){
MemberList mi, mi_static, mi_instance;

mi_instance = TypeContainer.FindMembers (
ptype, MemberTypes.Method,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance,
MethodSignature.inheritable_method_signature_filter,
ms);

if (mi_instance.Count > 0){
mi = mi_instance;
} else {
mi_static = TypeContainer.FindMembers (
ptype, MemberTypes.Method,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static,
MethodSignature.inheritable_method_signature_filter, ms);

if (mi_static.Count > 0)
mi = mi_static;
else
mi = null;
if (ptype != null) {

//
// Explicit implementations do not have `parent' methods, however,
// the member cache stores them there. Without this check, we get
// an incorrect warning in corlib.
//
if (! IsExplicitImpl) {
parent_method = (MethodInfo)((IMemberContainer)container).Parent.MemberCache.FindMemberToOverride (
container.TypeBuilder, Name, ParameterTypes, false);
}

if (mi != null && mi.Count > 0){
parent_method = (MethodInfo) mi [0];

if (parent_method != null) {
string name = parent_method.DeclaringType.Name + "." +
parent_method.Name;

Expand Down Expand Up @@ -4356,17 +4344,20 @@ protected override bool CheckBase (TypeContainer container)
"with the same parameter types");
return false;
}

PropertyInfo parent_property = null;

//
// Explicit implementations do not have `parent' methods, however,
// the member cache stores them there. Without this check, we get
// an incorrect warning in corlib.
//
if (! IsExplicitImpl) {
parent_property = (PropertyInfo) ((IMemberContainer)container).Parent.MemberCache.FindMemberToOverride (
container.TypeBuilder, Name, ParameterTypes, true);
}

MemberList mi_props;

mi_props = TypeContainer.FindMembers (
ptype, MemberTypes.Property,
BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance | BindingFlags.Static,
MethodSignature.inheritable_method_signature_filter, base_ms);

if (mi_props.Count > 0){
PropertyInfo parent_property = (PropertyInfo) mi_props [0];
if (parent_property != null) {
string name = parent_property.DeclaringType.Name + "." +
parent_property.Name;

Expand Down Expand Up @@ -5426,22 +5417,7 @@ struct MethodSignature {
/// This delegate is used to extract methods which have the
/// same signature as the argument
/// </summary>
public static MemberFilter method_signature_filter;

/// <summary>
/// This delegate is used to extract inheritable methods which
/// have the same signature as the argument. By inheritable,
/// this means that we have permissions to override the method
/// from the current assembly and class
/// </summary>
public static MemberFilter inheritable_method_signature_filter;

static MethodSignature ()
{
method_signature_filter = new MemberFilter (MemberSignatureCompare);
inheritable_method_signature_filter = new MemberFilter (
InheritableMemberSignatureCompare);
}
public static MemberFilter method_signature_filter = new MemberFilter (MemberSignatureCompare);

public MethodSignature (string name, Type ret_type, Type [] parameters)
{
Expand Down Expand Up @@ -5548,50 +5524,5 @@ static bool MemberSignatureCompare (MemberInfo m, object filter_criteria)
}
return true;
}

//
// This filter should be used when we are requesting methods that
// we want to override.
//
// This makes a number of assumptions, for example
// that the methods being extracted are of a parent
// class (this means we know implicitly that we are
// being called to find out about members by a derived
// class).
//
static bool InheritableMemberSignatureCompare (MemberInfo m, object filter_criteria)
{
MethodInfo mi;
PropertyInfo pi = m as PropertyInfo;

if (pi != null) {
mi = pi.GetGetMethod (true);
if (mi == null)
mi = pi.GetSetMethod (true);
} else
mi = m as MethodInfo;

if (mi == null){
Console.WriteLine ("Nothing found");
}

MethodAttributes prot = mi.Attributes & MethodAttributes.MemberAccessMask;

// If only accessible to the current class.
if (prot == MethodAttributes.Private)
return false;

if (!MemberSignatureCompare (m, filter_criteria))
return false;

// If only accessible to the defining assembly or
if (prot == MethodAttributes.FamANDAssem ||
prot == MethodAttributes.Assembly){
return m.DeclaringType.Assembly == CodeGen.Assembly.Builder;
}

// Anything else (FamOrAssembly and Public) is fine
return true;
}
}
}
95 changes: 95 additions & 0 deletions mcs/gmcs/decl.cs
Expand Up @@ -1719,5 +1719,100 @@ protected bool DoneSearching (ArrayList list)
global.CopyTo (copy);
return new MemberList (copy);
}

//
// This finds the method or property for us to override. invocationType is the type where
// the override is going to be declared, name is the name of the method/property, and
// paramTypes is the parameters, if any to the method or property
//
// Because the MemberCache holds members from this class and all the base classes,
// we can avoid tons of reflection stuff.
//
public MemberInfo FindMemberToOverride (Type invocationType, string name, Type [] paramTypes, bool is_property)
{
ArrayList applicable;
if (method_hash != null && !is_property)
applicable = (ArrayList) method_hash [name];
else
applicable = (ArrayList) member_hash [name];

if (applicable == null)
return null;
//
// Walk the chain of methods, starting from the top.
//
for (int i = applicable.Count - 1; i >= 0; i--) {
CacheEntry entry = (CacheEntry) applicable [i];

if ((entry.EntryType & (is_property ? EntryType.Property : EntryType.Method)) == 0)
continue;

PropertyInfo pi = null;
MethodInfo mi = null;
Type [] cmpAttrs;

if (is_property) {
pi = (PropertyInfo) entry.Member;
cmpAttrs = TypeManager.GetArgumentTypes (pi);
} else {
mi = (MethodInfo) entry.Member;
cmpAttrs = TypeManager.GetArgumentTypes (mi);
}

//
// Check the arguments
//
if (cmpAttrs.Length != paramTypes.Length)
continue;

for (int j = cmpAttrs.Length - 1; j >= 0; j --)
if (paramTypes [j] != cmpAttrs [j])
goto next;

//
// get one of the methods because this has the visibility info.
//
if (is_property) {
mi = pi.GetGetMethod (true);
if (mi == null)
mi = pi.GetSetMethod (true);
}

//
// Check visibility
//
switch (mi.Attributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.Private:
//
// A private method is Ok if we are a nested subtype.
// The spec actually is not very clear about this, see bug 52458.
//
if (invocationType == entry.Container.Type ||
TypeManager.IsNestedChildOf (invocationType, entry.Container.Type))
return entry.Member;

break;
case MethodAttributes.FamANDAssem:
case MethodAttributes.Assembly:
//
// Check for assembly methods
//
if (mi.DeclaringType.Assembly == CodeGen.Assembly.Builder)
return entry.Member;

break;
default:
//
// A protected method is ok, because we are overriding.
// public is always ok.
//
return entry.Member;
}
next:
;
}

return null;
}
}
}

0 comments on commit 55ca6c7

Please sign in to comment.