Skip to content

Releases: joezhuo2/ObjectPoolLinter

ObjectPoolLinter 1.5.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 02:31

Added

  • Code fixes for OPL002, in a new HiddenAllocationCodeFixProvider. Each is offered only for the shapes
    it can rewrite without changing behaviour; the others are still reported, with no fix.
    • Cache the lambda in a field assigned in Awake(): Run(() => count + 1) becomes Run(_next),
      the lambda is assigned to _next in Awake() (added when the class has none), and each captured
      local becomes a field whose declaration turns into an assignment. Offered on a MonoBehaviour for
      lambdas that capture no parameter, call no local function and are not nested in another lambda,
      when every captured local is declared alone, with an initializer, outside a loop.
    • Cache the delegate in a field assigned in Awake(): Action callback = Spawn; becomes
      Action callback = _spawn; with _spawn = Spawn; in Awake(). Offered for methods of the class
      itself and static methods, not for other.Method or local functions.
    • Build the string with a reused StringBuilder: var text = $"hp: {hp}"; becomes
      _textBuilder.Clear().Append("hp: ").Append(hp); and var text = _textBuilder.ToString();, with a
      readonly StringBuilder field and using System.Text; added when missing. Struct, enum and array
      holes are appended as (object)value so they format as interpolation does. Not offered for
      alignment or format clauses, conditionally evaluated strings, or statements that have side effects
      before the string.
    • Replace LINQ with a loop filling a reused List<T>: Where(...).ToList(),
      Select(...).ToList() and Where(...).Select(...).ToList() over a List<T> or an array, with
      single-parameter expression lambdas, become a for loop that clears and fills a readonly List<T>
      field, and the result refers to that list.
  • 15 tests, for 154 in total.

Changed

  • docs/rules/OPL002.md has a Code fixes section with before-and-after code and
    the exact conditions for each fix. The README, the Unity package README and the NuGet description
    mention the new fixes.

Notes

  • The new fixes have no fix-all support: each picks a free field name from the document as it stands,
    so fixes applied in one batch could pick the same name.
  • The StringBuilder fix still allocates the final string, which OPL002 keeps reporting as
    StringBuilder.ToString(). The LINQ fix returns the same list on every run, so a result kept past the
    frame must be copied.

ObjectPoolLinter 1.4.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 01:15

Added

  • OPL002 reports explicit string building in hot paths:
    • string.Concat(...), every overload (two or more strings or objects, the params form, and
      IEnumerable<string>), as string.Concat();
    • string.Format(...), every overload including those taking an IFormatProvider, as
      string.Format();
    • StringBuilder.ToString() and StringBuilder.ToString(int, int), as StringBuilder.ToString().
      Reusing a StringBuilder avoids intermediate strings, but each ToString() still allocates the
      result.
  • The implicit params array built for a string.Concat or string.Format call, and the boxing of
    value-type arguments passed to one, are part of the call's allocation and are not reported again.
    a + b, which compiles to string.Concat, is still reported once as string concatenation.
  • 5 tests, for 139 in total.

Changed

  • The OPL002 descriptor description, docs/rules/OPL002.md, the README and the
    Unity package README list the new constructs.

ObjectPoolLinter 1.3.0

Choose a tag to compare

@github-actions github-actions released this 14 Sep 02:39

Added

  • OPL002, Hidden allocation in hot path, Info by default. It reports allocations with no new in
    the source, in the same hot paths OPL001 watches: string concatenation (reported once per + chain,
    constants excluded) and interpolation, lambdas that capture a local, a parameter or this,
    method groups converted to delegates (static ones only below C# 11, which caches them), implicit
    params arrays with at least one element, LINQ method chains (reported once, on the outermost call)
    and query expressions, boxing of an existing value (object o = count;), and struct calls to
    object, ValueType or Enum methods the struct does not override. It stays out of OPL001's way:
    new expressions, including new Action(Spawn) and a struct boxed as it is created, are not
    reported twice. It is Info rather than Warning so it does not bury OPL001; the Unity Console shows it
    only after dotnet_diagnostic.OPL002.severity = warning. Documented in
    docs/rules/OPL002.md.
  • OPL003, Allocating Unity API in hot path, Warning by default. It reports any method or property
    getter declared in the core UnityEngine namespace that returns an array
    (GetComponentsInChildren<T>(), Physics.RaycastAll, Camera.allCameras, Input.touches,
    Mesh.vertices), plus reads of Object.name, Component.tag and GameObject.tag. Buffer-filling
    overloads, property writes, and managed packages such as UnityEngine.UI are not matched.
    GameObject.Find is not reported, because it allocates nothing. The message names the returned
    type: 'Physics.RaycastAll' returns a new 'RaycastHit[]' on every call inside the frequently-called method 'Update'. Documented, with a non-allocating replacement for each API, in
    docs/rules/OPL003.md.
  • Both rules honour object_pool_linter.additional_hot_methods and object_pool_linter.excluded_types.
  • The sample interpolates a string and reads Camera.allCameras in Update, and its .editorconfig
    raises OPL002 to a warning. build/verify-sample.ps1 now matches all three rules and identifies each
    warning by rule ID as well as allocation and method.
  • 31 tests for the new rules, for 134 in total.

Changed

  • The hot-path detection and .editorconfig parsing moved out of ObjectPoolAnalyzer into a shared
    HotPathDetector, so the three rules agree on which methods are hot. No behavior change for OPL001.
  • The README's Known limitations, the OPL001 page and the Unity package README describe the three
    rules and the gaps that remain, replacing the note that these allocations were planned as OPL002+.

ObjectPoolLinter 1.2.0

Choose a tag to compare

@github-actions github-actions released this 14 Sep 02:16

Added

  • OPL001 reads two .editorconfig options. Closes A9.
    • object_pool_linter.additional_hot_methods: comma-separated method names treated as hot paths in
      addition to the 18 built-in Unity messages, for custom update loops (Tick, Simulate) and
      messages the list leaves out (OnPreCull). A bare name matches on any type with any signature;
      Type.Method limits the entry to one type.
    • object_pool_linter.excluded_types: comma-separated type names, simple or namespace-qualified,
      whose methods are never reported. It applies to methods declared on the listed type, not to
      derived types, and wins over additional_hot_methods.
    • Names are case-sensitive and options are read per file. Documented under
      Configuration, including the caveat that Unity's own editor
      compile has not been verified to pass the options to analyzers.
  • The sample has an .editorconfig that adds Tick and excludes LoadingScreen;
    build/verify-sample.ps1 expects the new Tick warning and none from LoadingScreen.

ObjectPoolLinter 1.1.0

Choose a tag to compare

@github-actions github-actions released this 14 Sep 02:16

Added

  • OPL001 reports a struct that is boxed as it is created in a hot path: object o = new MyStruct();,
    a cast to object or an interface, or a struct passed or returned as one. The message names the
    target type: 'new MyStruct boxed to object' allocates inside the frequently-called method 'Update'.
    Previously the value-type filter dropped these before the conversion was considered. Boxing an
    existing value (object o = count;), new int?() (which boxes to null) and struct calls to
    non-overridden object methods are still not reported. Closes A8.
  • On a boxed struct, the TODO-comment fix suggests keeping the value typed as the struct or reusing a
    single box. The object-pool Get() fix is not offered there, because a pooled struct is boxed
    again at the same conversion.
  • The sample boxes a Vector3 in Update; build/verify-sample.ps1 expects the new warning.

Changed

  • Removed a dead clause from the value-type check in the OPL001 analyzer:
    type.IsValueType && type is not IArrayTypeSymbol is now type.IsValueType. Array types are
    never value types, so the second clause could not change the result. No behavior change.
    Closes A7.

ObjectPoolLinter 1.0.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 02:55

First published release: the ObjectPoolLinter package on nuget.org, plus the Unity
.unitypackage and UPM .tgz attached to the GitHub release. The 0.x versions below were never
published.

Changed

  • The OPL001 message names the allocation consistently and puts it first:
    'new List<int>' allocates inside the frequently-called method 'Update'. Allocations are named
    from the resolved type rather than the source text, so new System.Collections.Generic.List<int>(),
    new List<int>() and new() all read new List<int>, and arrays read as their type
    (new int[]) instead of echoing the size (int[10]). Instantiate calls read
    'Instantiate' allocates inside ... rather than 'Instantiate' is allocated inside ....
    Anything that parses the message text needs the new wording; build/verify-sample.ps1 is updated.
  • The message format arguments are in reading order: {0} is the allocation, {1} the method.
    Closes A6.
  • OPL001 moved from AnalyzerReleases.Unshipped.md to a Release 1.0.0 section in
    AnalyzerReleases.Shipped.md.

Build

  • The release workflow publishes to nuget.org with Trusted Publishing instead of the static
    NUGET_API_KEY secret. NuGet/login@v1 exchanges the job's GitHub OIDC token for a one-hour API
    key, so no long-lived key is stored. The workflow now requests id-token: write and reads the
    nuget.org profile name from the NUGET_USER secret.