internal TypeSymbol GetTypeSymbol(MetadataHelpers.AssemblyQualifiedTypeName fullName, out bool refersToNoPiaLocalType) { // // Section 23.3 (Custom Attributes) of CLI Spec Partition II: // // If the parameter kind is System.Type, (also, the middle line in above diagram) its value is // stored as a SerString (as defined in the previous paragraph), representing its canonical name. // The canonical name is its full type name, followed optionally by the assembly where it is defined, // its version, culture and public-key-token. If the assembly name is omitted, the CLI looks first // in the current assembly, and then in the system library (mscorlib); in these two special cases, // it is permitted to omit the assembly-name, version, culture and public-key-token. int referencedAssemblyIndex; if (fullName.AssemblyName != null) { AssemblyIdentity identity; if (!AssemblyIdentity.TryParseDisplayName(fullName.AssemblyName, out identity)) { refersToNoPiaLocalType = false; return(GetUnsupportedMetadataTypeSymbol()); } // the assembly name has to be a full name: referencedAssemblyIndex = GetIndexOfReferencedAssembly(identity); if (referencedAssemblyIndex == -1) { // In rare cases (e.g. assemblies emitted by Reflection.Emit) the identity // might be the identity of the containing assembly. The metadata spec doesn't disallow this. if (!this.IsContainingAssembly(identity)) { refersToNoPiaLocalType = false; return(GetUnsupportedMetadataTypeSymbol()); } } } else { // Use this assembly referencedAssemblyIndex = -1; } // Find the top level type Debug.Assert(MetadataHelpers.IsValidMetadataIdentifier(fullName.TopLevelType)); var mdName = MetadataTypeName.FromFullName(fullName.TopLevelType); TypeSymbol container = LookupTopLevelTypeDefSymbol(ref mdName, referencedAssemblyIndex, out refersToNoPiaLocalType); // Process any nested types if (fullName.NestedTypes != null) { if (refersToNoPiaLocalType) { // Types nested into local types are not supported. refersToNoPiaLocalType = false; return(GetUnsupportedMetadataTypeSymbol()); } for (int i = 0; i < fullName.NestedTypes.Length; i++) { Debug.Assert(MetadataHelpers.IsValidMetadataIdentifier(fullName.NestedTypes[i])); mdName = MetadataTypeName.FromTypeName(fullName.NestedTypes[i]); // Find nested type in the container container = LookupNestedTypeDefSymbol(container, ref mdName); } } // Substitute type arguments if any if (fullName.TypeArguments != null) { ImmutableArray <bool> argumentRefersToNoPiaLocalType; var typeArguments = ResolveTypeArguments(fullName.TypeArguments, out argumentRefersToNoPiaLocalType); container = SubstituteTypeParameters(container, typeArguments, argumentRefersToNoPiaLocalType); foreach (bool flag in argumentRefersToNoPiaLocalType) { if (flag) { refersToNoPiaLocalType = true; break; } } } else { container = SubstituteWithUnboundIfGeneric(container); } for (int i = 0; i < fullName.PointerCount; i++) { container = MakePointerTypeSymbol(container, ImmutableArray <ModifierInfo <TypeSymbol> > .Empty); } // Process any array type ranks if (fullName.ArrayRanks != null) { foreach (int rank in fullName.ArrayRanks) { Debug.Assert(rank == 0); container = GetSZArrayTypeSymbol(container, default(ImmutableArray <ModifierInfo <TypeSymbol> >)); } } return(container); }
protected abstract bool IsContainingAssembly(AssemblyIdentity identity);
/// <summary> /// Given that an assembly with identity assemblyGrantingAccessIdentity granted access to assemblyWantingAccess, /// check the public keys to ensure the internals-visible-to check should succeed. This is used by both the /// C# and VB implementations as a helper to implement `bool IAssemblySymbol.GivesAccessTo(IAssemblySymbol toAssembly)`. /// </summary> internal static IVTConclusion PerformIVTCheck( this AssemblyIdentity assemblyGrantingAccessIdentity, ImmutableArray <byte> assemblyWantingAccessKey, ImmutableArray <byte> grantedToPublicKey) { // This gets a bit complicated. Let's break it down. // // First off, let's assume that the "other" assembly is GrantingAssembly.DLL, that the "this" // assembly is "WantingAssembly.DLL", and that GrantingAssembly has named WantingAssembly as a friend (that is a precondition // to calling this method). Whether we allow WantingAssembly to see internals of GrantingAssembly depends on these four factors: // // q1) Is GrantingAssembly strong-named? // q2) Did GrantingAssembly name WantingAssembly as a friend via a strong name? // q3) Is WantingAssembly strong-named? // q4) Does GrantingAssembly give a strong-name for WantingAssembly that matches our strong name? // // Before we dive into the details, we should mention two additional facts: // // * If the answer to q1 is "yes", and GrantingAssembly was compiled by a Roslyn compiler, then q2 must be "yes" also. // Strong-named GrantingAssembly must only be friends with strong-named WantingAssembly. See the blog article // http://blogs.msdn.com/b/ericlippert/archive/2009/06/04/alas-smith-and-jones.aspx // for an explanation of why this feature is desirable. // // Now, just because the compiler enforces this rule does not mean that we will never run into // a scenario where GrantingAssembly is strong-named and names WantingAssembly via a weak name. Not all assemblies // were compiled with a Roslyn compiler. We still need to deal sensibly with this situation. // We do so by ignoring the problem; if strong-named GrantingAssembly extends friendship to weak-named // WantingAssembly then we're done; any assembly named WantingAssembly is a friend of GrantingAssembly. // // Incidentally, the C# compiler produces error CS1726, ERR_FriendAssemblySNReq, and VB produces // the error VB31535, ERR_FriendAssemblyStrongNameRequired, when compiling // a strong-named GrantingAssembly that names a weak-named WantingAssembly as its friend. // // * If the answer to q1 is "no" and the answer to q3 is "yes" then we are in a situation where // strong-named WantingAssembly is referencing weak-named GrantingAssembly, which is illegal. In the dev10 compiler // we do not give an error about this until emit time. In Roslyn we have a new error, CS7029, // which we give before emit time when we detect that weak-named GrantingAssembly has given friend access // to strong-named WantingAssembly, which then references GrantingAssembly. However, we still want to give friend // access to WantingAssembly for the purposes of semantic analysis. // // Roslyn C# does not yet give an error in other circumstances whereby a strong-named assembly // references a weak-named assembly. See https://github.com/dotnet/roslyn/issues/26722 // // Let's make a chart that illustrates all the possible answers to these four questions, and // what the resulting accessibility should be: // // case q1 q2 q3 q4 Result Explanation // 1 YES YES YES YES SUCCESS GrantingAssembly has named this strong-named WantingAssembly as a friend. // 2 YES YES YES NO NO MATCH GrantingAssembly has named a different strong-named WantingAssembly as a friend. // 3 YES YES NO NO NO MATCH GrantingAssembly has named a strong-named WantingAssembly as a friend, but this WantingAssembly is weak-named. // 4 YES NO YES NO SUCCESS GrantingAssembly has improperly (*) named any WantingAssembly as its friend. But we honor its offer of friendship. // 5 YES NO NO NO SUCCESS GrantingAssembly has improperly (*) named any WantingAssembly as its friend. But we honor its offer of friendship. // 6 NO YES YES YES SUCCESS, BAD REF GrantingAssembly has named this strong-named WantingAssembly as a friend, but WantingAssembly should not be referring to a weak-named GrantingAssembly. // 7 NO YES YES NO NO MATCH GrantingAssembly has named a different strong-named WantingAssembly as a friend. // 8 NO YES NO NO NO MATCH GrantingAssembly has named a strong-named WantingAssembly as a friend, but this WantingAssembly is weak-named. // 9 NO NO YES NO SUCCESS, BAD REF GrantingAssembly has named any WantingAssembly as a friend, but WantingAssembly should not be referring to a weak-named GrantingAssembly. // 10 NO NO NO NO SUCCESS GrantingAssembly has named any WantingAssembly as its friend. // // (*) GrantingAssembly was not built with a Roslyn compiler, which would have prevented this. // // This method never returns NoRelationshipClaimed because if control got here, then we assume // (as a precondition) that GrantingAssembly named WantingAssembly as a friend somehow. bool q1 = assemblyGrantingAccessIdentity.IsStrongName; bool q2 = !grantedToPublicKey.IsDefaultOrEmpty; bool q3 = !assemblyWantingAccessKey.IsDefaultOrEmpty; bool q4 = (q2 & q3) && ByteSequenceComparer.Equals(grantedToPublicKey, assemblyWantingAccessKey); // Cases 2, 3, 7 and 8: if (q2 && !q4) { return(IVTConclusion.PublicKeyDoesntMatch); } // Cases 6 and 9: if (!q1 && q3) { return(IVTConclusion.OneSignedOneNot); } // Cases 1, 4, 5 and 10: return(IVTConclusion.Match); }
internal override bool ApplyUnificationPolicies( ref AssemblyIdentity reference, ref AssemblyIdentity definition, AssemblyIdentityParts referenceParts, out bool isDefinitionFxAssembly) { if (reference.ContentType == AssemblyContentType.Default && SimpleNameComparer.Equals(reference.Name, definition.Name) && SimpleNameComparer.Equals(reference.Name, "mscorlib")) { isDefinitionFxAssembly = true; reference = definition; return(true); } if (!reference.IsRetargetable && definition.IsRetargetable) { // Reference is not retargetable, but definition is retargetable. // Non-equivalent. isDefinitionFxAssembly = false; return(false); } // Notes: // an assembly might be both retargetable and portable // in that case retargetable table acts as an override. // Apply portability policy transforms first (e.g. rewrites references to SL assemblies to their desktop equivalents) // If the reference is partial and is missing version or PKT it is not ported. reference = Port(reference); definition = Port(definition); if (reference.IsRetargetable && !definition.IsRetargetable) { if (!AssemblyIdentity.IsFullName(referenceParts)) { isDefinitionFxAssembly = false; return(false); } // Reference needs to be retargeted before comparison, // unless it's optionally retargetable and we already match the PK bool skipRetargeting = IsOptionallyRetargetableAssembly(reference) && AssemblyIdentity.KeysEqual(reference, definition); if (!skipRetargeting) { reference = Retarget(reference); } } // At this point we are in one of the following states: // // 1) Both ref/def are not retargetable // 2) Both ref/def are retargetable // 3) Ref is retargetable (and has been retargeted) // // We can do a straight compare of ref/def at this point using the // regular rules if (reference.IsRetargetable && definition.IsRetargetable) { isDefinitionFxAssembly = IsRetargetableAssembly(definition); } else { isDefinitionFxAssembly = IsFrameworkAssembly(definition); } return(true); }
/// <summary> /// Resolves a missing assembly reference. /// </summary> /// <param name="definition">The metadata definition (assembly or module) that declares assembly reference <paramref name="referenceIdentity"/> in its list of dependencies.</param> /// <param name="referenceIdentity">Identity of the assembly reference that couldn't be resolved against metadata references explicitly specified to in the compilation.</param> /// <returns>Resolved reference or null if the identity can't be resolved.</returns> public virtual PortableExecutableReference ResolveMissingAssembly(MetadataReference definition, AssemblyIdentity referenceIdentity) => null;
// Windows[.winmd] internal static bool IsWindowsRuntime(this AssemblyIdentity identity) { return((identity.ContentType == AssemblyContentType.WindowsRuntime) && string.Equals(identity.Name, "windows", StringComparison.OrdinalIgnoreCase)); }
// Windows.*[.winmd] internal static bool IsWindowsComponent(this AssemblyIdentity identity) { return((identity.ContentType == AssemblyContentType.WindowsRuntime) && identity.Name.StartsWith("windows.", StringComparison.OrdinalIgnoreCase)); }