Browse Source

Fix problem with an IronPython local variable not being resolved after assigning a value to its property and then calling a method on the variable.

pull/2/head
mrward 15 years ago
parent
commit
b3bfd0ef5a
  1. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
  2. 74
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonLocalVariableAssignment.cs
  3. 58
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonLocalVariableResolver.cs
  4. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
  5. 33
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/PythonLocalVariableAssignmentTests.cs
  6. 30
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/PythonLocalVariableResolverTests.cs

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

@ -106,6 +106,7 @@
<Compile Include="Src\PythonInsightWindowHandler.cs" /> <Compile Include="Src\PythonInsightWindowHandler.cs" />
<Compile Include="Src\PythonLanguageBinding.cs" /> <Compile Include="Src\PythonLanguageBinding.cs" />
<Compile Include="Src\PythonLineIndenter.cs" /> <Compile Include="Src\PythonLineIndenter.cs" />
<Compile Include="Src\PythonLocalVariableAssignment.cs" />
<Compile Include="Src\PythonLocalVariableResolver.cs" /> <Compile Include="Src\PythonLocalVariableResolver.cs" />
<Compile Include="Src\PythonMemberResolver.cs" /> <Compile Include="Src\PythonMemberResolver.cs" />
<Compile Include="Src\PythonMethod.cs" /> <Compile Include="Src\PythonMethod.cs" />

74
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonLocalVariableAssignment.cs

@ -0,0 +1,74 @@
// 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 IronPython.Compiler.Ast;
namespace ICSharpCode.PythonBinding
{
public class PythonLocalVariableAssignment
{
AssignmentStatement assignment;
string variableName = String.Empty;
string typeName = String.Empty;
public PythonLocalVariableAssignment(AssignmentStatement assignment)
{
this.assignment = assignment;
ParseAssignment();
}
public string TypeName {
get { return typeName; }
}
public string VariableName {
get { return variableName; }
}
public bool IsLocalVariableAssignment()
{
return !String.IsNullOrEmpty(variableName);
}
void ParseAssignment()
{
NameExpression nameExpression = assignment.Left[0] as NameExpression;
CallExpression callExpression = assignment.Right as CallExpression;
if ((nameExpression != null) && (callExpression != null)) {
variableName = nameExpression.Name;
typeName = GetTypeName(callExpression.Target);
}
}
/// <summary>
/// Gets the fully qualified name of the type from the expression.
/// </summary>
/// <remarks>
/// The expression is the first target of a call expression.
///
/// A call expression is a method or constructor call (right hand side of expression below):
///
/// a = Root.Test.Class1()
///
/// So the expression passed to this method will be a field expression in the
/// above example which refers to Class1. The next target will be a field
/// expression referring to Test. The The last target will be a name expression
/// referring to Root.
///
/// If we have
///
/// a = Class1()
///
/// then the expression will be a name expression referring to Class1.
/// </remarks>
string GetTypeName(Expression expression)
{
NameExpression nameExpression = expression as NameExpression;
if (nameExpression != null) {
return nameExpression.Name;
}
return PythonControlFieldExpression.GetMemberName(expression as MemberExpression);
}
}
}

58
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonLocalVariableResolver.cs

@ -27,8 +27,6 @@ namespace ICSharpCode.PythonBinding
PythonClassResolver classResolver; PythonClassResolver classResolver;
string variableName = String.Empty; string variableName = String.Empty;
string typeName; string typeName;
AssignmentStatement currentAssignStatement;
bool foundVariableAssignment;
public PythonLocalVariableResolver(PythonClassResolver classResolver) public PythonLocalVariableResolver(PythonClassResolver classResolver)
{ {
@ -66,63 +64,15 @@ namespace ICSharpCode.PythonBinding
public override bool Walk(AssignmentStatement node) public override bool Walk(AssignmentStatement node)
{ {
currentAssignStatement = node; PythonLocalVariableAssignment localVariableAssignment = new PythonLocalVariableAssignment(node);
foundVariableAssignment = false; if (localVariableAssignment.IsLocalVariableAssignment()) {
return base.Walk(node); if (localVariableAssignment.VariableName == variableName) {
} typeName = localVariableAssignment.TypeName;
public override bool Walk(NameExpression node)
{
if (currentAssignStatement != null) {
string nodeName = node.Name;
if (nodeName == variableName) {
foundVariableAssignment = true;
} }
} }
return base.Walk(node); return base.Walk(node);
} }
public override bool Walk(CallExpression node)
{
if (foundVariableAssignment) {
typeName = GetTypeName(node.Target);
currentAssignStatement = null;
foundVariableAssignment = false;
}
return base.Walk(node);
}
/// <summary>
/// Gets the fully qualified name of the type from the expression.
///
/// </summary>
/// <remarks>
/// The expression is the first target of a call expression.
///
/// A call expression is a method or constructor call (right hand side of expression below):
///
/// a = Root.Test.Class1()
///
/// So the expression passed to this method will be a field expression in the
/// above example which refers to Class1. The next target will be a field
/// expression referring to Test. The The last target will be a name expression
/// referring to Root.
///
/// If we have
///
/// a = Class1()
///
/// then the expression will be a name expression referring to Class1.
/// </remarks>
public static string GetTypeName(Expression node)
{
NameExpression nameExpression = node as NameExpression;
if (nameExpression != null) {
return nameExpression.Name;
}
return PythonControlFieldExpression.GetMemberName(node as MemberExpression);
}
public ResolveResult Resolve(PythonResolverContext resolverContext) public ResolveResult Resolve(PythonResolverContext resolverContext)
{ {
return GetLocalVariable(resolverContext); return GetLocalVariable(resolverContext);

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

@ -351,6 +351,7 @@
<Compile Include="Resolver\ImportModuleResolveResultTests.cs" /> <Compile Include="Resolver\ImportModuleResolveResultTests.cs" />
<Compile Include="Resolver\InvalidResolveInputsTestFixture.cs" /> <Compile Include="Resolver\InvalidResolveInputsTestFixture.cs" />
<Compile Include="Resolver\MemberNameTests.cs" /> <Compile Include="Resolver\MemberNameTests.cs" />
<Compile Include="Resolver\PythonLocalVariableAssignmentTests.cs" />
<Compile Include="Resolver\PythonLocalVariableResolverTests.cs" /> <Compile Include="Resolver\PythonLocalVariableResolverTests.cs" />
<Compile Include="Resolver\PythonSelfResolverTests.cs" /> <Compile Include="Resolver\PythonSelfResolverTests.cs" />
<Compile Include="Resolver\ResolveBuiltInRoundMethodTests.cs" /> <Compile Include="Resolver\ResolveBuiltInRoundMethodTests.cs" />

33
src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/PythonLocalVariableAssignmentTests.cs

@ -0,0 +1,33 @@
// 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.PythonBinding;
using IronPython.Compiler.Ast;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Resolver
{
[TestFixture]
public class PythonLocalVariableAssignmentTests
{
[Test]
public void TypeName_CallExpressionTargetIsNotNameOrMemberExpression_ReturnsEmptyStringAndDoesNotGetStuckInInfiniteLoop()
{
string code = "a = 2";
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement(code);
Expression constantExpression = statement.Right;
CallExpression callExpression = new CallExpression(constantExpression, new Arg[0]);
List<Expression> expressions = new List<Expression>(statement.Left);
statement = new AssignmentStatement(expressions.ToArray(), callExpression);
PythonLocalVariableAssignment localVariableAssignment = new PythonLocalVariableAssignment(statement);
string typeName = localVariableAssignment.TypeName;
Assert.AreEqual(String.Empty, typeName);
}
}
}

30
src/AddIns/BackendBindings/Python/PythonBinding/Test/Resolver/PythonLocalVariableResolverTests.cs

@ -26,8 +26,9 @@ namespace PythonBinding.Tests.Resolver
{ {
string code = "a = Class1()"; string code = "a = Class1()";
Resolve("a", code); Resolve("a", code);
string expectedTypeName = "Class1";
Assert.AreEqual("Class1", typeName); Assert.AreEqual(expectedTypeName, typeName);
} }
/// <summary> /// <summary>
@ -42,8 +43,9 @@ namespace PythonBinding.Tests.Resolver
"b = Class2()"; "b = Class2()";
Resolve("a", code); Resolve("a", code);
string expectedTypeName = "Class1";
Assert.AreEqual("Class1", typeName); Assert.AreEqual(expectedTypeName, typeName);
} }
[Test] [Test]
@ -59,6 +61,7 @@ namespace PythonBinding.Tests.Resolver
public void Resolve_CodeIsNull_ReturnsNull() public void Resolve_CodeIsNull_ReturnsNull()
{ {
Resolve("a", null); Resolve("a", null);
Assert.IsNull(typeName); Assert.IsNull(typeName);
} }
@ -67,7 +70,9 @@ namespace PythonBinding.Tests.Resolver
{ {
string code = "a = Test.Class1()"; string code = "a = Test.Class1()";
Resolve("a", code); Resolve("a", code);
Assert.AreEqual("Test.Class1", typeName); string expectedTypeName = "Test.Class1";
Assert.AreEqual(expectedTypeName, typeName);
} }
[Test] [Test]
@ -75,16 +80,23 @@ namespace PythonBinding.Tests.Resolver
{ {
string code = "a = Root.Test.Class1()"; string code = "a = Root.Test.Class1()";
Resolve("a", code); Resolve("a", code);
Assert.AreEqual("Root.Test.Class1", typeName); string expectedTypeName = "Root.Test.Class1";
Assert.AreEqual(expectedTypeName, typeName);
} }
[Test] [Test]
public void GetTypeName_ExpressionIsNotNameOrMemberExpression_ReturnsEmptyStringAndDoesNotGetStuckInInfiniteLoop() public void Resolve_AssignmentToPropertyOnLocalVariableThenMethodCallOnLocalVariable_CorrectLocalVariableTypeReturned()
{ {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("a = 2"); string code =
Expression expression = statement.Right; "connection = OracleClient.OracleConnection()\r\n" +
string typeName = PythonLocalVariableResolver.GetTypeName(expression); "connection.ConnectionString = connectionString\r\n" +
Assert.AreEqual(String.Empty, typeName); "connection.Open()\r\n" +
"connection";
Resolve("connection", code);
Assert.AreEqual("OracleClient.OracleConnection", typeName);
} }
} }
} }

Loading…
Cancel
Save