public void SubclassingNinjectModule() { var testCode = @" namespace RoslynSandbox { using System; using Ninject.Modules; internal class Foo : NinjectModule { ↓private readonly IDisposable disposable = new Disposable(); public override void Load() { throw new NotImplementedException(); } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using Ninject.Modules; internal class Foo : NinjectModule { private readonly IDisposable disposable = new Disposable(); private bool disposed; public override void Load() { throw new NotImplementedException(); } public override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } base.Dispose(disposing); } protected virtual void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, testCode }, fixedCode); }
public void WhenNegatingNegatedCondition() { var fooConditionCode = @" 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) { } } }"; var barConditionCode = @" namespace RoslynSandbox { using System.Reactive.Linq; using Gu.Reactive; public class BarCondition : Condition { public BarCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class MegaMeh : AndCondition { public MegaMeh(Negated<FooCondition> notFooCondition, BarCondition barCondition) : base(notFooCondition.↓Negate(), barCondition) { } } }"; var fixedCode = @" namespace RoslynSandbox { using Gu.Reactive; public class MegaMeh : AndCondition { public MegaMeh(FooCondition fooCondition, BarCondition barCondition) : base(fooCondition, barCondition) { } } }"; AnalyzerAssert.CodeFix(Analyzer, Codefix, ExpectedDiagnostic, new[] { FooCode, fooConditionCode, barConditionCode, testCode }, fixedCode); }
public void Virtual() { var testCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; ↓public virtual int Value { get { return this.value; } private set { this.value = value; } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var fixedCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; public virtual int Value { get { return this.value; } private 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)); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, fixTitle: "Notify when value changes."); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, fixTitle: "Notify when value changes."); }
public void WithOverridingProperties() { var baseCode = @" namespace RoslynSandbox { public abstract class FooBase { public virtual int Value1 { get; protected set; } public abstract int Value2 { get; set; } protected virtual int Value3 { get; set; } } }"; var testCode = @" namespace RoslynSandbox { using System; public class Foo : FooBase, ↓IDisposable { public override int Value1 { get; protected set; } public override int Value2 { get; set; } protected override int Value3 { get; set; } } }"; var fixedCode = @" namespace RoslynSandbox { using System; public sealed class Foo : FooBase, IDisposable { private bool disposed; public override int Value1 { get; protected set; } public override int Value2 { get; set; } protected override int Value3 { get; set; } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; AnalyzerAssert.CodeFix(Fix, CS0535, new[] { baseCode, testCode }, fixedCode, "Implement IDisposable and make class sealed."); }
public void CallPrivateMethodRefParameterTwiceDifferentMethods() { var testCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo : IDisposable { private readonly Stream stream; public Foo() { this.Assign1(ref this.stream); this.Assign2(↓ref this.stream); } public void Dispose() { this.stream?.Dispose(); } private void Assign1(ref Stream arg) { arg = File.OpenRead(string.Empty); } private void Assign2(ref Stream arg) { arg = File.OpenRead(string.Empty); } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo : IDisposable { private readonly Stream stream; public Foo() { this.Assign1(ref this.stream); this.stream?.Dispose(); this.Assign2(ref this.stream); } public void Dispose() { this.stream?.Dispose(); } private void Assign1(ref Stream arg) { arg = File.OpenRead(string.Empty); } private void Assign2(ref Stream arg) { arg = File.OpenRead(string.Empty); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); }
public void StyleCopCallingBaseThrowIfDisposed() { var baseCode = @" namespace RoslynSandbox { using System; public class BaseClass : IDisposable { private bool disposed; public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } } protected virtual void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { ↓private readonly Stream stream = File.OpenRead(string.Empty); } }"; var fixedCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } base.Dispose(disposing); } protected override void ThrowIfDisposed() { if (this.disposed) { throw new System.ObjectDisposedException(this.GetType().FullName); } base.ThrowIfDisposed(); } } }"; AnalyzerAssert.CodeFix <IDISP006ImplementIDisposable, ImplementIDisposableCodeFixProvider>(new[] { baseCode, testCode }, fixedCode); AnalyzerAssert.FixAll <IDISP006ImplementIDisposable, ImplementIDisposableCodeFixProvider>(new[] { baseCode, testCode }, fixedCode); }
public void DisposeSecondMemberWhenOverriddenDisposeMethod() { var baseCode = @" namespace RoslynSandbox { using System; public class BaseClass : IDisposable { private bool disposed; public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } } protected void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { private readonly Stream stream1 = File.OpenRead(string.Empty); ↓private readonly Stream stream2 = File.OpenRead(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { this.stream1.Dispose(); } base.Dispose(disposing); } } }"; var fixedCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { private readonly Stream stream1 = File.OpenRead(string.Empty); private readonly Stream stream2 = File.OpenRead(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { this.stream1.Dispose(); this.stream2?.Dispose(); } base.Dispose(disposing); } } }"; AnalyzerAssert.CodeFix <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(new[] { baseCode, testCode }, fixedCode); AnalyzerAssert.FixAll <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(new[] { baseCode, testCode }, fixedCode); }
public void UglyViewModelBase() { var barCode = @" namespace RoslynSandbox { public class Bar { public int BarValue; } }"; var viewModelBaseCode = @" using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Reflection; namespace MVVM { /// <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 { #region Constructor protected ViewModelBase() { } #endregion // Constructor #region DisplayName /// <summary> /// Returns the user-friendly name of this object. /// Child classes can set this property to a new value, /// or override it to determine the value on-demand. /// </summary> public virtual string DisplayName { get => this.displayName; protected set { if (value == this.displayName) { return; } this.displayName = value; this.NotifyPropertyChanged(); } } #endregion // DisplayName #region Debugging Aides /// <summary> /// Warns the developer if this object does not have /// a public property with the specified name. This /// method does not exist in a Release build. /// </summary> [Conditional(""DEBUG"")] [DebuggerStepThrough] public void VerifyPropertyName(string propertyName) { // Verify that the property name matches a real, // public, instance property on this object. if (TypeDescriptor.GetProperties(this)[propertyName] == null) { string msg = ""Invalid property name: "" + propertyName; if (this.ThrowOnInvalidPropertyName) throw new Exception(msg); else Debug.Fail(msg); } } /// <summary> /// Returns whether an exception is thrown, or if a Debug.Fail() is used /// when an invalid property name is passed to the VerifyPropertyName method. /// The default value is false, but subclasses used by unit tests might /// override this property's getter to return true. /// </summary> protected virtual bool ThrowOnInvalidPropertyName { get; private set; } #endregion // Debugging Aides #region INotifyPropertyChanged Members /// <summary> /// Raised when a property on this object has a new value. /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Raises this object's PropertyChanged event. /// </summary> /// <param name=""propertyName"">The property that has a new value.</param> protected virtual void NotifyPropertyChanged(string propertyName) { this.VerifyPropertyName(propertyName); PropertyChangedEventHandler handler = this.PropertyChanged; if (handler != null) { var e = new PropertyChangedEventArgs(propertyName); handler(this, e); } } protected virtual void NotifyPropertyChangedAll(object inOjbect) { foreach (PropertyInfo pi in inOjbect.GetType().GetProperties()) { NotifyPropertyChanged(pi.Name); } } public virtual void Refresh() { NotifyPropertyChangedAll(this); } #endregion // INotifyPropertyChanged Members #region IDisposable Members readonly List<IDisposable> _disposables = new List<IDisposable>(); readonly object _disposeLock = new object(); bool _isDisposed; /// <summary> /// Invoked when this object is being removed from the application /// and will be subject to garbage collection. /// </summary> public void Dispose() { lock (_disposeLock) { this.OnDispose(); if (_isDisposed) return; foreach (var disposable in _disposables) disposable.Dispose(); _isDisposed = true; } } /// <summary> /// Child classes can override this method to perform /// clean-up logic, such as removing event handlers. /// </summary> protected virtual void OnDispose() { } #if DEBUG /// <summary> /// Useful for ensuring that ViewModel objects are properly garbage collected. /// </summary> ~ViewModelBase() { string msg = string.Format(""{0} ({1}) ({2}) Finalized"", this.GetType().Name, this.DisplayName, this.GetHashCode()); System.Diagnostics.Debug.WriteLine(msg); } #endif #endregion // IDisposable Members } }"; var testCode = @" namespace RoslynSandbox { using MVVM; public class Foo : ViewModelBase { private readonly Bar bar = new Bar(); ↓public int Value { get => this.bar.BarValue; set => this.bar.BarValue = value; } } }"; var fixedCode = @" namespace RoslynSandbox { using MVVM; public class Foo : ViewModelBase { private readonly Bar bar = new Bar(); public int Value { get => this.bar.BarValue; set => this.bar.BarValue = value; } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { viewModelBaseCode, barCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { viewModelBaseCode, barCode, testCode }, fixedCode); }
public void ImplementIDisposableAndMakeSealed() { var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo { ↓private readonly Stream stream = File.OpenRead(string.Empty); public Foo() { } public int Value { get; } protected virtual void Bar() { } private void Meh() { } } }"; var fixedCode = @" namespace RoslynSandbox { using System.IO; public sealed class Foo : System.IDisposable { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public Foo() { } public int Value { get; } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void Bar() { } private void Meh() { } private void ThrowIfDisposed() { if (this.disposed) { throw new System.ObjectDisposedException(this.GetType().FullName); } } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, "Implement IDisposable and make class sealed."); }
public void AddInterface() { var testCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public Foo() { } public int Value { get; } ↓public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void Bar() { } private void Meh() { } private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo : IDisposable { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public Foo() { } public int Value { get; } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } private void Bar() { } private void Meh() { } private void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } } }"; AnalyzerAssert.CodeFix <IDISP009IsIDisposable, ImplementIDisposableCodeFixProvider>(testCode, fixedCode); }
public void Constructor() { var testCode = @" namespace RoslynSandbox { public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Foo Create(int a, int b, int c, int d) { return new Foo↓( a, b, c, d); } } }"; var fixedCode = @" namespace RoslynSandbox { public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Foo Create(int a, int b, int c, int d) { return new Foo( a: a, b: b, c: c, d: d); } } }"; AnalyzerAssert.CodeFix <GU0001NameArguments, NameArgumentsCodeFixProvider>(testCode, fixedCode); }
public void UnsafeWhenNotInjectingChainedPropertyOnInjected() { var fooCode = @" namespace RoslynSandbox { public class Foo { private readonly Bar bar; public Foo(Bar bar) { this.bar = bar; } } }"; var barCode = @" namespace RoslynSandbox { public class Bar { } }"; var bazCode = @" namespace RoslynSandbox { public class Baz { public Baz(Bar bar) { this.Bar = bar; } public Bar Bar { get; } } }"; var mehCode = @" namespace RoslynSandbox { public class Meh : Foo { public Meh(Baz baz) : base(baz.↓Bar) { } } }"; var fixedCode = @" namespace RoslynSandbox { public class Meh : Foo { public Meh(Baz baz, Bar bar) : base(bar) { } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { fooCode, barCode, bazCode, mehCode }, fixedCode); }
public void UnsafeWhenNotInjectingChainedPassingInPropertyOfInjected() { var fooCode = @" namespace RoslynSandbox { public class Foo { private readonly Bar bar; public Foo(Bar bar) { this.bar = bar; } } }"; var barCode = @" namespace RoslynSandbox { public class Bar { private readonly int value; public Bar(int value) { this.value = value; } } }"; var bazCode = @" namespace RoslynSandbox { public class Baz { public int Value { get; } = 2; } }"; var mehCode = @" namespace RoslynSandbox { public class Meh : Foo { public Meh(Baz baz) : base(↓new Bar(baz.Value)) { } } }"; var fixedCode = @" namespace RoslynSandbox { public class Meh : Foo { public Meh(Baz baz, Bar bar) : base(bar) { } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { fooCode, barCode, bazCode, mehCode }, fixedCode); }
public void WhenPassingNegatedConditionToBaseCtorArgPerLine() { var fooConditionCode = @" 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) { } } }"; var barConditionCode = @" namespace RoslynSandbox { using System.Reactive.Linq; using Gu.Reactive; public class BarCondition : Condition { public BarCondition(Foo foo) : base( foo.ObservePropertyChangedSlim(x => x.Value), () => foo.Value == 2) { } } }"; var testCode = @" namespace RoslynSandbox { using Gu.Reactive; public class MegaMeh : AndCondition { public MegaMeh( FooCondition fooCondition, BarCondition barCondition) : base( fooCondition.↓Negate(), barCondition) { } } }"; var fixedCode = @" namespace RoslynSandbox { using Gu.Reactive; public class MegaMeh : AndCondition { public MegaMeh( Negated<FooCondition> notFooCondition, BarCondition barCondition) : base( notFooCondition, barCondition) { } } }"; AnalyzerAssert.CodeFix <GUREA07DontNegateCondition, InjectNegatedCodeFix>(new[] { FooCode, fooConditionCode, barConditionCode, testCode }, fixedCode); }
public void AssignedAffectsCalculatedPropertyOnPropertyChanged() { var testCode = @" namespace RoslynSandbox.Client { public class ViewModel : RoslynSandbox.Core.ViewModelBase { private string firstName; private string lastName; public string FullName => $""{this.FirstName} {this.LastName}""; public string FirstName { get { return this.firstName; } set { if (value == this.firstName) { return; } ↓this.firstName = value; this.OnPropertyChanged(); } } public string LastName { get { return this.lastName; } set { if (value == this.lastName) { return; } this.lastName = value; this.OnPropertyChanged(); this.OnPropertyChanged(nameof(this.FullName)); } } } }"; var fixedCode = @" namespace RoslynSandbox.Client { public class ViewModel : RoslynSandbox.Core.ViewModelBase { private string firstName; private string lastName; public string FullName => $""{this.FirstName} {this.LastName}""; public string FirstName { get { return this.firstName; } set { if (value == this.firstName) { return; } this.firstName = value; this.OnPropertyChanged(); this.OnPropertyChanged(nameof(this.FullName)); } } public string LastName { get { return this.lastName; } set { if (value == this.lastName) { return; } this.lastName = value; this.OnPropertyChanged(); this.OnPropertyChanged(nameof(this.FullName)); } } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { ViewModelBaseCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { ViewModelBaseCode, testCode }, fixedCode); }
public void ImplementIDisposableWithVirtualDisposeMethod() { var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo { ↓private readonly Stream stream = File.OpenRead(string.Empty); public Foo() { } public int Value { get; } public int this[int value] { get { return value; } } protected virtual void Bar() { } private void Meh() { } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.IO; public class Foo : IDisposable { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public Foo() { } public int Value { get; } public int this[int value] { get { return value; } } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } protected virtual void Bar() { } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } } protected virtual void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().FullName); } } private void Meh() { } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, "Implement IDisposable with virtual dispose method."); }
public void SubclassStreamReader() { var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo : StreamReader { ↓private readonly Stream stream = File.OpenRead(string.Empty); public Foo(string path) : base(path) { } } }"; var fixedCode = @" namespace RoslynSandbox { using System.IO; public class Foo : StreamReader { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public Foo(string path) : base(path) { } protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } base.Dispose(disposing); } protected virtual void ThrowIfDisposed() { if (this.disposed) { throw new System.ObjectDisposedException(this.GetType().FullName); } } } }"; AnalyzerAssert.CodeFix <IDISP006ImplementIDisposable, ImplementIDisposableCodeFixProvider>(testCode, fixedCode); AnalyzerAssert.FixAll <IDISP006ImplementIDisposable, ImplementIDisposableCodeFixProvider>(testCode, fixedCode); }
public void Vanguard_MVVM_ViewModels_MainWindowViewModel() { var childDataContext = @" namespace Vanguard_MVVM.ViewModels { public interface IChildDataContext { string Title { get; } } }"; var testCode = @" namespace Vanguard_MVVM.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel; public sealed class MainWindowViewModel : INotifyPropertyChanged { IChildDataContext _childDataContext; readonly string _title; MainWindowViewModel() { _title = ""MVVM Attempt""; } public IChildDataContext ChildDataContext { get { return _childDataContext; } private set { if (Equals(value, _childDataContext)) return; ↓_childDataContext = value; NotifyPropertyChanged(nameof(ChildDataContext)); } } public static MainWindowViewModel Instance { get; } = new MainWindowViewModel(); public string Title => ChildDataContext?.Title == null ? _title : string.Concat(_title, "" - "", ChildDataContext?.Title); public event PropertyChangedEventHandler PropertyChanged; void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }"; var fixedCode = @" namespace Vanguard_MVVM.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel; public sealed class MainWindowViewModel : INotifyPropertyChanged { IChildDataContext _childDataContext; readonly string _title; MainWindowViewModel() { _title = ""MVVM Attempt""; } public IChildDataContext ChildDataContext { get { return _childDataContext; } private set { if (Equals(value, _childDataContext)) return; _childDataContext = value; NotifyPropertyChanged(nameof(ChildDataContext)); NotifyPropertyChanged(nameof(Title)); } } public static MainWindowViewModel Instance { get; } = new MainWindowViewModel(); public string Title => ChildDataContext?.Title == null ? _title : string.Concat(_title, "" - "", ChildDataContext?.Title); public event PropertyChangedEventHandler PropertyChanged; void NotifyPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { childDataContext, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { childDataContext, testCode }, fixedCode); }
public void DisposeMemberWhenVirtualDisposeMethodUnderscoreNames() { var testCode = @" namespace RoslynSandbox { using System; public abstract class Foo : IDisposable { ↓private readonly IDisposable _disposable = new Disposable(); private bool _disposed; public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (_disposed) { return; } _disposed = true; if (disposing) { } } protected void ThrowIfDisposed() { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; var fixedCode = @" namespace RoslynSandbox { using System; public abstract class Foo : IDisposable { private readonly IDisposable _disposable = new Disposable(); private bool _disposed; public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (_disposed) { return; } _disposed = true; if (disposing) { _disposable.Dispose(); } } protected void ThrowIfDisposed() { if (_disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; AnalyzerAssert.CodeFix <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(new[] { DisposableCode, testCode }, fixedCode); AnalyzerAssert.FixAll <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(new[] { DisposableCode, testCode }, fixedCode); }
public void AutoPropertyWhenRecursionInTrySet() { var viewModelBaseCode = @" namespace RoslynSandbox.Core { using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; public abstract class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected bool TrySet<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null) { return this.TrySet(ref field, newValue, propertyName); } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var testCode = @" namespace RoslynSandbox.Client { public class Foo : RoslynSandbox.Core.ViewModelBase { ↓public int Bar { get; set; } } }"; var fixedCode = @" namespace RoslynSandbox.Client { public class Foo : RoslynSandbox.Core.ViewModelBase { private int bar; public int Bar { get => this.bar; set { if (value == this.bar) { return; } this.bar = value; this.OnPropertyChanged(); } } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { viewModelBaseCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { viewModelBaseCode, testCode }, fixedCode); }
public void DisposeMemberWhenVirtualDisposeMethod() { var testCode = @" namespace RoslynSandbox { using System; using System.IO; public class Foo : IDisposable { ↓private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } } protected void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.IO; public class Foo : IDisposable { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { this.stream?.Dispose(); } } protected void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; AnalyzerAssert.CodeFix <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(testCode, fixedCode); AnalyzerAssert.FixAll <IDISP002DisposeMember, DisposeMemberCodeFixProvider>(testCode, fixedCode); }
public void AssignedInCoalesce() { var testCode = @" namespace RoslynSandbox { using System; public sealed class Foo : IDisposable { ↓private readonly IDisposable created; private bool disposed; public Foo(IDisposable injected) { this.Disposable = injected ?? (this.created = new Disposable()); } public IDisposable Disposable { get; } public void Dispose() { if (this.disposed) { return; } this.disposed = true; } } }"; var fixedCode = @" namespace RoslynSandbox { using System; public sealed class Foo : IDisposable { private readonly IDisposable created; private bool disposed; public Foo(IDisposable injected) { this.Disposable = injected ?? (this.created = new Disposable()); } public IDisposable Disposable { get; } public void Dispose() { if (this.disposed) { return; } this.disposed = true; this.created?.Dispose(); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, testCode }, fixedCode); }
public void Constructor() { var testCode = @" namespace RoslynSandbox { public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Foo Create(int a, int b, int c, int d) { return new Foo↓( a, b, c, d); } } }"; var fixedCode = @" namespace RoslynSandbox { public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Foo Create(int a, int b, int c, int d) { return new Foo( a: a, b: b, c: c, d: d); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); }
public void DisposeFirstMemberWhenOverriddenDisposeMethodEmptyBlock() { var baseCode = @" namespace RoslynSandbox { using System; public class BaseClass : IDisposable { private bool disposed; public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } } protected void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(GetType().FullName); } } } }"; var testCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { ↓private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { } base.Dispose(disposing); } } }"; var fixedCode = @" namespace RoslynSandbox { using System.IO; public class Foo : BaseClass { private readonly Stream stream = File.OpenRead(string.Empty); private bool disposed; protected override void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { this.stream?.Dispose(); } base.Dispose(disposing); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { baseCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { baseCode, testCode }, fixedCode); }
public void AssigningFieldViaRefParameterInCtor() { var testCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo : IDisposable { ↓private readonly Stream stream; public Foo() { if (TryGetStream(ref this.stream)) { } } public bool TryGetStream(ref Stream outValue) { outValue = File.OpenRead(string.Empty); return true; } public void Dispose() { } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.IO; public sealed class Foo : IDisposable { private readonly Stream stream; public Foo() { if (TryGetStream(ref this.stream)) { } } public bool TryGetStream(ref Stream outValue) { outValue = File.OpenRead(string.Empty); return true; } public void Dispose() { this.stream?.Dispose(); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); }
public void WhenCallingBaseDispose() { var baseCode = @" namespace RoslynSandbox { using System; public abstract class FooBase : IDisposable { private readonly IDisposable disposable = new Disposable(); private bool disposed; /// <inheritdoc/> public void Dispose() { this.Dispose(true); } protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } this.disposed = true; if (disposing) { this.disposable.Dispose(); } } } }"; var testCode = @" namespace RoslynSandbox { using System; public class Foo : FooBase { ↓private readonly IDisposable disposable = new Disposable(); protected override void Dispose(bool disposing) { base.Dispose(disposing); } } }"; var fixedCode = @" namespace RoslynSandbox { using System; public class Foo : FooBase { private readonly IDisposable disposable = new Disposable(); protected override void Dispose(bool disposing) { if (disposing) { this.disposable.Dispose(); } base.Dispose(disposing); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, baseCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { DisposableCode, baseCode, testCode }, fixedCode); }
public void WithTrivia() { var testCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Some text /// </summary> ↓public int Value { /*1*/ get { /*2*/ return this.value; /*3*/ } /*4*/ /*5*/ set /*6*/ { /*7*/ this.value = value; /*8*/ } /*9*/ } /*10*/ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var fixedCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private int value; public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// Some text /// </summary> public int Value { /*1*/ get { /*2*/ return this.value; /*3*/ } /*4*/ /*5*/ set /*6*/ { if (value == this.value) { return; } /*7*/ this.value = value; /*8*/ this.OnPropertyChanged(); } /*9*/ } /*10*/ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, fixTitle: "Notify when value changes."); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode, fixTitle: "Notify when value changes."); }
public void ConstructorInFunc() { var testCode = @" namespace RoslynSandbox { using System; public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Func<Foo> Create(int a, int b, int c, int d) { return () => new Foo↓( b: b, a: a, c: c, d: d); } } }"; var fixedCode = @" namespace RoslynSandbox { using System; public class Foo { public Foo(int a, int b, int c, int d) { this.A = a; this.B = b; this.C = c; this.D = d; } public int A { get; } public int B { get; } public int C { get; } public int D { get; } private Func<Foo> Create(int a, int b, int c, int d) { return () => new Foo( a: a, b: b, c: c, d: d); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, testCode, fixedCode); }
public void WithNestedBackingFieldUnderScore() { var barCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Bar : 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.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private readonly Bar _bar = new Bar(); public event PropertyChangedEventHandler PropertyChanged; ↓public int Value { get { return _bar.Value; } private set { _bar.Value = value; } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; var fixedCode = @" namespace RoslynSandbox { using System.ComponentModel; using System.Runtime.CompilerServices; public class Foo : INotifyPropertyChanged { private readonly Bar _bar = new Bar(); public event PropertyChangedEventHandler PropertyChanged; public int Value { get { return _bar.Value; } private set { if (value == _bar.Value) { return; } _bar.Value = value; OnPropertyChanged(); } } protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }"; AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { barCode, testCode }, fixedCode, fixTitle: "Notify when value changes."); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { barCode, testCode }, fixedCode, fixTitle: "Notify when value changes."); }
public void Check(TestCase check) { var testCode = @" namespace RoslynSandbox { using System; using System.ComponentModel; public class ViewModel : INotifyPropertyChanged { private Foo bar; public event PropertyChangedEventHandler PropertyChanged; public Foo Bar { get { return this.bar; } set { ↓if (ReferenceEquals(value, this.bar)) { return; } this.bar = value; this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Bar))); } } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { this.PropertyChanged?.Invoke(this, e); } } }"; var fixedCode = @" namespace RoslynSandbox { using System; using System.ComponentModel; public class ViewModel : INotifyPropertyChanged { private Foo bar; public event PropertyChangedEventHandler PropertyChanged; public Foo Bar { get { return this.bar; } set { if (Equals(value, this.bar)) { return; } this.bar = value; this.OnPropertyChanged(new PropertyChangedEventArgs(nameof(Bar))); } } protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { this.PropertyChanged?.Invoke(this, e); } } }"; testCode = testCode.AssertReplace("ReferenceEquals(value, this.bar)", check.Call); fixedCode = check.FixedCall == null ? fixedCode.AssertReplace("Equals(value, this.bar)", check.Call) : fixedCode.AssertReplace("Equals(value, this.bar)", check.FixedCall); AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, new[] { FooCode, testCode }, fixedCode); AnalyzerAssert.FixAll(Analyzer, Fix, ExpectedDiagnostic, new[] { FooCode, testCode }, fixedCode); }