[CanBeNull] object Test() { ... }
void UseTest()
{
var p = Test();
var s = p.ToString(); // Warning: Possible 'System.NullReferenceException'
}
[NotNull] object Foo()
{
return null; // Warning: Possible 'null' assignment
}
public void Foo([ItemNotNull]List<string> books)
{
foreach (var book in books)
{
if (book != null) // Warning: Expression is always true
{
Console.WriteLine(book.ToUpper());
}
}
}
public void Foo([ItemCanBeNull]List<string> books)
{
foreach (var book in books)
{
// Warning: Possible 'System.NullReferenceException'
Console.WriteLine(book.ToUpper());
}
}
[StringFormatMethod("message")]
void ShowError(string message, params object[] args) { ... }
void Foo()
{
ShowError("Failed: {0}"); // Warning: Non-existing argument in format string
}
void LogInfo([StructuredMessageTemplate]string message, params object[] args) { ... }
void Foo()
{
LogInfo("User created: {username}"); // Warning: Non-existing argument in format string
}
namespace TestNamespace
{
public class Constants
{
public static int INT_CONST = 1;
public const string STRING_CONST = "1";
}
public class Class1
{
[ValueProvider("TestNamespace.Constants")] public int myField;
public void Foo([ValueProvider("TestNamespace.Constants")] string str) { }
public void Test()
{
Foo(/*try completion here*/);//
myField = /*try completion here*/
}
}
}
void Foo([ValueRange(0, 100)] int value)
{
if (value == -1) // Warning: Expression is always 'false'
{
...
}
}
void Foo([NonNegativeValue] int value)
{
if (value == -1) // Warning: Expression is always 'false'
{
...
}
}
void Foo(string param)
{
if (param == null)
throw new ArgumentNullException("par"); // Warning: Cannot resolve symbol
}
public class ObservableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void NotifyChanged(string propertyName) { ... }
string _name;
public string Name
{
get { return _name; }
set { _name = value; NotifyChanged("LastName"); /* Warning */ }
}
}
Examples of generated notifications:
Function Definition Table syntax:
[ContractAnnotation("=> halt")]
public void TerminationMethod()
[ContractAnnotation("null <= param:null")] // reverse condition syntax
public string GetName(string surname)
[ContractAnnotation("s:null => true")]
public bool IsNullOrEmpty(string s) // string.IsNullOrEmpty()
// A method that returns null if the parameter is null,
// and not null if the parameter is not null
[ContractAnnotation("null => null; notnull => notnull")]
public object Transform(object data)
[ContractAnnotation("=> true, result: notnull; => false, result: null")]
public bool TryParse(string s, out Person result)
[LocalizationRequiredAttribute(true)]
class Foo
{
string str = "my string"; // Warning: Localizable string
}
[CannotApplyEqualityOperator]
class NoEquality { }
class UsesNoEquality
{
void Test()
{
var instance1 = new NoEquality();
var instance2 = new NoEquality();
if (instance1 != null) // OK
{
bool condition = instance1 == instance2; // Warning
}
}
}
struct StructWithDefaultEquality { /* no Equals & GetHashCode override */ }
class MySet<[DefaultEqualityUsage] T> { ... }
static class Extensions
{
public static MySet<T> ToMySet<[DefaultEqualityUsage] T>(this IEnumerable<T> items) { ... }
}
class MyList<T>
{
public int IndexOf([DefaultEqualityUsage] T item) { ... }
}
class UsesDefaultEquality
{
void Test()
{
var list = new MyList<StructWithDefaultEquality>();
// Warning: Default equality of struct 'StructWithDefaultEquality' is used
list.IndexOf(new StructWithDefaultEquality());
// Warning: Default equality of struct 'StructWithDefaultEquality' is used
var set1 = new MySet<StructWithDefaultEquality>();
// Warning: Default equality of struct 'StructWithDefaultEquality' is used
var set2 = new StructWithDefaultEquality[1].ToMySet();
}
}
[BaseTypeRequired(typeof(IComponent)] // Specify requirement
class ComponentAttribute : Attribute { }
[Component] // ComponentAttribute requires implementing IComponent interface
class MyComponent : IComponent { }
[UsedImplicitly]
public class TypeConverter { }
public class SummaryData
{
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)]
public SummaryData() { }
}
[UsedImplicitly(ImplicitUseTargetFlags.WithInheritors | ImplicitUseTargetFlags.Default)]
public interface IService { }
[Pure] int Multiply(int x, int y) => x * y;
void M()
{
Multiply(123, 42); // Warning: Return value of pure method is not used
}
[MustUseReturnValue("Use the return value to...")].
class Foo
{
[ProvidesContext] IBarService _barService = ...;
void ProcessNode(INode node)
{
DoSomething(node, node.GetGlobalServices().Bar);
// ^ Warning: use value of '_barService' field
}
}
[SourceTemplate]
public static void forEach<T>(this IEnumerable<T> xs)
{
foreach (var x in xs)
{
//$ $END$
}
}
[SourceTemplate, Macro(Target = "item", Expression = "suggestVariableName()")]
public static void forEach<T>(this IEnumerable<T> collection)
{
foreach (var item in collection)
{
//$ $END$
}
}
Applying the attribute to a template method parameter:
[SourceTemplate]
public static void something(this Entity x, [Macro(Expression = "guid()", Editable = -1)] string newguid)
{
/*$ var $x$Id = "$newguid$" + x.ToString();
x.DoSomething($x$Id); */
}
public class MyStringCollection : List<string>
{
[CollectionAccess(CollectionAccessType.Read)]
public string GetFirstString()
{
return this.ElementAt(0);
}
}
class Test
{
public void Foo()
{
// Warning: Contents of the collection is never updated
var col = new MyStringCollection();
string x = col.GetFirstString();
}
}
static void ThrowIfNull<T>([NoEnumeration] T v, string n) where T : class
{
// custom check for null but no enumeration
}
void Foo(IEnumerable<string> values)
{
ThrowIfNull(values, nameof(values));
var x = values.ToList(); // No warnings about multiple enumeration
}
void Foo([LanguageInjection(InjectedLanguage.CSS, Prefix = "body{", Suffix = "}")] string cssProps)
{
// cssProps should only contain a list of CSS properties
}
void Bar([LanguageInjection("json")] string json)
{
}
[ActionName("Foo")]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = Url.Action("Foo"); // OK
return RedirectToAction("Bar"); // Error: Cannot resolve action
}
public class BaseTestClass<[MeansTestSubject] T>
{
protected T Component { get; }
}
public class CalculatorAdditionTests : BaseTestClass<Calculator>
{
[Test]
public void Should_add_two_numbers()
{
Assert.That(Component.Add(2, 3), Is.EqualTo(5));
}
}
public class User
{
private string Name;
[CqrsCommand]
public void SetUserNameCommand(string newName)
{
if (newName == GetUserName()) // Warning about 'GetUserName' is called from Command but belongs to the Query
return;
Name = newName;
}
[CqrsQuery]
public string GetUserName() // Suggestion to rename it to the 'GetUserNameQuery'
{
return Name;
}
}
public class User
{
private string Name;
[CqrsCommand]
public void SetUserNameCommand(string newName)
{
if (newName == GetUserName()) // Warning about 'GetUserName' is called from Command but belongs to the Query
return;
Name = newName;
}
[CqrsQuery]
public string GetUserName() // Suggestion to rename it to the 'GetUserNameQuery'
{
return Name;
}
}
[CqrsCommandHandler]
public class UserCommandHandler
{
public void Handle(SetUserNameCommand command)
{
var query = new GetUserNameQuery() { Id = command.Id }; // Warning about Query use inside Command
var handler = new UserQuery(); // Warning about using Query inside Command
if (command.Name == handler.Handle(query)) // Warning about using Query inside Command
return;
// ...
}
}
[CqrsQueryHandler]
public class UserQuery // Suggestion to rename to the 'UserQueryHandler'
{
public string Handle(GetUserNameQuery query)
{
return ...;
}
}
[CqrsCommandHandler]
public class UserCommandHandler
{
public void Handle(SetUserNameCommand command)
{
var query = new GetUserNameQuery() { Id = command.Id }; // Warning about using Query inside Command
var handler = new UserQuery(); // Warning about using Query inside Command
if (command.Name == handler.Handle(query)) // Warning about using Query inside Command
return;
// ...
}
}
[CqrsQueryHandler]
public class UserQuery // Suggestion to rename to the 'UserQueryHandler'
{
public string Handle(GetUserNameQuery query)
{
return ...;
}
}
public class User
{
private string Name;
[CqrsCommand]
public void SetUserNameCommand(string newName)
{
if (newName == GetUserName()) // Warning about 'GetUserName' being called from Command but belongs to the Query
return;
Name = newName;
CheckName();
}
[CqrsQuery]
public string GetUserName() // Suggestion to rename it to the 'GetUserNameQuery'
{
CheckName();
return Name;
}
[CqrsExcludeFromAnalysis]
public bool CheckName() // Although this method is used both in Command and Query, will be ignored in all CQRS analyzes
{
...
}
}