Skip to content

Instantly share code, notes, and snippets.

@sonnemaf
Created December 14, 2017 21:02
Show Gist options
  • Save sonnemaf/0001b88db198be33d83f346a47ad874f to your computer and use it in GitHub Desktop.
Save sonnemaf/0001b88db198be33d83f346a47ad874f to your computer and use it in GitHub Desktop.
InParameterOnNonReadonlyStructAnalyzer
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Analyzer1 {
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class InParameterOnNonReadonlyStructAnalyzer : DiagnosticAnalyzer {
public const string DiagnosticId = "InParameterOnNonReadonlyStructAnalyzer";
// You can change these strings in the Resources.resx file. If you do not want your analyzer to be localize-able, you can use regular strings for Title and MessageFormat.
// See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Localizing%20Analyzers.md for more on localization
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
private const string Category = "Naming";
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Warning, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context) {
context.RegisterSyntaxNodeAction(AnalyzeNode, ImmutableArray.Create(SyntaxKind.Parameter));
}
private static void AnalyzeNode(SyntaxNodeAnalysisContext context) {
var syntaxNode = context.Node;
var semanticModel = context.SemanticModel;
var cancellationToken = context.CancellationToken;
var parameterNode = syntaxNode as ParameterSyntax;
if (parameterNode != null) {
var parameterSymbol = semanticModel.GetDeclaredSymbol(parameterNode, cancellationToken);
// Test for an InParameter with a Non-Readonly ValueType
if (parameterNode != null &&
parameterNode.Modifiers.Any(m => m.IsKind(SyntaxKind.InKeyword)) &&
parameterSymbol.Type.IsValueType &&
!IsReadonly(parameterSymbol.Type)) {
// Create the Code Diagnostic
var diagnostic = Diagnostic.Create(Rule, parameterNode.GetLocation(), parameterNode.Identifier.Text.ToString());
context.ReportDiagnostic(diagnostic);
}
}
}
private static bool IsReadonly(ITypeSymbol type) {
return type.GetAttributes().Any(a => a.AttributeClass.GetType().FullName == "System.Runtime.CompilerServices.IsReadOnlyAttribute");
}
private void Foo(in int a) {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment