private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                return;
            }

            MakeMemberReadOnlyWalker walker = null;

            try
            {
                walker = MakeMemberReadOnlyWalker.GetInstance();

                walker.SemanticModel     = context.SemanticModel;
                walker.CancellationToken = context.CancellationToken;

                AnalyzeTypeDeclaration(context, typeDeclaration, walker);
            }
            finally
            {
                if (walker != null)
                {
                    MakeMemberReadOnlyWalker.Free(walker);
                }
            }
        }
Пример #2
0
        public static HashSet <AssignedInfo> GetAssignedAndFree(MakeMemberReadOnlyWalker walker)
        {
            HashSet <AssignedInfo> assigned = walker.Assigned;

            Free(walker);

            return(assigned);
        }
        public virtual HashSet <ISymbol> GetFixableSymbols(
            SymbolAnalysisContext context,
            INamedTypeSymbol containingType,
            HashSet <ISymbol> symbols)
        {
            CancellationToken cancellationToken = context.CancellationToken;
            ImmutableArray <SyntaxReference> syntaxReferences = containingType.DeclaringSyntaxReferences;

            for (int i = 0; i < syntaxReferences.Length; i++)
            {
                var typeDeclaration = (TypeDeclarationSyntax)syntaxReferences[i].GetSyntax(cancellationToken);

                SemanticModel semanticModel = context.Compilation.GetSemanticModel(typeDeclaration.SyntaxTree);

                foreach (MemberDeclarationSyntax memberDeclaration in typeDeclaration.Members)
                {
                    MakeMemberReadOnlyWalker walker = MakeMemberReadOnlyWalkerCache.GetInstance();

                    walker.Visit(memberDeclaration);

                    HashSet <AssignedInfo> assigned = MakeMemberReadOnlyWalkerCache.GetAssignedAndFree(walker);

                    if (assigned != null)
                    {
                        foreach (AssignedInfo info in assigned)
                        {
                            foreach (ISymbol symbol in symbols)
                            {
                                if (symbol.Name == info.NameText &&
                                    ((symbol.IsStatic) ? !info.IsInStaticConstructor : !info.IsInInstanceConstructor))
                                {
                                    ISymbol nameSymbol = semanticModel.GetSymbol(info.Name, cancellationToken);

                                    if (ValidateSymbol(nameSymbol) &&
                                        symbols.Remove(nameSymbol.OriginalDefinition))
                                    {
                                        if (symbols.Count == 0)
                                        {
                                            return(symbols);
                                        }

                                        break;
                                    }
                                }
                            }
                        }

                        assigned.Clear();
                    }
                }
            }

            return(symbols);
        }
Пример #4
0
        public static MakeMemberReadOnlyWalker GetInstance()
        {
            MakeMemberReadOnlyWalker walker = _cachedInstance;

            if (walker != null)
            {
                _cachedInstance = null;
                walker.Clear();
                return(walker);
            }

            return(new MakeMemberReadOnlyWalker());
        }
Пример #5
0
        private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

            if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                return;
            }

            bool skipField = !DiagnosticRules.MakeFieldReadOnly.IsEffective(context);

            bool skipProperty = !DiagnosticRules.UseReadOnlyAutoProperty.IsEffective(context) ||
                                ((CSharpCompilation)context.Compilation).LanguageVersion < LanguageVersion.CSharp6;

            MakeMemberReadOnlyWalker walker = MakeMemberReadOnlyWalker.GetInstance();

            walker.SemanticModel     = context.SemanticModel;
            walker.CancellationToken = context.CancellationToken;

            Dictionary <string, (SyntaxNode node, ISymbol symbol)> symbols = walker.Symbols;

            foreach (MemberDeclarationSyntax memberDeclaration in typeDeclaration.Members)
            {
                switch (memberDeclaration.Kind())
                {
                case SyntaxKind.PropertyDeclaration:
                {
                    if (skipProperty)
                    {
                        break;
                    }

                    var propertyDeclaration = (PropertyDeclarationSyntax)memberDeclaration;

                    AccessorDeclarationSyntax setter = propertyDeclaration.Setter();

                    if (setter?.IsKind(SyntaxKind.InitAccessorDeclaration) == false &&
                        setter.BodyOrExpressionBody() == null &&
                        !setter.AttributeLists.Any() &&
                        !setter.SpanContainsDirectives())
                    {
                        IPropertySymbol propertySymbol = context.SemanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken);

                        IMethodSymbol setMethod = propertySymbol.SetMethod;

                        if (setMethod?.DeclaredAccessibility == Accessibility.Private &&
                            setMethod.GetAttributes().IsEmpty &&
                            !propertySymbol.IsIndexer &&
                            !propertySymbol.IsReadOnly &&
                            ValidateType(propertySymbol.Type) &&
                            propertySymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty &&
                            AnalyzePropertyAttributes(propertySymbol))
                        {
                            symbols[propertySymbol.Name] = (propertyDeclaration, propertySymbol);
                        }
                    }

                    break;
                }

                case SyntaxKind.FieldDeclaration:
                {
                    if (skipField)
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    foreach (VariableDeclaratorSyntax declarator in fieldDeclaration.Declaration.Variables)
                    {
                        if (context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken) is IFieldSymbol fieldSymbol &&
                            !fieldSymbol.IsConst &&
                            fieldSymbol.DeclaredAccessibility == Accessibility.Private &&
                            !fieldSymbol.IsReadOnly &&
                            !fieldSymbol.IsVolatile &&
                            ValidateType(fieldSymbol.Type))
                        {
                            symbols[fieldSymbol.Name] = (declarator, fieldSymbol);
                        }
                    }

                    break;
                }
                }
            }

            if (symbols.Count > 0)
            {
                foreach (MemberDeclarationSyntax memberDeclaration in typeDeclaration.Members)
                {
                    walker.Visit(memberDeclaration);

                    if (symbols.Count == 0)
                    {
                        break;
                    }
                }

                if (symbols.Count > 0)
                {
                    foreach (KeyValuePair <string, (SyntaxNode node, ISymbol symbol)> kvp in symbols)
                    {
                        if (kvp.Value.node is PropertyDeclarationSyntax propertyDeclaration)
                        {
                            AccessorDeclarationSyntax setter = propertyDeclaration.Setter();

                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseReadOnlyAutoProperty, setter);
                        }
                    }

                    foreach (IGrouping <VariableDeclarationSyntax, SyntaxNode> grouping in symbols
                             .Select(f => f.Value.node)
                             .Where(f => f.IsKind(SyntaxKind.VariableDeclarator))
                             .GroupBy(f => (VariableDeclarationSyntax)f.Parent))
                    {
                        int count = grouping.Key.Variables.Count;

                        if (count == 1 ||
                            count == grouping.Count())
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.MakeFieldReadOnly, grouping.Key.Parent);
                        }
                    }
                }
            }

            MakeMemberReadOnlyWalker.Free(walker);
Пример #6
0
 public static void Free(MakeMemberReadOnlyWalker walker)
 {
     _cachedInstance = walker;
 }