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); } } }
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); }
public static MakeMemberReadOnlyWalker GetInstance() { MakeMemberReadOnlyWalker walker = _cachedInstance; if (walker != null) { _cachedInstance = null; walker.Clear(); return(walker); } return(new MakeMemberReadOnlyWalker()); }
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);
public static void Free(MakeMemberReadOnlyWalker walker) { _cachedInstance = walker; }