public void ConstructorCycle(DiagnosticAnalyzer analyzer) { var testCode = @" namespace RoslynSandbox { using System; public class Constructors : IDisposable { private IDisposable disposable; public Constructors(int i, IDisposable disposable) : this(disposable, i) { this.disposable = disposable; } public Constructors(IDisposable disposable, int i) : this(i, disposable) { this.disposable = disposable; } public void Dispose() { } } }"; var solution = CodeFactory.CreateSolution(testCode, CodeFactory.DefaultCompilationOptions(analyzer, AnalyzerAssert.SuppressedDiagnostics), AnalyzerAssert.MetadataReferences); AnalyzerAssert.NoDiagnostics(Analyze.GetDiagnostics(analyzer, solution)); }
public void WithSyntaxErrors(DiagnosticAnalyzer analyzer) { var testCode = @" namespace RoslynSandbox { using System; using System.IO; public class Foo : SyntaxError { private readonly Stream stream = File.SyntaxError(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.syntaxError) { return; } this.disposed = true; if (disposing) { this.stream.Dispose(); } base.Dispose(disposing); } } }"; var solution = CodeFactory.CreateSolution(testCode, CodeFactory.DefaultCompilationOptions(analyzer, AnalyzerAssert.SuppressedDiagnostics), AnalyzerAssert.MetadataReferences); AnalyzerAssert.NoDiagnostics(Analyze.GetDiagnostics(analyzer, solution)); }
public void InsideObservableFromEventArg() { var fooCode = @" namespace RoslynSandbox { using System; public class Foo { public event EventHandler<int> SomeEvent; } }"; var testCode = @" namespace RoslynSandbox { using System; public class Bar { public Bar() { var foo = new Foo(); System.Reactive.Linq.Observable.FromEvent<System.EventHandler, EventArgs>( h => (_, e) => h(e), h => foo.SomeEvent += h, h => foo.SomeEvent -= h) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA11PreferObservableFromEvent>(fooCode, testCode); }
public void GenericConstraint() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public interface IFoo : INotifyPropertyChanged { public int Value { get; } } }"; var testCode = @" namespace RoslynSandbox { using System; using Gu.Reactive; public class Bar<T> where T : class, IFoo { public Bar(T foo) { foo.ObservePropertyChanged(x => x.Value) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA03PathMustNotify>(fooCode, testCode); }
public void ActionOfInt() { var fooCode = @" namespace RoslynSandbox { using System; public class Foo { public event Action<int> SomeEvent; } }"; var testCode = @" namespace RoslynSandbox { using System; public class Bar { public Bar() { var foo = new Foo(); System.Reactive.Linq.Observable.FromEvent<System.Action<int>, int>( h => foo.SomeEvent += h, h => foo.SomeEvent -= h) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA12ObservableFromEventDelegateType>(fooCode, testCode); }
public void ObservingGetOnlyPropertyInSelf() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; internal class Foo : INotifyPropertyChanged { private int _value; public event PropertyChangedEventHandler PropertyChanged; public int Value { get { return _value; } set { if (value == _value) { return; } _value = value; OnPropertyChanged(); } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var testCode = @"namespace RoslynSandbox { using System; using Gu.Reactive; internal class Meh { public Meh() { this.Foo = new Foo(); this.Foo.ObserveFullPropertyPathSlim(x => x.Value) .Subscribe(_ => Console.WriteLine(""meh"")); } public Foo Foo { get; } } }"; AnalyzerAssert.NoDiagnostics <GUREA01DontObserveMutableProperty>(fooCode, testCode); }
public void WhenSingleLine() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; public int Value { get { return this.value; } set { if (value == this.value) { return; } this.value = value; this.OnPropertyChanged(); } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var testCode = @" namespace RoslynSandbox { using System.Reactive.Linq; using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA08InlineSingleLine>(fooCode, testCode); }
public void OneLevel() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; public int Value { get { return this.value; } set { if (value == this.value) { return; } this.value = value; this.OnPropertyChanged(); } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var testCode = @" namespace RoslynSandbox { using System; using Gu.Reactive; public class Bar { public Bar() { var foo = new Foo(); foo.ObservePropertyChanged(x => x.Value) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA03PathMustNotify>(fooCode, testCode); }
public void WhenUsingNullableValue() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public sealed class Foo : INotifyPropertyChanged { private int? value; public event PropertyChangedEventHandler PropertyChanged; public int? Value { get => this.value; set { if (value == this.value) { return; } this.value = value; this.OnPropertyChanged(); } } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => { return foo.Value == null ? (bool?)null : foo.Value.Value == 1; }) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA02ObservableAndCriteriaMustMatch>(fooCode, testCode); }
public void MultipleIEnumerableInterfaces() { var testCode = @" namespace RoslynSandbox { using System.Collections; using System.Collections.Generic; class Foo : IEnumerable<IEnumerable<char>>, IEnumerable<int> { IEnumerator<int> IEnumerable<int>.GetEnumerator() { yield return 42; } void GetEnumerator(int x) { } IEnumerator<IEnumerable<char>> IEnumerable<IEnumerable<char>>.GetEnumerator() { yield return string.Empty; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<IEnumerable<char>>)this).GetEnumerator(); } } public class A { public void F() { foreach(int a in new Foo()) { } } } }"; var sln = CodeFactory.CreateSolution(testCode, CodeFactory.DefaultCompilationOptions(Analyzer), AnalyzerAssert.MetadataReferences); var diagnostics = Analyze.GetDiagnostics(Analyzer, sln); AnalyzerAssert.NoDiagnostics(diagnostics); }
public void AndConditionSortArgs() { var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : AndCondition { public FooCondition(Condition1 condition1, Condition2 condition2) : base(condition1, condition2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA13SyncParametersAndArgs>(Condition1, Condition2, testCode); }
public void CtorCallingSelf(DiagnosticAnalyzer analyzer) { var testCode = @" namespace RoslynSandbox { internal abstract class Foo { public Foo() : this() { } } }"; var sln = CodeFactory.CreateSolution(testCode, CodeFactory.DefaultCompilationOptions(analyzer), AnalyzerAssert.MetadataReferences); var diagnostics = Analyze.GetDiagnostics(analyzer, sln); AnalyzerAssert.NoDiagnostics(diagnostics); }
public void GenericProperty() { var iBarCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public interface IBar : INotifyPropertyChanged { int Value { get; set; } } }"; var iFooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public interface IFoo<T> : INotifyPropertyChanged where T: class, IBar { T Bar { get; set; } } }"; var testCode = @" namespace RoslynSandbox { using System; using Gu.Reactive; public class Bar { public Bar(IFoo<IBar> foo) { foo.ObservePropertyChangedSlim(x => x.Bar.Value) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA03PathMustNotify>(iBarCode, iFooCode, testCode); }
public void Correct() { var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value1), () => foo.Value1 == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA02ObservableAndCriteriaMustMatch>(FooCode, testCode); }
public void WhenPassingSlimToConditionCtor() { var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value1), () => foo.Value1 == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA04PreferSlim>(FooCode, testCode); }
public void ObservableCollectionCount() { var testCode = @" namespace RoslynSandbox { using System; using Gu.Reactive; public class Bar { public Bar(System.Collections.ObjectModel.ObservableCollection<int> foo) { foo.ObservePropertyChanged(x => x.Count) .Subscribe(_ => Console.WriteLine(string.Empty)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA03PathMustNotify>(testCode); }
public void WhenSubscribingToSlimUsingArg() { var testCode = @" namespace RoslynSandbox { using System; using Gu.Reactive; public class Bar { public Bar() { var foo = new Foo(); foo.ObservePropertyChangedSlim(x => x.Value1) .Subscribe(x => Console.WriteLine(x.PropertyName)); } } }"; AnalyzerAssert.NoDiagnostics <GUREA04PreferSlim>(FooCode, testCode); }
public void Recursion() { var code = @" namespace RoslynSandbox { using System; public class C<T1, T2> where T1 : T2 where T2 : T1 { public static void Bar() { var type = typeof(C<,>).MakeGenericType(typeof(int), typeof(int)); } } }"; var solution = CodeFactory.CreateSolution(code, CodeFactory.DefaultCompilationOptions(Analyzer), AnalyzerAssert.MetadataReferences); AnalyzerAssert.NoDiagnostics(Analyze.GetDiagnostics(Analyzer, solution)); }
public void WhenCorrectOrder() { var testCode = @" namespace RoslynSandbox { using System.Reactive.Linq; using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA09ObservableBeforeCriteria>(FooCode, testCode); }
public void WhenNoMerge() { var testCode = @" namespace RoslynSandbox { using System.Reactive.Linq; using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA10DontMergeInObservable>(FooCode, testCode); }
public void Run(DiagnosticAnalyzer analyzer) { var diagnostics = Analyze.GetDiagnostics(Solution, analyzer); AnalyzerAssert.NoDiagnostics(diagnostics); }
public void IgnoreUsageInThrowTwoLevels() { var fooCode = @" namespace RoslynSandbox { using System; using System.ComponentModel; using System.Runtime.CompilerServices; public sealed class Foo : INotifyPropertyChanged, IDisposable { private bool disposed; private Bar bar; public event PropertyChangedEventHandler PropertyChanged; public Bar Bar { get { ThrowIfDisposed(); return this.bar; } set { ThrowIfDisposed(); if (ReferenceEquals(value, this.bar)) { return; } this.bar = value; this.OnPropertyChanged(); } } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; var barCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Bar : INotifyPropertyChanged, IDisposable { private int value; public event PropertyChangedEventHandler PropertyChanged; public int Value { get { ThrowIfDisposed(); return this.value; } set { ThrowIfDisposed(); if (value == this.value) { return; } this.value = value; this.OnPropertyChanged(); } } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA02ObservableAndCriteriaMustMatch>(fooCode, barCode, testCode); }
public void Issue63() { var viewModelBaseCode = @" namespace MVVM { using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; /// <summary> /// Base class for all ViewModel classes in the application. /// It provides support for property change notifications /// and has a DisplayName property. This class is abstract. /// </summary> public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable { private readonly List<IDisposable> disposables = new List<IDisposable>(); private readonly object disposeLock = new object(); private bool isDisposed; protected ViewModelBase() { } public event PropertyChangedEventHandler PropertyChanged; public void Dispose() { lock (disposeLock) { this.OnDispose(); if (isDisposed) return; foreach (var disposable in disposables) disposable.Dispose(); isDisposed = true; } } protected virtual void OnDispose() { } } }"; var popupViewModelCode = @" namespace ProjectX.ViewModel { using System; using MVVM; public class PopupViewModel : ViewModelBase { public PopupViewModel() { ClosePopupCommand = new ClosePopupCommand(this); } // Gives an IDISP006 warning (need to implement IDispose) public ClosePopupCommand ClosePopupCommand { get; } protected override void OnDispose() { ClosePopupCommand.Dispose(); CloseProgramCommand.Dispose(); } } }"; var closePopupCommandCode = @" namespace ProjectX.Commands { using System; public sealed class ClosePopupCommand : IDisposable { private readonly object disposeLock = new object(); private bool isDisposed; private bool isBusy = false; internal ClosePopupCommand() { } public event EventHandler CanExecuteChanged; public void Dispose() { lock (disposeLock) { if (isDisposed) return; // Here we have code that actually needs to be disposed off... isDisposed = true; } } } }"; var solution = CodeFactory.CreateSolution( new[] { viewModelBaseCode, popupViewModelCode, closePopupCommandCode }, CodeFactory.DefaultCompilationOptions(Analyzer, AnalyzerAssert.SuppressedDiagnostics), AnalyzerAssert.MetadataReferences); AnalyzerAssert.NoDiagnostics(Analyze.GetDiagnostics(Analyzer, solution)); }
public void WhenUsingImmutableProperty() { var fooCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public sealed class Foo : INotifyPropertyChanged { private Bar bar; public event PropertyChangedEventHandler PropertyChanged; public Bar Bar { get => this.bar; set { if (ReferenceEquals(value, this.bar)) { return; } this.bar = value; this.OnPropertyChanged(); } } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var barCode = @" namespace RoslynSandbox { public class Bar { public Bar(int value) { Value = value; } public int Value { get; } } }"; var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class FooCondition : Condition { public FooCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Bar), () => foo.Bar.Value == 2) { } } }"; AnalyzerAssert.NoDiagnostics <GUREA02ObservableAndCriteriaMustMatch>(fooCode, barCode, testCode); }