Browse Source

Fixed SD2-1465 - Convert integer casts correctly between VB and C#

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4570 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
34e76133c3
  1. 70
      src/Libraries/NRefactory/Project/Src/PrettyPrinter/VBNet/VBNetOutputVisitor.cs
  2. 48
      src/Libraries/NRefactory/Project/Src/Visitors/ToCSharpConvertVisitor.cs
  3. 34
      src/Libraries/NRefactory/Project/Src/Visitors/ToVBNetConvertVisitor.cs
  4. 4
      src/Libraries/NRefactory/Project/Src/Visitors/ToVBNetRenameConflictingVariables.cs
  5. 6
      src/Libraries/NRefactory/Test/Output/CSharp/VBNetToCSharpConverterTest.cs
  6. 36
      src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBNetConverterTest.cs
  7. 25
      src/Libraries/NRefactory/Test/Output/VBNet/VBNetOutputTest.cs
  8. 28
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/CSharpToVBNetConvertVisitor.cs
  9. 14
      src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/CodeSnippetConverterTests.cs

70
src/Libraries/NRefactory/Project/Src/PrettyPrinter/VBNet/VBNetOutputVisitor.cs

@ -2080,53 +2080,70 @@ namespace ICSharpCode.NRefactory.PrettyPrinter
} }
public override object TrackedVisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) public override object TrackedVisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
{
outputFormatter.PrintText(ToVBNetString(primitiveExpression));
return null;
}
internal static string ToVBNetString(PrimitiveExpression primitiveExpression)
{ {
object val = primitiveExpression.Value; object val = primitiveExpression.Value;
if (val == null) { if (val == null) {
outputFormatter.PrintToken(Tokens.Nothing); return "Nothing";
return null;
} }
if (val is bool) { if (val is bool) {
if ((bool)primitiveExpression.Value) { if ((bool)primitiveExpression.Value) {
outputFormatter.PrintToken(Tokens.True); return "True";
} else { } else {
outputFormatter.PrintToken(Tokens.False); return "False";
} }
return null;
} }
if (val is string) { if (val is string) {
outputFormatter.PrintText(ConvertString((string)val)); return ConvertString((string)val);
return null;
} }
if (val is char) { if (val is char) {
outputFormatter.PrintText(ConvertCharLiteral((char)primitiveExpression.Value)); return ConvertCharLiteral((char)primitiveExpression.Value);
return null;
} }
if (val is decimal) { if (val is decimal) {
outputFormatter.PrintText(((decimal)primitiveExpression.Value).ToString(NumberFormatInfo.InvariantInfo) + "D"); return ((decimal)primitiveExpression.Value).ToString(NumberFormatInfo.InvariantInfo) + "D";
return null;
} }
if (val is float) { if (val is float) {
outputFormatter.PrintText(((float)primitiveExpression.Value).ToString(NumberFormatInfo.InvariantInfo) + "F"); return ((float)primitiveExpression.Value).ToString(NumberFormatInfo.InvariantInfo) + "F";
return null; }
if (val is double) {
string text = ((double)val).ToString(NumberFormatInfo.InvariantInfo);
if (text.IndexOf('.') < 0 && text.IndexOf('E') < 0)
return text + ".0";
else
return text;
} }
if (val is IFormattable) { if (val is IFormattable) {
StringBuilder b = new StringBuilder();
if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) { if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) {
outputFormatter.PrintText("&H"); b.Append("&H");
outputFormatter.PrintText(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo)); b.Append(((IFormattable)val).ToString("x", NumberFormatInfo.InvariantInfo));
} else { } else {
outputFormatter.PrintText(((IFormattable)val).ToString(null, NumberFormatInfo.InvariantInfo)); b.Append(((IFormattable)val).ToString(null, NumberFormatInfo.InvariantInfo));
} }
if (val is ushort || val is uint || val is ulong) {
b.Append('U');
if (val is uint)
b.Append('I');
}
if (val is long || val is ulong)
b.Append('L');
if (val is short || val is ushort)
b.Append('S');
return b.ToString();
} else { } else {
outputFormatter.PrintText(val.ToString()); return val.ToString();
} }
return null;
} }
public override object TrackedVisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) public override object TrackedVisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
@ -2348,12 +2365,18 @@ namespace ICSharpCode.NRefactory.PrettyPrinter
case UnaryOperatorType.Dereference: case UnaryOperatorType.Dereference:
outputFormatter.PrintToken(Tokens.Times); outputFormatter.PrintToken(Tokens.Times);
TrackedVisit(unaryOperatorExpression.Expression, data);
return null; return null;
case UnaryOperatorType.AddressOf: case UnaryOperatorType.AddressOf:
outputFormatter.PrintToken(Tokens.AddressOf); outputFormatter.PrintToken(Tokens.AddressOf);
TrackedVisit(unaryOperatorExpression.Expression, data);
return null; return null;
default: default:
Error("unknown unary operator: " + unaryOperatorExpression.Op.ToString(), unaryOperatorExpression.StartLocation); Error("unknown unary operator: " + unaryOperatorExpression.Op.ToString(), unaryOperatorExpression.StartLocation);
outputFormatter.PrintText(unaryOperatorExpression.Op.ToString());
outputFormatter.PrintText("(");
TrackedVisit(unaryOperatorExpression.Expression, data);
outputFormatter.PrintText(")");
return null; return null;
} }
} }
@ -2422,11 +2445,7 @@ namespace ICSharpCode.NRefactory.PrettyPrinter
public override object TrackedVisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data) public override object TrackedVisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data)
{ {
if (!sizeOfExpression.TypeReference.IsArrayType) { if (!sizeOfExpression.TypeReference.IsArrayType && sizeOfExpression.TypeReference.PointerNestingLevel == 0) {
if (sizeOfExpression.TypeReference.PointerNestingLevel != 0) {
outputFormatter.PrintText("IntPtr.Size");
return null;
} else {
switch (sizeOfExpression.TypeReference.Type) { switch (sizeOfExpression.TypeReference.Type) {
case "System.Byte": case "System.Byte":
case "System.SByte": case "System.SByte":
@ -2449,7 +2468,6 @@ namespace ICSharpCode.NRefactory.PrettyPrinter
return null; return null;
} }
} }
}
UnsupportedNode(sizeOfExpression); UnsupportedNode(sizeOfExpression);
outputFormatter.PrintText("sizeof("); outputFormatter.PrintText("sizeof(");
TrackedVisit(sizeOfExpression.TypeReference, data); TrackedVisit(sizeOfExpression.TypeReference, data);

48
src/Libraries/NRefactory/Project/Src/Visitors/ToCSharpConvertVisitor.cs

@ -5,6 +5,7 @@
// <version>$Revision$</version> // <version>$Revision$</version>
// </file> // </file>
using ICSharpCode.NRefactory.AstBuilder;
using System; using System;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Ast;
@ -24,6 +25,7 @@ namespace ICSharpCode.NRefactory.Visitors
// => create additional member for implementing the interface // => create additional member for implementing the interface
// or convert to implicit interface implementation // or convert to implicit interface implementation
// Modules: make all members static // Modules: make all members static
// Use Convert.ToInt32 for VB casts
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{ {
@ -226,5 +228,51 @@ namespace ICSharpCode.NRefactory.Visitors
} }
return base.VisitSwitchSection(switchSection, data); return base.VisitSwitchSection(switchSection, data);
} }
public override object VisitCastExpression(CastExpression castExpression, object data)
{
base.VisitCastExpression(castExpression, data);
if (castExpression.CastType == CastType.Conversion || castExpression.CastType == CastType.PrimitiveConversion) {
switch (castExpression.CastTo.Type) {
case "System.Boolean":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToBoolean");
case "System.Byte":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToByte");
case "System.Char":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToChar");
case "System.DateTime":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToDateTime");
case "System.Decimal":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToDecimal");
case "System.Double":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToDouble");
case "System.Int16":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToInt16");
case "System.Int32":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToInt32");
case "System.Int64":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToInt64");
case "System.SByte":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToSByte");
case "System.Single":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToSingle");
case "System.String":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToString");
case "System.UInt16":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToUInt16");
case "System.UInt32":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToUInt32");
case "System.UInt64":
return ReplacePrimitiveCastWithConvertMethodCall(castExpression, "ToUInt64");
}
}
return null;
}
object ReplacePrimitiveCastWithConvertMethodCall(CastExpression castExpression, string methodName)
{
ReplaceCurrentNode(ExpressionBuilder.Identifier("Convert").Call(methodName, castExpression.Expression));
return null;
}
} }
} }

34
src/Libraries/NRefactory/Project/Src/Visitors/ToVBNetConvertVisitor.cs

@ -8,6 +8,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.AstBuilder;
using Attribute = ICSharpCode.NRefactory.Ast.Attribute; using Attribute = ICSharpCode.NRefactory.Ast.Attribute;
namespace ICSharpCode.NRefactory.Visitors namespace ICSharpCode.NRefactory.Visitors
@ -27,6 +28,7 @@ namespace ICSharpCode.NRefactory.Visitors
// Move Imports-statements out of namespaces // Move Imports-statements out of namespaces
// Parenthesis around Cast expressions remove - these are syntax errors in VB.NET // Parenthesis around Cast expressions remove - these are syntax errors in VB.NET
// Decrease array creation size - VB specifies upper bound instead of array length // Decrease array creation size - VB specifies upper bound instead of array length
// Automatic properties are converted to explicit implementation
List<INode> nodesToMoveToCompilationUnit = new List<INode>(); List<INode> nodesToMoveToCompilationUnit = new List<INode>();
@ -309,6 +311,25 @@ namespace ICSharpCode.NRefactory.Visitors
ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(propertyDeclaration); ToVBNetRenameConflictingVariablesVisitor.RenameConflicting(propertyDeclaration);
if (!IsClassType(ClassType.Interface) && (propertyDeclaration.Modifier & Modifiers.Abstract) == 0) {
if (propertyDeclaration.HasGetRegion && propertyDeclaration.HasSetRegion) {
if (propertyDeclaration.GetRegion.Block.IsNull && propertyDeclaration.SetRegion.Block.IsNull) {
// automatically implemented property
string fieldName = "m_" + propertyDeclaration.Name;
Modifiers fieldModifier = propertyDeclaration.Modifier & ~(Modifiers.Visibility) | Modifiers.Private;
FieldDeclaration newField = new FieldDeclaration(null, propertyDeclaration.TypeReference, fieldModifier);
newField.Fields.Add(new VariableDeclaration(fieldName));
InsertAfterSibling(propertyDeclaration, newField);
propertyDeclaration.GetRegion.Block = new BlockStatement();
propertyDeclaration.GetRegion.Block.Return(ExpressionBuilder.Identifier(fieldName));
propertyDeclaration.SetRegion.Block = new BlockStatement();
propertyDeclaration.SetRegion.Block.Assign(ExpressionBuilder.Identifier(fieldName), ExpressionBuilder.Identifier("Value"));
}
}
}
return null; return null;
} }
@ -335,7 +356,9 @@ namespace ICSharpCode.NRefactory.Visitors
{ {
base.VisitParenthesizedExpression(parenthesizedExpression, data); base.VisitParenthesizedExpression(parenthesizedExpression, data);
if (parenthesizedExpression.Expression is CastExpression) { if (parenthesizedExpression.Expression is CastExpression) {
ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis around casts
} else if (parenthesizedExpression.Parent is CastExpression) {
ReplaceCurrentNode(parenthesizedExpression.Expression); // remove parenthesis inside casts
} }
return null; return null;
} }
@ -347,5 +370,14 @@ namespace ICSharpCode.NRefactory.Visitors
} }
return base.VisitArrayCreateExpression(arrayCreateExpression, data); return base.VisitArrayCreateExpression(arrayCreateExpression, data);
} }
public override object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
{
base.VisitDefaultValueExpression(defaultValueExpression, data);
Expression defaultValue = ExpressionBuilder.CreateDefaultValueForType(defaultValueExpression.TypeReference);
if (!(defaultValue is DefaultValueExpression))
ReplaceCurrentNode(defaultValue);
return null;
}
} }
} }

4
src/Libraries/NRefactory/Project/Src/Visitors/ToVBNetRenameConflictingVariables.cs

@ -20,7 +20,7 @@ namespace ICSharpCode.NRefactory.Visitors
{ {
// variable name => case sensitive variable name // variable name => case sensitive variable name
// value is null if there are multiple casings for the variable -> the variable is conflicting // value is null if there are multiple casings for the variable -> the variable is conflicting
Dictionary<string, string> caseInsensitive = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); Dictionary<string, string> caseInsensitive = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
LookupTableVisitor ltv = new LookupTableVisitor(SupportedLanguage.CSharp); LookupTableVisitor ltv = new LookupTableVisitor(SupportedLanguage.CSharp);
method.AcceptVisitor(ltv, null); method.AcceptVisitor(ltv, null);
@ -59,7 +59,7 @@ namespace ICSharpCode.NRefactory.Visitors
static void RenameVariable(INode method, string from, ref int index) static void RenameVariable(INode method, string from, ref int index)
{ {
index += 1; index += 1;
method.AcceptVisitor(new RenameLocalVariableVisitor(from, from + "__" + index, StringComparer.InvariantCulture), null); method.AcceptVisitor(new RenameLocalVariableVisitor(from, from + "__" + index, StringComparer.Ordinal), null);
} }
static void AddVariableToDict(Dictionary<string, string> caseInsensitive, string varName, bool hasDeclaration) static void AddVariableToDict(Dictionary<string, string> caseInsensitive, string varName, bool hasDeclaration)

6
src/Libraries/NRefactory/Test/Output/CSharp/VBNetToCSharpConverterTest.cs

@ -697,5 +697,11 @@ static int static_Test2_j = 0;");
" public const int C = 0;" + Environment.NewLine + " public const int C = 0;" + Environment.NewLine +
"}" + Environment.NewLine); "}" + Environment.NewLine);
} }
[Test]
public void CastToInteger()
{
TestStatement("Dim x As Integer = CInt(obj)", "int x = Convert.ToInt32(obj);");
}
} }
} }

36
src/Libraries/NRefactory/Test/Output/VBNet/CSharpToVBNetConverterTest.cs

@ -547,10 +547,40 @@ namespace ICSharpCode.NRefactory.Tests.PrettyPrinter
} }
[Test] [Test]
public void SizeOfInt32Pointer() public void AutomaticProperty()
{ {
TestStatement(@"int i = sizeof(int*);", TestMember(@"public string Name { get; set; }",
@"Dim i As Integer = IntPtr.Size"); @"Public Property Name() As String
Get
Return m_Name
End Get
Set
m_Name = Value
End Set
End Property
Private m_Name As String");
}
[Test]
public void AutomaticPropertyPrivateSetter()
{
TestMember(@"public string Name { get; private set; }",
@"Public Property Name() As String
Get
Return m_Name
End Get
Private Set
m_Name = Value
End Set
End Property
Private m_Name As String");
}
[Test]
public void DefaultValueExpression()
{
TestStatement(@"object x = default(int);",
@"Dim x As Object = 0");
} }
} }
} }

25
src/Libraries/NRefactory/Test/Output/VBNet/VBNetOutputTest.cs

@ -380,6 +380,12 @@ End Using");
TestTypeMember("Sub Main(ByRef one As Integer, ByRef two As Integer, <Out> ByRef three As Integer)\nEnd Sub"); TestTypeMember("Sub Main(ByRef one As Integer, ByRef two As Integer, <Out> ByRef three As Integer)\nEnd Sub");
} }
[Test]
public void FieldWithoutType()
{
TestTypeMember("Dim X");
}
[Test] [Test]
public void UsingStatementForExistingVariable() public void UsingStatementForExistingVariable()
{ {
@ -431,6 +437,12 @@ End Using");
TestExpression("16"); TestExpression("16");
} }
[Test]
public void Double()
{
TestExpression("1.0");
}
[Test] [Test]
public void HexadecimalInteger() public void HexadecimalInteger()
{ {
@ -442,5 +454,18 @@ End Using");
{ {
TestExpression("&Hffffffff"); TestExpression("&Hffffffff");
} }
[Test]
public void TypeCharacters()
{
TestExpression("347S");
TestExpression("347L");
TestExpression("347D");
TestExpression("347F");
TestExpression("347US");
TestExpression("347UI");
TestExpression("347UL");
TestExpression("\".\"C");
}
} }
} }

28
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/CSharpToVBNetConvertVisitor.cs

@ -331,6 +331,19 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return false; return false;
} }
bool IsFloatingPoint(IReturnType rt)
{
if (rt != null && rt.IsDefaultReturnType) {
switch (rt.FullyQualifiedName) {
case "System.Single":
case "System.Double":
case "System.Decimal":
return true;
}
}
return false;
}
bool NeedsExplicitConversionToString(IReturnType rt) bool NeedsExplicitConversionToString(IReturnType rt)
{ {
if (rt != null) { if (rt != null) {
@ -441,13 +454,21 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
if (resolver.CompilationUnit == null) if (resolver.CompilationUnit == null)
return null; return null;
if (castExpression.CastType != CastType.TryCast) {
IReturnType targetType = ResolveType(castExpression.CastTo); IReturnType targetType = ResolveType(castExpression.CastTo);
if (targetType != null) { IClass targetClass = targetType != null ? targetType.GetUnderlyingClass() : null;
IClass targetClass = targetType.GetUnderlyingClass(); if (castExpression.CastType != CastType.TryCast) {
if (targetClass != null && (targetClass.ClassType == ClassType.Struct || targetClass.ClassType == ClassType.Enum)) { if (targetClass != null && (targetClass.ClassType == ClassType.Struct || targetClass.ClassType == ClassType.Enum)) {
// cast to value type is a conversion // cast to value type is a conversion
castExpression.CastType = CastType.Conversion; castExpression.CastType = CastType.Conversion;
if (IsInteger(targetType)) {
ResolveResult sourceRR = resolver.ResolveInternal(castExpression.Expression, ExpressionContext.Default);
IReturnType sourceType = sourceRR != null ? sourceRR.ResolvedType : null;
if (IsFloatingPoint(sourceType)) {
// casts from float to int in C# truncate, but VB rounds
// we'll have to introduce a call to Math.Truncate
castExpression.Expression = ExpressionBuilder.Identifier("Math").Call("Truncate", castExpression.Expression);
}
}
} }
if (targetClass != null && targetClass.FullyQualifiedName == "System.Char") { if (targetClass != null && targetClass.FullyQualifiedName == "System.Char") {
// C# cast to char is done using ChrW function // C# cast to char is done using ChrW function
@ -458,7 +479,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
} }
} }
} }
}
return null; return null;
} }

14
src/Main/ICSharpCode.SharpDevelop.Dom/Tests/ICSharpCode.SharpDevelop.Dom.Tests/CodeSnippetConverterTests.cs

@ -83,6 +83,20 @@ namespace ICSharpCode.SharpDevelop.Dom.Tests
out errors))); out errors)));
} }
[Test]
public void ConvertFloatingPointToInteger()
{
Assert.AreEqual("CInt(Math.Truncate(-3.5))", converter.CSharpToVB("(int)(-3.5)", out errors));
Assert.AreEqual("CInt(Math.Truncate(-3.5F))", converter.CSharpToVB("(int)(-3.5f)", out errors));
Assert.AreEqual("CInt(Math.Truncate(-3.5D))", converter.CSharpToVB("(int)(-3.5m)", out errors));
}
[Test]
public void ConvertLongToInteger()
{
Assert.AreEqual("CInt(-35L)", converter.CSharpToVB("(int)(-35L)", out errors));
}
string Normalize(string text) string Normalize(string text)
{ {
return text.Replace("\t", " ").Replace("\r", "").Trim(); return text.Replace("\t", " ").Replace("\r", "").Trim();

Loading…
Cancel
Save