I've been searching all day and have read many posts but I just can't quite come to a conclusion on this. I'm trying to create a Roslyn analyzer to report a diagnostic when a private field is unread. Registering the syntax action and finding out if its private was really easy. But now I'm stuck on trying to find out if the field is read in the class.
Assume we have the following example code:
public class C {
private int foo; //private field is declared but never read. Should report diagnostic here
public void DoNothing() {
//irrelevant
}
}
There are several examples of where I'd want this flagged (initialized or not, injected or not, multiple declarations on single line, etc.), but I think maybe they're not necessary for illustrating the question.
What I have so far is this:
public override void Initialize(AnalysisContext context) {
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.RegisterSyntaxNodeAction(AnalyzeField, SyntaxKind.FieldDeclaration);
}
private void AnalyzeField(SyntaxNodeAnalysisContext context) {
if (!(context.Node is FieldDeclarationSyntax fieldDeclarationSyntax)) {
return;
}
foreach (var variableDeclaration in fieldDeclarationSyntax.Declaration.Variables) {
if (context.SemanticModel.GetDeclaredSymbol(variableDeclaration) is IFieldSymbol variableDeclarationSymbol &&
IsFieldPrivate(variableDeclarationSymbol) &&
!IsFieldRead(context, variableDeclarationSymbol)) {
//report diagnostic here
}
}
}
private bool IsFieldPrivate(IFieldSymbol fieldSymbol) {
return fieldSymbol.DeclaredAccessibility == Accessibility.Private || // the field itself is explicitly private
fieldSymbol.ContainingType?.DeclaredAccessibility == Accessibility.Private; //the field is not private, but is contained within a private class
}
private bool IsFieldRead(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol) {
//context.Node.Parent will be the class declaration here since we're analyzing a field declaration
//but let's be safe about that just in case and make sure we traverse up until we find the class declaration
var classDeclarationSyntax = context.Node.Parent;
while (!(classDeclarationSyntax is ClassDeclarationSyntax)) {
classDeclarationSyntax = classDeclarationSyntax.Parent;
}
var methodsInClassContainingPrivateField = classDeclarationSyntax.DescendantNodes().OfType<MethodDeclarationSyntax>().ToImmutableArray();
foreach (var method in methodsInClassContainingPrivateField) {
var dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(method); //does not work because this is not a StatementSyntax or ExpressionSyntax
if (dataFlowAnalysis.ReadInside.Contains(fieldSymbol) || dataFlowAnalysis.ReadOutside.Contains(fieldSymbol)) {
return true;
}
}
return false;
}
I just can't quite figure out how to get the IsFieldRead() method to work. This really feels like something that should be easy to do but I just can't quite wrap my head around it. I figured getting the methods and analyzing those for my field to see if it was read would be a decent idea, but that doesn't cover if the field is read by another private field, and I can't get it working anyway. :)
I managed to get this figured out thanks to this other SO answer by someone who actually works on Roslyn at Microsoft. Here is my IsFieldRead() method now. The key apparently lied in the Microsoft.CodeAnalysis.Operations namespace.
private bool IsFieldRead(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol) {
var classDeclarationSyntax = context.Node.Parent;
while (!(classDeclarationSyntax is ClassDeclarationSyntax)) {
classDeclarationSyntax = classDeclarationSyntax.Parent;
if (classDeclarationSyntax == null) {
throw new InvalidOperationException("You have somehow traversed up and out of the syntax tree when determining if a private member field is being read.");
}
}
//get all methods in the class
var methodsInClass = classDeclarationSyntax.DescendantNodes().OfType<MethodDeclarationSyntax>().ToImmutableArray();
foreach (var method in methodsInClass) {
//get all member references in those methods
if (context.SemanticModel.GetOperation(method).Descendants().OfType<IMemberReferenceOperation>().ToImmutableArray().Any(x => x.Member.Equals(fieldSymbol))) {
return true;
}
}
return false;
}
Note that this only covers usages within methods. There are several other places like other fields, properties, and constructors that would also need to be checked.
Related
I am trying to write an analyzer that prevents users from providing parameters that are automatically provided (ex: by the compiler with [CallerMemberName]) and I want the analyzer to error you when you have provided a parameter that shouldn't be provided (to tell a parameter shouldn't be provided I created an attribute : DontProvideAttribute).
The thing is such automatically provided parameters must be optional (otherwise the value provided by the user would be written over the one provided automatically) so I've made a second analyze to prevent users from using [DontProvide] on non-optional parameters.
And there comes the problem, I want the error on the method invocation to be there only if the parameter declaration doesn't have the [DontProvide] should only be used on optional parameters error which
foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
{
if (parameterDefinition.GetSyntax().ContainsDiagnostics)
{
return;
}
}
should complete this but it seems like it doesn't consider diagnostics you reported yourself.
What i have tried :
-Changing the order of diagnostics to make the declaration being analyzed before the method invocation
-Use .GetDiagnostics().Count() > 0 instead
-Changing the order of the text in the analyzed document to have the method declaration above the method invocation
The analyzer :
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(AnalyzeParametersDeclaration, SymbolKind.Parameter);
context.RegisterOperationAction(AnalyzeArguments, OperationKind.Argument);
}
private void AnalyzeArguments(OperationAnalysisContext context)
{
IArgumentOperation reference = (IArgumentOperation)context.Operation;
IParameterSymbol parameter = reference.Parameter;
foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
{
if (parameterDefinition.GetSyntax().ContainsDiagnostics)
return;
}
foreach (AttributeData attribute in parameter.GetAttributes())
{
if (attribute.AttributeClass.Name == "DontProvideAttribute")
{
context.ReportDiagnostic(Diagnostic.Create(DontProvide, reference.Syntax.GetLocation(), parameter.Name));
}
}
}
private void AnalyzeParametersDeclaration(SymbolAnalysisContext context)
{
IParameterSymbol parameter = (IParameterSymbol)context.Symbol;
if (parameter.GetAttributes().Any(a => a.AttributeClass.Name == "DontProvideAttribute") && !parameter.IsOptional)
{
context.ReportDiagnostic(Diagnostic.Create(DontProvideOnlyForOptional, parameter.Locations[0]))
}
}
Some test code for analyze :
using System;
namespace test
{
internal class Program
{
private static void Main(string[] args)
{
MyClass.MyMethod(null);
}
}
internal class MyClass
{
public static void MyMethod([DontProvide] object parameter)
{
}
}
[AttributeUsage(AttributeTargets.Parameter)]
public class DontProvideAttribute : Attribute
{
}
}
PS : The compiler may tell you that context.RegisterSymbolAction() used with SymbolKind.Parameter isn't supported, which is wrong (see more here)
From the discussion here and #Kris Vandermotten's comment
ContainsDiagnostics is only for syntactic diagnostics (i.e. diagnostics acutally inside the syntax tree)
not for diagnostics reported by later passes (i.e. semantic diagnostics or your own analyzer diagnostics).
Here's why : a specific syntax tree may be contained in many different semantic contexts due to roslyn being able to fork and speculate about things
so in one context, the syntax may be semantically correct, and in another, it won't be
as such, the diagnostics are not stored on the tree itself.
In fact the solution in my case was pretty simple : i just had to remove
foreach (SyntaxReference parameterDefinition in parameter.DeclaringSyntaxReferences)
{
if (parameterDefinition.GetSyntax().ContainsDiagnostics)
return;
}
and add && parameter.IsOptionnal on the if statement there :
foreach (AttributeData attribute in parameter.GetAttributes())
{
if (attribute.AttributeClass.Name == "DontProvideAttribute")
{
context.ReportDiagnostic(Diagnostic.Create(DontProvide, reference.Syntax.GetLocation(), parameter.Name));
}
}
In C++, it's fairly easy to write a Guard class which takes a reference to a variable (usually a bool) and when the instance object exits scope and gets destructed, the destructor resets the variable to the original value.
void someFunction() {
if(!reentryGuard) {
BoolGuard(&reentryGuardA, true);
// do some stuff that might cause reentry of this function
// this section is both early-exit and exception proof, with regards to restoring
// the guard variable to its original state
}
}
I'm looking for a graceful way to do this in C# using the disposal pattern (or maybe some other mechanism?) I'm thinking that passing a delegate to call might work, but seems a bit more error-prone than the guard above. Suggestions welcome!
Something like:
void someFunction() {
if(!reentryGuard) {
using(var guard = new BoolGuard(ref reentryGuard, true)) {
// do some stuff that might cause reentry of this function
// this section is both early-exit and exception proof, with regards to restoring
// the guard variable to its original state
}
}
}
With the understanding that the above code won't work.
You are correct…without unsafe code, you can't save the address of a by-ref parameter. But, depending on how much you can change the overall design, you can create a "guardable" type, such that it's a reference type containing the value to actually guard.
For example:
class Program
{
class Guardable<T>
{
public T Value { get; private set; }
private sealed class GuardHolder<TGuardable> : IDisposable where TGuardable : Guardable<T>
{
private readonly TGuardable _guardable;
private readonly T _originalValue;
public GuardHolder(TGuardable guardable)
{
_guardable = guardable;
_originalValue = guardable.Value;
}
public void Dispose()
{
_guardable.Value = _originalValue;
}
}
public Guardable(T value)
{
Value = value;
}
public IDisposable Guard(T newValue)
{
GuardHolder<Guardable<T>> guard = new GuardHolder<Guardable<T>>(this);
Value = newValue;
return guard;
}
}
static void Main(string[] args)
{
Guardable<int> guardable = new Guardable<int>(5);
using (var guard = guardable.Guard(10))
{
Console.WriteLine(guardable.Value);
}
Console.WriteLine(guardable.Value);
}
}
Here's a functional (as in lambda-based) way to do it. Pluses are, no need to use a using:
(note: This is not thread-safe. If you are looking to keep different threads from running the same code simultaneously, look at the lock statement, the monitor, and the mutex)
// usage
GuardedOperation TheGuard = new GuardedOperation() // instance variable
public void SomeOperationToGuard()
{
this.TheGuard.Execute(() => TheCodeToExecuteGuarded);
}
// implementation
public class GuardedOperation
{
public bool Signalled { get; private set; }
public bool Execute(Action guardedAction)
{
if (this.Signalled)
return false;
this.Signalled = true;
try
{
guardedAction();
}
finally
{
this.Signalled = false;
}
return true;
}
}
EDIT
Here is how you could use the guarded with parameters:
public void SomeOperationToGuard(int aParam, SomeType anotherParam)
{
// you can pass the params to the work method using closure
this.TheGuard.Execute(() => TheMethodThatDoesTheWork(aParam, anotherParam);
}
private void TheMethodThatDoesTheWork(int aParam, SomeType anotherParam) {}
You could also introduce overloads of the Execute method that accept a few different variants of the Action delegate, like Action<T> and Action<T1, T2>
If you need return values, you could introduce overloads of Execute that accept Func<T>
Sounds like the sort of thing you'd have to implement yourself - there are no such mechanisms built into C# or the .NET framework, though I did locate a deprecated class Guard on MSDN.
This sort of functionality would likely need to use a Using statement to operate without passing around an Action block, which as you said could get messy. Note that you can only call using against and IDisposable object, which will then be disposed - the perfect trigger for resetting the value of the object in question.
You can derive your object from IDisposable interface and implement it.
In specific case you are presenting here Dispose will be called as soon as you leave using scope.
Example:
public class BoolGuard : IDisposable
{
....
...
public void Dispose()
{
//DISPOSE IMPLEMANTATION
}
}
I recently learned about yield and then created the following test console program:
public static string Customers = "Paul,Fred,Doug,Mark,Josh";
public static string Admins = "Paul,Doug,Mark";
public static void Main()
{
var test = CreateEfficientObject();
Console.WriteLine(test.Admins.FirstOrDefault());
//Note that 'GetAllCustomers' never runs.
}
public static IEnumerable<string> GetAllCustomers()
{
var databaseFetch = Customers.Split(',');
foreach (var s in databaseFetch)
{
yield return s;
}
}
public static IEnumerable<string> GetAllAdmins()
{
var databaseFetch = Admins.Split(',');
foreach (var s in databaseFetch)
{
yield return s;
}
}
static LoginEntitys CreateEfficientObject()
{
var returnObject = new LoginEntitys {};
returnObject.Admins = GetAllAdmins();
returnObject.Customers = GetAllCustomers();
return returnObject;
}
}
public class LoginEntitys
{
public IEnumerable<String> Admins { get; set; }
public IEnumerable<String> Customers { get; set; }
}
Yet I noticed Resharper wants to convert my foreach loops to :
public static IEnumerable<string> GetAllCustomers()
{
var databaseFetch = Customers.Split(',');
return databaseFetch;
}
Why does Resharper want to remove yield from this case? It changes the functionality completely as it will no longer lazy load without yield. I can only guess that either
A) I am using yield incorrectly/in bad pratice
B) It's a Resharper bug/suggestion that can just be ignored.
Any insight would be great.
You are correct that this proposed transformation changes the functionality of the code in subtle ways, preventing it from deferring the evaluation of the properties and performing the Split from being evaluated as early.
Perhaps those that implemented it were well aware that it was a change in functionality and felt that it was still a useful suggestion, one that could be ignored if the existing semantics were important, or if they actually failed to realize that the semantics were being altered. There's no good way for us to know, we can only guess. If those semantics are important for your program, then you are correct to not make the suggested transformation.
I think Resharper is being a bit dumb here, in the sense that its applying a standard "convert foreach to LINQ" transform without being aware of the context.
It doesn't suggest the same edits for a while loop:
public static IEnumerable<string> ReadLineFromFile(TextReader fileReader)
{
using (fileReader)
{
string currentLine;
while ((currentLine = fileReader.ReadLine()) != null)
{
yield return currentLine;
}
}
}
I guess the next iteration of Resharper which uses Roslyn will be much more context aware.
Thanks #servy for an engaging and refreshing discussion!
The code in your example is not calling the iterator on the IEnumerable you are returning. If you were using the result of GetAllAdmins() in a LINQ query for example the yield would be useful because execution of the expression could resume on each iteration.
I would imagine Resharper is just suggesting you remove unused code.
I have a class that creates a List<Action<int>> and holds on to them until a later time. This class can add and remove delegates from this list. This works well as long as people don't get too fancy. To combat anonymous function (which can't be removed) I check against the target of the delegate being null. If its null I throw an exception. The problem comes in when there is an anonymous delegate that contains a function. This has a target, but is just as unremovable. The simplified code below illustrates my issues
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public void Add(Action<int> del)
{
if (del.Target == null)
{
throw new Exception("No static handlers");
}
m_Container.Add(del);
}
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
return false;
}
}
public class MyFakeActionClass
{
public void Test(int temp) { }
}
class Program
{
static void Main(string[] args)
{
bool removed = false;
int counter = 0;
MyDelegateContainer container = new MyDelegateContainer();
MyFakeActionClass fake = new MyFakeActionClass();
//container.Add(p => { }); //Throws, this is what I want to happen
container.Add(fake.Test); //Works, this is the use case
removed = container.Remove(fake.Test); //Works, this is the use case
Debug.Assert(removed);
container.Add(p => { fake.Test(p); counter++; }); //Works but I would like it not to
removed = container.Remove(p => { fake.Test(p); counter++; }); //doesn't work
Debug.Assert(removed);
}
}
I need some way to identify
p => { fake.Test(p); counter++; }
is an anonymous function so I can throw if someone tries it. Thanks for any help
EDIT: I should note that I could use an Action<int> variable for the anonymous function and everything would work, but the Add and Remove are never in the same scope in practice.
In your example, the caller is responsible from removing the handler. So, if the caller doesn't want to remove the handler, it won't get removed, no matter if the handler is an anonymous delegate/lambda or not.
My suggestion is to change the delegate container to something like this:
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public Action Add(Action<int> del)
{
m_Container.Add(del);
return new Action(() =>
{
m_Container.Remove(del);
});
}
}
The caller is still responsible for removing the handler, but instead of passing the handler again to the container, it receives a "token" that it can save and use later to remove the handler.
There is no way to reliably determine whether a function is "anonymous" because all functions have names to the CLR. It's only anonymous within the language that generates it, and that's compiler-dependent. You may be able to determine the algorithm used by Microsoft's current C# compiler, only to have it stop working on C# 5 or Mono.
Since you want to prevent users of your type from writing code that uses it wrong, you just need to throw an exception at some point that will make their program crash. What I would do is throw the exception in the Remove function when the target delegate isn't found. At that point your users will still get a crash and the only way to fix it is to write the delegate in some way that it's removable.
As an added bonus, you will catch bugs where somebody tries to remove delegates twice or that were never added in the first place. The code would look like this:
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
throw new ArgumentException("Attempt to remove nonexistent delegate");
}
I would use introspection to check the names of the methods.
Anonymous methods typically have very predictable names. (I don't remember the exact format, but run some tests, and it should be obvious).
The drawback would be that if anyone created a non-anonymous method, but decided to name it anonMethod123 (or whatever the format is...) It would be falsely rejected.
Of course you can remove an anonymous method, you just need to have a reference to the same anonymous method.
var myAnonymousMethod = p => { fake.Test(p); counter++; };
container.Add(myAnonymousMethod);
removed = container.Remove(myAnonymousMethod);
As jonnii suggested in a comment, another way you could implement it is with a dictionary:
public class MyDelegateContainer
{
Dictionary<string, Action<int>> m_Container =
new Dictionary<string, Action<int>>();
public void Add(string key, Action<int> del)
{
m_Container.Add(key, del);
}
public bool Remove(string key)
{
return m_Container.Remove(key);
}
}
Then you could easily remove a known delegate at some arbitrary point in your code just by knowing what name was used to add it:
container.Add("fake.Test", fake.Test);
removed = container.Remove("fake.Test");
Debug.Assert(removed);
container.Add("anon", p => { fake.Test(p); counter++; });
removed = container.Remove("anon"); // works!
Debug.Assert(removed);
Old question I know but I would think that this would be a current (and future) proofed way of checking if a method is anonymous:
bool isAnonymous = !System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(del.Method.Name);
The runtime name of the anonymous method would have to be invalid if used at compilation time to ensure that it didn't clash.
I am porting a library from C++ to C#. The old library uses vectors from C++ and in the C# I am using generic Dictionaries because they're actually a good data structure for what I'm doing (each element has an ID, then I just use using TypeDictionary = Dictionary<String, Type>;). Now, in the C# code I use a loop like this one
TypeDictionary.Enumerator tdEnum = MyTypeDictionary.GetEnumerator();
while( tdEnum.MoveNext() )
{
Type element = typeElement.Current.Value;
// More code here
}
to iterate through the elements of the collection. The problem is that in particular cases I need to check if a certain enumerator has reached the end of the collection, in C++ I would have done a check like this:
if ( tdEnum == MyTypeDictionary.end() ) // More code here
But I just don't know how to handle this situation in C#, any ideas?
Thank you
Tommaso
Here's a pretty simple way of accomplishing this.
bool hasNext = tdEnum.MoveNext();
while (hasNext) {
int i = tdEnum.Current;
hasNext = tdEnum.MoveNext();
}
I found an online tutorial that also may help you understand how this works.
http://www.c-sharpcorner.com/UploadFile/prasadh/Enumerators11132005232321PM/Enumerators.aspx
You know that you're at the end of an iterator when MoveNext() returns false. Otherwise you need to upgrade to a more descriptive data structure like IList<T>.
I have a "smart iterator" class in MiscUtil which you may find useful. It lets you test whether you're currently looking at the start or end of the sequence, and the index within the sequence. See the usage page for more information.
Of course in most cases you can just get away with doing this manually using the result of MoveNext(), but occasionally the extra encapsulation comes in handy.
Note that by necessity, this iterator will always have actually consumed one more value than it's yielded, in order to know whether or not it's reached the end. In most cases that isn't an issue, but it could occasionally give some odd experiences when debugging.
Using the decorator pattern to hold a value if the enumerator has ended is a valid approach.
Since it implements IEnumerator, you won't find difficulties to replace it in your code.
Here's a test class:
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyDictionary = System.Collections.Generic.Dictionary<int, string>;
using MyKeyValue = System.Collections.Generic.KeyValuePair<int, string>;
namespace TestEnumerator
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestingMyEnumeradorPlus()
{
var itens = new MyDictionary()
{
{ 1, "aaa" },
{ 2, "bbb" }
};
var enumerator = new EnumeradorPlus<MyKeyValue>(itens.GetEnumerator());
enumerator.MoveNext();
Assert.IsFalse(enumerator.Ended);
enumerator.MoveNext();
Assert.IsFalse(enumerator.Ended);
enumerator.MoveNext();
Assert.IsTrue(enumerator.Ended);
}
}
public class EnumeradorPlus<T> : IEnumerator<T>
{
private IEnumerator<T> _internal;
private bool _hasEnded = false;
public EnumeradorPlus(IEnumerator<T> enumerator)
{
_internal = enumerator;
}
public T Current
{
get { return _internal.Current; }
}
public void Dispose()
{
_internal.Dispose();
}
object System.Collections.IEnumerator.Current
{
get { return _internal.Current; }
}
public bool MoveNext()
{
bool moved = _internal.MoveNext();
if (!moved)
_hasEnded = true;
return moved;
}
public void Reset()
{
_internal.Reset();
_hasEnded = false;
}
public bool Ended
{
get { return _hasEnded; }
}
}
}
Coming from C++ you might not be up to date on C# syntax. Perhaps you could simply use the foreach construct to avoid the test all together. The following code will be executed once for each element in your dictionary:
foreach (var element in MyTypeDictionary)
{
// More code here
}