Browse Source

Improved code completion with default constructors:

- don't add default constructor when a class has internal constructors
 - always add default constructor to value types
Disable "Rename" command for operators.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@5002 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 17 years ago
parent
commit
503cb2b06e
  1. 5
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs
  2. 2
      src/Main/Base/Project/Src/TextEditor/Commands/ClassMemberMenuBuilder.cs
  3. 5
      src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs
  4. 7
      src/Main/Base/Test/GenerateOverrideMethodTests.cs
  5. 39
      src/Main/Base/Test/NRefactoryResolverTests.cs
  6. 16
      src/Main/Base/Test/ReflectionLayerTests.cs
  7. 1
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs
  8. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CompoundClass.cs
  9. 28
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs
  10. 9
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs
  11. 10
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs
  12. 26
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IClass.cs
  13. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs
  14. 6
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs
  15. 1
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs
  16. 63
      src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/NRefactoryAstConverterTests.cs

5
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs

@ -418,16 +418,13 @@ namespace Grunwald.BooBinding.CodeCompletion @@ -418,16 +418,13 @@ namespace Grunwald.BooBinding.CodeCompletion
if (callingClass != null)
isClassInInheritanceTree = callingClass.IsTypeInInheritanceTree(trr.ResolvedClass);
foreach (IMethod m in trr.ResolvedClass.Methods) {
foreach (IMethod m in trr.ResolvedClass.DefaultReturnType.GetMethods()) {
if (m.IsConstructor && !m.IsStatic
&& m.IsAccessible(callingClass, isClassInInheritanceTree))
{
methods.Add(m);
}
}
if (methods.Count == 0) {
methods.Add(ICSharpCode.SharpDevelop.Dom.Constructor.CreateDefault(trr.ResolvedClass));
}
ResolveInvocation(methods, node.Arguments);
if (resolveResult != null)
resolveResult.ResolvedType = trr.ResolvedType;

2
src/Main/Base/Project/Src/TextEditor/Commands/ClassMemberMenuBuilder.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands @@ -45,7 +45,7 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Commands
member.DeclaringType.ProjectContent.Language.CodeGenerator != null
&& !FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType);
if (method == null || !method.IsConstructor) {
if (method == null || !method.IsConstructor && !method.GetIsOperator()) {
if (!FindReferencesAndRenameHelper.IsReadOnly(member.DeclaringType) &&
!(member is IProperty && ((IProperty)member).IsIndexer)) {
cmd = new MenuCommand("${res:SharpDevelop.Refactoring.RenameCommand}", Rename);

5
src/Main/Base/Project/Src/TextEditor/Gui/Editor/InsightWindow/MethodInsightDataProvider.cs

@ -144,11 +144,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor @@ -144,11 +144,6 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor
if (trr != null || expressionResult.Context == ExpressionContext.BaseConstructorCall) {
if (results.ResolvedType != null) {
methods.AddRange(GetConstructorMethods(results.ResolvedType.GetMethods()));
IClass resolvedClass = (trr != null) ? trr.ResolvedClass : results.ResolvedType.GetUnderlyingClass();
if (methods.Count == 0 && resolvedClass != null && !resolvedClass.IsStatic) {
// add default constructor
methods.Add(Constructor.CreateDefault(resolvedClass));
}
}
}
} else {

7
src/Main/Base/Test/GenerateOverrideMethodTests.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Linq;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.Refactoring;
@ -28,10 +29,10 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -28,10 +29,10 @@ namespace ICSharpCode.SharpDevelop.Tests
Assert.AreEqual(2, cu.Classes.Count);
Assert.AreEqual(1, cu.Classes[0].Methods.Count + cu.Classes[0].Properties.Count);
IMember virtualMember;
if (cu.Classes[0].Methods.Count > 0)
virtualMember = cu.Classes[0].Methods[0];
else //if (cu.Classes[0].Properties.Count > 0)
if (cu.Classes[0].Properties.Count > 0)
virtualMember = cu.Classes[0].Properties[0];
else
virtualMember = cu.Classes[0].Methods[0];
CSharpCodeGenerator ccg = new CSharpCodeGenerator();
AttributedNode result = ccg.GetOverridingMethod(virtualMember, new ClassFinder(cu.Classes[1], 3, 1));
Assert.IsNotNull(result);

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

@ -578,11 +578,50 @@ class A { @@ -578,11 +578,50 @@ class A {
IMethod m = (IMethod)result.ResolvedMember;
Assert.IsNotNull(m);
Assert.AreEqual("A", result.ResolvedType.FullyQualifiedName);
Assert.AreEqual(0, m.Parameters.Count);
ArrayList ar = result.GetCompletionData(result.CallingClass.ProjectContent);
Assert.IsTrue(ContainsMember(ar, "A.Method"));
}
[Test]
public void DefaultStructCTorOverloadLookupTest()
{
string program = @"struct A {
void Method() {
}
public A(int x) {}
}
";
MemberResolveResult result = Resolve<MemberResolveResult>(program, "new A()", 3);
IMethod m = (IMethod)result.ResolvedMember;
Assert.IsNotNull(m);
Assert.AreEqual("A", result.ResolvedType.FullyQualifiedName);
Assert.AreEqual(0, m.Parameters.Count);
ArrayList ar = result.GetCompletionData(result.CallingClass.ProjectContent);
Assert.IsTrue(ContainsMember(ar, "A.Method"));
}
[Test]
public void ReflectionStructCTorOverloadLookupTest()
{
string program = @"using System;
class A {
void Method() {
}
}
";
MemberResolveResult result = Resolve<MemberResolveResult>(program, "new DateTime()", 4);
IMethod m = (IMethod)result.ResolvedMember;
Assert.IsNotNull(m);
Assert.AreEqual("System.DateTime", result.ResolvedType.FullyQualifiedName);
Assert.AreEqual(0, m.Parameters.Count);
}
[Test]
public void ValueInsideSetterTest()
{

16
src/Main/Base/Test/ReflectionLayerTests.cs

@ -171,6 +171,22 @@ namespace ICSharpCode.SharpDevelop.Tests @@ -171,6 +171,22 @@ namespace ICSharpCode.SharpDevelop.Tests
Assert.AreEqual("System.Void", prt.BaseType.FullyQualifiedName);
}
[Test]
public void DateTimeDefaultConstructor()
{
IClass c = mscorlib.GetClass("System.DateTime", 0);
Assert.IsFalse(c.Methods.Any(p => p.IsConstructor && p.Parameters.Count == 0));
Assert.IsTrue(c.GetAddDefaultConstructorIfRequired());
}
[Test]
public void NoEncodingInfoDefaultConstructor()
{
IClass c = mscorlib.GetClass("System.Text.EncodingInfo", 0);
Assert.IsFalse(c.Methods.Any(p => p.IsConstructor)); // EncodingInfo only has an internal constructor
Assert.IsFalse(c.GetAddDefaultConstructorIfRequired());
}
[Test]
public void ParameterComparisonTest()
{

1
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs

@ -324,6 +324,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -324,6 +324,7 @@ namespace ICSharpCode.SharpDevelop.Dom
foreach (MethodDefinition method in type.Constructors) {
AddMethod(method);
}
this.AddDefaultConstructorIfRequired = (this.ClassType == ClassType.Struct || this.ClassType == ClassType.Enum);
foreach (MethodDefinition method in type.Methods) {
if (!method.IsSpecialName) {
AddMethod(method);

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CompoundClass.cs

@ -107,6 +107,8 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -107,6 +107,8 @@ namespace ICSharpCode.SharpDevelop.Dom
this.Properties.AddRange(part.Properties);
this.Events.AddRange(part.Events);
this.Fields.AddRange(part.Fields);
this.AddDefaultConstructorIfRequired |= part.GetAddDefaultConstructorIfRequired();
}
this.CompilationUnit.FileName = shortestFileName;
if ((modifier & ModifierEnum.VisibilityMask) == ModifierEnum.None) {

28
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultClass.cs

@ -12,7 +12,7 @@ using System.Threading; @@ -12,7 +12,7 @@ using System.Threading;
namespace ICSharpCode.SharpDevelop.Dom
{
public class DefaultClass : AbstractEntity, IClass, IComparable
public class DefaultClass : AbstractEntity, IClass2, IComparable
{
ClassType classType;
DomRegion region;
@ -64,13 +64,16 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -64,13 +64,16 @@ namespace ICSharpCode.SharpDevelop.Dom
}
*/
byte flags;
byte flags = addDefaultConstructorIfRequiredFlag;
const byte calculatedFlagsReady = 0x01;
const byte hasPublicOrInternalStaticMembersFlag = 0x02;
const byte hasExtensionMethodsFlag = 0x04;
internal byte Flags {
const byte addDefaultConstructorIfRequiredFlag = 0x08;
internal byte CalculatedFlags {
get {
if (flags == 0) {
flags = 1;
if ((flags & calculatedFlagsReady) == 0) {
flags |= calculatedFlagsReady;
foreach (IMember m in this.Fields) {
if (m.IsStatic && (m.IsPublic || m.IsInternal)) {
flags |= hasPublicOrInternalStaticMembersFlag;
@ -112,12 +115,23 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -112,12 +115,23 @@ namespace ICSharpCode.SharpDevelop.Dom
}
public bool HasPublicOrInternalStaticMembers {
get {
return (Flags & hasPublicOrInternalStaticMembersFlag) == hasPublicOrInternalStaticMembersFlag;
return (CalculatedFlags & hasPublicOrInternalStaticMembersFlag) == hasPublicOrInternalStaticMembersFlag;
}
}
public bool HasExtensionMethods {
get {
return (Flags & hasExtensionMethodsFlag) == hasExtensionMethodsFlag;
return (CalculatedFlags & hasExtensionMethodsFlag) == hasExtensionMethodsFlag;
}
}
public bool AddDefaultConstructorIfRequired {
get {
return (flags & addDefaultConstructorIfRequiredFlag) == addDefaultConstructorIfRequiredFlag;
}
set {
if (value)
flags |= addDefaultConstructorIfRequiredFlag;
else
flags &= unchecked((byte)~addDefaultConstructorIfRequiredFlag);
}
}

9
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ICSharpCode.SharpDevelop.Dom
@ -36,7 +37,13 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -36,7 +37,13 @@ namespace ICSharpCode.SharpDevelop.Dom
if (c == null)
throw new ArgumentNullException("c");
Constructor con = new Constructor(ModifierEnum.Public, c.Region, c.Region, c);
ModifierEnum modifiers = ModifierEnum.Synthetic;
if (c.IsAbstract)
modifiers |= ModifierEnum.Protected;
else
modifiers |= ModifierEnum.Public;
DomRegion region = new DomRegion(c.Region.BeginLine, c.Region.BeginColumn, c.Region.BeginLine, c.Region.BeginColumn);
Constructor con = new Constructor(modifiers, region, region, c);
con.Documentation = "Default constructor of " + c.Name;
return con;
}

10
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs

@ -81,6 +81,16 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -81,6 +81,16 @@ namespace ICSharpCode.SharpDevelop.Dom
using (var busyLock = busyManager.Enter(this)) {
if (busyLock.Success) {
l.AddRange(c.Methods);
if (c.GetAddDefaultConstructorIfRequired() && !c.IsStatic) {
// A constructor is added for classes that do not have a default constructor;
// and for all structs.
if (c.ClassType == ClassType.Class && !l.Exists(m => m.IsConstructor)) {
l.Add(Constructor.CreateDefault(c));
} else if (c.ClassType == ClassType.Struct || c.ClassType == ClassType.Enum) {
l.Add(Constructor.CreateDefault(c));
}
}
if (c.ClassType == ClassType.Interface) {
if (c.BaseTypes.Count == 0) {
AddMethodsFromBaseType(l, c.ProjectContent.SystemTypes.Object);

26
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Interfaces/IClass.cs

@ -151,4 +151,30 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -151,4 +151,30 @@ namespace ICSharpCode.SharpDevelop.Dom
///// </summary>
//IClass Unfreeze();
}
public interface IClass2 : IClass
{
/// <summary>
/// Gets whether a default constructor should be added to this class if it is required.
/// Such automatic default constructors will not appear in IClass.Methods, but will be present
/// in IClass.DefaultReturnType.GetMethods().
/// </summary>
/// <remarks>This way of creating the default constructor is necessary because
/// we cannot create it directly in the IClass - we need to consider partial classes.</remarks>
bool AddDefaultConstructorIfRequired {
get;
}
}
public static class Class2Compatibility
{
public static bool GetAddDefaultConstructorIfRequired(this IClass c)
{
IClass2 c2 = c as IClass2;
if (c2 != null)
return c2.AddDefaultConstructorIfRequired;
else
return false;
}
}
}

5
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs

@ -444,11 +444,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver @@ -444,11 +444,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
bool resultIsAcceptable;
IMethod result = MemberLookupHelper.FindOverload(methods, argumentTypes, out resultIsAcceptable);
if (result == null) {
IClass c = rt.GetUnderlyingClass();
if (c != null)
result = Constructor.CreateDefault(c);
}
ResolveResult rr = CreateMemberResolveResult(result);
if (rr != null)
rr.ResolvedType = rt;

6
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/DomPersistence.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -20,7 +20,7 @@ namespace ICSharpCode.SharpDevelop.Dom
{
public const long FileMagic = 0x11635233ED2F428C;
public const long IndexFileMagic = 0x11635233ED2F427D;
public const short FileVersion = 24;
public const short FileVersion = 25;
ProjectContentRegistry registry;
string cacheDirectory;
@ -384,7 +384,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -384,7 +384,7 @@ namespace ICSharpCode.SharpDevelop.Dom
}
writer.Write((int)c.Modifiers);
if (c is DefaultClass) {
writer.Write(((DefaultClass)c).Flags);
writer.Write(((DefaultClass)c).CalculatedFlags);
} else {
writer.Write((byte)0);
}
@ -453,7 +453,7 @@ namespace ICSharpCode.SharpDevelop.Dom @@ -453,7 +453,7 @@ namespace ICSharpCode.SharpDevelop.Dom
c.BaseTypes.Add(ReadType());
}
c.Modifiers = (ModifierEnum)reader.ReadInt32();
c.Flags = reader.ReadByte();
c.CalculatedFlags = reader.ReadByte();
c.ClassType = (ClassType)reader.ReadByte();
ReadAttributes(c);
count = reader.ReadInt32();

1
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ReflectionLayer/ReflectionClass.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer @@ -55,6 +55,7 @@ namespace ICSharpCode.SharpDevelop.Dom.ReflectionLayer
Methods.Add(new ReflectionMethod(methodInfo, this));
}
}
this.AddDefaultConstructorIfRequired = (this.ClassType == ClassType.Struct || this.ClassType == ClassType.Enum);
foreach (EventInfo eventInfo in type.GetEvents(flags)) {
Events.Add(new ReflectionEvent(eventInfo, this));

63
src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/NRefactoryAstConverterTests.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using ICSharpCode.NRefactory;
@ -242,5 +243,67 @@ class Outer<T1> where T1 : IDisposable { @@ -242,5 +243,67 @@ class Outer<T1> where T1 : IDisposable {
Assert.AreSame(inner.TypeParameters[1], method.TypeParameters[0].Constraints[0].CastToGenericReturnType().TypeParameter);
}
[Test]
public void DefaultConstructorTest()
{
ICompilationUnit cu = Parse("class X { }", SupportedLanguage.CSharp, true);
Assert.AreEqual(0, cu.Classes[0].Methods.Count);
IMethod ctor = cu.Classes[0].DefaultReturnType.GetMethods().Single(m => m.IsConstructor);
Assert.AreEqual(ModifierEnum.Public | ModifierEnum.Synthetic, ctor.Modifiers);
Assert.AreEqual(0, ctor.Parameters.Count);
}
[Test]
public void DefaultConstructorOnAbstractClassTest()
{
ICompilationUnit cu = Parse("abstract class X { }", SupportedLanguage.CSharp, true);
Assert.AreEqual(0, cu.Classes[0].Methods.Count);
IMethod ctor = cu.Classes[0].DefaultReturnType.GetMethods().Single(m => m.IsConstructor);
Assert.AreEqual(ModifierEnum.Protected | ModifierEnum.Synthetic, ctor.Modifiers);
Assert.AreEqual(0, ctor.Parameters.Count);
}
[Test]
public void NoDefaultConstructorWithExplicitConstructorTest()
{
ICompilationUnit cu = Parse("class X { private X(int a) {} }", SupportedLanguage.CSharp, true);
Assert.AreEqual(1, cu.Classes[0].Methods.Count);
IMethod ctor = cu.Classes[0].DefaultReturnType.GetMethods().Single(m => m.IsConstructor);
Assert.AreEqual(ModifierEnum.Private, ctor.Modifiers);
Assert.AreEqual(1, ctor.Parameters.Count);
}
[Test]
public void DefaultConstructorWithExplicitConstructorOnStructTest()
{
ICompilationUnit cu = Parse("struct X { private X(int a) {} }", SupportedLanguage.CSharp, true);
Assert.AreEqual(1, cu.Classes[0].Methods.Count);
List<IMethod> ctors = cu.Classes[0].DefaultReturnType.GetMethods().FindAll(m => m.IsConstructor);
Assert.AreEqual(2, ctors.Count);
Assert.AreEqual(ModifierEnum.Private, ctors[0].Modifiers);
Assert.AreEqual(1, ctors[0].Parameters.Count);
Assert.AreEqual(ModifierEnum.Public | ModifierEnum.Synthetic, ctors[1].Modifiers);
Assert.AreEqual(0, ctors[1].Parameters.Count);
}
[Test]
public void NoDefaultConstructorOnStaticClassTest()
{
ICompilationUnit cu = Parse("static class X { }", SupportedLanguage.CSharp, true);
Assert.AreEqual(0, cu.Classes[0].Methods.Count);
Assert.IsFalse(cu.Classes[0].DefaultReturnType.GetMethods().Any(m => m.IsConstructor));
}
}
}

Loading…
Cancel
Save