/// <summary>
        /// Returns a value indicating whether the <see cref="Type"/>specified by <paramref name="typeName"/>
        /// from the reference project is also visible to the dependent project.
        /// </summary>
        /// <param name="typeName">The full name of the <see cref="Type"/>from the reference project.</param>
        /// <returns>The <see cref="CodeMemberShareKind"/> representing whether it is shared and in what way.</returns>
        public CodeMemberShareKind GetTypeShareKind(string typeName)
        {
            CodeMemberKey         key         = CodeMemberKey.CreateTypeKey(typeName);
            SharedCodeDescription description = this.GetSharedCodeDescription(key);

            return(description.ShareKind);
        }
        /// <summary>
        /// Returns the location of the shared assembly containing the
        /// code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">The description of the code element.</param>
        /// <returns>The location of the assembly that contains it or <c>null</c> if it is not in a shared assembly.</returns>
        public string GetSharedAssemblyPath(CodeMemberKey key)
        {
            Debug.Assert(key != null, "key cannot be null");
            ModuleDefinition location = null;

            TypeInfo typeInfo;

            if (TryGetSharedType(key.TypeName, out typeInfo))
            {
                switch (key.KeyKind)
                {
                case CodeMemberKey.CodeMemberKeyKind.TypeKey:
                    location = typeInfo.ModuleDefinition;
                    break;

                case CodeMemberKey.CodeMemberKeyKind.PropertyKey:
                    location = HasProperty(typeInfo, key.MemberName)?.ModuleDefinition;
                    break;

                case CodeMemberKey.CodeMemberKeyKind.MethodKey:
                    var method = FindSharedMethodOrConstructor(typeInfo, key);
                    if (method != null)
                    {
                        location = method.DeclaringType.Module;
                    }
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            return(location?.Assembly.Name.Name);
        }
        /// <summary>
        /// Returns a value indicating whether the a property named <paramref name="propertyName"/>
        /// exposed by the <see cref="Type"/> specified by <paramref name="typeName"/>
        /// from the reference project is also visible to the dependent project.
        /// </summary>
        /// <param name="typeName">The full name of the <see cref="Type"/> from the reference project.</param>
        /// <param name="propertyName">The name of the property.</param>
        /// <returns>The <see cref="CodeMemberShareKind"/> representing whether it is shared and in what way.</returns>
        public CodeMemberShareKind GetPropertyShareKind(string typeName, string propertyName)
        {
            CodeMemberKey         key         = CodeMemberKey.CreatePropertyKey(typeName, propertyName);
            SharedCodeDescription description = this.GetSharedCodeDescription(key);

            return(description.ShareKind);
        }
        /// <summary>
        /// Returns a value indicating whether a method named <paramref name="methodName"/>
        /// exposed by the <see cref="Type"/> specified by <paramref name="typeName"/>
        /// from the reference project is also visible to the dependent project.
        /// </summary>
        /// <param name="typeName">The full name of the <see cref="Type"/> from the reference project.</param>
        /// <param name="methodName">The name of the method.</param>
        /// <param name="parameterTypeNames">The full type names of the method parameters, in the order they must be declared.</param>
        /// <returns>The <see cref="CodeMemberShareKind"/> representing whether it is shared and in what way.</returns>
        public CodeMemberShareKind GetMethodShareKind(string typeName, string methodName, IEnumerable <string> parameterTypeNames)
        {
            CodeMemberKey         key         = CodeMemberKey.CreateMethodKey(typeName, methodName, parameterTypeNames == null ? null : parameterTypeNames.ToArray());
            SharedCodeDescription description = this.GetSharedCodeDescription(key);

            return(description.ShareKind);
        }
        /// <summary>
        /// Locates the <see cref="MethodDefinition"/> in the set of shared assemblies that
        /// corresponds to the method described by <paramref name="key"/>.
        /// </summary>
        /// <param name="sharedType">The <see cref="TypeInfo"/> we have already located in our set of shared assemblies.</param>
        /// <param name="key">The key describing the method to find.</param>
        /// <returns>The matching <see cref="MethodDefinition"/> or <c>null</c> if no match is found.</returns>
        private MethodDefinition FindSharedMethodOrConstructor(TypeInfo sharedType, CodeMemberKey key)
        {
            TypeInfo[] parameterTypes = GetSharedTypes(key.ParameterTypeNames);
            if (parameterTypes == null)
            {
                return(null);
            }
            bool isConstructor = key.IsConstructor;

            do
            {
                foreach (var method in sharedType.TypeDefinition.Methods)
                {
                    // Name matches or it is a constructur we are
                    if (isConstructor ? !method.IsConstructor : !string.Equals(method.Name, key.MemberName, StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    var parameterInfos = method.Parameters;
                    if (parameterInfos.Count != parameterTypes.Length)
                    {
                        continue;
                    }
                    int matchedParameters = 0;
                    for (int i = 0; i < parameterInfos.Count; ++i)
                    {
                        if (string.Equals(parameterInfos[i].ParameterType.FullName, parameterTypes[i].FullName, StringComparison.OrdinalIgnoreCase))
                        {
                            ++matchedParameters;
                        }
                        else
                        {
                            break;
                        }
                    }

                    if (matchedParameters == parameterInfos.Count)
                    {
                        return(method);
                    }
                }

                // Continue searching in base types
            } while (!isConstructor &&
                     (sharedType = GetBaseType(sharedType)) != null);

            return(null);
        }
        /// <summary>
        /// Returns the <see cref="MethodBase"/> of the method or constructor from the
        /// set of shared assemblies, if it exists.
        /// </summary>
        /// <param name="typeName">The fully qualified type name declaring the method.</param>
        /// <param name="methodName">The name of the method</param>
        /// <param name="parameterTypeNames">The fully qualified type names of the method parameters.</param>
        /// <returns>The <see cref="MethodBase"/> if it exists in the shared assemblies, otherwise <c>null</c></returns>
        internal MethodBase GetSharedMethod(string typeName, string methodName, IEnumerable <string> parameterTypeNames)
        {
            Debug.Assert(!string.IsNullOrEmpty(typeName), "typeName cannot be null");
            Debug.Assert(!string.IsNullOrEmpty(methodName), "methodName cannot be null");

            MethodBase sharedMethod = null;
            Type       sharedType   = this.GetSharedType(typeName);

            if (sharedType != null)
            {
                CodeMemberKey key = CodeMemberKey.CreateMethodKey(typeName, methodName, parameterTypeNames == null ? new string[0] : parameterTypeNames.ToArray());
                sharedMethod = this.FindSharedMethodOrConstructor(sharedType, key);
            }

            return(sharedMethod);
        }
        /// <summary>
        /// Gets the <see cref="SharedCodeDescription"/> for the code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">Describes the code member.</param>
        /// <returns>The <see cref="SharedCodeDescription"/> or <c>null</c>.</returns>
        internal SharedCodeDescription GetSharedCodeDescription(CodeMemberKey key)
        {
            return this._cachedDescriptions.GetOrAdd(key, k =>
            {
                string sharedAssemblyLocation = this.SharedAssemblies.GetSharedAssemblyPath(key);
                if (sharedAssemblyLocation != null)
                {
                    return new SharedCodeDescription(CodeMemberShareKind.SharedByReference, new[] { this._filenameMap.AddOrGet(sharedAssemblyLocation) });
                }

                int[] fileIds = this.SharedSourceFiles.GetSharedFileIds(key);
                if (fileIds != null && fileIds.Length != 0)
                {
                    return new SharedCodeDescription(CodeMemberShareKind.SharedBySource, fileIds);
                }

                return new SharedCodeDescription(CodeMemberShareKind.NotShared, null);
            });
        }
        /// <summary>
        /// Gets the <see cref="SharedCodeDescription"/> for the code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">Describes the code member.</param>
        /// <returns>The <see cref="SharedCodeDescription"/> or <c>null</c>.</returns>
        internal SharedCodeDescription GetSharedCodeDescription(CodeMemberKey key)
        {
            return(this._cachedDescriptions.GetOrAdd(key, k =>
            {
                string sharedAssemblyLocation = this._sharedAssemblies.GetSharedAssemblyPath(key);
                if (sharedAssemblyLocation != null)
                {
                    return new SharedCodeDescription(CodeMemberShareKind.SharedByReference, new[] { this._filenameMap.AddOrGet(sharedAssemblyLocation) });
                }

                int[] fileIds = this.SharedSourceFiles.GetSharedFileIds(key);
                if (fileIds != null && fileIds.Length != 0)
                {
                    return new SharedCodeDescription(CodeMemberShareKind.SharedBySource, fileIds);
                }

                return new SharedCodeDescription(CodeMemberShareKind.NotShared, null);
            }));
        }
        /// <summary>
        /// Returns the location of the shared assembly containing the
        /// code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">The description of the code element.</param>
        /// <returns>The location of the assembly that contains it or <c>null</c> if it is not in a shared assembly.</returns>
        internal string GetSharedAssemblyPath(CodeMemberKey key)
        {
            Debug.Assert(key != null, "key cannot be null");
            string location = null;

            Type type = this.GetSharedType(key.TypeName);

            if (type != null)
            {
                switch (key.KeyKind)
                {
                case CodeMemberKey.CodeMemberKeyKind.TypeKey:
                    location = type.Assembly.Location;
                    break;

                case CodeMemberKey.CodeMemberKeyKind.PropertyKey:
                    PropertyInfo propertyInfo = type.GetProperty(key.MemberName);
                    if (propertyInfo != null)
                    {
                        location = propertyInfo.DeclaringType.Assembly.Location;
                    }
                    break;

                case CodeMemberKey.CodeMemberKeyKind.MethodKey:
                    Type[] parameterTypes = this.GetSharedTypes(key.ParameterTypeNames);
                    if (parameterTypes != null)
                    {
                        MethodBase methodBase = this.FindSharedMethodOrConstructor(type, key);
                        if (methodBase != null)
                        {
                            location = methodBase.DeclaringType.Assembly.Location;
                        }
                    }
                    break;

                default:
                    Debug.Fail("unsupported key kind");
                    break;
                }
            }
            return(location);
        }
        /// <summary>
        /// Returns the location of the shared assembly containing the
        /// code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">The description of the code element.</param>
        /// <returns>The location of the assembly that contains it or <c>null</c> if it is not in a shared assembly.</returns>
        internal string GetSharedAssemblyPath(CodeMemberKey key)
        {
            Debug.Assert(key != null, "key cannot be null");
            string location = null;

            Type type = this.GetSharedType(key.TypeName);
            if (type != null)
            {
                switch (key.KeyKind)
                {
                    case CodeMemberKey.CodeMemberKeyKind.TypeKey:
                        location = type.Assembly.Location;
                        break;

                    case CodeMemberKey.CodeMemberKeyKind.PropertyKey:
                        PropertyInfo propertyInfo = type.GetProperty(key.MemberName);
                        if (propertyInfo != null)
                        {
                            location = propertyInfo.DeclaringType.Assembly.Location;
                        }
                        break;

                    case CodeMemberKey.CodeMemberKeyKind.MethodKey:
                        Type[] parameterTypes = this.GetSharedTypes(key.ParameterTypeNames);
                        if (parameterTypes != null)
                        {
                            MethodBase methodBase = this.FindSharedMethodOrConstructor(type, key);
                            if (methodBase != null)
                            {
                                location = methodBase.DeclaringType.Assembly.Location;
                            }
                        }
                        break;

                    default:
                        Debug.Fail("unsupported key kind");
                        break;
                }
            }
            return location;
        }
        /// <summary>
        /// Locates the <see cref="MethodBase"/> in the set of shared assemblies that
        /// corresponds to the method described by <paramref name="key"/>.
        /// </summary>
        /// <param name="sharedType">The <see cref="Type"/> we have already located in our set of shared assemblies.</param>
        /// <param name="key">The key describing the method to find.</param>
        /// <returns>The matching <see cref="MethodBase"/> or <c>null</c> if no match is found.</returns>
        private MethodBase FindSharedMethodOrConstructor(Type sharedType, CodeMemberKey key)
        {
            Type[] parameterTypes = this.GetSharedTypes(key.ParameterTypeNames);
            if (parameterTypes == null)
            {
                return(null);
            }
            bool isConstructor = key.IsConstructor;
            IEnumerable <MethodBase> methods = isConstructor ? sharedType.GetConstructors().Cast <MethodBase>() : sharedType.GetMethods().Cast <MethodBase>();

            foreach (MethodBase method in methods)
            {
                if (!isConstructor && !string.Equals(method.Name, key.MemberName, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                ParameterInfo[] parameterInfos = method.GetParameters();
                if (parameterInfos.Length != parameterTypes.Length)
                {
                    continue;
                }
                int matchedParameters = 0;
                for (int i = 0; i < parameterInfos.Length; ++i)
                {
                    if (string.Equals(parameterInfos[i].ParameterType.FullName, parameterTypes[i].FullName, StringComparison.OrdinalIgnoreCase))
                    {
                        ++matchedParameters;
                    }
                    else
                    {
                        break;
                    }
                }

                if (matchedParameters == parameterInfos.Length)
                {
                    return(method);
                }
            }
            return(null);
        }
Example #12
0
        /// <summary>
        /// Override to provide property equality checks using value-based comparison.
        /// </summary>
        /// <param name="obj">The object to compare against the current instance.</param>
        /// <returns><c>true</c> if the objects are equal.</returns>
        public override bool Equals(object obj)
        {
            CodeMemberKey other = obj as CodeMemberKey;

            if (Object.ReferenceEquals(other, null))
            {
                return(false);
            }
            if (Object.ReferenceEquals(this, other))
            {
                return(true);
            }
            if ((this.KeyKind != other.KeyKind) ||
                !string.Equals(this.TypeName, other.TypeName, StringComparison.Ordinal) ||
                !string.Equals(this.MemberName, other.MemberName, StringComparison.Ordinal))
            {
                return(false);
            }
            int parameterCount      = this.ParameterTypeNames == null ? 0 : this.ParameterTypeNames.Length;
            int otherParameterCount = other.ParameterTypeNames == null ? 0 : other.ParameterTypeNames.Length;

            if (parameterCount != otherParameterCount)
            {
                return(false);
            }

            for (int i = 0; i < parameterCount; ++i)
            {
                if (!string.Equals(this.ParameterTypeNames[i], other.ParameterTypeNames[i], StringComparison.Ordinal))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Gets the collection of internal ID's of the files that collectively
        /// define the code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">The key describing the code member.</param>
        /// <returns>The collection of internal ID's, or <c>null</c> if no shared files exist for this code element.</returns>
        internal int[] GetSharedFileIds(CodeMemberKey key)
        {
            Debug.Assert(key != null, "key cannot be null");

            // Early exit if no shared files were specified
            if (!this._anySharedFiles)
            {
                return null;
            }

            Type type = key.Type;

            // If we don't have the type in this AppDomain, then we don't consider it shared.
            // For the sake of performance, System types are never considered
            // shared from the perspective of source files.   This optimization
            // skips attempts to open PDB's or reflect into system types.
            // We don't even add an entry in the cache for these.
            if (type == null || type.Assembly.IsSystemAssembly())
            {
                return null;
            }

            int[] fileIds = null;

            switch (key.KeyKind)
            {
                case CodeMemberKey.CodeMemberKeyKind.TypeKey:
                    IEnumerable<string> files = this.SourceFileLocationService.GetFilesForType(type);
                    if (files != null && files.Any())
                    {
                        IEnumerable<int> filesAsIds = files.Select<string, int>(s => this.FileNameToSharedID(s)).Distinct();
                        int[] sharedFileIds = filesAsIds.Where(i => i != SharedSourceFiles.NotShared).ToArray();
                        fileIds = sharedFileIds.Length == 0 ? null : sharedFileIds;
                    }

                    break;

                case CodeMemberKey.CodeMemberKeyKind.PropertyKey:
                    PropertyInfo propertyInfo = key.PropertyInfo;
                    if (propertyInfo == null)
                    {
                        return null;
                    }
                    string propertyFile = this.SourceFileLocationService.GetFileForMember(propertyInfo);
                    int sharedPropertyFileId = this.FileNameToSharedID(propertyFile);
                    if (sharedPropertyFileId != SharedSourceFiles.NotShared)
                    {
                        fileIds = new int[] { sharedPropertyFileId };
                    }

                    break;

                case CodeMemberKey.CodeMemberKeyKind.MethodKey:
                    MethodBase methodBase = key.MethodBase;
                    if (methodBase == null)
                    {
                        return null;
                    }
                    string methodFile = this.SourceFileLocationService.GetFileForMember(methodBase);
                    int sharedMethodFileId = this.FileNameToSharedID(methodFile);
                    if (sharedMethodFileId != SharedSourceFiles.NotShared)
                    {
                        fileIds = new int[] { sharedMethodFileId };
                    }
                    break;

                default:
                    Debug.Fail("unsupported key kind");
                    break;
            }
            return fileIds;
        }
Example #14
0
        /// <summary>
        /// Gets the collection of internal ID's of the files that collectively
        /// define the code member described by <paramref name="key"/>.
        /// </summary>
        /// <param name="key">The key describing the code member.</param>
        /// <returns>The collection of internal ID's, or <c>null</c> if no shared files exist for this code element.</returns>
        internal int[] GetSharedFileIds(CodeMemberKey key)
        {
            Debug.Assert(key != null, "key cannot be null");

            // Early exit if no shared files were specified
            if (!this._anySharedFiles)
            {
                return(null);
            }

            Type type = key.Type;

            // If we don't have the type in this AppDomain, then we don't consider it shared.
            // For the sake of performance, System types are never considered
            // shared from the perspective of source files.   This optimization
            // skips attempts to open PDB's or reflect into system types.
            // We don't even add an entry in the cache for these.
            if (type == null || type.Assembly.IsSystemAssembly())
            {
                return(null);
            }

            int[] fileIds = null;

            switch (key.KeyKind)
            {
            case CodeMemberKey.CodeMemberKeyKind.TypeKey:
                IEnumerable <string> files = this.SourceFileLocationService.GetFilesForType(type);
                if (files != null && files.Any())
                {
                    IEnumerable <int> filesAsIds    = files.Select <string, int>(s => this.FileNameToSharedID(s)).Distinct();
                    int[]             sharedFileIds = filesAsIds.Where(i => i != SharedSourceFiles.NotShared).ToArray();
                    fileIds = sharedFileIds.Length == 0 ? null : sharedFileIds;
                }

                break;

            case CodeMemberKey.CodeMemberKeyKind.PropertyKey:
                PropertyInfo propertyInfo = key.PropertyInfo;
                if (propertyInfo == null)
                {
                    return(null);
                }
                string propertyFile         = this.SourceFileLocationService.GetFileForMember(propertyInfo);
                int    sharedPropertyFileId = this.FileNameToSharedID(propertyFile);
                if (sharedPropertyFileId != SharedSourceFiles.NotShared)
                {
                    fileIds = new int[] { sharedPropertyFileId };
                }

                break;

            case CodeMemberKey.CodeMemberKeyKind.MethodKey:
                MethodBase methodBase = key.MethodBase;
                if (methodBase == null)
                {
                    return(null);
                }
                string methodFile         = this.SourceFileLocationService.GetFileForMember(methodBase);
                int    sharedMethodFileId = this.FileNameToSharedID(methodFile);
                if (sharedMethodFileId != SharedSourceFiles.NotShared)
                {
                    fileIds = new int[] { sharedMethodFileId };
                }
                break;

            default:
                Debug.Fail("unsupported key kind");
                break;
            }
            return(fileIds);
        }
Example #15
0
 /// <summary>
 /// Creates a new instance of the <see cref="CodeMemberKey"/> class that describes
 /// a property.
 /// </summary>
 /// <param name="propertyInfo">The <see cref="PropertyInfo"/> of that property.</param>
 /// <returns>A new instance which describes that property.</returns>
 internal static CodeMemberKey CreatePropertyKey(PropertyInfo propertyInfo)
 {
     Debug.Assert(propertyInfo != null, "propertyInfo cannot be null");
     return(CodeMemberKey.CreatePropertyKey(propertyInfo.DeclaringType.AssemblyQualifiedName, propertyInfo.Name));
 }
Example #16
0
 /// <summary>
 /// Creates a new instance of the <see cref="CodeMemberKey"/> class
 /// to describe the a <see cref="Type"/> from the given <paramref name="type"/>.
 /// </summary>
 /// <param name="type">The <see cref="Type"/> from which to construct the key.</param>
 /// <returns>A new instance which describes that type.</returns>
 internal static CodeMemberKey CreateTypeKey(Type type)
 {
     Debug.Assert(type != null, "type cannot be null");
     return(CodeMemberKey.CreateTypeKey(type.AssemblyQualifiedName));
 }
Example #17
0
 /// <summary>
 /// Creates a new instance of the <see cref="CodeMemberKey"/> class that describes
 /// a method or a constructor.
 /// </summary>
 /// <param name="methodBase">The <see cref="MethodBase"/> of the method or constructor.</param>
 /// <returns>A new instance that describes that method.</returns>
 internal static CodeMemberKey CreateMethodKey(MethodBase methodBase)
 {
     Debug.Assert(methodBase != null, "methodBase cannot be null");
     string[] parameterTypes = methodBase.GetParameters().Select <ParameterInfo, string>(p => p.ParameterType.AssemblyQualifiedName).ToArray();
     return(CodeMemberKey.CreateMethodKey(methodBase.DeclaringType.AssemblyQualifiedName, methodBase.Name, parameterTypes));
 }
        /// <summary>
        /// Locates the <see cref="MethodBase"/> in the set of shared assemblies that
        /// corresponds to the method described by <paramref name="key"/>.
        /// </summary>
        /// <param name="sharedType">The <see cref="Type"/> we have already located in our set of shared assemblies.</param>
        /// <param name="key">The key describing the method to find.</param>
        /// <returns>The matching <see cref="MethodBase"/> or <c>null</c> if no match is found.</returns>
        private MethodBase FindSharedMethodOrConstructor(Type sharedType, CodeMemberKey key)
        {
            Type[] parameterTypes = this.GetSharedTypes(key.ParameterTypeNames);
            if (parameterTypes == null)
            {
                return null;
            }
            bool isConstructor = key.IsConstructor;
            IEnumerable<MethodBase> methods = isConstructor ? sharedType.GetConstructors().Cast<MethodBase>() : sharedType.GetMethods().Cast<MethodBase>();
            foreach (MethodBase method in methods)
            {
                if (!isConstructor && !string.Equals(method.Name, key.MemberName, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                ParameterInfo[] parameterInfos = method.GetParameters();
                if (parameterInfos.Length != parameterTypes.Length)
                {
                    continue;
                }
                int matchedParameters = 0;
                for (int i = 0; i < parameterInfos.Length; ++i)
                {
                    if (string.Equals(parameterInfos[i].ParameterType.FullName, parameterTypes[i].FullName, StringComparison.OrdinalIgnoreCase))
                    {
                        ++matchedParameters;
                    }
                    else
                    {
                        break;
                    }
                }

                if (matchedParameters == parameterInfos.Length)
                {
                    return method;
                }
            }
            return null;
        }