https://github.com/butr/butr.harmony.analyzer
Roslyn analyzer for Harmony.
https://github.com/butr/butr.harmony.analyzer
harmony roslyn-analyzer
Last synced: about 1 month ago
JSON representation
Roslyn analyzer for Harmony.
- Host: GitHub
- URL: https://github.com/butr/butr.harmony.analyzer
- Owner: BUTR
- License: mit
- Created: 2021-12-03T14:12:14.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-07-07T11:33:15.000Z (almost 2 years ago)
- Last Synced: 2024-11-02T04:05:44.532Z (7 months ago)
- Topics: harmony, roslyn-analyzer
- Language: C#
- Homepage:
- Size: 221 KB
- Stars: 8
- Watchers: 3
- Forks: 1
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# BUTR.Harmony.Analyzer
A Roslyn analyzer for [`Harmony`](https://github.com/pardeike/Harmony) which adds the ability to do dynamic type checking and ensures that there are no typos when using the AccessTools* methods.
For example, if the user wants to access `_privateField` from some class/struct, but typed instead `_privateFld`, the analyzer will highlight that. It leverages the [`System.Reflection.Metadata`](https://www.nuget.org/packages/System.Reflection.Metadata/) package for fast analysys or public and non-public members of types, since Roslyn can't access non public members.
This drastically reduces runtime errors when using Harmony.
Also, when speaking in long-term maintenance of mods, if the game's internal API changes and a type member will be renamed or it will be changed to another type (e.g. field to a property), the analyzer will highlight that.
![]()
```csharp
// The analyzer works only when full data is provided for the method in compile-time
// so the following methods will work:
AccessTools.Method(typeof(Class), "MemberName");
AccessTools.Method("System.Class:MemberName");// But this won't be supported, because the information will be available only at runtime
Type type = ExternalMethod();
AccessTools.Method(type, "MemberName");
```## Rules
You'll find the rules in the documentation: [the rules and their explanation](https://github.com/BUTR/BUTR.Harmony.Analyzer/tree/master/docs)
## Installation
- NuGet package (recommended):
## Supported API
Supports `AccessTools` classes from [`Harmony`](https://github.com/pardeike/Harmony), [`HarmonyX`](https://github.com/BepInEx/HarmonyX) and [`Harmony.Extensions`](https://github.com/BUTR/Harmony.Extensions).
As long as the class starts with `AccessTools`, it will be supported.
The following API's are supported:
* Constructor/DeclaredConstructor
* Field/DeclaredField
* Property/DeclaredProperty
* Method/DeclaredMethod
* PropertyGetter/DeclaredPropertyGetter
* PropertySetter/DeclaredPropertySetter
* Delegate/DeclaredDelegate
* FieldRefAccess
* StaticFieldRefAccess
* StructFieldRefAccess## Additional Analyzers
We provide conversions from static typed check from AccessTools and SymbolExtensions to dynamic string based, marked by default as suggestions.We believe that static typed member check (via `typeof(Type)`) adds more problems than it solves, because we are bound to the public ABI of the library that is patched.
Instead, we suggest to use dynamic typed member check (via a string containing the full name of the type).
Common sense would suggest that this is a bad idea, since you can't check whether the member you want to get exists, but the sole purpose of `BUTR.Harmony.Analyzer` is to solve this exact problem by creating warnings at compile time if the type was not found.One of the most common problems that is solved is type namespace moving, since it breaks the public ABI.
Usually, the modder won't notice that a type was moved if both old and new namespaces are referenced and the full name of the type is not used. It will compile, but won't be binary compatible.
The dynamic typed check requires the full name of the type, so a namespace change will create a warning that the type does not exists.
There is a edge case that is not covered by the analyzer - moving a type within different assemblies with keeping the exact namespace.