Example #1
0
        private void AnalyzeClassOrStruct(
            SyntaxNodeAnalysisContext context,
            MutabilityInspector inspector
            )
        {
            // TypeDeclarationSyntax is the base class of
            // ClassDeclarationSyntax and StructDeclarationSyntax
            var root = (TypeDeclarationSyntax)context.Node;

            var symbol = context.SemanticModel
                         .GetDeclaredSymbol(root);

            // skip classes not marked immutable
            var scope = symbol.GetImmutabilityScope();

            if (scope == ImmutabilityScope.None)
            {
                return;
            }

            var mutabilityResult = inspector.InspectConcreteType(
                symbol,
                MutabilityInspectionFlags.IgnoreImmutabilityAttribute                 // we're _validating_ the attribute
                );

            if (mutabilityResult.IsMutable)
            {
                var reason     = m_resultFormatter.Format(mutabilityResult);
                var location   = GetLocationOfClassIdentifierAndGenericParameters(root);
                var diagnostic = Diagnostic.Create(
                    Diagnostics.ImmutableClassIsnt,
                    location,
                    reason
                    );
                context.ReportDiagnostic(diagnostic);
            }
            else if (mutabilityResult.SeenUnauditedReasons.Count > 0)
            {
                ImmutableHashSet <string> immutableExceptions = symbol.GetAllImmutableExceptions();

                if (!mutabilityResult.SeenUnauditedReasons.IsSubsetOf(immutableExceptions))
                {
                    string missingExceptions = string.Join(", ", mutabilityResult.SeenUnauditedReasons.Except(immutableExceptions));

                    var location   = GetLocationOfClassIdentifierAndGenericParameters(root);
                    var diagnostic = Diagnostic.Create(
                        Diagnostics.InvalidUnauditedReasonInImmutable,
                        location,
                        missingExceptions
                        );

                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
Example #2
0
        /// <summary>
        /// All logic relating to either emitting or not emitting diagnostics other
        /// than the ones about unnecessary annotations belong in this function.
        /// This allows InspectMember to implement the logic around the unnecessary
        /// annotations diagnostic. Any time we bail early in AnalyzeField or
        /// AnalyzeProperty we risk not emitting unnecessary annotation
        /// diagnostics.
        /// </summary>
        private IEnumerable <Diagnostic> GatherDiagnostics(
            SemanticModel model,
            MutabilityInspector inspector,
            Location location,
            bool isStatic,
            bool isReadOnly,
            ITypeSymbol fieldOrPropertyType,
            string fieldOrPropertyName,
            ExpressionSyntax initializationExpression,
            bool isProperty,
            bool isAutoImplementedProperty
            )
        {
            if (!isStatic)
            {
                yield break;
            }

            if (isProperty && !isAutoImplementedProperty)
            {
                // non-auto-implemented properties don't hold their own state.
                // We should never emit diagnostics for them.
                yield break;
            }

            // Auto-implemented properties should be treated similar to fields:
            // 1. They should not have a setter (i.e. isReadOnly)
            // 2. Their type should be immutable
            //    a. Unless an initializer ensures it isn't

            if (!isReadOnly)
            {
                yield return(CreateDiagnostic(
                                 location,
                                 fieldOrPropertyName,
                                 fieldOrPropertyType.GetFullTypeNameWithGenericArguments(),
                                 MutabilityInspectionResult.Mutable(
                                     fieldOrPropertyName,
                                     fieldOrPropertyType.GetFullTypeNameWithGenericArguments(),
                                     MutabilityTarget.Member,
                                     MutabilityCause.IsNotReadonly
                                     )
                                 ));

                // TODO: it'd probably be reasonable to not bail here. However
                // we need to update the unsafestatics report because it counts
                // the number of diagnostics that come out (it assumes at most one
                // error per-field.)
                yield break;
            }

            // Always prefer the type from the initializer if it exists because
            // it may be more specific.
            if (initializationExpression != null)
            {
                var initializerType = model.GetTypeInfo(initializationExpression).Type;

                // Fall back to the declaration type if we can't get a type for
                // the initializer.
                if (initializerType != null && !(initializerType is IErrorTypeSymbol))
                {
                    fieldOrPropertyType = initializerType;
                }
            }

            MutabilityInspectionResult result;

            // When we know the concrete type as in "new T()" we don't have to
            // be paranoid about mutable derived classes.
            if (initializationExpression is ObjectCreationExpressionSyntax)
            {
                result = inspector.InspectConcreteType(fieldOrPropertyType);
            }
            else
            {
                result = inspector.InspectType(fieldOrPropertyType);
            }

            if (result.IsMutable)
            {
                result = result.WithPrefixedMember(fieldOrPropertyName);
                yield return(CreateDiagnostic(
                                 location,
                                 fieldOrPropertyName,
                                 fieldOrPropertyType.GetFullTypeNameWithGenericArguments(),
                                 result
                                 ));
            }
        }