From ea84a94055e232ba3b6e257d27e552caf2529bbd Mon Sep 17 00:00:00 2001 From: davidramnero Date: Wed, 24 Jun 2026 15:51:52 +0200 Subject: [PATCH 1/2] fix/ avoid overwriting existing diagnostics of included files when opening a new file --- src/extension.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index c8436a8..b57ec7c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -349,7 +349,7 @@ async function runCppcheckOnFileXML( const errors = result.results?.errors?.[0]?.error || []; const diagnostics: Record = {}; - + console.log('errors from file', document.fileName, errors); for (const e of errors) { const isCriticalError = criticalWarningTypes.includes(e.$.id); const locations = e.location || []; @@ -377,7 +377,7 @@ async function runCppcheckOnFileXML( // Cppcheck col number is 1-indexed, while VS Code uses 0-indexing let col = Number(mainLoc.column) - 1; - if (isNaN(col) || col < 0 || col > document.lineAt(line).text.length) { + if (isNaN(col) || col < 0) { col = 0; } @@ -405,12 +405,16 @@ async function runCppcheckOnFileXML( const loc = locations[locations.length - i].$; const msg = loc.info; const lLine = Number(loc.line) - 1; - const lCol = Number(loc.col) - 1; + var lCol = Number(loc.col) - 1; if (msg === null || msg === undefined || isNaN(lLine) || lLine < 0 || lLine >= document.lineCount) { continue; } + if (isNaN(lCol) || lCol < 0) { + lCol = 0; + } + const relatedRange = new vscode.Range( lLine, lCol, lLine, document.lineAt(lLine).text.length @@ -444,7 +448,26 @@ async function runCppcheckOnFileXML( } const sourceDocumentUri = document.uri.toString(); for (const uri of Object.keys(diagnostics)) { - diagnosticCollection.set(vscode.Uri.parse(uri), diagnostics[uri]); + const existingDiagnostics = + diagnosticCollection.get(vscode.Uri.parse(uri)); + // If file has existing diagnostics from analyzing other files we do not want to overwrite those + const newDiagnostics = diagnostics[uri]; + + if (existingDiagnostics) { + // Compare existing diagnostics to new diagnostics (error code & range) to only push unique ones + for (const diagnostic of existingDiagnostics) { + if (!newDiagnostics.some((d) => { + if (typeof(diagnostic?.code) === "object" && typeof(diagnostic?.code) !== null && typeof(d?.code) === "object" && typeof(d?.code) !== null) { + return diagnostic.code.value === d.code.value && diagnostic.range.isEqual(d.range); + } else { + return diagnostic.code === d.code && diagnostic.range.isEqual(d.range); + } + })) { + newDiagnostics.push(diagnostic); + } + } + } + diagnosticCollection.set(vscode.Uri.parse(uri), newDiagnostics); if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { fileRelationMap[uri] = new Set; } From 8506e8e6575d266a8695d51e27574be7b68a0c45 Mon Sep 17 00:00:00 2001 From: davidramnero Date: Wed, 24 Jun 2026 16:15:57 +0200 Subject: [PATCH 2/2] fix checking line length in wrong file --- src/extension.ts | 39 ++++++++++++--------------------------- src/util/diagnostics.ts | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 27 deletions(-) create mode 100644 src/util/diagnostics.ts diff --git a/src/extension.ts b/src/extension.ts index b57ec7c..ab87963 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,6 +6,7 @@ import * as crypto from 'crypto'; import { documentationLinkMap, getPremiumCertLink } from './util/documentation'; import { runCommand } from './util/scripts'; import { looksLikePath, resolvePath, findWorkspaceRoot } from './util/path'; +import { diagnosticsUnion } from './util/diagnostics'; // To keep track of document changes we save hashed versions of their content to this record let documentHashMemory : Record = {}; @@ -349,7 +350,6 @@ async function runCppcheckOnFileXML( const errors = result.results?.errors?.[0]?.error || []; const diagnostics: Record = {}; - console.log('errors from file', document.fileName, errors); for (const e of errors) { const isCriticalError = criticalWarningTypes.includes(e.$.id); const locations = e.location || []; @@ -358,12 +358,13 @@ async function runCppcheckOnFileXML( } const mainLoc = locations[locations.length - 1].$; - // If main location is not current file, we are not using a project file and warning is not critical then skip displaying warning if (!isCriticalError && usingProjectFile && !filePath.endsWith(mainLoc.file)) { continue; } + const mainLocDocument = await vscode.workspace.openTextDocument(mainLoc.file); + // Cppcheck line number is 1-indexed, while VS Code uses 0-indexing let line = Number(mainLoc.line) - 1; // Invalid line number usually means non-analysis output @@ -377,7 +378,7 @@ async function runCppcheckOnFileXML( // Cppcheck col number is 1-indexed, while VS Code uses 0-indexing let col = Number(mainLoc.column) - 1; - if (isNaN(col) || col < 0) { + if (isNaN(col) || col < 0 || col > mainLocDocument.lineAt(line).text.length) { col = 0; } @@ -386,7 +387,7 @@ async function runCppcheckOnFileXML( continue; } - const range = new vscode.Range(line, col, line, document.lineAt(line).text.length); + const range = new vscode.Range(line, col, line, mainLocDocument.lineAt(line).text.length); const diagnostic = new vscode.Diagnostic(range, e.$.msg, severity); diagnostic.source = "cppcheck"; // If we have a link to documentation, include it @@ -405,21 +406,17 @@ async function runCppcheckOnFileXML( const loc = locations[locations.length - i].$; const msg = loc.info; const lLine = Number(loc.line) - 1; - var lCol = Number(loc.col) - 1; + const lCol = Number(loc.col) - 1; if (msg === null || msg === undefined || isNaN(lLine) || lLine < 0 || lLine >= document.lineCount) { continue; } - if (isNaN(lCol) || lCol < 0) { - lCol = 0; - } - + const relatedDocument = await vscode.workspace.openTextDocument(loc.file); const relatedRange = new vscode.Range( lLine, lCol, - lLine, document.lineAt(lLine).text.length + lLine, relatedDocument.lineAt(lLine).text.length ); - const relatedDocument = await vscode.workspace.openTextDocument(loc.file); relatedInfos.push( new vscode.DiagnosticRelatedInformation( new vscode.Location(relatedDocument?.uri ?? '', relatedRange), @@ -427,6 +424,7 @@ async function runCppcheckOnFileXML( ) ); } + if (relatedInfos.length > 0) { diagnostic.relatedInformation = relatedInfos; } @@ -448,24 +446,11 @@ async function runCppcheckOnFileXML( } const sourceDocumentUri = document.uri.toString(); for (const uri of Object.keys(diagnostics)) { - const existingDiagnostics = - diagnosticCollection.get(vscode.Uri.parse(uri)); + var newDiagnostics = diagnostics[uri]; // If file has existing diagnostics from analyzing other files we do not want to overwrite those - const newDiagnostics = diagnostics[uri]; - + const existingDiagnostics = diagnosticCollection.get(vscode.Uri.parse(uri)); if (existingDiagnostics) { - // Compare existing diagnostics to new diagnostics (error code & range) to only push unique ones - for (const diagnostic of existingDiagnostics) { - if (!newDiagnostics.some((d) => { - if (typeof(diagnostic?.code) === "object" && typeof(diagnostic?.code) !== null && typeof(d?.code) === "object" && typeof(d?.code) !== null) { - return diagnostic.code.value === d.code.value && diagnostic.range.isEqual(d.range); - } else { - return diagnostic.code === d.code && diagnostic.range.isEqual(d.range); - } - })) { - newDiagnostics.push(diagnostic); - } - } + newDiagnostics = diagnosticsUnion(newDiagnostics, existingDiagnostics.flat()); } diagnosticCollection.set(vscode.Uri.parse(uri), newDiagnostics); if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { diff --git a/src/util/diagnostics.ts b/src/util/diagnostics.ts new file mode 100644 index 0000000..0054b1a --- /dev/null +++ b/src/util/diagnostics.ts @@ -0,0 +1,23 @@ +import * as vscode from 'vscode'; + +export function diagnosticsUnion(diagnosticsA : vscode.Diagnostic[], diagnosticB : vscode.Diagnostic[]) : vscode.Diagnostic[] { + const diagnosticsUnion = new Array; + // Add all elements from diagnosticsA to result array + diagnosticsUnion.push(...diagnosticsA); + + // Add all elements present in diagnosticsB but not in diagnosticsA to result array + for (const diagnostic of diagnosticB) { + if (!diagnosticsA.some((d) => { + if (typeof(diagnostic?.code) === "object" && typeof(diagnostic?.code) !== null && typeof(d?.code) === "object" && typeof(d?.code) !== null) { + return diagnostic.code.value === d.code.value && diagnostic.range.isEqual(d.range); + } else { + return diagnostic.code === d.code && diagnostic.range.isEqual(d.range); + } + })) { + diagnosticsUnion.push(diagnostic); + } + } + + // Return result + return diagnosticsUnion; +} \ No newline at end of file