// // VariableHidesMemberIssue.cs // // Author: // Mansheng Yang // // Copyright (c) 2012 Mansheng Yang // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System.Collections.Generic; using System.Linq; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; using System; namespace ICSharpCode.NRefactory.CSharp.Refactoring { public abstract class VariableHidesMemberIssue : ICodeIssueProvider { public IEnumerable GetIssues(BaseRefactoringContext context) { return GetGatherVisitor(context).GetIssues(); } protected static bool HidesMember(BaseRefactoringContext ctx, AstNode node, string variableName) { var typeDecl = node.GetParent(); if (typeDecl == null) return false; var entityDecl = node.GetParent(); var memberResolveResult = ctx.Resolve(entityDecl) as MemberResolveResult; if (memberResolveResult == null) return false; var typeResolveResult = ctx.Resolve(typeDecl) as TypeResolveResult; if (typeResolveResult == null) return false; var sourceMember = memberResolveResult.Member; return typeResolveResult.Type.GetMembers(m => m.Name == variableName).Any(m2 => IsAccessible(sourceMember, m2)); } static bool IsAccessible(IMember sourceMember, IMember targetMember) { if (sourceMember.IsStatic != targetMember.IsStatic) return false; var sourceType = sourceMember.DeclaringType; var targetType = targetMember.DeclaringType; switch (targetMember.Accessibility) { case Accessibility.None: return false; case Accessibility.Private: // check for members of outer classes (private members of outer classes can be accessed) var targetTypeDefinition = targetType.GetDefinition(); for (var t = sourceType.GetDefinition(); t != null; t = t.DeclaringTypeDefinition) { if (t.Equals(targetTypeDefinition)) return true; } return false; case Accessibility.Public: return true; case Accessibility.Protected: return IsProtectedAccessible(sourceType, targetType); case Accessibility.Internal: return IsInternalAccessible(sourceMember.ParentAssembly, targetMember.ParentAssembly); case Accessibility.ProtectedOrInternal: return IsInternalAccessible(sourceMember.ParentAssembly, targetMember.ParentAssembly) || IsProtectedAccessible(sourceType, targetType); case Accessibility.ProtectedAndInternal: return IsInternalAccessible(sourceMember.ParentAssembly, targetMember.ParentAssembly) && IsProtectedAccessible(sourceType, targetType); default: throw new Exception("Invalid value for Accessibility"); } } static bool IsProtectedAccessible(IType sourceType, IType targetType) { return sourceType.GetAllBaseTypes().Any(type => targetType.Equals(type)); } static bool IsInternalAccessible(IAssembly sourceAssembly, IAssembly targetAssembly) { return sourceAssembly.InternalsVisibleTo(targetAssembly); } internal abstract GatherVisitorBase GetGatherVisitor(BaseRefactoringContext context); } }