From 0ab566c3c0f44ffa8cb2507ee83ae9f1d9d0762a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Kr=C3=BCger?= Date: Wed, 2 Nov 2011 12:41:02 +0100 Subject: [PATCH] Fixed "partial" context. --- .../Completion/CSharpCompletionEngine.cs | 122 ++++++++++++++---- .../Parser/TypeSystemConvertVisitor.cs | 3 + .../Resolver/CSharpResolver.cs | 4 + .../CodeCompletion/CodeCompletionBugTests.cs | 22 ++++ ICSharpCode.NRefactory/TypeSystem/IMember.cs | 7 + .../Implementation/AbstractMember.cs | 11 ++ .../Implementation/SpecializedMember.cs | 4 + 7 files changed, 148 insertions(+), 25 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs index 21479c399c..fd7a51b823 100644 --- a/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs +++ b/ICSharpCode.NRefactory.CSharp/Completion/CSharpCompletionEngine.cs @@ -898,36 +898,35 @@ namespace ICSharpCode.NRefactory.CSharp.Completion if (!IsLineEmptyUpToEol ()) return null; var overrideCls = CSharpParsedFile.GetInnermostTypeDefinition (location); - if (overrideCls != null && (overrideCls.Kind == TypeKind.Class || overrideCls.Kind == TypeKind.Struct)) { string modifiers = document.GetText (firstMod, wordStart - firstMod); return GetOverrideCompletionData (overrideCls, modifiers); } return null; -// case "partial": -// // Look for modifiers, in order to find the beginning of the declaration -// firstMod = wordStart; -// i = wordStart; -// for (int n = 0; n < 3; n++) { -// string mod = GetPreviousToken (ref i, true); -// if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") { -// firstMod = i; -// } else if (mod == "static") { -// // static methods are not overridable -// return null; -// } else -// break; -// } -// if (!IsLineEmptyUpToEol ()) -// return null; -// -// overrideCls = NRefactoryResolver.GetTypeAtCursor (Document.CompilationUnit, Document.FileName, new TextLocation (completionContext.TriggerLine, completionContext.TriggerLineOffset)); -// if (overrideCls != null && (overrideCls.ClassType == ClassType.Class || overrideCls.ClassType == ClassType.Struct)) { -// string modifiers = document.GetTextBetween (firstMod, wordStart); -// return GetPartialCompletionData (completionContext, overrideCls, modifiers); -// } -// return null; -// + case "partial": + // Look for modifiers, in order to find the beginning of the declaration + firstMod = wordStart; + i = wordStart; + for (int n = 0; n < 3; n++) { + string mod = GetPreviousToken (ref i, true); + if (mod == "public" || mod == "protected" || mod == "private" || mod == "internal" || mod == "sealed") { + firstMod = i; + } else if (mod == "static") { + // static methods are not overridable + return null; + } else + break; + } + if (!IsLineEmptyUpToEol ()) + return null; + + overrideCls = CSharpParsedFile.GetInnermostTypeDefinition (location); + if (overrideCls != null && (overrideCls.Kind == TypeKind.Class || overrideCls.Kind == TypeKind.Struct)) { + string modifiers = document.GetText (firstMod, wordStart - firstMod); + return GetPartialCompletionData (overrideCls, modifiers); + } + return null; + case "public": case "protected": case "private": @@ -1125,6 +1124,79 @@ namespace ICSharpCode.NRefactory.CSharp.Completion return wrapper.Result; } + IEnumerable GetPartialCompletionData (ITypeDefinition type, string modifiers) + { + var wrapper = new CompletionDataWrapper (this); + var partialType = GetTypeFromContext (type); + if (partialType != null) { + int declarationBegin = offset; + int j = declarationBegin; + for (int i = 0; i < 3; i++) { + switch (GetPreviousToken (ref j, true)) { + case "public": + case "protected": + case "private": + case "internal": + case "sealed": + case "override": + declarationBegin = j; + break; + case "static": + return null; // don't add override completion for static members + } + } + + var methods = new List (); + // gather all partial methods without implementation + foreach (var part in partialType.GetParts ()) + foreach (var method in part.Methods) { + if (method.IsPartial && method.BodyRegion.IsEmpty) { + methods.Add (method); + } + } + + // now filter all methods that are implemented in the compound class + foreach (var part in partialType.GetParts ()) { + if (part == type) + continue; + for (int i = 0; i < methods.Count; i++) { + var curMethod = methods[i]; + var method = GetImplementation (partialType, curMethod); + if (method != null && !method.BodyRegion.IsEmpty) { + methods.RemoveAt (i); + i--; + continue; + } + } + } + + foreach (var method in methods) { + wrapper.Add (factory.CreateNewOverrideCompletionData (declarationBegin, type, method)); + } + + } + return wrapper.Result; + } + + IMethod GetImplementation (ITypeDefinition type, IMethod method) + { + foreach (var cur in type.Methods) { + if (cur.Name == method.Name && cur.Parameters.Count == method.Parameters.Count && !cur.BodyRegion.IsEmpty) { + bool equal = true; + for (int i = 0; i < cur.Parameters.Count; i++) { + if (!cur.Parameters[i].Type.Resolve (ctx).Equals (method.Parameters[i].Type.Resolve (ctx))) { + equal = false; + break; + } + } + if (equal) + return cur; + } + } + return null; + } + + static string GetNameWithParamCount (IMember member) { var e = member as IMethod; diff --git a/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs index 1eac3f9091..8e03c367d2 100644 --- a/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Parser/TypeSystemConvertVisitor.cs @@ -710,6 +710,9 @@ namespace ICSharpCode.NRefactory.CSharp m.IsShadowing = (modifiers & Modifiers.New) != 0; m.IsStatic = (modifiers & Modifiers.Static) != 0; m.IsVirtual = (modifiers & Modifiers.Virtual) != 0; + m.IsPartial = (modifiers & Modifiers.Partial) != 0; + + } static Accessibility? GetAccessibility(Modifiers modifiers) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 4b8b067770..8b68564132 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -483,6 +483,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver get { return false; } } + bool IMember.IsPartial { + get { return false; } + } + EntityType IEntity.EntityType { get { return EntityType.Operator; } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs index 1dd0639505..d2ccbd97a1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CodeCompletion/CodeCompletionBugTests.cs @@ -3593,5 +3593,27 @@ void TestMethod () Assert.IsNotNull (provider.Find ("TF1")); } + + [Test()] + public void TestPartialCompletionData () + { + var provider = CreateProvider ( +@" +public partial class TestMe +{ + partial void MyMethod (); + partial void Implemented (); +} + +public partial class TestMe +{ + $partial $ + + partial void Implemented () { } +}"); + Assert.IsNotNull (provider, "provider not found."); + Assert.IsNotNull (provider.Find ("MyMethod"), "method 'MyMethod' not found."); + Assert.IsNull (provider.Find ("Implemented"), "method 'Implemented' found."); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/ICSharpCode.NRefactory/TypeSystem/IMember.cs index 6674e02d23..99ad30e552 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -73,6 +73,13 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOverridable { get; } + + /// + /// Gets if the member is partial. Returns true when the member is "partial". + /// + bool IsPartial { + get; + } } #if WITH_CONTRACTS diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs index 0c4c69f7a1..a3fb7316c9 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractMember.cs @@ -53,6 +53,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation const ushort FlagVirtual = 0x0010; const ushort FlagOverride = 0x0020; const ushort FlagStatic = 0x0040; + const ushort FlagPartial = 0x0080; + // Flags of form 0xY000 are reserved for use in derived classes (DefaultMethod etc.) protected override void FreezeInternal() @@ -144,6 +146,15 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } + public bool IsPartial { + get { return flags[FlagPartial]; } + set { + CheckBeforeMutation(); + flags[FlagPartial] = value; + } + } + + public bool IsOverridable { get { return (IsAbstract || IsVirtual || IsOverride) && !IsSealed; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs index cc9c88c0f4..2a9616ab40 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs @@ -166,6 +166,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return memberDefinition.IsProtectedAndInternal; } } + public bool IsPartial { + get { return memberDefinition.IsPartial; } + } + public IProjectContent ProjectContent { get { return memberDefinition.ProjectContent; } }