Giter Club home page Giter Club logo

genericsanalyzer's People

Contributors

rekkonnect avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

genericsanalyzer's Issues

Emit diagnostics on function calls with implicit type arguments

Currently, it is speculated that no diagnostics will be emitted in the best case, with the worst being that the analyzer will crash attempting to report one on a nonexistent token.

An example case of this error occuring:

void Function
<
    [ProhibitedTypes(typeof(int))]
    T
>
(T v)
{
}

// usage
Function(5);

The error should be reported on the function's name, since there is no type to explicitly show it on.

Support copying the type constraint system of another type parameter

This would only require the creation of a new attribute, InheritTypeConstraintsAttribute, which has the following design specifications:

  • Only contains a single constructor, InheritTypeConstraintsAttribute(params string[] typeParameterNames).
  • Is used by referring to the type parameters to copy the type constraint system from, by using their names (because using type parameters in attributes is prohibited by the language).

Example:

class ObjectConverter
<
    [PermittedTypes(typeof(string), typeof(int))]
    [OnlyPermitSpecifiedTypes]
    T1,
    [InheritTypeConstraints(nameof(T1))] // for functions this is illegal as of now
    T2
>
{
}

Constraint scripting "language" used through attribute compiling it

Credits

Suggested by @KoziLord

Feature Review

The feature would implement a way for the user to specify the constriants in a more natural way through a variation of C#'s syntax for generic constraints that would be parsed and compiled. Syntax errors will be reported as diagnostic errors within the string.

Syntax Error Reporting

The diagnostics reported for syntax errors within the scripting code will have to make use of a brand new rule prefix, GAS. This is so that it can follow the respective C# error rule ID system, without reporting actual CS errors.

Example

Here is an example of an early concept of the implemenation:

[TypeConstraintScript(
@"
IEquatable<int>, IEnumerable<string>, new();
(class; unmanaged), IEquatable<long>, IEnumerable<char>
")]

In that example, the , denotes an AND, ; denotes an OR, and parentheses work as better proioritizing the expression within them. AND has a higher priority than OR, meaning that the first line is a constraint, and the second line is another constraint, requiring that one of the two constraints be met.

More specifically, the type argument must meet one of the following criteria in this case:

  • Implement IEquatable<int>, IEnumerable<string>, and have a new() constructor, OR
  • Be either a class, or an unmanaged struct, and also implement IEquatable<long>, IEnumerable<char>

Passes:

struct S0 : IEquatable<int>, IEnumerable<string>
{
    // implement interfaces
}

Fails:

struct S1 : IEquatable<long>, IEnumerable<char>
{
    private string s;
    // implement interfaces
}

API Design

TODO

Fix Project Directories

Upon the solution's creation, the 5 initial projects (all but GenericsAnalyzer.Core) were included in a GenericsAnalyzer directory, instead of being in the solution's root directory. For consistency (and to avoid some notable VS bugs when it comes to project dependencies), it would be good if they were all migrated to the root solution directory.

Support ability to specify that multiple generic type arguments must be distinct

Title currently sucks but the meaning is conveyed in some way or another

Functionality Design

This feature enables the end user to prevent usage of a type with type arguments that may match some criteria, with regards to other type arguments. For example, the currently considered possibilities are:

  • Different type arguments (T1 != T2)
    • Example: C<T1, T2> may be specified in a way where replacing both T1 and T2 with the same type argument is prevented
  • Non-related type arguments (T1 must not inherit T2)
    • Example: C<T1, T2> may be specified in a way where replacing T1 with a type that inherits T2 is prevented
    • Could also further specify that it would only check class inheritance tree, disregarding potentially mathcing interfaces
  • Type arguments' size must match or be related (sizeof(T1) == a * sizeof(T2))
    • Example: C<T1, T2> may be specified in a way where T1's size is equal to that of T2, or a fixed multiple of it
  • Type arguments both matching the same special constraints (class, struct, unmanaged)
    • Example: C<T1, T2> requires that both T1 and T2 suit either the class, the struct, or the unmanaged constraint
    • Consider applying this to more other special constraints like notnull, new() (could be adjusted by the time shapes arrive)

API Design

TODO

Implement the ability to only permit the specified types and prohibit everything else

The attribute should be named ProhibitNotPermittedTypes or OnlyPermitSpecifiedTypes.

That feature would also come with the following design specifications:

  • Prohibition attributes will be ignored (GA0010 will be emitted).
  • The attribute may only be added once per generic type parameter.
  • Lack of presence of this attribute may emit warning GA0011: Redundant explicit type permissions; no prohibitions or explicit specification for only permitting the specified permitted types via {attribute name}.
  • Using this attribute with no permission attributes emits error GA0012.

Implement diagnostics emitted by usage of type constraint attributes

Currently, the permitted type argument analyzer alone could use the following diagnostics:

  • GA0002
    • Code fix: removing all but the specified instance of the same type (based on the cursor's location)
  • GA0003
  • GA0004
    • Code fix: removing the specified constraint
  • GA0005
    • Code fix: removing the specified type constraint
  • GA0006
    • Code fix: adding the interface to the constraint clause of the appropriate type
  • GA0008
    • Code fix: changing the constraint for the type to an exact type one
  • GA0009
    • Code fix: removing the duplicates of the detected type in the same rule

Consider reporting the diagnostics on the nodes that represent the type, not the whole `typeof` expressions

Motivation

For diagnostics emitted in attribute argument syntax nodes that are typeof expressions, the error lies on the types themselves, not the fact that a typeof expression was used. Therefore, semantically it would make more sense to only highlight the type that was used instead of the whole expression.

Another benefit is that it reduces clutter by having smaller chunks of code being highlighted with red squiggles.

Drawbacks

Smaller type names will be harder to distinguish an error on. The main problem would be those with too short names, of up to about 3 letters which seem to be common enough. In a dense document, along with the syntax that generic type arguments come with, users could have a harder time distinguishing where the error is at without resorting to having the IDE navigate them.

Example

Current:

[Attribute(__typeof(int*)__, __typeof(void)__)]

Proposed:

[Attribute(typeof(__int*__), typeof(__void__)]

Base type parameter usage is misinterpreted

The feature revolving around presence of InheritBaseTypeUsageConstraintsAttribute in a type parameter does not properly evaluate the usage of the marked type parameter in the inherited types' type arguments.

In fact, what this would do is inherit the type constraints system from type parameters in the base type whose names matched the marked one's. This means that in the following example:

class A
<
    T,
    U,
    V,
    W
>

class B
<
    [InheritBaseTypeUsageConstraints]
    U,
    [InheritBaseTypeUsageConstraints]
    V,
    [InheritBaseTypeUsageConstraints]
    T
>
    : A<U, V, T, V>
  • B.U would inherit from A.U
  • B.V would inherit from A.V
  • B.T would inherit from A.T

when instead the following should happen:

  • B.U should inherit from A.T
  • B.V should inherit from A.U and A.W
  • B.T should inherit from A.V

This bug is being fixed in #33; the test case for GA0001 has been updated to properly reflect this fix

Add ability to inherit type constraints for specific type from inherited types

The attribute, named InheritBaseTypeUsageConstraintsAttribute should automatically inherit type constraints from the specific type's usage in base types.

For example:

class A
<
    [PermittedTypes(typeof(int), typeof(short))]
    [OnlyPermitSpecifiedTypes]
    T
>
{ }

class B
<
    [InheritBaseTypeUsageConstraints]
    T
> : A<T>
{ }

The type constraint system for B.T should only permit usage of the types int and short, just like A.T's.

This only applies to types that may use their declared type arguments when inheriting other types.

Specific type member constraints for generic type arguments

Credits

Suggested by @ZacharyPatten

Summary

This feature is about having specific constraints about requiring certain members, including fields, properties, functions, events, and so on.

Functionality Design

The available constraint information would be:

  • Member kind (required)
  • Member name (required)
  • Member accessibility (optional)
  • Member return type (optional)

For properties or events:

  • Accessors (optional)

For functions:

  • Argument types (optional)
  • Generic information (arity, constraints) (optional)

Such constraints can also be generalized on type constraint profiles.

API Design

Attributed Declaration

This feature introduces 6 new attributes that can be assigned to both interfaces (type constraint profiles) and directly on the type parameters themselves.

Each of those attributes declares that a required member of the specified member kind be declared with the aforementioned properties.

public class RequiredFieldTypeConstraintAttribute { }
public class RequiredPropertyTypeConstraintAttribute { }
public class RequiredEventTypeConstraintAttribute { }
public class RequiredMethodTypeConstraintAttribute { }
public class RequiredConstructorTypeConstraintAttribute { }

The only unsupported feature of attributed declaration is generic type constraint clauses. This is intentionally unsupported due to the complexity it adds to both the analyzer, and the end user that may wish to apply such constraints. Instead, templated declaration is preferred.

Templated Declaration

The aforementioned attributes may also be used in declaring the required member from an already explicitly declared member, acting as a template. In other words, a member found in a (preferably sealed) instance class type can act as a template for a required member declaration. Its accessibility, name, return type, etc. will all be taken into account. Instance class types are preferred for this case so that accessibility does not require an extra declaration attribute. An additional analyzer-internal identifier can be also declared on the member through the RequiredMemberTypeConstraintTemplateAttribute attribute.

Update docs regarding usage of the analyzer

Currently, the docs/usage.md file only covers the basics of the analyzer, which are not sufficient through the most recent changes of adding new features. The usage docs should be changed accordingly:

  • Consider the directory docs/guides which will contain such docs about usage of the analyzer
  • usage.md should be split into 4 separate documents, or chapters, that will cover the single most basic feature
  • New docs about profiles and constraint inheritance through all methods should be included
  • Future features will have to abide to that new framework too

Type constraint reasons

Add a Reason property in the type constraint attributes. This should probably only be allowed for prohibition attributes.

The feature would display the reason behind prohibiting usage of the specified type (or type argument) in emitted GA0001 and GA0017 diagnostics. It would be accompanied by the source of the prohibition.

JetBrains Rider support

There is a great portion of developers that use Rider, so this analyzer should also be available to that IDE.

Type constraint system inheritance collision handling

There is the case of using both the base type parameter inheritance and a locally declared type parameter inheritance attribute, in which case conflicting rules cannot be prioritized. This should yield an error:

  • GA0022: Type constraint inheritance results in a rule collision

Upgrade to .NET 5.0

The project is currently on .NET Standard 2.0. This dependency was used with creating the VSIX in mind. Ever since its deprecation, there is no real reason to not use .NET 5.0, since analyzers using that version are supported by the latest VS versions.

Support more generic type constraint patterns and rules

Credits

Idea from JiiLib

Concepts

  • Filter interfaces
  • Filter generic types (with potential specific arity)
  • Filter abstract classes
  • Filter arrays (with potential specific rank)

All of the above filters can be exclusive or excluded. An exclusive filter denotes that no other type is permitted (equivalent to "only"), whereas an excluded filter denotes that the specified type category is prohibited (equivalent to "not").

Attributes

TODO

Support type constraint profiles

Design

  • Interfaces can serve as type constraint profiles through the TypeConstraintProfileAttribute, as in the example:
[TypeConstraintProfile]
interface IExampleProfile { }
  • Type constraint attributes will have to also be valid on interfaces
    • This won't apply for inheritance-related attributes.

Type constraint profile interfaces can be inherited. Inheriting automatically inherits the base profiles' constraints.

Profile usage can be achieved through the InheritProfileTypeConstraintsAttribute:

[InheritProfileTypeConstraints(typeof(IExampleProfile))]
T

Using the profile automatically inherits the profile's type constraints. Multiple profiles may be used simultaneously. Conflicts emit GA0022.

Profile groups

Profile groups may restrict usage of multiple profiles that belong to the same group. Profile group interfaces may be declared like this:

[TypeConstraintProfileGroup]
interface IExampleProfileGroup { }

A profile may belong to multiple groups. Assigning profiles to groups happens in the attribute constructor:

[TypeConstraintProfile(typeof(IExampleProfileGroup), typeof(IExampleProfileGroup1))]
interface IExampleProfile { }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.