Skip to content

fix: Base64QRCode chama base SetQRCodeData e dispoem o renderizador interno#90

Merged
afonsoft merged 1 commit into
mainfrom
feature/devin-20260712-devin-review-fixes
Jul 12, 2026
Merged

fix: Base64QRCode chama base SetQRCodeData e dispoem o renderizador interno#90
afonsoft merged 1 commit into
mainfrom
feature/devin-20260712-devin-review-fixes

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

All Submissions:

  • Have you followed the guidelines in our Contributing document?
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

New Feature Submissions:

  1. Does your submission pass tests?
  2. Have you lint your code locally prior to submission?

Changes to Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

What is being fixed?

After merging the SonarCloud cleanup consolidation PR (#83), the Devin Review comments pointed out a remaining pre-existing issue in Base64QRCode:

  • Base64QRCode.SetQRCodeData forwarded the call only to the inner QRCode renderer, without updating the inherited QrCodeData property. This left Base64QRCode itself with a stale null data reference, making the inherited Dispose unable to clean up the actual data.
  • Base64QRCode did not dispose its inner QRCode instance, which holds a QRCodeData reference and implements IDisposable.

Changes

  • Base64QRCode.SetQRCodeData(QRCodeData) now calls base.SetQRCodeData(data) before forwarding to the inner renderer.
  • Added Base64QRCode.Dispose(bool) to dispose the inner QRCode and then call the base implementation.
  • Added unit tests covering the parameterless Base64QRCode disposal and the SetQRCodeData + GetGraphic + dispose path.

Verification

  • dotnet build QRCoder.Core.sln --configuration Release — 0 warnings, 0 errors.
  • dotnet test QRCoder.Core.Tests/ -f net10.0 --configuration Release — 504 passed, 0 failed.

Link to Devin session: https://app.devin.ai/sessions/20c92a1bad724f63b8be89a9e195e664
Requested by: @afonsoft


Open in Devin Review

@afonsoft afonsoft self-assigned this Jul 12, 2026
@afonsoft
afonsoft self-requested a review July 12, 2026 21:00
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

Qodana Community for .NET

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked

View the detailed Qodana report

To be able to view the detailed Qodana report, you can either:

To get *.log files or any other Qodana artifacts, run the action with upload-result option set to true,
so that the action will upload the files as the job artifacts:

      - name: 'Qodana Scan'
        uses: JetBrains/qodana-action@v2026.1.3
        with:
          upload-result: true
Contact Qodana team

Contact us at qodana-support@jetbrains.com

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Open in Devin Review

Comment on lines +100 to +108
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.qr?.Dispose();
}

base.Dispose(disposing);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Shared QR code data is disposed twice during cleanup, once by the inner renderer and again by the base class

The shared data object is disposed by the inner renderer (this.qr?.Dispose() at QRCoder.Core/Renderers/Base64QRCode.cs:104) and then disposed again by the base class call, so the same object undergoes disposal twice per cleanup cycle.

Impact: Currently benign because the data's dispose only nulls fields, but will cause errors if that disposal ever performs non-idempotent cleanup.

Double-dispose mechanism through shared QRCodeData reference

When Base64QRCode is constructed via Base64QRCode(QRCodeData data) at line 81-84, both this.QrCodeData (set by base(data)) and this.qr.QrCodeData (set by new QRCode(data)) point to the same QRCodeData instance.

Similarly, when SetQRCodeData(data) is called (lines 90-94), both base.SetQRCodeData(data) and this.qr.SetQRCodeData(data) set the same reference.

During Dispose(true) (lines 100-108):

  1. this.qr?.Dispose() calls AbstractQRCode.Dispose(true) on the inner QRCode, which calls qr.QrCodeData?.Dispose() and sets qr.QrCodeData = null (QRCoder.Core/Abstractions/AbstractQRCode.cs:63-65)
  2. base.Dispose(disposing) then calls this.QrCodeData?.Dispose() on the SAME object (since this.QrCodeData still holds the reference) and sets this.QrCodeData = null

QRCodeData.Dispose() (QRCoder.Core/Models/QRCodeData.cs:214-221) has no _disposed guard, so its body executes twice.

Fix: Either don't call base.Dispose(disposing) (but then this.QrCodeData won't be nulled), or null out this.QrCodeData without disposing it (since qr already disposed it), or add a disposed guard.

Prompt for agents
In Base64QRCode.Dispose(bool disposing), the inner `this.qr` and the base class both hold a reference to the same QRCodeData instance. When qr.Dispose() is called, it disposes the shared QRCodeData. Then base.Dispose(disposing) disposes it again.

To fix this, you should avoid the double-dispose. Options:
1. Set `this.QrCodeData = null` before calling `base.Dispose(disposing)` so the base class skips the dispose (since it checks `?.Dispose()`). But this accesses a protected field directly.
2. Override Dispose to only dispose qr and then null out QrCodeData without calling its Dispose again. For example:
   - Dispose qr (which disposes the shared QRCodeData)
   - Set this.QrCodeData = null (to prevent base from disposing it again)
   - Call base.Dispose(disposing) (which will see QrCodeData is null and skip it)
3. Add a _disposed flag to prevent re-entrance.

Option 2 is simplest: insert `this.QrCodeData = null;` between `this.qr?.Dispose();` and `base.Dispose(disposing);` in the Dispose override at QRCoder.Core/Renderers/Base64QRCode.cs:100-108.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrigido. O Dispose agora nulifica this.QrCodeData depois de dispor o qr interno, evitando o duplo Dispose no mesmo objeto. O base.Dispose segue chamado para manter a cadeia de descarte e garantir o idempotence do padrão.

Comment on lines +92 to 93
base.SetQRCodeData(data);
this.qr.SetQRCodeData(data);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: The SetQRCodeData fix corrects a pre-existing bug where base class data was never set

Before this PR, SetQRCodeData in Base64QRCode only called this.qr.SetQRCodeData(data) without calling base.SetQRCodeData(data). This meant that this.QrCodeData (the inherited property from AbstractQRCode) remained null when using the parameterless constructor + SetQRCodeData flow. While this didn't cause runtime issues because Base64QRCode delegates all rendering to the inner qr field (which did have the data), it violated the contract of AbstractQRCode and could confuse any code that inspects QrCodeData on the base class. The addition of base.SetQRCodeData(data) at QRCoder.Core/Renderers/Base64QRCode.cs:92 is a correct fix.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +100 to +108
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.qr?.Dispose();
}

base.Dispose(disposing);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: The Dispose override fixes a resource leak where the inner QRCode was never cleaned up

Before this PR, Base64QRCode had no Dispose(bool) override, so when disposed, only base.Dispose(true) ran — which disposed this.QrCodeData but never disposed the inner this.qr field. The QRCode instance (which is itself an AbstractQRCode with its own QrCodeData reference) was leaked. The new override at QRCoder.Core/Renderers/Base64QRCode.cs:100-108 correctly addresses this leak, though it introduces a double-dispose of the shared QRCodeData (reported separately as a bug).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…nterno

Resolve comentários do Devin Review: o Base64QRCode delegava a definição de dados apenas para o QRCode interno, sem atualizar o QrCodeData herdado, e não dispoem o renderizador interno no Dispose.

Co-Authored-By: Afonso Dutra Nogueira Filho <afonsoft@gmail.com>
@devin-ai-integration
devin-ai-integration Bot force-pushed the feature/devin-20260712-devin-review-fixes branch from 356c3e1 to 92b4766 Compare July 12, 2026 21:02
@sonarqubecloud

Copy link
Copy Markdown

@afonsoft
afonsoft merged commit e7fd592 into main Jul 12, 2026
27 checks passed
@afonsoft
afonsoft deleted the feature/devin-20260712-devin-review-fixes branch July 13, 2026 01:29
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