Пример #1
0
        private void LookForPropertyIdentifierReassignment(SyntaxNodeAnalysisContext context)
        {
            var assignment = context.Node as AssignmentExpressionSyntax;

            if (assignment == null)
            {
                return;
            }

            var targetName = assignment.Left as IdentifierNameSyntax;

            if (targetName == null)
            {
                return;
            }

            var assignmentTargetAsParameter = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol as IParameterSymbol;

            if ((assignmentTargetAsParameter == null) || !CommonAnalyser.HasPropertyIdentifierAttribute(assignmentTargetAsParameter))
            {
                return;
            }

            context.ReportDiagnostic(Diagnostic.Create(
                                         NoReassignmentRule,
                                         assignment.Left.GetLocation()
                                         ));
        }
Пример #2
0
        private void LookForIllegalPropertyAttributeIdentifierSpecification(SyntaxNodeAnalysisContext context)
        {
            var invocation = context.Node as InvocationExpressionSyntax;

            if (invocation == null)
            {
                return;
            }

            IEnumerable <IParameterSymbol> parameters;
            var delegateParameter = context.SemanticModel.GetSymbolInfo(invocation.Expression).Symbol as IParameterSymbol;

            if (delegateParameter != null)
            {
                var delegateType = delegateParameter.Type as INamedTypeSymbol;
                if ((delegateType != null) && (delegateType.TypeKind == TypeKind.Delegate) && (delegateType.DelegateInvokeMethod != null))
                {
                    parameters = delegateType.DelegateInvokeMethod.Parameters;
                }
                else
                {
                    return;                     // We can't analyse this delegate call if we can't get the parameter data
                }
            }
            else
            {
                var method = context.SemanticModel.GetSymbolInfo(invocation.Expression).Symbol as IMethodSymbol;
                if (method == null)
                {
                    return;
                }

                parameters = method.Parameters;
            }

            // Note: If the target method is an extension method then GetSymbolInfo does something clever based upon how it's called. If, for example, the extension method has two
            // arguments - the "this" argument and a second one - and the method is called as an extension method then the "method" instance here will have a single parameter
            // (because it only requires a single parameter to be provided since the first is provided by the reference that the extension method is being called on). However, if
            // the same extension method is called as a regular static method then the "method" instance here will list two parameters. So the number of argument values and the
            // number of expected method parameters will be consistent for the same extension method, even though it will appear to have one less parameter when called one way
            // rather than the other. One way that the argument values and the number of parameters MAY appear inconsistent, though, is if the method has parameters with default
            // values - in this case, there may be fewer argument values than there are parameters (meaning the last parameters are satisfied with their defaults). This means that
            // we need to be sure to only look at the provided argument values and to ignore any method parameters that are left to their defaults (default values have to be compile
            // time constants and so, for delegates, these will have to null - so it won't be possible for a method parameter to have an invalid default value other than null, so
            // we only need to worry about validating the actual argument values).
            var invocationArgumentDetails = parameters
                                            .Take(invocation.ArgumentList.Arguments.Count) // Only consider argument values that are specified (ignore any parameters that are taking default values)
                                            .Select((p, i) => new
            {
                Index     = i,
                Parameter = p,
                HasPropertyIdentifierAttribute = CommonAnalyser.HasPropertyIdentifierAttribute(p)
            });

            // Look for argument values passed to methods where the method argument is identified as [PropertyIdentifier] - we need to ensure that these meet the usual With / CtorSet / GetProperty criteria
            foreach (var propertyIdentifierArgumentDetails in invocationArgumentDetails.Where(a => a.HasPropertyIdentifierAttribute))
            {
                var argumentValue            = invocation.ArgumentList.Arguments[propertyIdentifierArgumentDetails.Index];
                var parameterTypeNamedSymbol = propertyIdentifierArgumentDetails.Parameter.Type as INamedTypeSymbol;
                if ((parameterTypeNamedSymbol == null) ||
                    (parameterTypeNamedSymbol.DelegateInvokeMethod == null) ||
                    (parameterTypeNamedSymbol.DelegateInvokeMethod.ReturnsVoid))
                {
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 ArgumentMustBeTwoArgumentDelegateRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;
                }

                IPropertySymbol propertyIfSuccessfullyRetrieved;
                switch (CommonAnalyser.GetPropertyRetrieverArgumentStatus(argumentValue, context, propertyValueTypeIfKnown: parameterTypeNamedSymbol.DelegateInvokeMethod.ReturnType, allowReadOnlyProperties: false, propertyIfSuccessfullyRetrieved: out propertyIfSuccessfullyRetrieved))
                {
                case CommonAnalyser.PropertyValidationResult.Ok:
                case CommonAnalyser.PropertyValidationResult.UnableToConfirmOrDeny:
                    continue;

                case CommonAnalyser.PropertyValidationResult.IndirectTargetAccess:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 IndirectTargetAccessorAccessRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;

                case CommonAnalyser.PropertyValidationResult.NotSimpleLambdaExpression:
                case CommonAnalyser.PropertyValidationResult.LambdaDoesNotTargetProperty:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 SimplePropertyAccessorArgumentAccessRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;

                case CommonAnalyser.PropertyValidationResult.MissingGetter:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 SimplePropertyAccessorArgumentAccessRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;

                case CommonAnalyser.PropertyValidationResult.GetterHasBridgeAttributes:
                case CommonAnalyser.PropertyValidationResult.SetterHasBridgeAttributes:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 BridgeAttributeAccessRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;

                case CommonAnalyser.PropertyValidationResult.IsReadOnly:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 ReadOnlyPropertyAccessRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    return;

                case CommonAnalyser.PropertyValidationResult.PropertyIsOfMoreSpecificTypeThanSpecificValueType:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 PropertyMayNotBeSetToInstanceOfLessSpecificTypeRule,
                                                 invocation.GetLocation(),
                                                 propertyIfSuccessfullyRetrieved.GetMethod.ReturnType,        // This will always have a value if we got PropertyIsOfMoreSpecificTypeThanSpecificValueType back
                                                 parameterTypeNamedSymbol.DelegateInvokeMethod.ReturnType.Name
                                                 ));
                    continue;

                case CommonAnalyser.PropertyValidationResult.MethodParameterWithoutPropertyIdentifierAttribute:
                    context.ReportDiagnostic(Diagnostic.Create(
                                                 MethodParameterWithoutPropertyIdentifierAttributeRule,
                                                 argumentValue.GetLocation()
                                                 ));
                    continue;
                }
            }

            // While we're looking at method calls, ensure that we don't pass a [PropertyIdentifier] argument for the current method into another method as an out or ref argument because reassignment
            // of [PropertyIdentifier] arguments is not allowed (because it would be too difficult - impossible, actually, I think - to ensure that it doesn't come back in a form that would mess up
            // With calls in bad ways)
            foreach (var argumentDetails in invocationArgumentDetails)
            {
                var argumentValue = invocation.ArgumentList.Arguments[argumentDetails.Index];
                if (argumentValue.RefOrOutKeyword.Kind() == SyntaxKind.None)
                {
                    continue;
                }

                var argumentValueAsParameter = context.SemanticModel.GetSymbolInfo(argumentValue.Expression).Symbol as IParameterSymbol;
                if ((argumentValueAsParameter == null) || !CommonAnalyser.HasPropertyIdentifierAttribute(argumentValueAsParameter))
                {
                    continue;
                }

                context.ReportDiagnostic(Diagnostic.Create(
                                             NoReassignmentRule,
                                             argumentValue.GetLocation()
                                             ));
            }
        }