Browse Source

Fixed SD2-1487: protected static members not visible in code completion of derived class

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3719 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
c4cca90012
  1. 5
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockProjectContent.cs
  2. 5
      src/AddIns/Misc/UnitTesting/Test/Utils/MockProjectContent.cs
  3. 6
      src/Main/Base/Test/GenericResolverTests.cs
  4. 77
      src/Main/Base/Test/NRefactoryResolverTests.cs
  5. 56
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractEntity.cs
  6. 3
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEntity.cs
  7. 24
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs
  8. 4
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs
  9. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs
  10. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs

5
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockProjectContent.cs

@ -349,5 +349,10 @@ namespace PythonBinding.Tests.Utils
ReferencedContentsChanged(this, e); ReferencedContentsChanged(this, e);
} }
} }
public bool InternalsVisibleTo(IProjectContent otherProjectContent)
{
throw new NotImplementedException();
}
} }
} }

5
src/AddIns/Misc/UnitTesting/Test/Utils/MockProjectContent.cs

@ -175,5 +175,10 @@ namespace UnitTesting.Tests.Utils
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public bool InternalsVisibleTo(IProjectContent otherProjectContent)
{
throw new NotImplementedException();
}
} }
} }

6
src/Main/Base/Test/GenericResolverTests.cs

@ -408,13 +408,13 @@ class Program {
d.T<char, int>('a', 1); d.T<char, int>('a', 1);
d.T<int, char>('a', 2); d.T<int, char>('a', 2);
} }
protected virtual void T<A, B>(A a, B b) { public virtual void T<A, B>(A a, B b) {
} }
protected virtual void T<X, Y>(Y a, X b) { public virtual void T<X, Y>(Y a, X b) {
} }
} }
class D : Program { class D : Program {
protected override void T<X, Y>(X a, Y b) { public override void T<X, Y>(X a, Y b) {
// overrides T<A,B> - type arguments are identified by position // overrides T<A,B> - type arguments are identified by position
} }
}"; }";

77
src/Main/Base/Test/NRefactoryResolverTests.cs

@ -1395,6 +1395,7 @@ class Method { }
bool MemberExists(ArrayList members, string name) bool MemberExists(ArrayList members, string name)
{ {
Assert.IsNotNull(members);
foreach (object o in members) { foreach (object o in members) {
IMember m = o as IMember; IMember m = o as IMember;
if (m != null && m.Name == name) return true; if (m != null && m.Name == name) return true;
@ -2671,5 +2672,81 @@ class Flags {
IReturnType rt = result.ResolvedClass.Attributes[0].AttributeType; IReturnType rt = result.ResolvedClass.Attributes[0].AttributeType;
Assert.AreEqual("System.FlagsAttribute", rt.FullyQualifiedName); Assert.AreEqual("System.FlagsAttribute", rt.FullyQualifiedName);
} }
[Test]
public void SD2_1487a()
{
string program = @"using System;
class C2 : C1 {
public static void M() {
}
}
class C1 {
protected static int Field;
}";
MemberResolveResult mrr;
mrr = Resolve<MemberResolveResult>(program, "Field", 4, 1, ExpressionContext.Default);
Assert.AreEqual("C1.Field", mrr.ResolvedMember.FullyQualifiedName);
mrr = Resolve<MemberResolveResult>(program, "C1.Field", 4, 1, ExpressionContext.Default);
Assert.AreEqual("C1.Field", mrr.ResolvedMember.FullyQualifiedName);
mrr = Resolve<MemberResolveResult>(program, "C2.Field", 4, 1, ExpressionContext.Default);
Assert.AreEqual("C1.Field", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void SD2_1487b()
{
string program = @"using System;
class C2 : C1 {
public static void M() {
}
}
class C1 {
protected static int Field;
}";
ArrayList arr = CtrlSpaceResolveCSharp(program, 4, ExpressionContext.Default);
Assert.IsTrue(MemberExists(arr, "Field"));
ResolveResult rr = Resolve(program, "C1", 4);
arr = rr.GetCompletionData(rr.CallingClass.ProjectContent);
Assert.IsTrue(MemberExists(arr, "Field"));
rr = Resolve(program, "C2", 4);
arr = rr.GetCompletionData(rr.CallingClass.ProjectContent);
Assert.IsTrue(MemberExists(arr, "Field"));
}
[Test]
public void ProtectedPrivateVisibilityTest()
{
string program = @"using System;
class B : A {
void M(C c) {
}
private int P2;
protected int Y;
}
class A {
private int P1;
protected int X;
}
class C : B {
private int P3;
protected int Z;
}";
LocalResolveResult rr = Resolve<LocalResolveResult>(program, "c", 4);
ArrayList arr = rr.GetCompletionData(lastPC);
Assert.IsFalse(MemberExists(arr, "P1"));
Assert.IsTrue(MemberExists(arr, "P2"));
Assert.IsFalse(MemberExists(arr, "P3"));
Assert.IsTrue(MemberExists(arr, "X"));
Assert.IsTrue(MemberExists(arr, "Y"));
Assert.IsFalse(MemberExists(arr, "Z"));
}
} }
} }

56
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractEntity.cs

@ -258,12 +258,14 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
} }
[Obsolete("This property does not do what one would expect - it merely checks if protected+internal are set, it is not the equivalent of AssemblyAndFamily in Reflection!")]
public bool IsProtectedAndInternal { public bool IsProtectedAndInternal {
get { get {
return (modifiers & (ModifierEnum.Internal | ModifierEnum.Protected)) == (ModifierEnum.Internal | ModifierEnum.Protected); return (modifiers & (ModifierEnum.Internal | ModifierEnum.Protected)) == (ModifierEnum.Internal | ModifierEnum.Protected);
} }
} }
[Obsolete("This property does not do what one would expect - it merely checks if one of protected+internal is set, it is not the equivalent of AssemblyOrFamily in Reflection!")]
public bool IsProtectedOrInternal { public bool IsProtectedOrInternal {
get { get {
return IsProtected || IsInternal; return IsProtected || IsInternal;
@ -298,44 +300,32 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
#endregion #endregion
bool IsInnerClass(IClass c, IClass possibleInnerClass) public bool IsAccessible(IClass callingClass, bool isAccessThoughReferenceOfCurrentClass)
{ {
foreach (IClass inner in c.InnerClasses) {
if (inner.FullyQualifiedName == possibleInnerClass.FullyQualifiedName) {
return true;
}
if (IsInnerClass(inner, possibleInnerClass)) {
return true;
}
}
return false;
}
// TODO: check inner classes for protected members too.
public bool IsAccessible(IClass callingClass, bool isClassInInheritanceTree)
{
if (IsInternal) {
return true;
}
if (IsPublic) { if (IsPublic) {
return true; return true;
} } else if (IsInternal) {
if (isClassInInheritanceTree && IsProtected) { return callingClass != null && this.DeclaringType.ProjectContent.InternalsVisibleTo(callingClass.ProjectContent);
return true; }
} // protected or private:
// search in callingClass and, if callingClass is a nested class, in its outer classes
return callingClass != null && (DeclaringType.FullyQualifiedName == callingClass.FullyQualifiedName || IsInnerClass(DeclaringType, callingClass)); while (callingClass != null) {
} if (IsProtected) {
if (!isAccessThoughReferenceOfCurrentClass && !IsStatic)
return false;
return callingClass.IsTypeInInheritanceTree(this.DeclaringType);
} else {
// private
if (DeclaringType.FullyQualifiedName == callingClass.FullyQualifiedName
&& DeclaringType.TypeParameters.Count == callingClass.TypeParameters.Count)
{
return true;
}
}
public bool MustBeShown(IClass callingClass, bool showStatic, bool isClassInInheritanceTree) callingClass = callingClass.DeclaringType;
{
if (DeclaringType.ClassType == ClassType.Enum) {
return true;
} }
if (!showStatic && IsStatic || (showStatic && !(IsStatic || IsConst))) { // const is automatically static return false;
return false;
}
return IsAccessible(callingClass, isClassInInheritanceTree);
} }
public virtual int CompareTo(IEntity value) public virtual int CompareTo(IEntity value)

3
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IEntity.cs

@ -130,7 +130,6 @@ namespace ICSharpCode.SharpDevelop.Dom
set; set;
} }
bool IsAccessible(IClass callingClass, bool isClassInInheritanceTree); bool IsAccessible(IClass callingClass, bool isAccessThoughReferenceOfCurrentClass);
//bool MustBeShown(IClass callingClass, bool showStatic, bool isClassInInheritanceTree);
} }
} }

24
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs

@ -35,16 +35,16 @@ namespace ICSharpCode.SharpDevelop.Dom
public static List<IList<IMember>> LookupMember( public static List<IList<IMember>> LookupMember(
IReturnType type, string name, IClass callingClass, IReturnType type, string name, IClass callingClass,
LanguageProperties language, bool isInvocation, bool? isClassInInheritanceTree) LanguageProperties language, bool isInvocation, bool? isAccessThoughReferenceOfCurrentClass)
{ {
if (language == null) if (language == null)
throw new ArgumentNullException("language"); throw new ArgumentNullException("language");
if (isClassInInheritanceTree == null) { if (isAccessThoughReferenceOfCurrentClass == null) {
isClassInInheritanceTree = false; isAccessThoughReferenceOfCurrentClass = false;
IClass underlyingClass = type.GetUnderlyingClass(); IClass underlyingClass = type.GetUnderlyingClass();
if (underlyingClass != null) if (underlyingClass != null)
isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); isAccessThoughReferenceOfCurrentClass = underlyingClass.IsTypeInInheritanceTree(callingClass);
} }
IEnumerable<IMember> members; IEnumerable<IMember> members;
@ -54,7 +54,7 @@ namespace ICSharpCode.SharpDevelop.Dom
members = GetAllMembers(type).Where(m => language.NameComparer.Equals(m.Name, name)); members = GetAllMembers(type).Where(m => language.NameComparer.Equals(m.Name, name));
} }
return LookupMember(members, callingClass, (bool)isClassInInheritanceTree, isInvocation); return LookupMember(members, callingClass, (bool)isAccessThoughReferenceOfCurrentClass, isInvocation);
} }
class SignatureComparer : IEqualityComparer<IMethod> class SignatureComparer : IEqualityComparer<IMethod>
@ -120,14 +120,14 @@ namespace ICSharpCode.SharpDevelop.Dom
public static List<IList<IMember>> LookupMember( public static List<IList<IMember>> LookupMember(
IEnumerable<IMember> possibleMembers, IClass callingClass, IEnumerable<IMember> possibleMembers, IClass callingClass,
bool isClassInInheritanceTree, bool isInvocation) bool isAccessThoughReferenceOfCurrentClass, bool isInvocation)
{ {
// Console.WriteLine("Possible members:"); // Console.WriteLine("Possible members:");
// foreach (IMember m in possibleMembers) { // foreach (IMember m in possibleMembers) {
// Console.WriteLine(" " + m.DotNetName); // Console.WriteLine(" " + m.DotNetName);
// } // }
IEnumerable<IMember> accessibleMembers = possibleMembers.Where(member => member.IsAccessible(callingClass, isClassInInheritanceTree)); IEnumerable<IMember> accessibleMembers = possibleMembers.Where(member => member.IsAccessible(callingClass, isAccessThoughReferenceOfCurrentClass));
if (isInvocation) { if (isInvocation) {
accessibleMembers = accessibleMembers.Where(IsInvocable); accessibleMembers = accessibleMembers.Where(IsInvocable);
} }
@ -202,24 +202,24 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary> /// </summary>
public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language) public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language)
{ {
bool isClassInInheritanceTree = false; bool isAccessThoughReferenceOfCurrentClass = false;
IClass underlyingClass = rt.GetUnderlyingClass(); IClass underlyingClass = rt.GetUnderlyingClass();
if (underlyingClass != null) if (underlyingClass != null)
isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); isAccessThoughReferenceOfCurrentClass = underlyingClass.IsTypeInInheritanceTree(callingClass);
return GetAccessibleMembers(rt, callingClass, language, isClassInInheritanceTree); return GetAccessibleMembers(rt, callingClass, language, isAccessThoughReferenceOfCurrentClass);
} }
/// <summary> /// <summary>
/// Gets all accessible members, including indexers and constructors. /// Gets all accessible members, including indexers and constructors.
/// </summary> /// </summary>
public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language, bool isClassInInheritanceTree) public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language, bool isAccessThoughReferenceOfCurrentClass)
{ {
if (language == null) if (language == null)
throw new ArgumentNullException("language"); throw new ArgumentNullException("language");
List<IMember> result = new List<IMember>(); List<IMember> result = new List<IMember>();
foreach (var g in GetAllMembers(rt).GroupBy(m => m.Name, language.NameComparer).OrderBy(g2=>g2.Key)) { foreach (var g in GetAllMembers(rt).GroupBy(m => m.Name, language.NameComparer).OrderBy(g2=>g2.Key)) {
foreach (var group in LookupMember(g, callingClass, isClassInInheritanceTree, false)) { foreach (var group in LookupMember(g, callingClass, isAccessThoughReferenceOfCurrentClass, false)) {
result.AddRange(group); result.AddRange(group);
} }
} }

4
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs

@ -640,9 +640,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
#region ResolveMember #region ResolveMember
internal ResolveResult ResolveMember(IReturnType declaringType, string memberName, internal ResolveResult ResolveMember(IReturnType declaringType, string memberName,
List<TypeReference> typeArguments, bool isInvocation, List<TypeReference> typeArguments, bool isInvocation,
bool allowExtensionMethods, bool? isClassInInheritanceTree) bool allowExtensionMethods, bool? isAccessThoughReferenceOfCurrentClass)
{ {
List<IList<IMember>> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation, isClassInInheritanceTree); List<IList<IMember>> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation, isAccessThoughReferenceOfCurrentClass);
List<IReturnType> typeArgs = null; List<IReturnType> typeArgs = null;
if (members != null && typeArguments != null && typeArguments.Count != 0) { if (members != null && typeArguments != null && typeArguments.Count != 0) {
typeArgs = typeArguments.ConvertAll(r => TypeVisitor.CreateReturnType(r, this)); typeArgs = typeArguments.ConvertAll(r => TypeVisitor.CreateReturnType(r, this));

7
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/DefaultProjectContent.cs

@ -579,7 +579,7 @@ namespace ICSharpCode.SharpDevelop.Dom
// check the outermost class (which is either public or internal) // check the outermost class (which is either public or internal)
while (c.DeclaringType != null) while (c.DeclaringType != null)
c = c.DeclaringType; c = c.DeclaringType;
return c.IsPublic || c.ProjectContent == this; return c.IsPublic || c.ProjectContent.InternalsVisibleTo(this);
} }
public IClass GetClass(string typeName, int typeParameterCount, LanguageProperties language, GetClassOptions options) public IClass GetClass(string typeName, int typeParameterCount, LanguageProperties language, GetClassOptions options)
@ -967,6 +967,11 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
} }
public bool InternalsVisibleTo(IProjectContent otherProjectContent)
{
return this == otherProjectContent;
}
public static readonly IProjectContent DummyProjectContent = new DummyContent(); public static readonly IProjectContent DummyProjectContent = new DummyContent();
private class DummyContent : DefaultProjectContent private class DummyContent : DefaultProjectContent

5
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ProjectContent/IProjectContent.cs

@ -113,6 +113,11 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary> /// </summary>
/// <param name="entity">The entity to get the position from.</param> /// <param name="entity">The entity to get the position from.</param>
FilePosition GetPosition(IEntity entity); FilePosition GetPosition(IEntity entity);
/// <summary>
/// Gets whether internals in the project content are visible to the other project content.
/// </summary>
bool InternalsVisibleTo(IProjectContent otherProjectContent);
} }
[Flags] [Flags]

Loading…
Cancel
Save