diff --git a/ILSpy/VB/ILSpyEnvironmentProvider.cs b/ILSpy/VB/ILSpyEnvironmentProvider.cs index 38df8e201..e23e9a3ea 100644 --- a/ILSpy/VB/ILSpyEnvironmentProvider.cs +++ b/ILSpy/VB/ILSpyEnvironmentProvider.cs @@ -17,8 +17,11 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.Linq; + using ICSharpCode.Decompiler; +using ICSharpCode.Decompiler.Ast; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.VB.Visitors; using Mono.Cecil; @@ -33,6 +36,21 @@ namespace ICSharpCode.ILSpy.VB } } + ITypeResolveContext context; + + CecilLoader loader = new CecilLoader(false); + + public ILSpyEnvironmentProvider(ITypeResolveContext context) + { + this.context = context; + } + + public ITypeResolveContext ResolveContext { + get { + return context; + } + } + public string GetTypeNameForAttribute(ICSharpCode.NRefactory.CSharp.Attribute attribute) { return attribute.Type.Annotations @@ -41,6 +59,21 @@ namespace ICSharpCode.ILSpy.VB .FullName; } + public IType ResolveType(NRefactory.VB.Ast.AstType type, NRefactory.VB.Ast.TypeDeclaration entity = null) + { + var annotation = type.Annotation(); + if (annotation == null ) + return null; + + IEntity current = null; + if (entity != null) { + var typeInfo = entity.Annotation(); + current = loader.ReadTypeReference(typeInfo).Resolve(context).GetDefinition(); + } + + return loader.ReadTypeReference(annotation, entity: current).Resolve(context); + } + public ClassType GetClassTypeForAstType(ICSharpCode.NRefactory.CSharp.AstType type) { var definition = type.Annotations.OfType().First().ResolveOrThrow(); @@ -59,9 +92,61 @@ namespace ICSharpCode.ILSpy.VB return ClassType.Module; } - public IType ResolveExpression(ICSharpCode.NRefactory.CSharp.Expression expression) + public TypeCode ResolveExpression(ICSharpCode.NRefactory.CSharp.Expression expression) { - throw new NotImplementedException(); + var annotation = expression.Annotations.OfType().FirstOrDefault(); + + if (annotation == null) + return TypeCode.Object; + + var definition = annotation.InferredType.Resolve(); + + if (definition == null) + return TypeCode.Object; + + switch (definition.FullName) { + case "System.String": + return TypeCode.String; + default: + + break; + } + + return TypeCode.Object; } + + public Nullable IsReferenceType(ICSharpCode.NRefactory.CSharp.Expression expression) + { + if (expression is ICSharpCode.NRefactory.CSharp.NullReferenceExpression) + return true; + + var annotation = expression.Annotations.OfType().FirstOrDefault(); + + if (annotation == null) + return null; + + var definition = annotation.InferredType.Resolve(); + + if (definition == null) + return null; + + return !definition.IsValueType; + } + + public IEnumerable CreateMemberSpecifiersForInterfaces(IEnumerable interfaces) + { + foreach (var type in interfaces) { + var def = type.Annotation().Resolve(); + if (def == null) continue; + foreach (var method in def.Methods.Where(m => !m.Name.StartsWith("get_") && !m.Name.StartsWith("set_"))) { + yield return new NRefactory.VB.Ast.InterfaceMemberSpecifier((NRefactory.VB.Ast.AstType)type.Clone(), method.Name); + } + + foreach (var property in def.Properties) { + yield return new NRefactory.VB.Ast.InterfaceMemberSpecifier((NRefactory.VB.Ast.AstType)type.Clone(), property.Name); + } + } + } + } } diff --git a/ILSpy/VB/VBLanguage.cs b/ILSpy/VB/VBLanguage.cs index a5de0efbe..f69ad677b 100644 --- a/ILSpy/VB/VBLanguage.cs +++ b/ILSpy/VB/VBLanguage.cs @@ -32,6 +32,7 @@ using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast.Transforms; using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.VB; using ICSharpCode.NRefactory.VB.Visitors; using Mono.Cecil; @@ -121,7 +122,7 @@ namespace ICSharpCode.ILSpy.VB using (options.FullDecompilation ? null : LoadedAssembly.DisableAssemblyLoad()) { AstBuilder codeDomBuilder = CreateAstBuilder(options, currentModule: assembly.AssemblyDefinition.MainModule); codeDomBuilder.AddAssembly(assembly.AssemblyDefinition, onlyAssemblyLevel: !options.FullDecompilation); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, assembly.AssemblyDefinition.MainModule); } } OnDecompilationFinished(null); @@ -303,7 +304,7 @@ namespace ICSharpCode.ILSpy.VB foreach (TypeDefinition type in file) { codeDomBuilder.AddType(type); } - RunTransformsAndGenerateCode(codeDomBuilder, new PlainTextOutput(w), options); + RunTransformsAndGenerateCode(codeDomBuilder, new PlainTextOutput(w), options, assembly.MainModule); } }); AstMethodBodyBuilder.PrintNumberOfUnhandledOpcodes(); @@ -394,7 +395,7 @@ namespace ICSharpCode.ILSpy.VB WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true)); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true); codeDomBuilder.AddMethod(method); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, method.Module); } public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) @@ -402,7 +403,7 @@ namespace ICSharpCode.ILSpy.VB WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true)); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: property.DeclaringType, isSingleMember: true); codeDomBuilder.AddProperty(property); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, property.Module); } public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) @@ -410,7 +411,7 @@ namespace ICSharpCode.ILSpy.VB WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true)); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: field.DeclaringType, isSingleMember: true); codeDomBuilder.AddField(field); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, field.Module); } public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) @@ -418,14 +419,14 @@ namespace ICSharpCode.ILSpy.VB WriteCommentLine(output, TypeToString(ev.DeclaringType, includeNamespace: true)); AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: ev.DeclaringType, isSingleMember: true); codeDomBuilder.AddEvent(ev); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, ev.Module); } public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) { AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: type); codeDomBuilder.AddType(type); - RunTransformsAndGenerateCode(codeDomBuilder, output, options); + RunTransformsAndGenerateCode(codeDomBuilder, output, options, type.Module); } public override bool ShowMember(MemberReference member) @@ -433,12 +434,12 @@ namespace ICSharpCode.ILSpy.VB return showAllMembers || !AstBuilder.MemberIsHidden(member, new DecompilationOptions().DecompilerSettings); } - void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options) + void RunTransformsAndGenerateCode(AstBuilder astBuilder, ITextOutput output, DecompilationOptions options, ModuleDefinition module) { astBuilder.RunTransformations(transformAbortCondition); if (options.DecompilerSettings.ShowXmlDocumentation) AddXmlDocTransform.Run(astBuilder.CompilationUnit); - var unit = astBuilder.CompilationUnit.AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider()), null); + var unit = astBuilder.CompilationUnit.AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider(CreateResolveContext(module))), null); var outputFormatter = new VBTextOutputFormatter(output); var formattingPolicy = new VBFormattingOptions(); unit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null); @@ -480,11 +481,28 @@ namespace ICSharpCode.ILSpy.VB return TypeToString(options, type, typeAttributes); } + ITypeResolveContext CreateResolveContext(ModuleDefinition module) + { + IProjectContent projectContent = new CecilTypeResolveContext(module); + + List resolveContexts = new List(); + resolveContexts.Add(projectContent); + foreach (AssemblyNameReference r in module.AssemblyReferences) { + AssemblyDefinition d = module.AssemblyResolver.Resolve(r); + if (d != null) { + resolveContexts.Add(new CecilTypeResolveContext(d.MainModule)); + } + } + + return new CompositeTypeResolveContext(resolveContexts); + } + string TypeToString(ConvertTypeOptions options, TypeReference type, ICustomAttributeProvider typeAttributes = null) { + var astType = AstBuilder .ConvertType(type, typeAttributes, options) - .AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider()), null); + .AcceptVisitor(new CSharpToVBConverterVisitor(new ILSpyEnvironmentProvider(CreateResolveContext(type.Resolve().Module))), null); StringWriter w = new StringWriter(); // TODO // if (type.IsByReference) { diff --git a/NRefactory/ICSharpCode.NRefactory.VB/Ast/Identifier.cs b/NRefactory/ICSharpCode.NRefactory.VB/Ast/Identifier.cs index 99028a896..0ffa568c9 100644 --- a/NRefactory/ICSharpCode.NRefactory.VB/Ast/Identifier.cs +++ b/NRefactory/ICSharpCode.NRefactory.VB/Ast/Identifier.cs @@ -89,8 +89,8 @@ namespace ICSharpCode.NRefactory.VB.Ast public override string ToString() { - return string.Format("[Identifier Name={0}, StartLocation={1}, TypeCharacter{4}]", - name, startLocation, TypeCharacter); + return string.Format("{0}", + name); } } } diff --git a/NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/AstType.cs b/NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/AstType.cs index d9f7e4ce2..ca39bd369 100644 --- a/NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/AstType.cs +++ b/NRefactory/ICSharpCode.NRefactory.VB/Ast/TypeName/AstType.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; using System.Collections.Generic; +using System.Linq; namespace ICSharpCode.NRefactory.VB.Ast { @@ -70,6 +71,24 @@ namespace ICSharpCode.NRefactory.VB.Ast return new ComposedType { BaseType = this }.MakeArrayType(rank); } + public static AstType FromName(string fullName) + { + if (string.IsNullOrEmpty(fullName)) + throw new ArgumentNullException("fullName"); + fullName = fullName.Trim(); + if (!fullName.Contains(".")) + return new SimpleType(fullName); + string[] parts = fullName.Split('.'); + + AstType type = new SimpleType(parts.First()); + + foreach (var part in parts.Skip(1)) { + type = new QualifiedType(type, part); + } + + return type; + } + /// /// Builds an expression that can be used to access a static member on this type. /// diff --git a/NRefactory/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs b/NRefactory/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs index 15cfcec0d..89ada8a5c 100644 --- a/NRefactory/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory.VB/Visitors/CSharpToVBConverterVisitor.cs @@ -16,7 +16,10 @@ namespace ICSharpCode.NRefactory.VB.Visitors string RootNamespace { get; } string GetTypeNameForAttribute(CSharp.Attribute attribute); ClassType GetClassTypeForAstType(CSharp.AstType type); - IType ResolveExpression(CSharp.Expression expression); + TypeCode ResolveExpression(CSharp.Expression expression); + bool? IsReferenceType(CSharp.Expression expression); + ITypeResolveContext ResolveContext { get; } + IType ResolveType(AstType type, TypeDeclaration entity = null); } /// @@ -177,8 +180,6 @@ namespace ICSharpCode.NRefactory.VB.Visitors var op = BinaryOperatorType.None; var right = (Expression)binaryOperatorExpression.Right.AcceptVisitor(this, data); - // TODO obj <> Nothing is wrong; correct would be obj IsNot Nothing - switch (binaryOperatorExpression.Operator) { case ICSharpCode.NRefactory.CSharp.BinaryOperatorType.BitwiseAnd: op = BinaryOperatorType.BitwiseAnd; @@ -202,10 +203,16 @@ namespace ICSharpCode.NRefactory.VB.Visitors op = BinaryOperatorType.GreaterThanOrEqual; break; case ICSharpCode.NRefactory.CSharp.BinaryOperatorType.Equality: - op = BinaryOperatorType.Equality; + if (IsReferentialEquality(binaryOperatorExpression)) + op = BinaryOperatorType.ReferenceEquality; + else + op = BinaryOperatorType.Equality; break; case ICSharpCode.NRefactory.CSharp.BinaryOperatorType.InEquality: - op = BinaryOperatorType.InEquality; + if (IsReferentialEquality(binaryOperatorExpression)) + op = BinaryOperatorType.ReferenceInequality; + else + op = BinaryOperatorType.InEquality; break; case ICSharpCode.NRefactory.CSharp.BinaryOperatorType.LessThan: op = BinaryOperatorType.LessThan; @@ -248,6 +255,17 @@ namespace ICSharpCode.NRefactory.VB.Visitors return EndNode(binaryOperatorExpression, new BinaryOperatorExpression(left, op, right)); } + bool IsReferentialEquality(CSharp.BinaryOperatorExpression binaryOperatorExpression) + { + var left = provider.IsReferenceType(binaryOperatorExpression.Left); + var right = provider.IsReferenceType(binaryOperatorExpression.Right); + + var leftCode = provider.ResolveExpression(binaryOperatorExpression.Left); + var rightCode = provider.ResolveExpression(binaryOperatorExpression.Right); + + return (left == true || right == true) && (leftCode != TypeCode.String && rightCode != TypeCode.String); + } + public AstNode VisitCastExpression(CSharp.CastExpression castExpression, object data) { var expr = new CastExpression(); @@ -806,6 +824,7 @@ namespace ICSharpCode.NRefactory.VB.Visitors if (typeDeclaration.ClassType == ClassType.Enum) { var type = new EnumDeclaration(); + CopyAnnotations(typeDeclaration, type); ConvertNodes(typeDeclaration.Attributes, type.Attributes); ConvertNodes(typeDeclaration.ModifierTokens, type.ModifierTokens); @@ -823,6 +842,7 @@ namespace ICSharpCode.NRefactory.VB.Visitors return EndNode(typeDeclaration, type); } else { var type = new TypeDeclaration(); + CopyAnnotations(typeDeclaration, type); CSharp.Attribute stdModAttr; @@ -1417,6 +1437,8 @@ namespace ICSharpCode.NRefactory.VB.Visitors result.Name = evt.Name; result.ReturnType = (AstType)eventDeclaration.ReturnType.AcceptVisitor(this, data); +// CreateImplementsClausesForEvent(result); + types.Peek().Members.Add(result); } @@ -1441,7 +1463,8 @@ namespace ICSharpCode.NRefactory.VB.Visitors if (!customEventDeclaration.PrivateImplementationType.IsNull) result.ImplementsClause.Add( new InterfaceMemberSpecifier((AstType)customEventDeclaration.PrivateImplementationType.AcceptVisitor(this, data), customEventDeclaration.Name)); - +// else +// CreateImplementsClausesForEvent(result); result.AddHandlerBlock = (Accessor)customEventDeclaration.AddAccessor.AcceptVisitor(this, data); result.RemoveHandlerBlock = (Accessor)customEventDeclaration.RemoveAccessor.AcceptVisitor(this, data); @@ -1553,9 +1576,22 @@ namespace ICSharpCode.NRefactory.VB.Visitors result.ImplementsClause.Add( new InterfaceMemberSpecifier((AstType)methodDeclaration.PrivateImplementationType.AcceptVisitor(this, data), methodDeclaration.Name)); +// else +// CreateImplementsClausesForMethod(result); if (!result.IsSub) result.ReturnType = (AstType)methodDeclaration.ReturnType.AcceptVisitor(this, data); + if (methodDeclaration.IsExtensionMethod) { + result.Attributes.Add( + new AttributeBlock { + Attributes = { + new Ast.Attribute { + Type = AstType.FromName("System.Runtime.CompilerServices.ExtensionAttribute") + } + } + }); + } + result.Body = (BlockStatement)methodDeclaration.Body.AcceptVisitor(this, data); if (members.Pop().inIterator) { @@ -1566,6 +1602,38 @@ namespace ICSharpCode.NRefactory.VB.Visitors } } + void CreateImplementsClausesForMethod(MethodDeclaration result) + { + if (!types.Any()) return; + var current = types.Peek(); + if (current.ClassType == ClassType.Interface) + return; + + foreach (var type in current.ImplementsTypes) { + var resolved = provider.ResolveType(type, current); + var found = resolved.GetMembers(provider.ResolveContext, m => m.EntityType == EntityType.Method && m.Name == result.Name.Name); + if (found.FirstOrDefault() != null) { + result.ImplementsClause.Add(new InterfaceMemberSpecifier((AstType)type.Clone(), found.FirstOrDefault().Name)); + } + } + } + + void CreateImplementsClausesForEvent(EventDeclaration result) + { + if (!types.Any()) return; + var current = types.Peek(); + if (current.ClassType == ClassType.Interface) + return; + + foreach (var type in current.ImplementsTypes) { + var resolved = provider.ResolveType(type, current); + var found = resolved.GetMembers(provider.ResolveContext, m => m.EntityType == EntityType.Event && m.Name == result.Name.Name); + if (found.FirstOrDefault() != null) { + result.ImplementsClause.Add(new InterfaceMemberSpecifier((AstType)type.Clone(), found.FirstOrDefault().Name)); + } + } + } + string ConvertAlias(CSharp.AstNodeCollection arguments) { var pattern = new CSharp.AssignmentExpression() { @@ -2106,8 +2174,18 @@ namespace ICSharpCode.NRefactory.VB.Visitors T EndNode(CSharp.AstNode node, T result) where T : VB.AstNode { + if (result != null) { + CopyAnnotations(node, result); + } + return result; } + + void CopyAnnotations(CSharp.AstNode node, T result) where T : VB.AstNode + { + foreach (var ann in node.Annotations) + result.AddAnnotation(ann); + } bool HasAttribute(CSharp.AstNodeCollection attributes, string name, out CSharp.Attribute foundAttribute) {