From e6b79a0398715024d4ecc62b1163a5dcb8e8ba85 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 3 Feb 2010 20:32:30 +0000 Subject: [PATCH] Improved python code completion for .NET library imports. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@5472 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/PythonClassResolver.cs | 39 ++++++++- .../Project/Src/PythonNamespaceResolver.cs | 13 ++- .../Project/Src/PythonResolverContext.cs | 4 +- .../Test/PythonBinding.Tests.csproj | 5 +- ...onsoleFromSystemImportEverythingFixture.cs | 59 +++++++++++++ .../Resolver/ResolveConsoleTestFixture.cs | 85 ------------------- .../ResolveSystemNamespaceTestFixture.cs | 14 +-- ...emNamespaceWithMissingImportTestFixture.cs | 47 ++++++++++ ...temWindowsFormsImportTextBoxTestFixture.cs | 55 ++++++++++++ ...dowsFormsImportedAsMyTextBoxTestFixture.cs | 55 ++++++++++++ .../ResolveUnknownNamespaceTestFixture.cs | 6 -- .../Utils/Tests/MockProjectContentTests.cs | 55 ++++++++++++ 12 files changed, 333 insertions(+), 104 deletions(-) create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleFromSystemImportEverythingFixture.cs delete mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleTestFixture.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceWithMissingImportTestFixture.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportTextBoxTestFixture.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportedAsMyTextBoxTestFixture.cs diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassResolver.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassResolver.cs index 89ce150a66..7884ebaa51 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassResolver.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassResolver.cs @@ -36,12 +36,49 @@ namespace ICSharpCode.PythonBinding return matchedClass; } - return context.GetImportedClass(name); + matchedClass = GetClassFromImportedNames(context, name); + if (matchedClass != null) { + return matchedClass; + } + + matchedClass = GetClassFromNamespaceThatImportsEverything(context, name); + if (matchedClass != null) { + return matchedClass; + } + return null; } TypeResolveResult CreateTypeResolveResult(IClass c) { return new TypeResolveResult(null, null, c); } + + IClass GetClassFromImportedNames(PythonResolverContext context, string name) + { + string moduleName = context.GetModuleForImportedName(name); + if (moduleName != null) { + name = context.UnaliasImportedName(name); + string fullyQualifiedName = GetQualifiedClassName(moduleName, name); + return context.GetClass(fullyQualifiedName); + } + return null; + } + + string GetQualifiedClassName(string namespacePrefix, string className) + { + return namespacePrefix + "." + className; + } + + IClass GetClassFromNamespaceThatImportsEverything(PythonResolverContext context, string name) + { + foreach (string moduleName in context.GetModulesThatImportEverything()) { + string fullyQualifiedName = GetQualifiedClassName(moduleName, name); + IClass matchedClass = context.GetClass(fullyQualifiedName); + if (matchedClass != null) { + return matchedClass; + } + } + return null; + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonNamespaceResolver.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonNamespaceResolver.cs index 862ffc69c9..b74b853356 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonNamespaceResolver.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonNamespaceResolver.cs @@ -18,9 +18,18 @@ namespace ICSharpCode.PythonBinding public ResolveResult Resolve(PythonResolverContext resolverContext, ExpressionResult expressionResult) { + if (!resolverContext.HasImport(expressionResult.Expression)) { + return null; + } + string actualNamespace = resolverContext.UnaliasImportedModuleName(expressionResult.Expression); - if (resolverContext.NamespaceExists(actualNamespace)) { - return new NamespaceResolveResult(null, null, actualNamespace); + return CreateNamespaceResolveResultIfNamespaceExists(resolverContext, actualNamespace); + } + + ResolveResult CreateNamespaceResolveResultIfNamespaceExists(PythonResolverContext resolverContext, string namespaceName) + { + if (resolverContext.NamespaceExistsInProjectReferences(namespaceName)) { + return new NamespaceResolveResult(null, null, namespaceName); } return null; } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs index 641a0324ba..16e74675e8 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs @@ -54,7 +54,7 @@ namespace ICSharpCode.PythonBinding get { return callingClass; } } - public bool NamespaceExists(string name) + public bool NamespaceExistsInProjectReferences(string name) { return projectContent.NamespaceExists(name); } @@ -158,7 +158,7 @@ namespace ICSharpCode.PythonBinding /// The unqualified class name. public IClass GetImportedClass(string name) { - foreach (Object obj in GetImportedTypes()) { + foreach (object obj in GetImportedTypes()) { IClass c = obj as IClass; if ((c != null) && IsSameClassName(name, c.Name)) { return c; diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj index 73e8f63a36..ecf0addb91 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj @@ -361,12 +361,12 @@ - + @@ -389,9 +389,12 @@ + + + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleFromSystemImportEverythingFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleFromSystemImportEverythingFixture.cs new file mode 100644 index 0000000000..4262309e9d --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleFromSystemImportEverythingFixture.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using ICSharpCode.PythonBinding; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using NUnit.Framework; +using PythonBinding.Tests.Utils; + +namespace PythonBinding.Tests.Resolver +{ + [TestFixture] + public class ResolveFromSystemImportEverythingFixture : ResolveTestFixtureBase + { + MockClass consoleClass; + + protected override ExpressionResult GetExpressionResult() + { + consoleClass = new MockClass(projectContent, "System.Console"); + projectContent.ClassToReturnFromGetClass = consoleClass; + projectContent.ClassNameForGetClass = "System.Console"; + + projectContent.AddExistingNamespaceContents("System", new ArrayList()); + + return new ExpressionResult("Console", ExpressionContext.Default); + } + + protected override string GetPythonScript() + { + return + "from System import *\r\n" + + "Console\r\n" + + "\r\n"; + } + + [Test] + public void ResolveResultResolvedClassIsConsoleClass() + { + Assert.AreEqual(consoleClass, TypeResolveResult.ResolvedClass); + } + + TypeResolveResult TypeResolveResult { + get { return (TypeResolveResult)resolveResult; } + } + + [Test] + public void ProjectContentNamespaceExistsReturnsTrueForSystem() + { + Assert.IsTrue(projectContent.NamespaceExists("System")); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleTestFixture.cs deleted file mode 100644 index 867f2535ce..0000000000 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveConsoleTestFixture.cs +++ /dev/null @@ -1,85 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Collections; -using ICSharpCode.PythonBinding; -using ICSharpCode.SharpDevelop.Dom; -using NUnit.Framework; -using PythonBinding.Tests; -using PythonBinding.Tests.Utils; - -namespace PythonBinding.Tests.Resolver -{ - /// - /// Tests the PythonResolver correctly resolves the expression: - /// "Console." when the System namespace is imported. - /// - [TestFixture] - public class ResolveConsoleTestFixture - { - PythonResolver resolver; - MockProjectContent mockProjectContent; - ResolveResult resolveResult; - MockClass testClass; - ICompilationUnit compilationUnit; - MockClass systemConsoleClass; - - [TestFixtureSetUp] - public void SetUpFixture() - { - resolver = new PythonResolver(); - ParseInformation parseInfo = new ParseInformation(); - mockProjectContent = new MockProjectContent(); - - // Do not return any class from GetClass call. This method - // will not return anything in the real class since the - // type is not fully qualified with its namespace. - mockProjectContent.ClassToReturnFromGetClass = null; - - systemConsoleClass = new MockClass(mockProjectContent, "System.Console"); - mockProjectContent.ClassesInProjectContent.Add(systemConsoleClass); - - compilationUnit = new DefaultCompilationUnit(mockProjectContent) { ErrorsDuringCompile = true }; - testClass = new MockClass(compilationUnit, "Test"); - compilationUnit.Classes.Add(testClass); - parseInfo.SetCompilationUnit(compilationUnit); - - string python = "import System\r\n" + - "class Test:\r\n" + - "\tdef __init__(self):\r\n" + - "\tConsole\r\n"; - ExpressionResult expressionResult = new ExpressionResult("Console", new DomRegion(3, 7), null, null); - resolveResult = resolver.Resolve(expressionResult, parseInfo, python); - } - - [Test] - public void IsTypeResolveResult() - { - Assert.IsInstanceOf(typeof(TypeResolveResult), resolveResult); - } - - [Test] - public void ResolvedClass() - { - TypeResolveResult typeResolveResult = resolveResult as TypeResolveResult; - Assert.AreEqual(systemConsoleClass, typeResolveResult.ResolvedClass); - } -// -// [Test] -// public void IsGetClassCalled() -// { -// Assert.IsTrue(mockProjectContent.GetClassCalled); -// } -// -// [Test] -// public void GetClassName() -// { -// Assert.AreEqual("System.Console", mockProjectContent.GetClassName); -// } - } -} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceTestFixture.cs index 3c814430bf..50ca06762f 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceTestFixture.cs @@ -30,22 +30,22 @@ namespace PythonBinding.Tests.Resolver public void SetUpFixture() { resolver = new PythonResolver(); - ParseInformation parseInfo = new ParseInformation(); mockProjectContent = new MockProjectContent(); mockProjectContent.AddExistingNamespaceContents("System", new ArrayList()); - DefaultCompilationUnit cu = new DefaultCompilationUnit(mockProjectContent); - cu.ErrorsDuringCompile = true; - cu.FileName = @"C:\Projects\Test\test.py"; - parseInfo.SetCompilationUnit(cu); - string python = "import System\r\n" + "class Test:\r\n" + " def __init__(self):\r\n" + " System.\r\n"; - ExpressionResult expressionResult = new ExpressionResult("System", new DomRegion(3, 2), null, null); + PythonParser parser = new PythonParser(); + string fileName = @"C:\Projects\Test\test.py"; + DefaultCompilationUnit cu = parser.Parse(mockProjectContent, fileName, python) as DefaultCompilationUnit; + cu.ErrorsDuringCompile = true; + ParseInformation parseInfo = new ParseInformation(cu); + + ExpressionResult expressionResult = new ExpressionResult("System", new DomRegion(4, 2), null, null); resolveResult = resolver.Resolve(expressionResult, parseInfo, python) as NamespaceResolveResult; } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceWithMissingImportTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceWithMissingImportTestFixture.cs new file mode 100644 index 0000000000..74937ea04b --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSystemNamespaceWithMissingImportTestFixture.cs @@ -0,0 +1,47 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using ICSharpCode.PythonBinding; +using ICSharpCode.SharpDevelop.Dom; +using NUnit.Framework; +using PythonBinding.Tests.Utils; + +namespace PythonBinding.Tests.Resolver +{ + [TestFixture] + public class ResolveSystemNamespaceWithMissingImportTestFixture : ResolveTestFixtureBase + { + protected override ExpressionResult GetExpressionResult() + { + MockClass systemConsoleClass = new MockClass(projectContent, "System.Console"); + ArrayList items = new ArrayList(); + items.Add(systemConsoleClass); + projectContent.AddExistingNamespaceContents("System", items); + + return new ExpressionResult("System", ExpressionContext.Default); + } + + protected override string GetPythonScript() + { + return "System\r\n"; + } + + [Test] + public void ResolveResultIsNullSinceSystemNamespaceIsNotImported() + { + Assert.IsNull(resolveResult); + } + + [Test] + public void ProjectContentNamespaceExistsReturnsTrueForSystemNamespace() + { + Assert.IsTrue(projectContent.NamespaceExists("System")); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportTextBoxTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportTextBoxTestFixture.cs new file mode 100644 index 0000000000..2f5d3448ff --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportTextBoxTestFixture.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using ICSharpCode.PythonBinding; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using NUnit.Framework; +using PythonBinding.Tests.Utils; + +namespace PythonBinding.Tests.Resolver +{ + [TestFixture] + public class ResolveTextBoxFromSystemWindowsFormsImportTextBoxTestFixture : ResolveTestFixtureBase + { + protected override ExpressionResult GetExpressionResult() + { + MockClass textBoxClass = new MockClass(projectContent, "System.Windows.Forms.TextBox"); + projectContent.ClassToReturnFromGetClass = textBoxClass; + projectContent.ClassNameForGetClass = "System.Windows.Forms.TextBox"; + + return new ExpressionResult("TextBox", ExpressionContext.Default); + } + + protected override string GetPythonScript() + { + return + "from System.Windows.Forms import TextBox\r\n" + + "TextBox\r\n" + + "\r\n"; + } + + [Test] + public void ResolveResultIsTypeResolveResult() + { + Assert.IsTrue(resolveResult is TypeResolveResult); + } + + [Test] + public void ResolveResultResolveClassNameIsTextBox() + { + Assert.AreEqual("TextBox", TypeResolveResult.ResolvedClass.Name); + } + + TypeResolveResult TypeResolveResult { + get { return (TypeResolveResult)resolveResult; } + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportedAsMyTextBoxTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportedAsMyTextBoxTestFixture.cs new file mode 100644 index 0000000000..3157cd7283 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveTextBoxFromSystemWindowsFormsImportedAsMyTextBoxTestFixture.cs @@ -0,0 +1,55 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using ICSharpCode.PythonBinding; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Dom.CSharp; +using NUnit.Framework; +using PythonBinding.Tests.Utils; + +namespace PythonBinding.Tests.Resolver +{ + [TestFixture] + public class ResolveTextBoxFromSystemWindowsFormsImportedAsMyTextBoxTestFixture : ResolveTestFixtureBase + { + protected override ExpressionResult GetExpressionResult() + { + MockClass textBoxClass = new MockClass(projectContent, "System.Windows.Forms.TextBox"); + projectContent.ClassToReturnFromGetClass = textBoxClass; + projectContent.ClassNameForGetClass = "System.Windows.Forms.TextBox"; + + return new ExpressionResult("MyTextBox", ExpressionContext.Default); + } + + protected override string GetPythonScript() + { + return + "from System.Windows.Forms import TextBox as MyTextBox\r\n" + + "MyTextBox\r\n" + + "\r\n"; + } + + [Test] + public void ResolveResultIsTypeResolveResult() + { + Assert.IsTrue(resolveResult is TypeResolveResult); + } + + [Test] + public void ResolveResultResolveClassNameIsTextBox() + { + Assert.AreEqual("TextBox", TypeResolveResult.ResolvedClass.Name); + } + + TypeResolveResult TypeResolveResult { + get { return (TypeResolveResult)resolveResult; } + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveUnknownNamespaceTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveUnknownNamespaceTestFixture.cs index db1a289470..e7ee51ea23 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveUnknownNamespaceTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveUnknownNamespaceTestFixture.cs @@ -43,11 +43,5 @@ namespace PythonBinding.Tests.Resolver { Assert.IsNull(resolveResult); } - - [Test] - public void NamespaceExistsCalled() - { - Assert.IsTrue(projectContent.NamespaceExistsCalled); - } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/Tests/MockProjectContentTests.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/Tests/MockProjectContentTests.cs index 29d0705565..42f37b0359 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/Tests/MockProjectContentTests.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/Tests/MockProjectContentTests.cs @@ -142,5 +142,60 @@ namespace PythonBinding.Tests.Utils.Tests projectContent.NamespaceExists("System"); Assert.IsTrue(projectContent.NamespaceExistsCalled); } + + [Test] + public void GetClassReturnsNullByDefault() + { + Assert.IsNull(projectContent.GetClass("test", 0)); + } + + [Test] + public void GetClassNameReturnsClassNamePassedToGetClassMethod() + { + projectContent.GetClass("abc", 0); + Assert.AreEqual("abc", projectContent.GetClassName); + } + + [Test] + public void GetClassCalledIsFalseByDefault() + { + Assert.IsFalse(projectContent.GetClassCalled); + } + + [Test] + public void GetClassCalledIsTrueAfterGetClassCalled() + { + projectContent.GetClass("abc", 0); + Assert.IsTrue(projectContent.GetClassCalled); + } + + [Test] + public void GetClassReturnsClassEvenIfClassNameDoesNotMatchAndNoClassNameForGetClassSpecified() + { + MockClass c = new MockClass(projectContent, "test"); + projectContent.ClassToReturnFromGetClass = c; + + Assert.AreEqual(c, projectContent.GetClass("abcdef", 0)); + } + + [Test] + public void GetClassReturnsNullIfClassNameDoesNotMatchClassNameForGetClassProperty() + { + MockClass c = new MockClass(projectContent, "test"); + projectContent.ClassToReturnFromGetClass = c; + projectContent.ClassNameForGetClass = "test"; + + Assert.IsNull(projectContent.GetClass("abcdef", 0)); + } + + [Test] + public void GetClassReturnsClassIfClassNameMatchesClassNameForGetClassProperty() + { + MockClass c = new MockClass(projectContent, "test"); + projectContent.ClassToReturnFromGetClass = c; + projectContent.ClassNameForGetClass = "test"; + + Assert.AreEqual(c, projectContent.GetClass("test", 0)); + } } }