Browse Source

replace ambiguous type names with FQNs

pull/728/head
Siegfried Pammer 11 years ago
parent
commit
f554a26a2b
  1. 273
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

273
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -20,7 +20,12 @@ using System; @@ -20,7 +20,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.CSharp.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
@ -39,6 +44,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -39,6 +44,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
requiredImports.ImportedNamespaces.Add("System"); // always import System, even when not necessary
var usingScope = new UsingScope();
// Now add using declarations for those namespaces:
foreach (string ns in requiredImports.ImportedNamespaces.OrderByDescending(n => n)) {
// we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards
@ -48,28 +55,32 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -48,28 +55,32 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
for (int i = 1; i < parts.Length; i++) {
nsType = new MemberType { Target = nsType, MemberName = parts[i] };
}
if (FullyQualifyAmbiguousTypeNames) {
var reference = nsType.ToTypeReference(NameLookupMode.TypeInUsingDeclaration) as TypeOrNamespaceReference;
if (reference != null)
usingScope.Usings.Add(reference);
}
compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole);
}
if (!FullyQualifyAmbiguousTypeNames)
return;
/*
FindAmbiguousTypeNames(context.CurrentModule, internalsVisible: true);
foreach (AssemblyNameReference r in context.CurrentModule.AssemblyReferences) {
AssemblyDefinition d = context.CurrentModule.AssemblyResolver.Resolve(r);
if (d != null)
FindAmbiguousTypeNames(d.MainModule, internalsVisible: false);
}
var astBuilder = CreateAstBuilderWithUsingScope(context, usingScope);
// verify that the SimpleTypes refer to the correct type (no ambiguities)
compilationUnit.AcceptVisitor(new FullyQualifyAmbiguousTypeNamesVisitor(this), null);*/
compilationUnit.AcceptVisitor(new FullyQualifyAmbiguousTypeNamesVisitor(astBuilder), null);
}
TypeSystemAstBuilder CreateAstBuilderWithUsingScope(TransformContext context, UsingScope usingScope)
{
var resolveContext = new CSharpTypeResolveContext(context.TypeSystem.MainAssembly, usingScope.Resolve(context.TypeSystem.Compilation), context.DecompiledTypeDefinition, context.DecompiledMember);
var resolver = new CSharpResolver(resolveContext);
return new TypeSystemAstBuilder(resolver) {
AddResolveResultAnnotations = true,
UseAliases = true
};
}
// Note that we store type names with `n suffix, so we automatically disambiguate based on number of type parameters.
//readonly HashSet<string> availableTypeNames = new HashSet<string>();
//readonly HashSet<string> ambiguousTypeNames = new HashSet<string>();
sealed class FindRequiredImports : DepthFirstAstVisitor
{
@ -117,237 +128,41 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -117,237 +128,41 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
/*
void FindAmbiguousTypeNames(ModuleDefinition module, bool internalsVisible)
{
foreach (TypeDefinition type in module.Types) {
if (internalsVisible || type.IsPublic) {
if (importedNamespaces.Contains(type.Namespace) || declaredNamespaces.Contains(type.Namespace)) {
if (!availableTypeNames.Add(type.Name))
ambiguousTypeNames.Add(type.Name);
}
}
}
}
sealed class FullyQualifyAmbiguousTypeNamesVisitor : DepthFirstAstVisitor<object, object>
{
readonly IntroduceUsingDeclarations transform;
string currentNamespace;
HashSet<string> currentMemberTypes;
Dictionary<string, MemberReference> currentMembers;
bool isWithinTypeReferenceExpression;
readonly TypeSystemAstBuilder astBuilder;
public FullyQualifyAmbiguousTypeNamesVisitor(IntroduceUsingDeclarations transform)
public FullyQualifyAmbiguousTypeNamesVisitor(TypeSystemAstBuilder astBuilder)
{
this.transform = transform;
this.currentNamespace = transform.context.CurrentType != null ? transform.context.CurrentType.Namespace : string.Empty;
}
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data)
{
string oldNamespace = currentNamespace;
foreach (Identifier ident in namespaceDeclaration.Identifiers) {
currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident.Name);
}
base.VisitNamespaceDeclaration(namespaceDeclaration, data);
currentNamespace = oldNamespace;
return null;
}
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
{
HashSet<string> oldMemberTypes = currentMemberTypes;
currentMemberTypes = currentMemberTypes != null ? new HashSet<string>(currentMemberTypes) : new HashSet<string>();
Dictionary<string, MemberReference> oldMembers = currentMembers;
currentMembers = new Dictionary<string, MemberReference>();
TypeDefinition typeDef = typeDeclaration.Annotation<TypeDefinition>();
bool privateMembersVisible = true;
ModuleDefinition internalMembersVisibleInModule = typeDef.Module;
while (typeDef != null) {
foreach (GenericParameter gp in typeDef.GenericParameters) {
currentMemberTypes.Add(gp.Name);
}
foreach (TypeDefinition t in typeDef.NestedTypes) {
if (privateMembersVisible || IsVisible(t, internalMembersVisibleInModule))
currentMemberTypes.Add(t.Name.Substring(t.Name.LastIndexOf('+') + 1));
}
foreach (MethodDefinition method in typeDef.Methods) {
if (privateMembersVisible || IsVisible(method, internalMembersVisibleInModule))
AddCurrentMember(method);
}
foreach (PropertyDefinition property in typeDef.Properties) {
if (privateMembersVisible || IsVisible(property.GetMethod, internalMembersVisibleInModule) || IsVisible(property.SetMethod, internalMembersVisibleInModule))
AddCurrentMember(property);
}
foreach (EventDefinition ev in typeDef.Events) {
if (privateMembersVisible || IsVisible(ev.AddMethod, internalMembersVisibleInModule) || IsVisible(ev.RemoveMethod, internalMembersVisibleInModule))
AddCurrentMember(ev);
}
foreach (FieldDefinition f in typeDef.Fields) {
if (privateMembersVisible || IsVisible(f, internalMembersVisibleInModule))
AddCurrentMember(f);
}
// repeat with base class:
if (typeDef.BaseType != null)
typeDef = typeDef.BaseType.Resolve();
else
typeDef = null;
privateMembersVisible = false;
}
// Now add current members from outer classes:
if (oldMembers != null) {
foreach (var pair in oldMembers) {
// add members from outer classes only if the inner class doesn't define the member
if (!currentMembers.ContainsKey(pair.Key))
currentMembers.Add(pair.Key, pair.Value);
}
}
base.VisitTypeDeclaration(typeDeclaration, data);
currentMembers = oldMembers;
return null;
}
void AddCurrentMember(MemberReference m)
{
MemberReference existingMember;
if (currentMembers.TryGetValue(m.Name, out existingMember)) {
// We keep the existing member assignment if it was from another class (=from a derived class),
// because members in derived classes have precedence over members in base classes.
if (existingMember != null && existingMember.DeclaringType == m.DeclaringType) {
// Use null as value to signalize multiple members with the same name
currentMembers[m.Name] = null;
}
} else {
currentMembers.Add(m.Name, m);
}
}
bool IsVisible(MethodDefinition m, ModuleDefinition internalMembersVisibleInModule)
{
if (m == null)
return false;
switch (m.Attributes & MethodAttributes.MemberAccessMask) {
case MethodAttributes.FamANDAssem:
case MethodAttributes.Assembly:
return m.Module == internalMembersVisibleInModule;
case MethodAttributes.Family:
case MethodAttributes.FamORAssem:
case MethodAttributes.Public:
return true;
default:
return false;
}
}
bool IsVisible(FieldDefinition f, ModuleDefinition internalMembersVisibleInModule)
{
if (f == null)
return false;
switch (f.Attributes & FieldAttributes.FieldAccessMask) {
case FieldAttributes.FamANDAssem:
case FieldAttributes.Assembly:
return f.Module == internalMembersVisibleInModule;
case FieldAttributes.Family:
case FieldAttributes.FamORAssem:
case FieldAttributes.Public:
return true;
default:
return false;
}
}
bool IsVisible(TypeDefinition t, ModuleDefinition internalMembersVisibleInModule)
{
if (t == null)
return false;
switch (t.Attributes & TypeAttributes.VisibilityMask) {
case TypeAttributes.NotPublic:
case TypeAttributes.NestedAssembly:
case TypeAttributes.NestedFamANDAssem:
return t.Module == internalMembersVisibleInModule;
case TypeAttributes.NestedFamily:
case TypeAttributes.NestedFamORAssem:
case TypeAttributes.NestedPublic:
case TypeAttributes.Public:
return true;
default:
return false;
}
this.astBuilder = astBuilder;
}
public override object VisitSimpleType(SimpleType simpleType, object data)
{
// Handle type arguments first, so that the fixed-up type arguments get moved over to the MemberType,
// if we're also creating one here.
base.VisitSimpleType(simpleType, data);
TypeReference tr = simpleType.Annotation<TypeReference>();
// Fully qualify any ambiguous type names.
if (tr != null && IsAmbiguous(tr.Namespace, tr.Name)) {
AstType ns;
if (string.IsNullOrEmpty(tr.Namespace)) {
ns = new SimpleType("global");
} else {
string[] parts = tr.Namespace.Split('.');
if (IsAmbiguous(string.Empty, parts[0])) {
// conflict between namespace and type name/member name
ns = new MemberType { Target = new SimpleType("global"), IsDoubleColon = true, MemberName = parts[0] };
} else {
ns = new SimpleType(parts[0]);
}
for (int i = 1; i < parts.Length; i++) {
ns = new MemberType { Target = ns, MemberName = parts[i] };
}
}
MemberType mt = new MemberType();
mt.Target = ns;
mt.IsDoubleColon = string.IsNullOrEmpty(tr.Namespace);
mt.MemberName = simpleType.Identifier;
mt.CopyAnnotationsFrom(simpleType);
simpleType.TypeArguments.MoveTo(mt.TypeArguments);
simpleType.ReplaceWith(mt);
}
TypeResolveResult rr;
if (simpleType.Ancestors.OfType<UsingDeclaration>().Any() || (rr = simpleType.Annotation<TypeResolveResult>()) == null)
return base.VisitSimpleType(simpleType, data);
simpleType.ReplaceWith(astBuilder.ConvertType(rr.Type));
return null;
}
public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
public override object VisitMemberType(MemberType memberType, object data)
{
isWithinTypeReferenceExpression = true;
base.VisitTypeReferenceExpression(typeReferenceExpression, data);
isWithinTypeReferenceExpression = false;
TypeResolveResult rr;
if (memberType.Ancestors.OfType<UsingDeclaration>().Any() || (rr = memberType.Annotation<TypeResolveResult>()) == null)
return base.VisitMemberType(memberType, data);
memberType.ReplaceWith(astBuilder.ConvertType(rr.Type));
return null;
}
bool IsAmbiguous(string ns, string name)
public override object VisitComposedType(ComposedType composedType, object data)
{
// If the type name conflicts with an inner class/type parameter, we need to fully-qualify it:
if (currentMemberTypes != null && currentMemberTypes.Contains(name))
return true;
// If the type name conflicts with a field/property etc. on the current class, we need to fully-qualify it,
// if we're inside an expression.
if (isWithinTypeReferenceExpression && currentMembers != null) {
MemberReference mr;
if (currentMembers.TryGetValue(name, out mr)) {
// However, in the special case where the member is a field or property with the same type
// as is requested, then we can use the short name (if it's not otherwise ambiguous)
PropertyDefinition prop = mr as PropertyDefinition;
FieldDefinition field = mr as FieldDefinition;
if (!(prop != null && prop.PropertyType.Namespace == ns && prop.PropertyType.Name == name)
&& !(field != null && field.FieldType.Namespace == ns && field.FieldType.Name == name))
return true;
}
}
// If the type is defined in the current namespace,
// then we can use the short name even if we imported type with same name from another namespace.
if (ns == currentNamespace && !string.IsNullOrEmpty(ns))
return false;
return transform.ambiguousTypeNames.Contains(name);
TypeResolveResult rr;
if (composedType.Ancestors.OfType<UsingDeclaration>().Any() || (rr = composedType.Annotation<TypeResolveResult>()) == null)
return base.VisitComposedType(composedType, data);
composedType.ReplaceWith(astBuilder.ConvertType(rr.Type));
return null;
}
}*/
}
}
}

Loading…
Cancel
Save