Skip to content

Releases: nrodear/StaticCodeAnalyser

v0.9.8 — Phase 1-4 + Hardening v3/v4 + FP-Reduction Sprint

Choose a tag to compare

@nrodear nrodear released this 09 Jun 22:39

Release 0.9.8 — Phase 1-4 + Hardening v3/v4 + FP-Reduction Sprint

Released: 2026-06-10
🇩🇪 Deutsche Version

This release closes the 0.9.8 development cycle that began on
2026-06-02. Three layers of work landed on top of v0.9.7:

  1. Scanner-Qualität Phases 1-4 (since v0.9.7) — 13 quick-wins,
    confidence audit, A.5 {$IFDEF}-Awareness, SCA165 UnusedSuppression,
    Golden-Corpus regression suite, SARIF partialFingerprints for
    baseline diffs.
  2. Hardening v3 + v4 (2026-06-07/08) — stack-overflow protection
    for deep ASTs (8 iterative-DFS detector refactors + 32 MB stack
    PE-patch), AST-Destroy reentrancy double-free fix, DFM
    resource-wrapper ($FF $0A $00) support, IDE-plugin Win32-OOM fix
    via FixHint memoize-cache, scan.log phase-tracking + skip-log.
  3. FP-Reduction Sprint (2026-06-09) — self-scan FPs in four style
    detectors reduced by 78% (67 → 15). Side-fix: FreeAndNil(Self.Field)
    with Self.-qualifier is now recognised as freeing.

Full real-world verification: 24 repos in
D:\git-sca-realworld\ scan in 411 s with 0 crashes and produce
1.055.283 findings at profile strict.


TL;DR Highlights (delta over the original Phase 1-only plan)

  • DFM Resource-Wrapper-Format $FF $0A $00 now parses correctly —
    GExperts jumps from 0 to 1.084 DFM-findings, JVCL DFM-coverage roughly
    doubles. The previous code mis-classified these as text and silently
    emitted nothing.
  • No more EInvalidPointer/SCA006 mid-scan crash on second file
    via the AST-Destroy reentrancy bug fix (5ecd498).
  • No more Win32 EOutOfMemory in the IDE plugin's
    HighlightAllFindingsInFile at ≥100k findings — TFixHintResolver
    now caches by (Kind, Severity).
  • scan.log Phase-Tracking — every Analyseabbruch: finding now
    reveals the last successful phase + current file in the log,
    replacing the old black box.
  • scan.log skip-log — ignored / excluded files appear with a reason
    instead of disappearing silently.
  • 4 style-detector FP-classes killed without weakening real-bug
    detection: SCA017 DebugOutput (string-literal contents), SCA070 CommentedOutCode (inline-doc + doc-block start), SCA019 TodoComment
    (detector-source mentions), SCA005 FormatMismatch (empty const
    resolve).
  • FieldLeak-DetectorFreeAndNil(Self.Field) with Self.-
    qualifier is now recognised (USepa.pas repro).
  • Two new configuration knobs
    [Detectors] MaxLineLength=N (default 120) and
    [Detectors] MaxCaseBranches=N (default 10).
  • Anfänger-Build-GuideHowTo_Build{,_de}.md walks Delphi
    newcomers from IDE installation to first IDE-plugin scan.

Earlier in the 0.9.8 cycle (the Phase 1 deliverables — still in this release)

13 commits since v0.9.7. Phase 1 of
Konzept_ScannerQualitaet.md is
complete (6/6 quick-wins); Phase 4 has begun with the A.3-Minimal
cross-unit visibility check. A multi-persona review (Architecture +
Security + Performance) hardened the code along the way.

Highlights

  • --time-detectors Markdown report — per-detector cumulative
    wall-time + call count for data-driven optimisation.
  • Test-fixture auto-detection — findings from uTest*.pas /
    *Sample.pas / *Demo.pas and test/samples/demos/resources
    directories are filtered out in the default and selftest-quiet
    profiles. Self-test report is now clean of intentional-fixture noise.
  • Unused-suppression tracking (SCA165)// noinspection X markers
    that never suppressed a finding are themselves flagged. Suppression
    hygiene now visible.
  • Golden-corpus FP-regression suite — 5 historical FP reproducers
    per Round-1..13 fix, PowerShell runner, CI-ready exit code. Every
    future detector change is regression-guarded.
  • SARIF + Baseline contextHash — SHA256 over the ±3-line snippet
    (whitespace-normalised) added to every finding. Baseline matches via
    contextHash or legacy fingerprint — survives method renames and
    small refactors. Old baselines remain valid (no migration needed).
  • Confidence audit (35 kinds → fcMedium) — heuristic / metric /
    style / DFM-schema / no-data-flow-security kinds tagged. With
    --min-confidence high the report shows only structural bugs without
    losing detector coverage.
  • A.3-Minimal: SCA052 cross-unit reactivatedgSymbolRefIndex is
    now consulted for fkUnusedPublicMember. Methods called via
    obj.Method(args) from another unit are no longer flagged as "dead
    public API".
  • Security hardeningnoinspection All excludes critical kinds,
    marker parsing is string-context-aware, test-fixture filter is
    repo-root-anchored, baseline JSON has entry + length caps.
  • PerformancegFileTextCache is mtime-aware and lives across
    the post-scan phase; saves ~191k redundant file reads + UTF-8
    validations on a real-world scan. uVisibilityCheck tree-walks cached
    once per unit.

Phase 1 quick-wins (6/6)

C.4 Per-detector performance profile

--time-detectors writes a Markdown table with per-detector
cumulative wall-time, call count, average. Lets you pick optimisation
targets based on data, not gut feeling.

analyser.exe --path D:\repo --full --time-detectors > perf.md

A.2 Test-fixture auto-detection

TDetectorUtils.IsTestFixturePath returns true for paths matching:

  • basenames: uTest*.pas, *_Test.pas, *_Tests.pas, *Sample.pas,
    *Demo.pas, *Sample_*.pas, *_Demo_*.pas, *Sample.dfm,
    *Demo.dfm, MeineUnit.pas (and a few SCA-internal demo files)
  • repo-root-relative directory components:
    test, tests, unittest, unittests, samples, demos,
    resources

Auto-on for --profile default and selftest-quiet, off for strict.
Manual override via --hide-test-fixtures / --show-test-fixtures.

C.3 Unused-suppression tracking (SCA165)

For every // noinspection X marker we record Consumed = false
initially. When ApplyToFindings suppresses a finding via the marker,
Consumed := true. After the suppression pass, any marker still at
Consumed = false emits an fkUnusedSuppression finding on the marker
line, with a quick-fix hint to remove the marker.

C.1 Golden-corpus regression tests

tests/golden-corpus/fp-reproducers/ holds 5 historical false-positive
reproducer .pas snippets (one per Round-1..13 fix). expected.json
maps each file to a must_not_flag list of rule IDs. The PowerShell
runner tools/check-golden-corpus.ps1 scans the corpus and exits 0/1
based on whether any previously-fixed FP class fires again.

powershell -ExecutionPolicy Bypass -File tools\check-golden-corpus.ps1

C.2 SARIF partialFingerprints.contextHash/v1

New unit uFindingFingerprint:

contextHash/v1  =  "v1:" + SHA256( Normalize( ±3 lines around finding ) )

Normalize collapses whitespace runs to a single space, tabs → space,
empty lines dropped, CRLF / LF normalised. The hash is stable against
re-indent, trailing-whitespace cleanup and small line-drift refactors.

uBaseline.Apply matches contextHash or legacy fingerprint —
old baselines without contextHash remain valid (backward-compat),
new baselines survive small refactors.

A.1 Confidence-tagging audit

KindDefaultConfidence in uSCAConsts tags ~35 detector kinds as
fcMedium (pattern-match, metrics, style, DFM heuristics, security
without data-flow). All structural-bug detectors stay fcHigh.
TLeakFinding.SetKind reads from this map. Override pattern (e.g.
uCommandInjection := fcLow) is preserved via the new
SetKind(K, AConfidence) overload. Per-kind justifications in
docs/ConfidenceAudit.md.


Phase 4 partial — A.3 cross-unit visibility (begun)

Minimal step

uVisibilityCheck for fkUnusedPublicMember (SCA052) now consults
gSymbolRefIndex.HasExternalRefs before emitting. If any external unit
references the member via Obj.Member(args), no finding is emitted.

Audit (spot-check 18 known cross-unit methods)

  • 8/18 (44 %) A.3 takes effect — pattern: instance.Method(args)
  • 10/18 (56 %) A.3 inactive — 3 known index limitations:
    • nkRef / value-use without parens (F.SeverityText)
    • class-function-call TClass.ClassMethod(args) — AST does not
      classify as Obj.Member
    • bare calls (Fingerprint(F)) — deliberate index simplification

All three are documented in Konzept_ScannerQualitaet.md §A.3+ as the
prioritised follow-up sprint.

Library FP class (not addressable by the index)

Real-world scan shows the top SCA052 hot-spots are vendor libraries
(mormot.*, MVCFramework, LoggerPro) where the consumers live in
other repos that the index cannot see. Recommendation: path-override
default for vendor/ directories.


Multi-persona review

After Phase 1 + A.3-Minimal a three-persona review (Architecture +
Security + Performance) was run on the branch. 9 of 10 findings were
implemented in commit 120894a:

# Area Fix
1 Perf Baseline.Apply skips ContextHash for legacy baselines
2 Sec noinspection All excludes security-critical kinds
3 Sec ParseMarkerLine uses ScanCodeLine (string-context-aware)
4 Sec IsTestFixturePath repo-root-anchored via BaseDir
5 Perf gFileTextCache lives through post-scan + leak fix
6 Sec Baseline JSON 1 M entry / 256 char cap
8 Perf Suppression uses AcquireLines (cache hits)
9 Perf uVisibilityCheck tree-walks cached per unit
10 API SetKind(K, AConfidence) overload

Finding #7 (DefaultConfidence into TFindingKindMeta record) deferred
as invasive (touches ~160 KIND_META entries) and would require an
explicit drift-test design.

TFileTextCache was subsequently made mtime-aware (commit 1e7e193) to
plug a stale-cache issue exposed by the regression suite after the
post-scan cache change.


Fil...

Read more

v0.9.7 - Audit-Nachzug + Round 11 Regex-Cache + Detector-Checkliste-Konformitaet

Choose a tag to compare

@nrodear nrodear released this 31 May 22:59

Highlights

Detector-Audit gegen Todo_neuerdetector.md-Checkliste - alle 156 Detektoren systematisch geprueft. Vier echte Gaps geschlossen:

  • fmCommandInjection (SCA163, Errors-Sektion)
  • fmInsecureCryptoAlgorithm (SCA162, Warnings-Sektion)
  • fmUnusedRoutine (SCA164, Hints-Sektion)
  • fmNoSonarMarker (SCA065, Hints-Sektion)

Pro Filter alle 5 Touch-Points abgedeckt:

  1. TFilterMode-Enum-Eintrag
  2. Matches()-case-Branch
  3. KindSearchKeywords-Eintrag (Freitext-Suche)
  4. IDE-Combo (uIDEAnalyserForm)
  5. Standalone-Combo (uMainForm)

Andere Audit-"Lücken" sind Architektur-by-design:

  • ~20 DFM-Detektoren via TDfmAnalysisRunner-Adapter registriert
  • ~14 Multi-Kind-Container (CodeSmells2/ConcurrencyExt/PerfHotspots/RestHttpSecurity) emittieren mehrere existing Kinds

Performance: Round 11 Regex-Cache

7 weitere Detektoren auf Module-Level-Lazy-Cache umgestellt (zusaetzlich zu Round 9 mit 4 Detektoren):

  • uIntegerOverflow, uBoolAlwaysTrue, uFloatEquality
  • uSetLengthAppendInLoop, uPublicMemberWithoutDoc, uHardcodedString
  • uConcurrencyExt (3 von 5 konstante Patterns)

Kumulativ Round 9 + 11: ~25 von ~30 moeglichen Regex-Compilations pro File eliminiert. Marginal in Prozenten (Delphi 12 TRegEx hat internen Pattern-Cache), aber sauber im Code.

Inhalt des ZIP

  • StaticCodeAnalyser.exe - Standalone Win64 (10.5 MB unkomprimiert)
  • rules/sca-rules.json + Schema
  • README.md + CHANGELOG.md

Run

StaticCodeAnalyser.exe --path <dir> --full --profile selftest-quiet `
  --report-html sca.html --report-sarif sca.sarif --quiet

Vollstaendiger Changelog: v0.9.6...v0.9.7

v0.9.6 - Self-Test FP-Reduction (43% Noise weniger) + Perf-Optimierungen

Choose a tag to compare

@nrodear nrodear released this 31 May 21:54

Highlights

Dogfooding-Workflow eingefuehrt: analyser.exe --path . --full --profile selftest-quiet --report-html sca-selftest.html triagiert das eigene Repo. Siehe HowTo_DetectorSelftest.md.

False-Positive-Reduction: 12 200 -> 6 917 Findings (-43%), Errors 37 -> 5 (-86%)

Acht Triage-Runden gegen das eigene Repo, jeder Detector-Fix mit struktureller Begruendung dokumentiert in Todo_FalsePositiveReduction.md Section D.

Detector-Fixes (16 Detektoren plus Parser)

  • uHardcodedSecret (SCA004): Meta-Felder (SourceToken/PasswordChar/TokenRef) skippen
  • uRestHttpSecurity (SCA116): TLS-Pattern auf string-stripped Code (kein Self-Match in Fix-Templates)
  • uSqlDangerousStatement (SCA058): := im Literal -> Pascal-Code-Zitat, kein SQL
  • uFormatMismatch (SCA005): IsInsideStringLiteral-Guard
  • uUseAfterFree (SCA134): Sibling-Free-Guard fuer if/else-Pattern
  • uFieldName (SCA103): Default-Visibility ist published (TForm/TFrame/TDataModule) - eliminierte ~3000 FPs
  • uRedundantJump (SCA080): Look-Ahead - nur flaggen wenn nach end; Block-Terminator - eliminierte ~900 FPs
  • uUnusedRoutine (SCA164): MaxLineOf statt NextStartAfter fuer Self-Call-Range
  • uPublicField (SCA089): Multi-line Method-Header-Continuation + Section-Boundaries
  • uGroupedDeclaration (SCA076): ParenDepth-Filter - Param-Listen idiomatisch, nicht geflaggt
  • uCommentedOutCode (SCA070): Backtick-Code-Spans aus Doc-Kommentaren strippen
  • uCanBeClassMethod (SCA148): Event-Handler-Signature (Sender: TObject) -> Instance-Method bleiben
  • uLeakDetector2 (SCA001): Acquire/Release/Dispose/Return/Recycle-Pool-Pattern erkennen - eliminierte 65 FPs
  • uExceptionTooGeneral (SCA078): Legit Top-Level-Handler (Log+Exit/Halt/Raise/Result-Assign)
  • uUnusedLocal (SCA053): Source-Verify gegen Parser-Cleanup-Edge-Case
  • uFreeWithoutNil (SCA139): Nur Felder flaggen - Locals fallen aus dem Scope - eliminierte 111 FPs
  • uTodoComment (SCA019): Skip Pfad-Refs (todo-sonar.md)
  • uMethodName (SCA106): DFM-Event-Handler-Skip
  • uTypeName (SCA104): Exception-Klassen (E*/*Error/*Exception)
  • uLockWithoutTryFinally (SCA109): Method-Header + Cache-Calls mit Args ausschliessen
  • Parser uParser2.ParseForStmt: Loop-Variable in for k := 1 to N do wird jetzt in TypeRef gejoint (war vorher aus AST verworfen)

Neue Infrastruktur

  • Profile-Negation-Syntax: [""*"", ""!Kind1"", ""-Kind2""] in rules/sca-rules.json
  • Bundled Profile selftest-quiet: 11 Style-Detektoren ausgeblendet fuer fokussiertes Dogfooding
  • CLI-Flag --report-html: Self-contained HTML Code-Review-Report (filter/sort/snippets)
  • HowTo_DetectorSelftest.md: Workflow-Dokumentation

Performance

Round 9 (commit 81749a0): 4 Hot-Path-Detektoren (uRestHttpSecurity, uPerfHotspots, uLockWithoutTryFinally, uUseAfterFree) compileren ihre Regex-Patterns nur noch EINMAL pro Prozess statt pro File. Gemessener Effekt: 3.0s -> 2.92s (-2.7% auf bereits sehr flotter Baseline).

Tests

Alle 1696 DUnit-Tests gruen. Zwei Tests an neues Verhalten angepasst:

  • uTestGroupedDeclaration.ParameterGrouped_Reported -> _NotReported
  • uTestFreeWithoutNil.FreeWithoutNil_Reported SRC von Local auf Field umgestellt

Version

Alle internen Version-Konstanten (uSCAConsts, uConsoleRunner, uIDEExpert, sca-rules.json, dproj VerInfo) jetzt einheitlich auf 0.9.6. Vorher waren drei verschiedene Versionen verstreut (0.9.1 / 0.9.3 / 0.9.5).

Vollstaendiger Changelog: v0.9.5...v0.9.6

v0.9.5 - Branding + Standalone-UI refresh + scan perf wins

Choose a tag to compare

@nrodear nrodear released this 31 May 13:43

Highlights

Branding (canonical Embarcadero pattern)

  • Standalone EXE: app icon via <Icon_MainIcon> + multi-res sca.ico
  • IDE-Plugin: Splash/About bitmap + Float-mode caption icon + Tools-menu entry with 16x16 icon via INTAServices.AddImages
  • BRCC32 16-bit-era constraints documented (24-bit BMPs, no 256x256 sub-icons, no PNG-in-ICO)

Standalone UI refresh (Tier 1+2)

  • Hamburger menu (Cancel/Export/Settings/Ignore) replaces scattered toolbar buttons
  • Segoe UI + IDE_BG_CHROME theming aligned with IDE-Plugin look
  • BtnBranch always visible, hamburger sits to its right

New detectors

  • SCA162 InsecureCryptoAlgorithm (MD5/SHA1/DES/RC4)
  • SCA163 CommandInjection (ShellExecute/CreateProcess/WinExec + string-concat)
  • SCA164 UnusedRoutine
  • TThreadDestroyWithoutTerminate: type-resolution via constructor-call fallback
  • DetectorReview filter mode (DEBUG-only, INI-gated)

Scan performance

  • RunAllDetectors post-filter O(n^2) -> O(n) via PrevCount tracking + lazy TStopwatch
  • TAstNode.FindAll lazy per-node cache: eliminates ~140 redundant tree-walks per file (54x nkMethod + 26x nkAssign + 22x nkCall + 11x nkClass over ~150 detectors). API unchanged, snapshot-copy preserves caller ownership.

IDE-Plugin

  • Tools-menu entry with icon (canonical INTAServices.AddImages + TAction + TMenuItem)
  • Hamburger menu entry to clear all hover-annotation markers

FP-Fixes & polish

  • InsecureCrypto: "des" as German word no longer matches the DES cipher
  • FloatEquality: if Value = nil no longer flagged (NEVER_FLOAT_TOKENS)
  • 195 missing DE translations backfilled + CI lock
  • Hint cleanup: H2443/H2219/H2077

Full changelog: v0.9.3...v0.9.5

v0.9.3 - Docked-mode theme refresh + encoding + multi-finding hint

Choose a tag to compare

@nrodear nrodear released this 26 May 23:07

Release 0.9.3 — 2026-05-27

🇩🇪 Deutsche Version

A polish release focused on IDE-plugin theme reliability in docked-mode,
file encoding correctness, and annotation-overlay usability when
multiple findings sit on the same line. No new detectors (count stays at
161); the changes target reliability, visual consistency, and false-positive
reduction.

Highlights

  • Docked-mode IDE-theme refresh now works for the entire plugin, not
    just the grid. Tiles, toolbar panels, help-panel caption and before/after
    memos now follow IDE theme switches reliably — previously only the grid
    picked up the new theme while everything else stayed in the old colors.
  • IDE plugin announces itself in the start sequence — splash-screen
    entry + About-Box registration via the standard ToolsAPI splash/about
    services.
  • File encoding detection — BOM-sniff → strict-UTF-8-validation →
    Windows-1252 fallback. Fixes mojibake on ANSI files with German umlauts
    in the unit header (the old code forced UTF-8 with lenient byte
    substitution).
  • Multi-finding annotation hint shows full descriptions per finding,
    not just titles. When two or three findings share the same line, the
    overlay no longer collapses them to a title list.
  • FloatEquality false-positive on string comparisons fixed
    aValue = '' (string) is no longer reported as a float-equality bug,
    even when another function in the same file has aValue: Double as
    a parameter.
  • Visible per-tile border in the Sonar stats row using clBtnShadow
    (was cl3DDkShadow — collapsed onto the chrome background in many
    IDE themes).
  • ~80× faster theme switch via cold/warm Apply split (per-Descendant
    ApplyTheme only on first apply; subsequent switches reuse style hooks).

🎨 IDE-plugin theme reliability (NEW)

The IDE plugin can run floating (its own window) or docked (as a
tab inside the IDE main window or a side bar). Theme handling between
the two modes diverged significantly in the VCL/ToolsAPI stack, and
0.9.2 only worked correctly when floating.

Symptoms before

Switch IDE → Options → Theme: only the result grid picked up the new
colors. Tiles, toolbar background, path/filter panels, the help-panel
caption, and before/after memos remained in the previous theme until
the IDE was restarted.

Diagnosis

Three independent root causes:

  1. IOTAIDEThemingServices.ApplyTheme doesn't propagate transitively
    through a TFrame to its descendants in Delphi 12. Only controls the
    caller passes directly get their style hooks updated.
  2. Vcl.Themes.StyleServices (global) stays stale in docked mode
    Theming.ApplyTheme(IDE-Main-Form) doesn't update the VCL-global
    StyleServices, so custom paint code reading clBtnFace via the
    global service gets the previous theme's RGB.
  3. System-color identifiers (TPanel.Color := clBtnFace) are resolved
    at paint time
    against the stale VCL-global, not against the IDE's
    theming service.

Solution: per-Descendant 5-step apply pipeline

uIDETheme.TIDETheme.Apply now walks the entire control tree under the
frame and, per node:

  1. Apply IDE-style-hook via IOTAIDEThemingServices.ApplyTheme.
  2. Preserve StyleElements - [seClient] across the apply (snapshot +
    restore). Lets controls keep their explicit Color instead of being
    overpainted by the style hook.
  3. Resolve Color and Font.Color against the IDE-theme's
    StyleServices and write the concrete RGB back. The original
    identifier (clBtnFace, clWindow, ...) is cached per control so
    subsequent theme switches still resolve correctly.
  4. Bind to the IDE style by setting TControl.StyleName := IdeStyle.Name
    (Delphi 10.4+ per-control routing). This is what fixes TButton,
    TStringGrid header/border, TComboBox, TProgressBar,
    TStatusBar — they go through VCL-StyleHooks that previously read
    from the stale VCL-global.
  5. Invalidate (with explicit Repaint on TCustomGrid descendants
    that have their own paint cache).

The key win: this avoids the 2-second IDE hang that
TStyleManager.SetStyle would cause — SetStyle broadcasts
CM_STYLECHANGED over every form in Screen.Forms[] (50+ forms ×
1000+ controls per form). Per-control StyleName gives the same
visual outcome for the plugin's own controls without the broadcast.

See Konzept_DockedThemeRefresh.md for
the full diagnostic trail.


🛠 IDE plugin start-sequence integration

The plugin now registers itself in the IDE start-up sequence with the
standard ToolsAPI hooks:

  • Splash-screen entry during IDE boot (the box that lists "Bundled
    in this product..." — your plugin shows up there alongside
    GExperts/CnPack/etc.).
  • About-Box entry — Help → About... → "Static Code Analyser" with
    version + description.

Visible confirmation that the plugin loaded correctly without opening
the tool window.


🧰 Visual polish

Per-tile border (Sonar stats row)

The 9 stat tiles (Errors / Warnings / Hints / Read errors / Bugs /
Security / Duplicates / Cyclomatic / Quality) now have a visible 1 px
border drawn in clBtnShadow (theme-aware via
ActiveStyleServices.GetSystemColor). Previously cl3DDkShadow was
used, which collapses onto clBtnFace (the tile background) in many
themes — the border was technically drawn but invisible.

"Quality" caption

FTileScore caption shortened from "Code Quality" to "Quality" (tile
label + hover tooltip title). The status-bar score line keeps the long
form — different context, more room.

Stats row 2 px taller

STATS_PANEL_HEIGHT 51 → 53 gives glyph + count + caption more vertical
breathing room. Tiles inherit the panel height via alLeft.

Toolbar simplification

The IDE-plugin toolbar dropped from 4 rows to 3 (Path / Filter+Search /
Stats). Less-used actions (Branch, Save, Quit, Settings, Ignore,
Export, Profile) moved into a hamburger menu. The Analyse button and
filter/severity combos stay always-visible. Responsive layout still
toggles labels and combo widths on width thresholds.


🔧 Infrastructure fixes

Encoding detection (file cache)

uFileTextCache previously called LoadFromFile(file, TEncoding.UTF8)
which is lenient — invalid UTF-8 bytes get silently replaced with
U+FFFD (replacement character), and the explicit-fallback except
branch never fired. Result: ANSI files with German umlauts (ä, ö,
ü in unit headers, copyright comments) came through with mojibake.

The new LoadFileSmart helper does three-stage detection:

  1. BOM sniff (UTF-8 / UTF-16 LE / UTF-16 BE) — if present, use
    that encoding and skip the BOM bytes.
  2. No BOM, all bytes form well-formed UTF-8 (RFC 3629 validation)
    — use UTF-8.
  3. OtherwiseTEncoding.Default (Windows-1252 on a typical
    Windows install).

Both TFileTextCache.GetLines (cached path) and AcquireLines
(fallback path) go through LoadFileSmart now.

Multi-finding annotation overlay

When two or more findings sit on the same source line, the editor
annotation overlay used to collapse them into a summary with bullet
list of titles only — descriptions were dropped. The bullet list now
includes each finding's full description indented under the title:

• PointerArithmeticOnString  [Warning]
   String + integer addition treated as pointer arithmetic ...
• UseAfterFree  [Error]
   Variable accessed after FreeAndNil ...

Title / severity / stripe-color still come from the strongest finding.
Fix-hint remains suppressed in multi-mark (showing only one fix would
be misleading).

FloatEquality detector — false-positive on string compares

The lexical detector strips strings and comments before scanning for
<var> = <token> patterns. Empty string literals ('') were replaced
with two spaces, which let the regex bridge over them and pick up the
next token. Concrete failure mode:

if aValue = '' then Exit;    // aValue: string

…was reported as Float equality (aValue = then) is unreliable
because aValue: Double existed as a parameter in another function in
the same file (file-wide FloatVars), and '' → spaces → regex skipped to "then". The detector also called the Pascal keyword then the RHS.

Fix: stripped string content now uses ~ (not \w, not \s) as the
marker. The regex \s*[\w.]+ fails at the first ~, so cross-string
matches no longer happen. New regression test:
StringEqualityWithFloatVarNameElsewhere_NotReported.


⚡ Theme-switch performance

The Apply pipeline keeps a per-control snapshot of the original color
identifiers (FOrigColors: TDictionary<Pointer, TControlColors>). On
first apply per control the original clBtnFace / clWindow value is
stored; on every subsequent theme switch the cache returns the
identifier and resolution runs against the fresh IDE-style — fixing
the "second-switch bug" where Color had already been written as
concrete RGB and lost the clSystemColor bit.

Combined with the cold/warm split (per-Descendant ApplyTheme only
once; later switches skip the style-hook registration), full theme
switch time dropped from ~2 s of broadcast-driven repaints to under
~25 ms.


🧱 Code structure

  • uIDETheme.TIDEThemeImpl.ApplyRecursive refactored — was an 80-line
    procedure with four mixed concerns, now four named helpers
    (ApplyStyleHookPreserveSeClient, ResolveDescendantColors,
    BindToIdeStyle, TriggerRepaint) plus a 15-line walker.
  • TIDEThemeImpl.RebuildCache reads from
    IOTAIDEThemingServices.StyleServices instead of the VCL-global —
    matches the rest of the pipeline and avoids stale docked-mode colors
    in FrameBg / FrameFg.
  • EngineSCA/ folder renamed to SCA.Engine/ (preparation for a later
    project-split into Engine / Standalone+CLI / IDE-Plugin / Tests, see
    Konzept_ProjektAufteilung.md).

Compatibility

  • **Delphi 12 At...
Read more

v0.9.2 - More detectors implemented + Standalone progress + Configurable IDE shortcuts

Choose a tag to compare

@nrodear nrodear released this 22 May 17:33

Release 0.9.2 — 2026-05-22

🇩🇪 Deutsche Version

v0.9.1 was already published earlier (2026-05-16, "SonarQube integration").
The work in this release tag bumps to 0.9.2 so the previous tag stays
intact in the history.

Highlights

  • 9 new mORMot-cluster detectors (SCA153-161): UnpairedLock,
    MoveSizeOfPointer, WithMultipleTargets, GetMemWithoutFreeMem,
    SetLengthAppendInLoop, PointerArithmeticOnString, EmptyOnHandler,
    StringFromPointer, PointerSubtraction.
  • Standalone GUI finally has a progress bar + Cancel button +
    MAX_SCAN_FILES scan-runaway protection (was IDE-only before).
  • IDE-plugin keyboard shortcuts are configurable (cnpack-style:
    press the key combo, store in INI). Master toggle to disable all
    shortcuts at once. Settings dialog now scrollable.
  • Detector count: 161 kinds (Sonar-style finding categories),
    delivered by ~130 pipeline classes — some classes emit multiple
    kinds (e.g. uVisibilityCheck → 4, uDfmAnalysisRunner → 22 DFM).
  • Translation completeness: 161 / 161 finding-hint descriptions
    covered in both DE translation stores (GDeMap runtime fallback
    • i18n/de.po dxgettext path), all 82 combo-labels translated.

What's new

Detectors

SCA138-152 — Sonar-50 expansion to cover the remaining
Maintainability + Code-Smell slots:

ID Name Type
138 GodClass Code Smell
139 FreeWithoutNil Bug
140 MultipleExit Code Smell
141 LargeClass Code Smell
142 UnsortedUses Code Smell
143 MissingUnitHeader Code Smell
144 FloatEquality Bug
145 ExceptInDestructor Bug
146 BooleanParam Code Smell
147 UnusedPrivateMethod Code Smell
148 CanBeClassMethod Code Smell
149 MissingOverride Bug
150 BoolAlwaysTrue Bug
151 ConstantReturn Code Smell
152 HardcodedString Code Smell

SCA153-161 — mORMot-cluster: patterns recurring in large
low-level Delphi codebases (threading primitives, raw heap
allocation, dynamic-array growth, byte-level buffer ops, PChar
arithmetic, multi-target with blocks, typed exception handlers,
string casts from raw pointers, Win64 pointer subtraction).

ID Name Type Severity
153 UnpairedLock Bug Warning
154 MoveSizeOfPointer Bug Warning
155 WithMultipleTargets Code Smell Hint
156 GetMemWithoutFreeMem Bug Warning
157 SetLengthAppendInLoop Code Smell Warning
158 PointerArithmeticOnString Bug Warning
159 EmptyOnHandler Bug Warning
160 StringFromPointer Bug Warning
161 PointerSubtraction Bug Warning

UI / UX

  • Standalone progress feedback: TProgressBar (Marquee during
    the directory scan, Position-bar with %-readout during the file
    phase) + a Cancel button + MAX_SCAN_FILES=20000 guard. Wired
    into all three analysis entry points: full-folder scan, branch-
    changes-only scan, single-file analysis.
  • IDE-plugin configurable shortcuts: Tools → Options → Static
    Code Analyser → Hotkeys section. Click into the edit field, press
    the desired key combo (e.g. Ctrl+Alt+A for silent analysis,
    Ctrl+Alt+↑/↓ for finding navigation). Stored in analyser.ini,
    master "Enable all keyboard shortcuts" toggle gates all of them.
  • Settings dialog as TScrollBox: groups (Silent → Rule-Set →
    Detectors → Hotkeys) stack vertically with auto-scroll, no more
    per-group height-engineering.
  • Use-cases section in README (EN+DE): 19-row capability matrix
    showing what each deployment mode (IDE plugin / Standalone GUI /
    CLI) supports, plus 4 role profiles.

Build / Infra

  • Central output directory: ..\Output\Test\<Platform> <Config>
    in all three .dproj — no more per-project Win32/Win64 build
    artefacts polluting the source tree. Added to .gitignore.
  • paths.optset.xml shared search path for the IDE plugin —
    one Form-sources directory per line with explanatory comments.
  • TestInsight CI: GitHub Actions workflow runs the full DUnitX
    test suite on push (Win32 + Win64).

Tests

  • uTestSuppressionCompleteness: three-test fixture that
    guarantees every one of the 161 detector kinds is reachable via
    the // noinspection <Name> suppression marker.
  • 36 new DUnitX fixtures for the new SCA138-161 detectors
    (~5 tests each: positive cases + negative cases + Kind/Severity
    round-trip).

Translations

  • 161 / 161 hint descriptions present in both
    uLocalization.pas:GDeMap (runtime fallback) and i18n/de.po
    (dxgettext path).
  • 82 / 82 UI combo-labels translated.
  • Todo_TexteTranslate.md (new): per-detector translation
    checklist with audit shell snippets.

Bug fixes

IDE-plugin progress bar

  • Scan→File-phase transition no longer waits for the 100ms
    throttle. First File-Phase callback always forces the
    pbstMarquee → pbstNormal style switch.
  • RunCurrent (single-file analysis) now toggles pbstMarquee
    for the duration. Previously the bar stayed idle.

Detectors (round 1)

Eight SCA138-152 detectors had AST-shape assumptions that didn't
match the actual parser output:

  • uBooleanParam: IfStmt condition is flat text in
    IfNode.TypeRef, not in children. Added word-boundary scan.
  • uCanBeClassMethod: method body lives in an nkBlock wrapper
    child, not direct children. Added nkBlock to body check, plus
    cross-decl lookup so interface-only ;virtual markers are seen.
  • uConstantReturn: IsFunctionMethod was looking for : in
    TypeRef; parser uses 'function:Integer' format. ExtractRhs
    was reading children; RHS lives in nkAssign.TypeRef.
  • uFloatEquality: rejected Ratio = 0.5 because 0.5 has a
    dot — was meant to filter qualified names. Now also accepts
    numeric literals (first char is a digit).
  • uLargeClass: measured span between method headers only;
    600-line method bodies were invisible. Added DeepMaxLine
    recursive descendant scan.
  • uExceptInDestructor: raises in the try-body of try/except
    were flagged even though the except catches them. Added
    nkTryExcept special case.
  • uFreeWithoutNil: identity check S = FreeCall between an
    nkAssign and an nkCall could never match. Switched to
    Line-number comparison.
  • uGodClass: ;abstract marker was being looked for on
    nkClass.TypeRef, but the parser only stores class-level
    modifiers there for inheritance lists. Detect "framework class"
    by checking all methods have ;abstract in their TypeRef instead.

Build

  • Forward-declaration for IsShortcutsMasterEnabled in
    uIDEAnalyserForm.pas — was called ~1700 lines before its
    definition, caused E2003 in the IDE build.
  • dpk + dproj sync for 15 implicit-import warnings (W1033):
    detector units must be listed in the package contains clause.
  • Hint cleanup: removed unused locals in uAbstractNotImpl
    (Other), uUnusedPrivateMethod (Sections, Mthods), dropped
    dead Found write in uFreeWithoutNil.

Breaking changes

None. All existing rule names, KIND_META entries, and suppression
markers remain stable.

Compatibility

  • Delphi 12 Athens (RAD Studio 23) - target
  • Sonar: External-Issues JSON format unchanged
  • SARIF: 2.1.0 output unchanged
  • analyser.ini schema: backward compatible; new keys for
    shortcut config and master-toggle (default = enabled)

Files added in this release

  • Todo_TexteTranslate.md — generic translation checklist
  • paths.optset.xml — IDE-plugin shared search path
  • RELEASE_NOTES.md / RELEASE_NOTES_de.md — this file
  • 9 new uXxx.pas detector units (SCA153-161)
  • 9 new uTestXxx.pas test fixtures
  • uTestSuppressionCompleteness.pas — completeness guard

Acknowledgements

Detectors SCA153-161 came out of an audit of the
mORMot2 source tree —
patterns that recur in large low-level Delphi codebases were
extracted into reusable lexical detectors.


Release 0.9.2 — 2026-05-22

🇬🇧 English version

v0.9.1 wurde bereits am 2026-05-16 als "SonarQube integration" veröffentlicht.
Die Arbeiten in diesem Release-Tag bumpen daher auf 0.9.2, damit der
ältere Tag in der Historie unverändert bleibt.

Highlights

  • 9 neue mORMot-Cluster-Detektoren (SCA153-161): UnpairedLock,
    MoveSizeOfPointer, WithMultipleTargets, GetMemWithoutFreeMem,
    SetLengthAppendInLoop, PointerArithmeticOnString, EmptyOnHandler,
    StringFromPointer, PointerSubtraction.
  • Standalone-GUI hat endlich Progressbar + Cancel-Button +
    MAX_SCAN_FILES-Schutz vor Scan-Runaway (vorher nur im IDE-Plugin).
  • IDE-Plugin Tastenkürzel sind konfigurierbar (cnpack-Stil:
    Tasten drücken, in INI speichern). Master-Toggle, um alle
    Kürzel auf einen Schlag abzuschalten. Einstellungs-Dialog
    scrollbar.
  • Detektor-Anzahl: 161 Kinds (Sonar-Befund-Kategorien),
    geliefert von ~130 Pipeline-Klassen — einige Klassen
    emittieren mehrere Kinds (z. B. uVisibilityCheck → 4,
    uDfmAnalysisRunner → 22 DFM).
  • Übersetzungs-Vollständigkeit: 161 / 161 Hint-Descriptions
    in beiden DE-Stores (GDeMap-Runtime-Fallback + i18n/de.po
    dxgettext-Pfad) abgedeckt, alle 82 Combo-Labels übersetzt.

Was ist neu

Detektoren

SCA138-152 — Sonar-50-Erweiterung für die verbleibenden
Maintainability + Code-Smell-Slots:

ID Name Type
138 GodClass Code Smell
139 FreeWithoutNil Bug
140 MultipleExit Code Smell
141 LargeClass Code Smell
142 UnsortedUses Code Smell
143 MissingUnitHeader Code Smell
144 FloatEquality Bug
145 ExceptInDestructor Bug
146 BooleanParam Code Smell
147 UnusedPrivateMethod Code Smell
148 CanBeClassMethod Code Smell
149 MissingOverride Bug
150 BoolAlwaysTrue Bug
151 ConstantReturn Code Smell
152 HardcodedString Code Smell
Read more

v0.9.0 - Silent-Mode + Tools>Options + Rule-Set profiles

Choose a tag to compare

@nrodear nrodear released this 14 May 17:06

v0.9.0 — Silent-Mode, Tools>Options Page, Rule-Set Profiles, IDE-Plugin polish

Workflow-focused release. Three big themes:

  1. Silent-Mode — single-file analysis directly from the editor
    right-click + Ctrl+Alt+A hotkey. No dock window opens. Findings
    appear as gutter markers + hover overlays in the code editor.
  2. Rule-Set profileside-fast, default, strict, security,
    bugs-only, code-quality, dfm-only shipped as a JSON catalog
    (rules/sca-rules.json) plus CLI flags --profile / --min-severity
    for CI integration.
  3. Tools > Options page under Third Party > Static Code Analyser
    in the Delphi IDE — Silent-Mode toggle, profile dropdowns,
    detector toggles. All persisted in analyser.ini.

🤫 Silent-Mode (NEW)

A new analysis path that bypasses the dock window entirely:

  • Editor right-click → "Analyse current file (silent)" — analyses
    the currently active .pas and renders findings inline.
  • Ctrl+Alt+A hotkey — same action, editor-wide. Registered as
    a proper IOTAKeyboardBinding, works without first opening the
    popup.
  • Inline rendering — gutter markers + [✕]-dismissible hover
    overlays per finding. Markers survive tab switches via multi-file
    marker storage; they auto-clear on file save (line numbers stale
    after edits).
  • Disable toggleTools > Options > Third Party > Static Code Analyser > Silent Mode. INI: [Silent] Enabled=0/1.

Implementation notes:

  • Editor-popup integration uses the OnPopup-chain pattern
    (GExperts/CnPack-style): each popup-show clears our previous item,
    lets the IDE rebuild the menu, then appends a fresh item. Permanent
    inserts clash with the IDE's action-manager rebuild.
  • IOTAKeyboardBinding registers Ctrl+Alt+A editor-wide so the
    hotkey works even without a prior right-click. Diagnostic logging
    on registration conflict (other plugins competing for the same
    shortcut).

🎚 Rule-Set profiles (NEW)

Seven bundled profiles cover the common analysis use-cases:

Profile Use-case
ide-fast Default for IDE-plugin Silent-Mode — fast subset for live feedback
default Standalone GUI default — full detector set
strict CI gate — everything on, including stylistic detectors
security OWASP / vulnerability focus
bugs-only Just Bug type findings (no smells, no style)
code-quality Smells + cyclomatic + duplication
dfm-only Just the 20 DFM detectors

Source: rules/sca-rules.json — single source of truth. The Delphi
IDE plugin and the CLI both read the same catalog.

CLI flags for CI:

analyser.d12.exe path/to/repo --profile strict --min-severity warning --format sarif

INI keys for persistent configuration:

[Rules]
Profile=strict          # standalone + CLI
IdeProfile=ide-fast     # IDE plugin (dock window + Silent-Mode)
MinSeverity=warning

⚙ Tools > Options page (NEW)

The Delphi IDE plugin now contributes a configuration page under
Tools > Options > Third Party > Static Code Analyser:

  • Silent Mode — enable/disable the editor right-click + hotkey
  • Rule-Set — Profile (CLI/Form), Min-Severity, IDE Profile
  • Detectors — UsesCheck, IncludeTests, AutoDiscoverClasses

All values persisted in the same analyser.ini the dock window uses,
so the Options page is just an alternative UI — no duplicate settings
store. Page open is fast (~5 ms): TMemIniFile + pre-warmed
TRuleCatalog.

The dock-window Profile combo also acts as a live override that wins
over the INI for Silent-Mode runs — you can switch between profiles
in the dock and have the next Silent-Mode trigger pick it up without
hitting Save.


✨ IDE-plugin polish

  • Annotation overlay[✕]-button per hover overlay to dismiss
    individual stale findings (in addition to the file-scoped reset on
    save). After-code section in the Help-panel comes with a
    marker prefix.
  • Multi-file marker storageTFindingHighlighter keys marks by
    NormalizePath(filename) so switching editor tabs no longer
    clears markers of background files.
  • Auto-clear on saveIOTAModuleNotifier attached per marked
    file; AfterSave clears its marks because line numbers are no
    longer reliable after edits.
  • PerformanceTIniFileTMemIniFile (~25 syscalls → 1)
    in uRepoSettings. TRuleCatalog.ProfileNames pre-warmed at
    plugin load so the first Tools>Options page render doesn't pay
    the ~20-50 ms JSON-parse cost.

🌍 Internationalisation (i18n)

All new IDE-plugin captions and the standalone form's UI strings
are wrapped with _() and have German translations in
uLocalization.BuildDeMap. 18 new DE mappings cover the Tools>Options
page, editor popup, View menu, and BtnBranch hint. Wording
cleanups for existing entries:

  • "Silent-Modus" / "Silent-Analyse" (unified, was mixed with
    "Stille Analyse")
  • "Markierungen" (was "Streifen")
  • "Regelsatz" (was "Regel-Set")
  • "auch DUnit/DUnitX-Test-Units analysieren" (was "mit analysieren")

DFM-level hardcoded hints (e.g. BtnBranch.Hint) moved to runtime
assignment in FormCreate so the translation actually applies.


🖥 Standalone form

UI parity with the IDE plugin: toolbar with toolbar buttons, stat
tiles row above the grid, hint panel right of the grid for
Before/After code examples, three-panel status bar. Profile +
Min-Severity combos in the toolbar populated from
TRuleCatalog.ProfileNames. The standalone EXE no longer pops a
black console window on launch (was {$APPTYPE CONSOLE} from the
old DPR template; now GUI subsystem with AttachConsole for the
optional CLI path).


🐛 Fixes

  • Silent-Mode AutoDiscoverCustomClasses — the global flag is
    now mirrored from Settings.AutoDiscoverClasses before every
    Silent run. Previously the detection ran with whatever state the
    last dock-window run left behind, or False on cold IDE start.
    DiscoveredClasses / DiscoveredStaticClasses are cleared per
    Silent run so leftover hits from a different project don't bleed
    into the current analysis.
  • FEditorEventsObj MemoryLeak false-positive// noinspection MemoryLeak marker added directly above the .Create line in
    uIDELineHighlighter. The detector flagged this as a leak, but
    TFindingEditorEvents inherits TInterfacedObject and the
    refcount is held by FEditorEvents : INTACodeEditorEvents. No
    explicit Free needed.
  • uDfmRepoIndex / uFormBinder H2077 hints — dead-store
    nil-assignments before re-assignment removed.

📦 Migration

  • No INI migration needed — new keys are read with sane defaults
    ([Silent] Enabled=1, [Rules] IdeProfile=ide-fast, etc.).
  • Rule profiles: existing setups with no [Rules] Profile= get
    default (the full detector set, same behaviour as v0.8.0).
  • Plugin file rename: package is now
    StaticCodeAnalyser.IDE.d12.bpl (was StaticCodeAnalyserIDE.bpl).
    Remove the old BPL from Tools > Configure > Component > Install Packages and add the new one.
  • docs/APP.png removed — replaced by docs/sca-demo.gif as the
    README hero. If you embedded docs/APP.png somewhere else, you'll
    need to update the path.
  • Co-Authored-By policy: commits in this release deliberately
    strip the Co-Authored-By: Claude footer per maintainer preference.

v0.8.0 - DFM Scanner + Headless CLI + Rule Catalog + SARIF + Win64

Choose a tag to compare

@nrodear nrodear released this 11 May 22:42

v0.8.0 — DFM Scanner + Headless CLI + Rule Catalog + SARIF + Win64

Major-feature release that bundles four years' worth of structural
work into one tagged version:

  1. DFM scanner with 20 form-file detectors (Pascal-AST coupled
    via FormBinder + repo-wide form index) — total detector count
    grows from 21 to 41.
  2. Headless CLI mode that turns the tool into a CI/CD building
    block — console mode + detector rule catalog as single source of
    truth + SARIF v2.1.0 export for GitHub Code Scanning.
  3. IDE plugin polish — Sonar-style stat tiles, three-tier
    responsive docked-mode layout (hamburger menu absorbs actions
    under 500 px), single-file live watch, hover-hint overlay,
    editor-as-text DFM viewer via Close-and-Reopen.
  4. Win64 readiness — the standalone EXE now compiles cleanly
    for both Win32 and Win64 (the IDE plugin remains Win32-only
    because the RAD Studio 12 IDE itself is 32-bit).

📐 DFM scanner (NEW)

20 dedicated detectors for .dfm form files, grouped into six
clusters. Pascal-AST coupling means findings like
"Btn1Click referenced in DFM doesn't exist in published section"
or "SQL property built from Edit1.Text in companion .pas" are
caught.

Detectors (cluster overview)

Cluster Detectors
Dead-Wiring DfmDeadEvent, DfmOrphanHandler, DfmEmptyBoundEvent
Data-Access DfmSchemaMismatch, DfmCircularDataSource, DfmFieldTypeMismatch, DfmRequiredFieldUnbound, DfmRequiredFieldNotVisible
Security DfmHardcodedDbCreds, DfmSqlFromUserInput
Layering DfmDbInUiForm, DfmCrossFormCoupling, DfmLayerViolation, DfmForbiddenClass
UI/UX DfmDuplicateBinding, DfmTabOrderConflict, DfmGodHandler, DfmActionMismatch
Naming DfmDefaultName, DfmHardcodedCaption

Full descriptions in DETECTORS.md.

Infrastructure

  • DFM lexer + parser + component graph in
    sources/Parsing/uDfmLexer.pas, uDfmParser.pas,
    uComponentGraph.pas — own parsing front-end, independent of
    ToolsAPI / IDE.
  • Binary-DFM reader (uDfmBinaryReader) — TPF0-prefix
    detection + text conversion via the RTL. Binary-saved forms
    used to be silently skipped; now they get analysed.
  • Typed property accessors on TPropValue /
    TComponentNodeGetBoolean / GetInteger / GetString / GetIdent / SetPropertyContains, default-aware (VCL defaults
    for properties not serialised in the DFM).
  • FormBinder + Repo-wide form index (uFormBinder,
    uDfmRepoIndex) — couples DFM graph to Pascal AST,
    BindWithParents walks the class inheritance chain so
    inherited members are visible to detectors.
  • Frame resolver (uDfmFrameResolver) —
    ResolveFrameGraph / EnumerateFrameComponents load a
    frame's components on demand for cross-frame analyses.
  • VCS-diff aware.dfm changes trigger analysis of the
    companion .pas automatically (and vice versa).
  • HTML report — file dropdown groups .pas + .dfm with
    the same basename under one heading.

🖥️ IDE plugin polish (NEW since v0.7.2)

  • Dockable tool window with three-tier responsive layout
    (Narrow/Medium/Full breakpoints at 500/700 px). In narrow mode
    the toolbar collapses to ▶ Analyse / 📄 File / SearchEdit /
    ☰ Hamburger
    — all hidden actions remain reachable through the
    hamburger menu.
  • Single-file live watch ("📄 Current file") — file gets
    re-analysed on every save (300 ms debounced) and every edit
    (1000 ms debounced) in a background thread. .dfm saves now
    also trigger re-analysis of the companion .pas.
  • DFM finding opens DFM as text in the Code Editor via the
    Close-and-Reopen pattern (DFMCheck/GExperts-style). When the
    companion .pas is modified, falls back to opening the .pas
    and showing a status-bar hint.
  • Hover-hint overlay for finding lines with multi-line wrap.
  • Sonar-style stat tiles above the grid (Errors / Warnings /
    Hints / Bugs / Vulnerabilities / Code Quality score).
  • Theme tracking — follows the active Delphi IDE theme via
    IOTAIDEThemingServices + INTAIDEThemingServicesNotifier
    (light/dark/Mountain Mist/Carbon).
  • Claude AI prompt copy — click a finding to copy a
    ready-made Markdown prompt with code context to the clipboard.

🛠️ Headless CLI + Rule Catalog + SARIF

Highlights

  • Headless CLI modeanalyser.d12.exe is now console-aware
    ({$APPTYPE CONSOLE}) and accepts switches:

    analyser.exe --path D:\repo --full --report-sarif sca.sarif
    analyser.exe --path D:\repo --branch --quiet
    analyser.exe --file MyUnit.pas
    analyser.exe --help / --version
    

    Without switch arguments the VCL GUI still launches as before.
    Exit-code convention follows the SCA-tool standard:

     0 = clean
     1 = hints only
     2 = warnings present
     3 = errors present
     4 = read errors (parser/IO)
    99 = tool error (bad args, missing path, ...)
    
  • Rule catalog (rules/sca-rules.json) — single source of truth
    for all 22 Pascal-AST detector rules (SCA001SCA022). Per rule:
    stable ID, name, short/full description, default severity, type,
    tags, CWE, OWASP refs, config key, detector unit, bad/good examples.
    Loader uRuleCatalog with lookup-by-kind and lookup-by-ID. JSON
    schema (rules/sca-rules.schema.json) for editor autocomplete and
    CI validation. The 20 new DFM detectors ship via KIND_META in
    uSCAConsts but are not yet in the JSON catalog — that integration
    is the first follow-up item after this release.

  • SARIF v2.1.0 export (--report-sarif <file>) — the OASIS
    standard for static-analysis output. Natively consumed by
    GitHub Code Scanning, Azure DevOps, Visual Studio Code
    (with the SARIF extension) and SonarCloud. Findings appear
    directly in PRs as inline annotations; the GitHub Security tab
    tracks history per branch.

    • Full tool.driver.rules[] from the rule catalog (every finding
      has a rule ID + helpUri pointing at docs/rules.md)
    • partialFingerprints.primaryLocationLineHash (SHA256 over rule ID
      • path + line + message) for cross-commit deduplication in GitHub
    • Repo-relative paths with forward slashes (SARIF/GitHub convention)
    • properties.tags includes catalog tags + CWE + OWASP for filtering

CI integration

  • GitHub Actions workflow (.github/workflows/sca.yml) as a template:

    • Job sca: full project scan on push + PR, SARIF upload via
      github/codeql-action/upload-sarif@v3
    • Job sca-pr-changes: branch diff only (--branch), fail-on-error
      for PRs
  • Distribution pattern: the workflow downloads a release asset
    (analyser-windows.zip) containing analyser.d12.exe and the
    rules/ folder. Upload once per release with:

    Compress-Archive -Path bin\analyser.d12.exe,rules -DestinationPath dist\analyser-windows.zip
    gh release upload v0.8.0 dist\analyser-windows.zip

Engine

  • uConsoleRunner (Console/uConsoleRunner.pas, NEW) — argument
    parser supporting both --key=value and --key value syntax, run
    dispatcher (Branch/SingleFile/Full), exit-code mapping, stderr
    logging. Fully testable through the ParseArgs(Args: array of string)
    API without process I/O.

  • uRuleCatalog (Common/uRuleCatalog.pas, NEW) — lazy JSON
    loader with file lookup order (ExeDir/rules/, ../rules/, .../rules/),
    fallback mode if catalog JSON is missing (minimal metadata from the
    KIND_META enum), lookup methods + ForEach iterator.

  • uExportSARIF (Output/uExportSARIF.pas, NEW) — SARIF writer
    via System.JSON, no external deps. WriteFile API + ToJsonString
    API (for tests). partialFingerprints via THashSHA2.GetHashString.

  • DPR dispatch (analyser.d12.dpr) — checks via IsCliMode
    whether any param starts with - or /. If yes:
    Halt(uConsoleRunner.RunFromCmdLine) without spawning a VCL form.
    Otherwise: Application.Run as before. The duplicate
    Application.CreateForm bug from v0.7.x is fixed in passing.

Tests

  • TTestRuleCatalog with 6 tests in uTestRuleCatalog:
    EveryFindingKindHasRule (every TFindingKind must have a catalog entry),
    RuleIDsFollowConvention (SCA\d{3}), RuleIDsAreUnique,
    KindNameMatchesCatalog, ToolInfoIsPopulated, GetRuleByIDRoundtrip.

  • TTestExportSARIF with 10 tests in uTestExportSARIF:
    SchemaUriPresent, VersionIs210, ToolDriverHasNameAndVersion,
    RulesArrayContainsAllKinds, ResultHasRuleIdAndLevel,
    ResultLocationHasFileAndLine, RelativePathsAreUsedWhenBaseDirSet,
    FingerprintHashIsStable, SeverityMapsCorrectly,
    EmptyFindingsListProducesEmptyResults.

Docs

  • docs/rules.md — consolidated Markdown reference for all 22
    rules with anchor links per rule ID. Referenced by SARIF helpUri
    (docs/rules.md#sca001); GitHub shows it on the "More info" click
    in PR annotations.

  • tools/gen-rules-docs.py (Python 3.7+) — generates per-rule
    Markdown pages (docs/rules/SCA001.md, ...) from the catalog JSON.
    Has a --check mode for CI (fails if docs are out of sync).
    Currently optional — the single docs/rules.md covers SARIF
    helpUri as well.

Known limitations

  • Per-rule HTML documentation is not yet shipped — SARIF
    helpUri points at anchors in the consolidated docs/rules.md
    rather than separate pages. With Python available,
    tools/gen-rules-docs.py generates separate files per rule.

  • Quality-gate flags (--max-errors N --max-warnings N) are not
    yet implemented — pipeline failure today is only via the generic
    exit code (3 = errors). For threshold-based fails, check via an
    if step in .github/workflows/sca.yml until then.

  • Custom-rule engine (YAML) is on the roadmap as a v0.9.0
    item — YAML parser, TCustomRuleDetector, --custom-rules flag.
    Today users are limited to the hardcoded detectors.

🏗️ Win64 readiness

...

Read more

v0.7.2

Choose a tag to compare

@nrodear nrodear released this 10 May 16:23

v0.7.2 — Responsive-Layout-Refactor + Detector-Accuracy

Patch-Release ueber v0.7.1. Schwerpunkt: Architektur-Cleanup der Plugin-
UI (zentraler 3-Stufen-Layout-Controller statt verstreuter Visibility-
Toggler), Font-skalierte Component-Hoehen, drei FormatMismatch-Detector-
Fixes nach Code-Reviews realer mORMot-2.4-Befunde, sowie Polish am
In-Editor Hover-Hint Overlay.

Highlights

  • Zentraler TResponsiveLayoutController (NEU, ersetzt
    TResponsiveVisibilityController) — eine Klasse, eine ClientWidth-
    Quelle (Frame.OnResize), eine Sichtbarkeitstabelle. Vorher 5 verteilte
    Controller-Instanzen ueber 4 Panels mit chained OnResize-Hooks; jetzt
    deklarative Stage-Registrierung an einer Stelle:

    FResp := TResponsiveLayoutController.Create(Self, Self,
               BREAKPOINT_MEDIUM, BREAKPOINT_FULL);
    FResp.RegisterCtrl(FBtnCancel,    usFull);             // nur FULL
    FResp.RegisterCtrl(FLblFilter,    usMedium);           // ab MEDIUM
    FResp.RegisterCtrl(FBtnHamburger, usNarrow, usMedium); // inverse

    Hat AfterApply-Callback fuer Folge-Anpassungen (Sub-Panel-Width-Sync,
    SearchEdit-MinWidth-Sync). Ergebnis: 5 Controller-Instanzen + chained-
    OnResize-Race-Conditions weg, +80 Zeilen Code geloescht, alle Sichtbar-
    keitsregeln auf einem Blick lesbar.

  • TToolbarSizing-Helper (NEU) — loest die VCL-Quirk dass TComboBox
    die Align.Height ignoriert (rendert immer auf ItemHeight + ~6 px).
    Drei statische Methoden:

    • HeightForFont(Font) — leitet Soll-Hoehe aus Abs(Font.Height) + 11
      ab. DPI-aware ueber Font.Height (Pixel, kein extra ScaleW noetig).
      Bei Segoe UI 8pt = 22 px, 9pt = 23 px, 10pt = 24 px.
    • Apply(Ctrl, AHeight) — setzt Constraints.MinHeight = MaxHeight
      (VCL respektiert das auch bei aktivem Align), bei TComboBox zusaetz-
      lich ItemHeight := AHeight - 6. Resultat: Buttons/Edits/Combos
      rendern uniform.
    • ApplyIconButton(Ctrl, AWidth, AHeight) — zusaetzlich Width-
      Constraints fuer pixel-genaue Icon-Buttons (Browse "...",
      Hamburger ☰, Branch-Changes ⎇ alle uniform 32 px).
  • Floated-Min-Width = 500 px (NEU) — Frame.Constraints.MinWidth +
    Propagation auf das IDE-Host-Form via GetParentForm in
    FrameCreated. Verhindert pathologisch schmale Floats - das floated
    Window kann nicht mehr unter den MEDIUM-Stufen-Threshold geschrumpft
    werden.

  • In-Editor Hover-Hint Overlay (verfeinert) — Theme-adaptiv (Light/
    Dark folgt aktivem IDE-Theme via INTACodeEditorServices.Options. BackgroundColor), mehrzeiliger Wrap-Text, Severity-getoenter Title-
    Bar mit Akzent-Stripe links + Type-Badge rechts. Klick auf eine
    Befundzeile markiert ALLE Befunde derselben Datei (Multi-Marker via
    TDictionary<Integer, TFindingMark>). Komplett i18n via _().

Engine

  • FormatMismatch: drei zusammenhaengende False-Positive-Fixes nach
    Code-Reviews realer mORMot-2.4-Befunde:

    1. Bare-%-Counting fuer mORMot-Funktionen (FormatUtf8,
      FormatString, StringFormatUtf8): diese nutzen % allein als
      Platzhalter (kein Type-Letter wie %s/%d). Neue IsBareStyle-
      Check + zweite Counting-Strategie via CountPlaceholders(ABareStyle).
      Hardcoded-Liste BARE_STYLE_FUNCS - bei weiteren mORMot-Idiom-
      Funktionen dort ergaenzen.

    2. %% ist KEIN Escape im Bare-Style - verifiziert in mORMot-
      Source (mormot.core.text.pas:9616 TFormatUtf8.Parse): jedes %
      konsumiert ein Argument, %% = zwei aufeinanderfolgende Args ohne
      Trenner (mORMot nutzt das z.B. um Where-Clauses zu kettenkonkate-
      nieren). Standard-RTL-Format bleibt streng - dort ist %% weiter-
      hin Escape.

    3. String-Literal-Konkatenation 'a' + 'b' wird vor dem Counting
      gemerged - typisch fuer mehrzeilige SQL-Strings:

      FormatUtf8('SELECT ... ' + 'WHERE Id=%', [id])  // OK, 1+1 match

      Helper ReadStringLiteral/SkipSpaces, Loop bis kein + '...'
      mehr folgt. Nicht-statische Fortsetzungen (+ IntToStr(x)) brechen
      den Merge ab und der Detector liefert nur das gemergete Prefix
      (konservativ, kein False Positive).

    Effekt auf reale mORMot-2.4-Findings:

    File v0.7.1 v0.7.2
    dmvc-ai/.../api.impl.pas:62 False Positive (0 vs 1) OK (1 vs 1)
    dmvc-ai/.../api.impl.pas:71 False Positive (1 vs 2) OK (2 vs 2)
    dmvc-ai/.../api.impl.pas:126 False Positive (1 vs 2) OK (2 vs 2)
    mormot.orm.rest.pas:1780 True Bug, Count falsch True Bug, Count korrekt (9 vs 8)

IDE-Plugin

  • TResponsiveVisibilityController entfernt (deprecated in v0.7.1,
    geloescht in v0.7.2) - TResponsiveLayoutController ersetzt vollstaendig.
  • 3-Stufen-Layout stabilisiert: NARROW (<500), MEDIUM (500..849),
    FULL (>=850). Zwei Stufen-Wechsel statt frueher einer - Uebergang
    vom Hamburger-Pattern zum vollen UI ist smoother (kein abrupter
    Sprung in voller Toolbar).
  • Hamburger-Menu neu strukturiert: Analyse Branch-Changes, Cancel
    Analysis, Export..., Settings..., Ignore list... (Browse "..." und
    ▶ Analyse + 📄 File sind im Toolbar IMMER sichtbar, nicht im Menu).
    HamburgerMenuPopup synct Enabled-State von Cancel + Branch-Changes
    Items mit den zugehoerigen Buttons - kein Doppelclick-Race wenn
    Analyse laeuft.
  • Branch-Changes-Button als Icon-Glyph ⎇ (32 px) statt Caption-Button
    (104 px). Caption "Branch-Changes" + Volltext bleiben im Tooltip und
    im Hamburger-Menu erreichbar.
  • TAnalyserDockableForm.FrameCreated propagiert die Frame-MinWidth/
    MinHeight auf das Host-Form via GetParentForm - das IDE-Floating-
    Container respektiert die Mindestbreite jetzt auch beim Resize.
  • Tile-Reihe: alle 9 Tiles uniform 55 px breit (statt frueher 65/72/72
    pro Severity-/Type-/Detector-Tile). Konsistente Sonar-Style-Reihe.
    Stage-Registrierung: 4 essentials immer, +5 ab MEDIUM (Read errors,
    Bugs, Security, Duplicates, Cyclomatic).
  • Toolbar-Padding reduziert (TB_PADDING_TB 2→1) - Toolbar-Reihen
    nehmen pro Zeile 2 px weniger Hoehe ein.

Tests

  • TTestFormatMismatchBareStyle mit 6 neuen Tests in
    uTestFormatMismatch:
    • FormatUtf8_TwoBarePercents_TwoArgs_NoFinding (Original-Bug-Case)
    • FormatUtf8_OneBarePercent_TwoArgs_ReportsError
    • FormatString_BarePercentSeparator_NoFinding
    • FormatUtf8_DoublePercent_ConsumesTwoArgs (verifiziert kein Escape)
    • FormatUtf8_ConcatenatedLiteral_AllPlaceholdersCounted
    • FormatUtf8_ConcatenatedLiteral_MismatchAcrossSplit_ReportsError
    • StandardFormat_PercentUnderscore_StillReportsMismatch (RTL-Format-
      Regression)

i18n

  • Hover-Overlay: alle Anzeige-Strings ueber _() lokalisiert -
    Severity-Texte, Badge-Beschriftungen, Tile-Hints. DE-Dict-Eintraege
    fuer Bug, Code Smell, Vulnerability, Security Hotspot,
    Code Duplication, Read Error.
  • TLeakFinding.SeverityText / TypeText: Source-Strings auf
    Englisch (Konvention von uLocalization), DE-Mapping ueber
    Dictionary. Falls analyser.ini [UI]/Language=de, wird in der UI
    automatisch Fehler/Warnung/Hinweis angezeigt.

Bekannte Einschraenkungen

  • %%-Heuristik im Bare-Style ist konservativ: jedes % zaehlt
    unabhaengig vom Kontext. Bei sehr exotischen mORMot-Patterns (z.B.
    FormatUtf8('%' + Var, [x])) kann der Detector daneben liegen wenn
    Var zur Compile-Zeit ein % enthaelt - aber das ist a) Bare-Style-
    konform (mORMot wuerde es auch falsch interpretieren) und b) schwer
    statisch zu erkennen.
  • Bare-Style-Funktionsliste ist hardcoded auf
    formatutf8/formatstring/stringformatutf8. Falls weitere mORMot-
    Helpers (StringFormatBuffer, FormatShort, FormatToShort) auf-
    tauchen, in BARE_STYLE_FUNCS ergaenzen. Optional spaeter via
    [Detectors] BareFormatFunctions=... konfigurierbar machen.

Upgrade von v0.7.1

  • Keine Source-Aenderungen im User-Code noetig. Alle Detector-Fixes
    sind reine Engine-Verbesserungen.
  • IDE-Plugin Layout identisch zu v0.7.1 (3-Stufen NARROW/MEDIUM/FULL),
    nur intern auf den zentralen Controller umgebaut. Keine User-
    sichtbaren Aenderungen.
  • analyser.ini-Konfiguration unveraendert. [Detectors] FormatFunctions aus v0.7.1 funktioniert weiterhin - die Bare-Style-
    Erkennung erfolgt orthogonal ueber den Funktionsnamen.
  • HTML-/JSON-/CSV-Exporte unveraendert.
  • Bestehende Suppressions, ignore.txt-Eintraege, Custom-LeakyClasses,
    Severity-Konfiguration
    bleiben gueltig.

v0.7.1 - Pre-Release

Choose a tag to compare

@nrodear nrodear released this 08 May 23:36

v0.7.1 — Pre-Release

Patch-Release ueber v0.7.0 mit Schwerpunkt auf Code-Metriken (neuer
Detector), responsive Docked-Mode-UI fuer das IDE-Plugin, AI-Prompt-
Verbesserungen und durchgaengiger DPI-Skalierung.

Highlights

  • Cyclomatic Complexity (McCabe) Detector (NEU, Phase 1 der Code-
    Metriken-Roadmap) — TCyclomaticComplexityDetector misst pro
    Methode die McCabe-Komplexitaet: 1 Base + if + case-Arm +
    for/while/repeat + on-Handler + and/or/xor BinaryOps.
    else zaehlt nicht (binary branch). Default-Schwelle: 10
    (Sonar/Checkstyle/PMD-Standard) via [Detectors] CyclomaticMax.
    Findings als fkCyclomaticComplexity mit Refactor-Hint in
    uFixHint (Before/After-Beispiel mit CanProcess/ProcessOrder-
    Methoden-Split).
  • Docked-Mode UI (NEU, IDE-Plugin) — der Plugin-Frame erkennt
    schmale Container (< 700 px ClientWidth, typisch fuer gedockte
    IDE-Tool-Panels) und reduziert sich auf das Wesentliche:
    • Stats-Tiles schrumpfen auf 4 essenzielle (Errors / Warnings /
      Hints / Code Quality)
    • Action-Buttons (Start / Current / Branch-Changes) wandern ins
      Hamburger-Menu (☰)
    • Settings / Ignore-Liste werden ebenfalls per Hamburger erreichbar
    • Filter-Combo-Labels verschwinden (Combos selbsterklaerend)
    • SearchEdit-MinWidth schrumpft von 120 auf 60 px im Docked
    • Sub-Panel-Container (Severity-/Type-Combo) passen ihre Width an
      Label-Visibility an
    • Floated: alles wie gewohnt - voller Funktionsumfang sichtbar
  • AI-Prompt-Rewrite (uClaudePrompt) — Role-Priming am Anfang
    ("senior Delphi developer reviewing static-analysis output"),
    strukturierte Antwort-Vorgabe (Cause / Fix / Verify), Vorher/Nachher
    als "Reference pattern (NOT the user's code)" markiert, Source-
    Marker >>> deutlich auffaelliger, False-Positive-Pfad mit
    // noinspection-Vorschlag. Komplett ueber _(...) lokalisiert -
    DE-User bekommt DE-Prompt -> DE AI-Antwort.
  • DPI-Scaling durchgehend in der IDE-Plugin-UI - alle hardcoded
    Pixel-Widths/Heights laufen jetzt durch ScaleW(...) (Frame) bzw.
    ScaleByPPI(...) (Stats-Tiles). Plugin sieht auf 200%-DPI nicht
    mehr halb so gross aus. Auch der Docked-Threshold 700 wird skaliert.

IDE-Plugin

  • Cyclomatic-Stats-Tile zwischen "Duplicates" und "Code Quality"
    (Magenta-Branch-Glyph, ICON_SMELL-Farbton). Zaehlt
    fkCyclomaticComplexity-Findings.
  • Klickbare Stats-Tiles - Hover zeigt Multi-Line-Tooltip mit
    Erklaerung, Klick filtert das Grid auf die jeweilige Severity bzw.
    Type-Bucket. Code-Quality-Tile resetet alle Filter.
  • Filter-Combo bekommt "Cyclomatic Complexity"-Eintrag.
  • TResponsiveVisibilityController (in uIDEStatsTiles) -
    generischer Layout-Controller, hookt Parent.OnResize chained ohne
    bestehende Handler zu zerstoeren, AInverse-Flag fuer "show-only-
    when-narrow"-Controls (Hamburger).
  • TAnalyserFrame.Resize-Override (statt nur OnResize-Event) -
    garantiert Responsive-Trigger auch bei Float->Dock-Transitions, wo
    die IDE-Dock-Logik den OnResize-Event manchmal verschluckt.
  • Magic-Numbers konsolidiert in BTN_W_*/LBL_W_*/CMB_W_*/
    STATS_*/TB_*-Konstanten. 14 verstreute Pixel-Werte vorher,
    jetzt benannte Const-Sektion.
  • BuildHamburgerMenu als eigene Methode extrahiert (war ~25
    Inline-Zeilen).

Engine

  • Cyclomatic-Detector-Implementation liest nkIfStmt.TypeRef
    fuer Boolean-Op-Counts (Parser baut keine Expression-AST, nur
    Cond-Text auf if-Knoten). while/repeat/case-Conditions liegen
    gar nicht vor - akzeptabler Trade-off vs. Parser-Erweiterung.

Tests

  • uTestAnalyserChecks (7500 LOC) zerlegt in 16 Per-Detector-
    Test-Units: uTestFindingHelper (shared TFindingHelper), plus
    je eine Unit pro Detector-Themengruppe (uTestLeakDetector,
    uTestSQLInjection, uTestHardcodedSecret, ...). DUnitX
    initialization-Block geloescht; Runner nutzt RTTI
    (UseRTTI := True) und findet [TestFixture]-Klassen automatisch
    sobald die Unit referenziert ist.
  • TTestCyclomaticComplexity mit 10 neuen Tests in
    uTestCodeMetrics (Trivial, SingleIf, ElseDoesNotCount,
    BooleanAndOr, ManyIfs, CaseArms, ForWhileRepeat, OnHandler,
    TryFinallyNotCounted, TwoMethodsOneOver).

i18n

  • ~40 neue Dict-Eintraege in uLocalization: Tile-Hints
    (Multi-Line, EN-source -> DE-dict), Hamburger-Menu-Items,
    Cyclomatic-Tile-Caption + FilterCombo-Eintrag, AI-Prompt-Headings
    • Strukturierte-Antwort-Bestandteile, Watch-Status, Cyclomatic-
      FixHint.
  • uIDEWatchMode Status-Strings durch Format(_(...), [...])
    ersetzt - vorher hardcoded English ohne _(...)-Wrap.
  • Stale Dict-Eintraege gefixt: Settings: ... next click of Branch-Changes -> ... the next analysis run (Source hatte ich
    geaendert, Dict zeigte alte Variante). Spelling-Drift fix:
    Analyzing: (US) -> Analysing: (BR), matched jetzt den
    existierenden Dict-Key.

Configuration

  • [Detectors] CyclomaticMax=10 (NEU, Default 10) - INI-Doc-
    Block ergaenzt mit Erklaerung was zaehlt.

Bekannte Einschraenkungen

  • Single-File-Live-Watch ohne Re-Entrancy-Guard - unveraendert
    zu v0.7.0. Bei langsamen Workers + aktivem Tippen kann der Backlog
    wachsen. Phase 2 (TODO.md Single-File-Live-Watch).
  • Docked-Mode UI ist Phase 1 der Roadmap - weitere Phasen in
    TODO.md (Layout-Architektur via TFlowPanel, Two-Mode-UI, Polish).

Upgrade von v0.7.0

  • [Detectors] CyclomaticMax=10 ist neu im Default-INI-Template,
    aber bestehende analyser.ini ohne diesen Eintrag bekommt einfach
    den Default. Kein Migrationspfad noetig.
  • IDE-Plugin Layout veraendert sich beim Resize/Dock - Floated-
    Mode visuell wie v0.7.0, Docked-Mode neu (Hamburger + reduzierte
    Toolbar). Keine User-Aktion noetig.
  • Bestehende Suppressions, ignore.txt-Eintraege, Custom-LeakyClasses,
    Severity-Konfiguration
    bleiben unveraendert gueltig.
  • HTML-Exporte unveraendert.