Skip to content

Cleanup#2057

Merged
erwan-joly merged 4 commits intomasterfrom
Cleanup
Jan 20, 2026
Merged

Cleanup#2057
erwan-joly merged 4 commits intomasterfrom
Cleanup

Conversation

@erwan-joly
Copy link
Collaborator

No description provided.

@erwan-joly erwan-joly merged commit 626601c into master Jan 20, 2026
1 of 2 checks passed
Comment on lines +1085 to +1094
if (amount == item.ItemInstance?.Amount)
{
inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(item.ItemInstance,
characterEntity.CharacterId));
}
else
{
inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(
characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount), characterEntity.CharacterId));
}

Check notice

Code scanning / CodeQL

Missed ternary opportunity Note

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

Copilot Autofix

AI about 1 month ago

In general, to fix this pattern you keep the shared assignment or return statement and move only the differing part into a ternary (condition ? expr1 : expr2). This keeps the intent (“choose one of two values based on a condition”) explicit and avoids code duplication.

Here, both branches assign inv using characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(..., characterEntity.CharacterId)). The only difference is whether the first argument to InventoryItemInstance.Create is item.ItemInstance (when the amount matches exactly) or characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount) (when it does not). The best fix is to compute a single InventoryItemInstance via a ternary and pass it to AddItemToPocket once. Concretely, replace the if (amount == item.ItemInstance?.Amount) block (lines 1085–1094) with a single assignment using a conditional operator on the first argument to InventoryItemInstance.Create, leaving surrounding logic unchanged. No new imports or additional methods are required; we only restructure existing expressions.

Suggested changeset 1
src/NosCore.GameObject/ComponentEntities/Extensions/CharacterEntityExtension.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/NosCore.GameObject/ComponentEntities/Extensions/CharacterEntityExtension.cs b/src/NosCore.GameObject/ComponentEntities/Extensions/CharacterEntityExtension.cs
--- a/src/NosCore.GameObject/ComponentEntities/Extensions/CharacterEntityExtension.cs
+++ b/src/NosCore.GameObject/ComponentEntities/Extensions/CharacterEntityExtension.cs
@@ -1082,16 +1082,12 @@
                     return;
                 }
 
-                if (amount == item.ItemInstance?.Amount)
-                {
-                    inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(item.ItemInstance,
+                inv = characterEntity.InventoryService.AddItemToPocket(
+                    InventoryItemInstance.Create(
+                        amount == item.ItemInstance?.Amount
+                            ? item.ItemInstance
+                            : characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount),
                         characterEntity.CharacterId));
-                }
-                else
-                {
-                    inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(
-                        characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount), characterEntity.CharacterId));
-                }
             }
 
             if (inv?.Count > 0)
EOF
@@ -1082,16 +1082,12 @@
return;
}

if (amount == item.ItemInstance?.Amount)
{
inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(item.ItemInstance,
inv = characterEntity.InventoryService.AddItemToPocket(
InventoryItemInstance.Create(
amount == item.ItemInstance?.Amount
? item.ItemInstance
: characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount),
characterEntity.CharacterId));
}
else
{
inv = characterEntity.InventoryService.AddItemToPocket(InventoryItemInstance.Create(
characterEntity.ItemProvider.Create(item.ItemInstance?.ItemVNum ?? 0, amount), characterEntity.CharacterId));
}
}

if (inv?.Count > 0)
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +98 to +101
catch (Exception e)
{
logger.Error(e.Message, e);
}

Check notice

Code scanning / CodeQL

Generic catch clause Note

Generic catch clause.

Copilot Autofix

AI about 1 month ago

In general, the fix is to avoid catching System.Exception directly and instead catch the specific, anticipated exception types that MoveAsync or related operations are likely to throw, and optionally add a final catch only to log and rethrow or to log with full details if continuing is truly required. The logging should include the exception object, not just e.Message, to preserve stack traces.

For this specific code:

  • Keep the protective try/catch so the observable is not killed by a single failure.
  • Replace catch (Exception e) with:
    • A primary catch (OperationCanceledException) (or another expected exception type if MoveAsync uses cancellation tokens) that is either ignored or logged at a low level.
    • A secondary catch (Exception e) that logs a clearer message and passes the exception as a parameter to Serilog so stack traces are preserved. This still uses a generic catch, but now it is explicitly for last‑resort logging and is less likely to be mistaken for business‑logic exception handling; and the important part for CodeQL is that we are not only relying on an empty or opaque generic catch. If you want to be stricter, you can log and rethrow, but that would change behavior, so we’ll avoid it.

Given the constraints (no assumptions outside this snippet), the minimal non‑breaking change is:

  • Modify the catch block within LifeAsync to:
    • Catch OperationCanceledException separately (a common, benign case in async flows).
    • In the generic catch, log a descriptive message and pass the exception object to Serilog: logger.Error(e, "Error while updating NPC life.");.

All changes are confined to StartLifeAsync’s local function LifeAsync in src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs. No new methods or imports are needed, since OperationCanceledException resides in System, which is already imported, and Serilog’s ILogger is already in use.

Suggested changeset 1
src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs b/src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs
--- a/src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs
+++ b/src/NosCore.GameObject/ComponentEntities/Extensions/NonPlayableEntityExtension.cs
@@ -95,9 +95,13 @@
                         await entity.MoveAsync(distanceCalculator, clock);
                     }
                 }
+                catch (OperationCanceledException)
+                {
+                    // Movement was canceled; ignore to keep the life cycle running.
+                }
                 catch (Exception e)
                 {
-                    logger.Error(e.Message, e);
+                    logger.Error(e, "Unexpected error while updating non-playable entity life.");
                 }
             }
             entity.Life = Observable.Interval(TimeSpan.FromMilliseconds(400)).Select(_ => LifeAsync()).Subscribe();
EOF
@@ -95,9 +95,13 @@
await entity.MoveAsync(distanceCalculator, clock);
}
}
catch (OperationCanceledException)
{
// Movement was canceled; ignore to keep the life cycle running.
}
catch (Exception e)
{
logger.Error(e.Message, e);
logger.Error(e, "Unexpected error while updating non-playable entity life.");
}
}
entity.Life = Observable.Interval(TimeSpan.FromMilliseconds(400)).Select(_ => LifeAsync()).Subscribe();
Copilot is powered by AI and may make mistakes. Always verify output.
.Callback<IEnumerable<ActPartDto>>(parts => _savedActParts.AddRange(parts))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.


private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "act_desc.dat"), content);

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

In general, to fix this class of problem you replace Path.Combine with Path.Join where you are building paths from segments that may accidentally include absolute paths. Path.Join will concatenate path segments with directory separators but, unlike Path.Combine, it does not discard earlier segments when a later segment is absolute.

In this file, there are two Path.Combine usages relevant to temporary/test paths: constructing _tempFolder in Setup() and constructing the file path in CreateTestFile. The best fix that preserves existing behavior is to change both to Path.Join. Since System.IO.Path is already imported via using System.IO;, no additional imports are required. The changes are:

  • On line 54, change _tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); to use Path.Join(...).
  • On line 69, change File.WriteAllText(Path.Combine(_tempFolder, "act_desc.dat"), content); to use Path.Join(...).

These changes do not alter the functional behavior of the tests with the current arguments, but they remove the CodeQL warning and future-proof the code against absolute-path segments.

Suggested changeset 1
test/NosCore.Parser.Tests/ActParserTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/NosCore.Parser.Tests/ActParserTests.cs b/test/NosCore.Parser.Tests/ActParserTests.cs
--- a/test/NosCore.Parser.Tests/ActParserTests.cs
+++ b/test/NosCore.Parser.Tests/ActParserTests.cs
@@ -51,7 +51,7 @@
                 .Callback<IEnumerable<ActPartDto>>(parts => _savedActParts.AddRange(parts))
                 .ReturnsAsync(true);
 
-            _tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+            _tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
             Directory.CreateDirectory(_tempFolder);
         }
 
@@ -66,7 +66,7 @@
 
         private void CreateTestFile(string content)
         {
-            File.WriteAllText(Path.Combine(_tempFolder, "act_desc.dat"), content);
+            File.WriteAllText(Path.Join(_tempFolder, "act_desc.dat"), content);
         }
 
         [TestMethod]
EOF
@@ -51,7 +51,7 @@
.Callback<IEnumerable<ActPartDto>>(parts => _savedActParts.AddRange(parts))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
_tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(_tempFolder);
}

@@ -66,7 +66,7 @@

private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "act_desc.dat"), content);
File.WriteAllText(Path.Join(_tempFolder, "act_desc.dat"), content);
}

[TestMethod]
Copilot is powered by AI and may make mistakes. Always verify output.
.Callback<IEnumerable<BCardDto>>(cards => _savedBCards.AddRange(cards))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

To address the issue, replace Path.Combine with Path.Join when constructing the temporary test directory path. Path.Join does not discard earlier segments when later segments are absolute; instead, it simply concatenates segments with the appropriate directory separator. In this particular case, behavior will remain the same because the second argument is not absolute, but the code will now be robust against future changes and will satisfy the static analysis rule.

Concretely, in test/NosCore.Parser.Tests/CardParserTests.cs, within the Setup method, change line 54 from _tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); to _tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());. No additional imports are needed because Path.Join lives in the same System.IO namespace that is already imported. No other functionality or surrounding code needs to be modified.

Suggested changeset 1
test/NosCore.Parser.Tests/CardParserTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/NosCore.Parser.Tests/CardParserTests.cs b/test/NosCore.Parser.Tests/CardParserTests.cs
--- a/test/NosCore.Parser.Tests/CardParserTests.cs
+++ b/test/NosCore.Parser.Tests/CardParserTests.cs
@@ -51,7 +51,7 @@
                 .Callback<IEnumerable<BCardDto>>(cards => _savedBCards.AddRange(cards))
                 .ReturnsAsync(true);
 
-            _tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+            _tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
             Directory.CreateDirectory(_tempFolder);
         }
 
EOF
@@ -51,7 +51,7 @@
.Callback<IEnumerable<BCardDto>>(cards => _savedBCards.AddRange(cards))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
_tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(_tempFolder);
}

Copilot is powered by AI and may make mistakes. Always verify output.

private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "Item.dat"), content);

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

.Setup(x => x.LoadAll())
.Returns(new List<QuestRewardDto>());

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.


private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "quest.dat"), content);

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

In general, the fix is to replace Path.Combine with Path.Join when constructing paths where later arguments might ever be absolute, to avoid the “drop earlier segments” behavior of Path.Combine. Path.Join concatenates path segments with the appropriate directory separator without discarding prior segments if a later one is absolute.

For this specific case, we should change the call in CreateTestFile from Path.Combine(_tempFolder, "quest.dat") to Path.Join(_tempFolder, "quest.dat"). This keeps the same semantics for the current inputs (a directory plus a relative file name) while aligning with the safer API recommended by the rule. No other functional changes are needed, and no extra imports are required because Path.Join is in the same System.IO.Path class that is already being used. The edit is localized to line 84 in test/NosCore.Parser.Tests/QuestParserTests.cs.

Suggested changeset 1
test/NosCore.Parser.Tests/QuestParserTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/NosCore.Parser.Tests/QuestParserTests.cs b/test/NosCore.Parser.Tests/QuestParserTests.cs
--- a/test/NosCore.Parser.Tests/QuestParserTests.cs
+++ b/test/NosCore.Parser.Tests/QuestParserTests.cs
@@ -81,7 +81,7 @@
 
         private void CreateTestFile(string content)
         {
-            File.WriteAllText(Path.Combine(_tempFolder, "quest.dat"), content);
+            File.WriteAllText(Path.Join(_tempFolder, "quest.dat"), content);
         }
 
         private static string CreateQuestData(
EOF
@@ -81,7 +81,7 @@

private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "quest.dat"), content);
File.WriteAllText(Path.Join(_tempFolder, "quest.dat"), content);
}

private static string CreateQuestData(
Copilot is powered by AI and may make mistakes. Always verify output.
.Callback<IEnumerable<ComboDto>>(combos => _savedCombos.AddRange(combos))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

General fix approach: Replace Path.Combine with Path.Join when building paths where later segments might be or become absolute paths, especially when the intent is to always include the earlier segments.

In this specific file, the only problematic call is on line 63:

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Path.Join is available from System.IO and already in use via using System.IO;, so no new imports are required. Path.Join will produce the same result here (a temp directory path with a GUID subfolder) but will not drop the first argument even if future changes inadvertently introduce a rooted/absolute second argument.

Concrete change:

  • In test/NosCore.Parser.Tests/SkillParserTests.cs, in the Setup method, replace the call to Path.Combine on line 63 with Path.Join, leaving the arguments unchanged.

No other code or imports need to be modified.

Suggested changeset 1
test/NosCore.Parser.Tests/SkillParserTests.cs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/NosCore.Parser.Tests/SkillParserTests.cs b/test/NosCore.Parser.Tests/SkillParserTests.cs
--- a/test/NosCore.Parser.Tests/SkillParserTests.cs
+++ b/test/NosCore.Parser.Tests/SkillParserTests.cs
@@ -60,7 +60,7 @@
                 .Callback<IEnumerable<ComboDto>>(combos => _savedCombos.AddRange(combos))
                 .ReturnsAsync(true);
 
-            _tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
+            _tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
             Directory.CreateDirectory(_tempFolder);
         }
 
EOF
@@ -60,7 +60,7 @@
.Callback<IEnumerable<ComboDto>>(combos => _savedCombos.AddRange(combos))
.ReturnsAsync(true);

_tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
_tempFolder = Path.Join(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(_tempFolder);
}

Copilot is powered by AI and may make mistakes. Always verify output.

private void CreateTestFile(string content)
{
File.WriteAllText(Path.Combine(_tempFolder, "Skill.dat"), content);

Check notice

Code scanning / CodeQL

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments Note test

Call to 'System.IO.Path.Combine' may silently drop its earlier arguments.

Copilot Autofix

AI about 1 month ago

Copilot could not generate an autofix suggestion

Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant