Browse Source

IronPython class fields defined in constructor now appear in code completion after typing 'self'.

pull/2/head
mrward 15 years ago
parent
commit
2d11b74a7b
  1. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
  2. 21
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs
  3. 64
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassFields.cs
  4. 14
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMemberResolver.cs
  5. 7
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs
  6. 7
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonSelfResolver.cs
  7. 57
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParseFieldTests.cs
  8. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
  9. 47
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSelfTests.cs

1
src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj

@ -94,6 +94,7 @@ @@ -94,6 +94,7 @@
<Compile Include="Src\MemberName.cs" />
<Compile Include="Src\PythonBuiltInModuleMemberName.cs" />
<Compile Include="Src\PythonClass.cs" />
<Compile Include="Src\PythonClassFields.cs" />
<Compile Include="Src\PythonClassMembers.cs" />
<Compile Include="Src\PythonClassResolver.cs" />
<Compile Include="Src\PythonCodeCompletionItemProvider.cs" />

21
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs

@ -60,16 +60,19 @@ namespace ICSharpCode.PythonBinding @@ -60,16 +60,19 @@ namespace ICSharpCode.PythonBinding
currentClass = null;
}
public override bool Walk(FunctionDefinition node)
public override bool Walk(FunctionDefinition functionDefinition)
{
if (node.Body == null) {
if (functionDefinition.Body == null) {
return false;
}
IClass c = GetClassBeingWalked();
PythonMethodDefinition methodDefinition = new PythonMethodDefinition(node);
methodDefinition.CreateMethod(c);
PythonMethodDefinition methodDefinition = new PythonMethodDefinition(functionDefinition);
PythonMethod method = methodDefinition.CreateMethod(c);
if (method is PythonConstructor) {
FindFields(c, functionDefinition);
}
return false;
}
@ -97,6 +100,12 @@ namespace ICSharpCode.PythonBinding @@ -97,6 +100,12 @@ namespace ICSharpCode.PythonBinding
}
}
void FindFields(IClass c, FunctionDefinition functionDefinition)
{
PythonClassFields fields = new PythonClassFields(functionDefinition);
fields.AddFields(c);
}
/// <summary>
/// Walks an import statement and adds it to the compilation unit's
/// Usings.
@ -118,13 +127,13 @@ namespace ICSharpCode.PythonBinding @@ -118,13 +127,13 @@ namespace ICSharpCode.PythonBinding
public override bool Walk(AssignmentStatement node)
{
if (currentClass != null) {
WalkPropertyAssignment(node);
FindProperty(node);
return false;
}
return base.Walk(node);
}
void WalkPropertyAssignment(AssignmentStatement node)
void FindProperty(AssignmentStatement node)
{
PythonPropertyAssignment propertyAssignment = new PythonPropertyAssignment(node);
propertyAssignment.CreateProperty(currentClass);

64
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClassFields.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.SharpDevelop.Dom;
using IronPython.Compiler.Ast;
namespace ICSharpCode.PythonBinding
{
public class PythonClassFields : PythonWalker
{
FunctionDefinition functionDefinition;
IClass declaringType;
List<string> fieldNamesAdded;
public PythonClassFields(FunctionDefinition functionDefinition)
{
this.functionDefinition = functionDefinition;
}
public void AddFields(IClass declaringType)
{
this.declaringType = declaringType;
fieldNamesAdded = new List<string>();
functionDefinition.Body.Walk(this);
}
public override bool Walk(AssignmentStatement node)
{
string fieldName = GetFieldName(node);
AddFieldToDeclaringType(fieldName);
return false;
}
string GetFieldName(AssignmentStatement node)
{
string[] memberNames = PythonControlFieldExpression.GetMemberNames(node.Left[0] as MemberExpression);
return GetFieldName(memberNames);
}
string GetFieldName(string[] memberNames)
{
if (memberNames.Length > 1) {
if (PythonSelfResolver.IsSelfExpression(memberNames[0])) {
return memberNames[1];
}
}
return null;
}
void AddFieldToDeclaringType(string fieldName)
{
if (fieldName != null) {
if (!fieldNamesAdded.Contains(fieldName)) {
DefaultField field = new DefaultField(declaringType, fieldName);
declaringType.Fields.Add(field);
fieldNamesAdded.Add(fieldName);
}
}
}
}
}

14
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMemberResolver.cs

@ -15,6 +15,7 @@ namespace ICSharpCode.PythonBinding @@ -15,6 +15,7 @@ namespace ICSharpCode.PythonBinding
PythonClassResolver classResolver;
PythonLocalVariableResolver localVariableResolver;
PythonResolverContext resolverContext;
PythonSelfResolver selfResolver = new PythonSelfResolver();
public PythonMemberResolver(PythonClassResolver classResolver, PythonLocalVariableResolver localVariableResolver)
{
@ -54,6 +55,9 @@ namespace ICSharpCode.PythonBinding @@ -54,6 +55,9 @@ namespace ICSharpCode.PythonBinding
if (c != null) {
return c;
}
if (PythonSelfResolver.IsSelfExpression(className)) {
return FindClassFromSelfResolver();
}
return FindClassFromLocalVariableResolver(className);
}
@ -72,6 +76,16 @@ namespace ICSharpCode.PythonBinding @@ -72,6 +76,16 @@ namespace ICSharpCode.PythonBinding
return null;
}
IClass FindClassFromSelfResolver()
{
PythonResolverContext newContext = resolverContext.Clone("self");
ResolveResult result = selfResolver.Resolve(newContext);
if (result != null) {
return result.ResolvedType.GetUnderlyingClass();
}
return null;
}
ResolveResult CreateResolveResult(IMember member)
{
if (member != null) {

7
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonResolverContext.cs

@ -300,5 +300,12 @@ namespace ICSharpCode.PythonBinding @@ -300,5 +300,12 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
public PythonResolverContext Clone(string newExpression)
{
ParseInformation parseInfo = new ParseInformation(compilationUnit);
ExpressionResult newExpressionResult = new ExpressionResult(newExpression);
return new PythonResolverContext(parseInfo, newExpressionResult, fileContent);
}
}
}

7
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonSelfResolver.cs

@ -21,9 +21,14 @@ namespace ICSharpCode.PythonBinding @@ -21,9 +21,14 @@ namespace ICSharpCode.PythonBinding
return null;
}
public static bool IsSelfExpression(string expression)
{
return expression == "self";
}
bool IsSelfExpression(PythonResolverContext resolverContext)
{
return resolverContext.Expression == "self";
return IsSelfExpression(resolverContext.Expression);
}
ResolveResult CreateResolveResult(PythonResolverContext resolverContext)

57
src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParseFieldTests.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using ICSharpCode.PythonBinding;
using ICSharpCode.SharpDevelop.Dom;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Parsing
{
[TestFixture]
public class PythonParserParseFieldTests
{
IClass myClass;
void ParseCode(string code)
{
ParseInformation parseInfo = PythonParserHelper.CreateParseInfo(code);
myClass = parseInfo.CompilationUnit.Classes[0];
}
[Test]
public void Parse_ClassHasOneFieldCalledCount_ReturnsParseInfoWithClassWithFieldCalledCount()
{
string code =
"class MyClass:\r\n" +
" def __init__(self):\r\n" +
" self._count = 0\r\n" +
"\r\n";
ParseCode(code);
IField field = myClass.Fields[0];
string name = field.Name;
string expectedName = "_count";
Assert.AreEqual(expectedName, name);
}
[Test]
public void Parse_ClassFieldInitialisedTwice_ReturnsParseInfoWithClassWithOnlyOneField()
{
string code =
"class MyClass:\r\n" +
" def __init__(self):\r\n" +
" self._count = 0\r\n" +
" self._count = 3\r\n" +
"\r\n";
ParseCode(code);
int howManyFields = myClass.Fields.Count;
int expectedNumberOfFields = 1;
Assert.AreEqual(expectedNumberOfFields, howManyFields);
}
}
}

1
src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

@ -343,6 +343,7 @@ @@ -343,6 +343,7 @@
<Compile Include="Parsing\InvalidClassTestFixture.cs" />
<Compile Include="Parsing\ParseTestClassTestFixture.cs" />
<Compile Include="Parsing\ParseTestClassWithBaseClassTestFixture.cs" />
<Compile Include="Parsing\PythonParserParseFieldTests.cs" />
<Compile Include="Parsing\PythonParserParsePropertyTests.cs" />
<Compile Include="PythonLanguage\CreateNewPythonProjectTestFixture.cs" />
<Compile Include="PythonLanguage\ProjectBindingTestFixture.cs" />

47
src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/ResolveSelfTests.cs

@ -42,6 +42,18 @@ namespace PythonBinding.Tests.Resolver @@ -42,6 +42,18 @@ namespace PythonBinding.Tests.Resolver
resolverHelper.Resolve("self");
}
void ResolveSelfMethodExpression()
{
string code =
"class Foo:\r\n" +
" def bar(self):\r\n" +
" return 0\r\n" +
"\r\n";
CreateResolver(code);
resolverHelper.Resolve("self.bar");
}
[Test]
public void Resolve_ExpressionIsSelf_ResolveResultCallingClassReturnsFooClass()
{
@ -60,25 +72,44 @@ namespace PythonBinding.Tests.Resolver @@ -60,25 +72,44 @@ namespace PythonBinding.Tests.Resolver
Assert.AreEqual("bar", methodName);
}
void ResolveSelfMethodExpression()
[Test]
public void Resolve_ExpressionIsSelfFollowedByMethodCall_MethodGroupResolveResultContainingTypeUnderlyingClassIsFooClass()
{
ResolveSelfMethodExpression();
IClass underlyingClass = resolverHelper.MethodGroupResolveResult.ContainingType.GetUnderlyingClass();
Assert.AreEqual(fooClass, underlyingClass);
}
[Test]
public void Resolve_ClassPropertyReferencedThroughSelf_MemberResolveResultResolvedMemberIsNamePropertyOnFooClass()
{
string code =
"class Foo:\r\n" +
" def bar(self):\r\n" +
" return 0\r\n" +
" def get_name(self):\r\n" +
" return 'test'\r\n" +
" name = property(fget=get_name)\r\n" +
"\r\n";
CreateResolver(code);
resolverHelper.Resolve("self.bar");
resolverHelper.Resolve("self.name");
IMember member = resolverHelper.MemberResolveResult.ResolvedMember;
IMember expectedMember = fooClass.Properties[0];
Assert.AreSame(expectedMember, member);
}
[Test]
public void Resolve_ExpressionIsSelfFollowedByMethodCall_MethodGroupResolveResultContainingTypeUnderlyingClassIsFooClass()
public void Resolve_PropertyReferencedThroughSelfButOutsideClass_ReturnsNull()
{
ResolveSelfMethodExpression();
IClass underlyingClass = resolverHelper.MethodGroupResolveResult.ContainingType.GetUnderlyingClass();
string code = String.Empty;
resolverHelper = new PythonResolverTestsHelper(code);
resolverHelper.Resolve("self.name");
Assert.AreEqual(fooClass, underlyingClass);
ResolveResult result = resolverHelper.ResolveResult;
Assert.IsNull(result);
}
}
}

Loading…
Cancel
Save