コード例 #1
0
ファイル: FlowAnnotations.cs プロジェクト: pranavkm/linker
 void LogValidationWarning(IMetadataTokenProvider provider, IMetadataTokenProvider baseProvider, IMemberDefinition origin)
 {
     _context.LogWarning(
         $"DynamicallyAccessedMemberTypes in DynamicallyAccessedMembersAttribute on {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (provider)} " +
         $"don't match overridden {DiagnosticUtilities.GetMetadataTokenDescriptionForErrorMessage (baseProvider)}. " +
         $"All overridden members must have the same DynamicallyAccessedMembersAttribute usage.",
         2047,
         origin);
 }
コード例 #2
0
 void ValidateMethodParametersHaveNoAnnotations(ref MethodAnnotations methodAnnotations, MethodDefinition method, MethodDefinition baseMethod, IMemberDefinition origin)
 {
     for (int parameterIndex = 0; parameterIndex < methodAnnotations.ParameterAnnotations.Length; parameterIndex++)
     {
         var annotation = methodAnnotations.ParameterAnnotations[parameterIndex];
         if (annotation != DynamicallyAccessedMemberTypes.None)
         {
             LogValidationWarning(
                 DiagnosticUtilities.GetMethodParameterFromIndex(method, parameterIndex),
                 DiagnosticUtilities.GetMethodParameterFromIndex(baseMethod, parameterIndex),
                 origin);
         }
     }
 }
コード例 #3
0
        void LogValidationWarning(IMetadataTokenProvider provider, IMetadataTokenProvider baseProvider, IMemberDefinition origin)
        {
            Debug.Assert(provider.GetType() == baseProvider.GetType());
            Debug.Assert(!(provider is GenericParameter genericParameter) || genericParameter.DeclaringMethod != null);
            switch (provider)
            {
            case ParameterDefinition parameterDefinition:
                var baseParameterDefinition = (ParameterDefinition)baseProvider;
                _context.LogWarning(
                    $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (parameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (parameterDefinition.Method)}' " +
                    $"don't match overridden parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (baseParameterDefinition)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (baseParameterDefinition.Method)}'. " +
                    $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
                    2092, origin, subcategory: MessageSubCategory.TrimAnalysis);
                break;

            case MethodReturnType methodReturnType:
                _context.LogWarning(
                    $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodReturnType.Method)}' " +
                    $"don't match overridden return value of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (((MethodReturnType) baseProvider).Method)}'. " +
                    $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
                    2093, origin, subcategory: MessageSubCategory.TrimAnalysis);
                break;

            // No fields - it's not possible to have a virtual field and override it
            case MethodDefinition methodDefinition:
                _context.LogWarning(
                    $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodDefinition)}' " +
                    $"don't match overridden implicit 'this' parameter of method '{DiagnosticUtilities.GetMethodSignatureDisplayName ((MethodDefinition) baseProvider)}'. " +
                    $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
                    2094, origin, subcategory: MessageSubCategory.TrimAnalysis);
                break;

            case GenericParameter genericParameterOverride:
                var genericParameterBase = (GenericParameter)baseProvider;
                _context.LogWarning(
                    $"'DynamicallyAccessedMemberTypes' in 'DynamicallyAccessedMembersAttribute' on the generic parameter '{genericParameterOverride.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterOverride)}' " +
                    $"don't match overridden generic parameter '{genericParameterBase.Name}' of '{DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName (genericParameterBase)}'. " +
                    $"All overridden members must have the same 'DynamicallyAccessedMembersAttribute' usage.",
                    2095, origin, subcategory: MessageSubCategory.TrimAnalysis);
                break;

            default:
                throw new NotImplementedException($"Unsupported provider type{provider.GetType ()}");
            }
        }
コード例 #4
0
        internal void ValidateMethodAnnotationsAreSame(MethodDefinition method, MethodDefinition baseMethod)
        {
            GetAnnotations(method.DeclaringType).TryGetAnnotation(method, out var methodAnnotations);
            GetAnnotations(baseMethod.DeclaringType).TryGetAnnotation(baseMethod, out var baseMethodAnnotations);

            if (methodAnnotations.ReturnParameterAnnotation != baseMethodAnnotations.ReturnParameterAnnotation)
            {
                LogValidationWarning(method.MethodReturnType, baseMethod.MethodReturnType, method);
            }

            if (methodAnnotations.ParameterAnnotations != null || baseMethodAnnotations.ParameterAnnotations != null)
            {
                if (methodAnnotations.ParameterAnnotations == null)
                {
                    ValidateMethodParametersHaveNoAnnotations(ref baseMethodAnnotations, method, baseMethod, method);
                }
                else if (baseMethodAnnotations.ParameterAnnotations == null)
                {
                    ValidateMethodParametersHaveNoAnnotations(ref methodAnnotations, method, baseMethod, method);
                }
                else
                {
                    if (methodAnnotations.ParameterAnnotations.Length != baseMethodAnnotations.ParameterAnnotations.Length)
                    {
                        return;
                    }

                    for (int parameterIndex = 0; parameterIndex < methodAnnotations.ParameterAnnotations.Length; parameterIndex++)
                    {
                        if (methodAnnotations.ParameterAnnotations[parameterIndex] != baseMethodAnnotations.ParameterAnnotations[parameterIndex])
                        {
                            LogValidationWarning(
                                DiagnosticUtilities.GetMethodParameterFromIndex(method, parameterIndex),
                                DiagnosticUtilities.GetMethodParameterFromIndex(baseMethod, parameterIndex),
                                method);
                        }
                    }
                }
            }

            if (methodAnnotations.GenericParameterAnnotations != null || baseMethodAnnotations.GenericParameterAnnotations != null)
            {
                if (methodAnnotations.GenericParameterAnnotations == null)
                {
                    ValidateMethodGenericParametersHaveNoAnnotations(ref baseMethodAnnotations, method, baseMethod, method);
                }
                else if (baseMethodAnnotations.GenericParameterAnnotations == null)
                {
                    ValidateMethodGenericParametersHaveNoAnnotations(ref methodAnnotations, method, baseMethod, method);
                }
                else
                {
                    if (methodAnnotations.GenericParameterAnnotations.Length != baseMethodAnnotations.GenericParameterAnnotations.Length)
                    {
                        return;
                    }

                    for (int genericParameterIndex = 0; genericParameterIndex < methodAnnotations.GenericParameterAnnotations.Length; genericParameterIndex++)
                    {
                        if (methodAnnotations.GenericParameterAnnotations[genericParameterIndex] != baseMethodAnnotations.GenericParameterAnnotations[genericParameterIndex])
                        {
                            LogValidationWarning(
                                method.GenericParameters[genericParameterIndex],
                                baseMethod.GenericParameters[genericParameterIndex],
                                method);
                        }
                    }
                }
            }
        }
コード例 #5
0
        TypeAnnotations BuildTypeAnnotations(TypeDefinition type)
        {
            var annotatedFields = new ArrayBuilder <FieldAnnotation> ();

            // First go over all fields with an explicit annotation
            if (type.HasFields)
            {
                foreach (FieldDefinition field in type.Fields)
                {
                    DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(field);
                    if (annotation == DynamicallyAccessedMemberTypes.None)
                    {
                        continue;
                    }

                    if (!IsTypeInterestingForDataflow(field.FieldType))
                    {
                        // Already know that there's a non-empty annotation on a field which is not System.Type/String and we're about to ignore it
                        _context.LogWarning(
                            $"Field '{field.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to fields of type 'System.Type' or 'System.String'",
                            2097, field, subcategory: MessageSubCategory.TrimAnalysis);
                        continue;
                    }

                    annotatedFields.Add(new FieldAnnotation(field, annotation));
                }
            }

            var annotatedMethods = new ArrayBuilder <MethodAnnotations> ();

            // Next go over all methods with an explicit annotation
            if (type.HasMethods)
            {
                foreach (MethodDefinition method in type.Methods)
                {
                    DynamicallyAccessedMemberTypes[] paramAnnotations = null;

                    // We convert indices from metadata space to IL space here.
                    // IL space assigns index 0 to the `this` parameter on instance methods.


                    DynamicallyAccessedMemberTypes methodMemberTypes = GetMemberTypesForDynamicallyAccessedMembersAttribute(method);

                    int offset;
                    if (method.HasImplicitThis())
                    {
                        offset = 1;
                        if (IsTypeInterestingForDataflow(method.DeclaringType))
                        {
                            // If there's an annotation on the method itself and it's one of the special types (System.Type for example)
                            // treat that annotation as annotating the "this" parameter.
                            if (methodMemberTypes != DynamicallyAccessedMemberTypes.None)
                            {
                                paramAnnotations    = new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset];
                                paramAnnotations[0] = methodMemberTypes;
                            }
                        }
                        else if (methodMemberTypes != DynamicallyAccessedMemberTypes.None)
                        {
                            _context.LogWarning(
                                $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.",
                                2041, method, subcategory: MessageSubCategory.TrimAnalysis);
                        }
                    }
                    else
                    {
                        offset = 0;
                        if (methodMemberTypes != DynamicallyAccessedMemberTypes.None)
                        {
                            _context.LogWarning(
                                $"The 'DynamicallyAccessedMembersAttribute' is not allowed on methods. It is allowed on method return value or method parameters though.",
                                2041, method, subcategory: MessageSubCategory.TrimAnalysis);
                        }
                    }

                    for (int i = 0; i < method.Parameters.Count; i++)
                    {
                        var methodParameter = method.Parameters[i];
                        DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute(methodParameter, method);
                        if (pa == DynamicallyAccessedMemberTypes.None)
                        {
                            continue;
                        }

                        if (!IsTypeInterestingForDataflow(methodParameter.ParameterType))
                        {
                            _context.LogWarning(
                                $"Parameter '{DiagnosticUtilities.GetParameterNameForErrorMessage (methodParameter)}' of method '{DiagnosticUtilities.GetMethodSignatureDisplayName (methodParameter.Method)}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to parameters of type 'System.Type' or 'System.String'",
                                2098, method, subcategory: MessageSubCategory.TrimAnalysis);
                            continue;
                        }

                        if (paramAnnotations == null)
                        {
                            paramAnnotations = new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset];
                        }
                        paramAnnotations[i + offset] = pa;
                    }

                    DynamicallyAccessedMemberTypes returnAnnotation = IsTypeInterestingForDataflow(method.ReturnType) ?
                                                                      GetMemberTypesForDynamicallyAccessedMembersAttribute(method.MethodReturnType, method) : DynamicallyAccessedMemberTypes.None;

                    DynamicallyAccessedMemberTypes[] genericParameterAnnotations = null;
                    if (method.HasGenericParameters)
                    {
                        for (int genericParameterIndex = 0; genericParameterIndex < method.GenericParameters.Count; genericParameterIndex++)
                        {
                            var genericParameter = method.GenericParameters[genericParameterIndex];
                            var annotation       = GetMemberTypesForDynamicallyAccessedMembersAttribute(genericParameter, method);
                            if (annotation != DynamicallyAccessedMemberTypes.None)
                            {
                                if (genericParameterAnnotations == null)
                                {
                                    genericParameterAnnotations = new DynamicallyAccessedMemberTypes[method.GenericParameters.Count];
                                }
                                genericParameterAnnotations[genericParameterIndex] = annotation;
                            }
                        }
                    }

                    if (returnAnnotation != DynamicallyAccessedMemberTypes.None || paramAnnotations != null || genericParameterAnnotations != null)
                    {
                        annotatedMethods.Add(new MethodAnnotations(method, paramAnnotations, returnAnnotation, genericParameterAnnotations));
                    }
                }
            }

            // Next up are properties. Annotations on properties are kind of meta because we need to
            // map them to annotations on methods/fields. They're syntactic sugar - what they do is expressible
            // by placing attribute on the accessor/backing field. For complex properties, that's what people
            // will need to do anyway. Like so:
            //
            // [field: Attribute]
            // Type MyProperty {
            //     [return: Attribute]
            //     get;
            //     [value: Attribute]
            //     set;
            //  }
            //

            if (type.HasProperties)
            {
                foreach (PropertyDefinition property in type.Properties)
                {
                    DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute(property);
                    if (annotation == DynamicallyAccessedMemberTypes.None)
                    {
                        continue;
                    }

                    if (!IsTypeInterestingForDataflow(property.PropertyType))
                    {
                        _context.LogWarning(
                            $"Property '{property.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'",
                            2099, property, subcategory: MessageSubCategory.TrimAnalysis);
                        continue;
                    }

                    FieldDefinition backingFieldFromSetter = null;

                    // Propagate the annotation to the setter method
                    MethodDefinition setMethod = property.SetMethod;
                    if (setMethod != null)
                    {
                        // Abstract property backing field propagation doesn't make sense, and any derived property will be validated
                        // to have the exact same annotations on getter/setter, and thus if it has a detectable backing field that will be validated as well.
                        if (setMethod.HasBody)
                        {
                            // Look for the compiler generated backing field. If it doesn't work out simply move on. In such case we would still
                            // propagate the annotation to the setter/getter and later on when analyzing the setter/getter we will warn
                            // that the field (which ever it is) must be annotated as well.
                            ScanMethodBodyForFieldAccess(setMethod.Body, write: true, out backingFieldFromSetter);
                        }

                        if (annotatedMethods.Any(a => a.Method == setMethod))
                        {
                            _context.LogWarning(
                                $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{setMethod.GetDisplayName ()}'.",
                                2043, setMethod, subcategory: MessageSubCategory.TrimAnalysis);
                        }
                        else
                        {
                            int offset = setMethod.HasImplicitThis() ? 1 : 0;
                            if (setMethod.Parameters.Count > 0)
                            {
                                DynamicallyAccessedMemberTypes[] paramAnnotations = new DynamicallyAccessedMemberTypes[setMethod.Parameters.Count + offset];
                                paramAnnotations[offset] = annotation;
                                annotatedMethods.Add(new MethodAnnotations(setMethod, paramAnnotations, DynamicallyAccessedMemberTypes.None, null));
                            }
                        }
                    }

                    FieldDefinition backingFieldFromGetter = null;

                    // Propagate the annotation to the getter method
                    MethodDefinition getMethod = property.GetMethod;
                    if (getMethod != null)
                    {
                        // Abstract property backing field propagation doesn't make sense, and any derived property will be validated
                        // to have the exact same annotations on getter/setter, and thus if it has a detectable backing field that will be validated as well.
                        if (getMethod.HasBody)
                        {
                            // Look for the compiler generated backing field. If it doesn't work out simply move on. In such case we would still
                            // propagate the annotation to the setter/getter and later on when analyzing the setter/getter we will warn
                            // that the field (which ever it is) must be annotated as well.
                            ScanMethodBodyForFieldAccess(getMethod.Body, write: false, out backingFieldFromGetter);
                        }

                        if (annotatedMethods.Any(a => a.Method == getMethod))
                        {
                            _context.LogWarning(
                                $"'DynamicallyAccessedMembersAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its accessor '{getMethod.GetDisplayName ()}'.",
                                2043, getMethod, subcategory: MessageSubCategory.TrimAnalysis);
                        }
                        else
                        {
                            annotatedMethods.Add(new MethodAnnotations(getMethod, null, annotation, null));
                        }
                    }

                    FieldDefinition backingField;
                    if (backingFieldFromGetter != null && backingFieldFromSetter != null &&
                        backingFieldFromGetter != backingFieldFromSetter)
                    {
                        _context.LogWarning(
                            $"Could not find a unique backing field for property '{property.GetDisplayName ()}' to propagate 'DynamicallyAccessedMembersAttribute'.",
                            2042, property, subcategory: MessageSubCategory.TrimAnalysis);
                        backingField = null;
                    }
                    else
                    {
                        backingField = backingFieldFromGetter ?? backingFieldFromSetter;
                    }

                    if (backingField != null)
                    {
                        if (annotatedFields.Any(a => a.Field == backingField))
                        {
                            _context.LogWarning(
                                $"'DynamicallyAccessedMemberAttribute' on property '{property.GetDisplayName ()}' conflicts with the same attribute on its backing field '{backingField.GetDisplayName ()}'.",
                                2056, backingField, subcategory: MessageSubCategory.TrimAnalysis);
                        }
                        else
                        {
                            annotatedFields.Add(new FieldAnnotation(backingField, annotation));
                        }
                    }
                }
            }

            DynamicallyAccessedMemberTypes[] typeGenericParameterAnnotations = null;
            if (type.HasGenericParameters)
            {
                for (int genericParameterIndex = 0; genericParameterIndex < type.GenericParameters.Count; genericParameterIndex++)
                {
                    var genericParameter = type.GenericParameters[genericParameterIndex];
                    var annotation       = GetMemberTypesForDynamicallyAccessedMembersAttribute(genericParameter, type);
                    if (annotation != DynamicallyAccessedMemberTypes.None)
                    {
                        if (typeGenericParameterAnnotations == null)
                        {
                            typeGenericParameterAnnotations = new DynamicallyAccessedMemberTypes[type.GenericParameters.Count];
                        }
                        typeGenericParameterAnnotations[genericParameterIndex] = annotation;
                    }
                }
            }

            return(new TypeAnnotations(type, annotatedMethods.ToArray(), annotatedFields.ToArray(), typeGenericParameterAnnotations));
        }