From 428f0423ec84d14126cdf5a2164e08eeb54b85ca Mon Sep 17 00:00:00 2001 From: davidramnero Date: Wed, 26 Aug 2026 21:55:24 +0200 Subject: [PATCH 1/5] fix / avoid throwing out hidden and filtered diagnostics --- src/extension.ts | 94 ++++++++++++++++++++++++----------------- src/util/diagnostics.ts | 1 + 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index aefec69..8e097b8 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -75,24 +75,10 @@ function severityToNumber(sev: vscode.DiagnosticSeverity): SeverityNumber { } } -function parseMinSeverity(str: string): SeverityNumber { - switch (str.toLowerCase()) { - case "error": return SeverityNumber.Error; - case "warning": return SeverityNumber.Warning; - default: return SeverityNumber.Info; - } -} - -function filterOutDiagnosticsBelowSeverityLevel(diagnosticCollection : vscode.DiagnosticCollection, severity : vscode.DiagnosticSeverity) { - diagnosticCollection.forEach((uri : vscode.Uri, diagnostics : readonly vscode.Diagnostic[], collection: vscode.DiagnosticCollection) => { - const filteredDiagnostics = diagnostics?.filter((diagnostic : vscode.Diagnostic) => { - if (severityToNumber(diagnostic.severity) < severityToNumber(severity)) { - return false; - } - return true; - }); - collection.set(uri, filteredDiagnostics); - }); +function setDiagnosticHiddenStatus(diagnostic : vscode.Diagnostic, hiddenStatus : boolean) { + var metadata = diagnosticMetadataStore.get(diagnostic); + const newMetaData = { ...metadata, hidden: hiddenStatus }; + diagnosticMetadataStore.set(diagnostic, newMetaData); } function updateProgressIndicator(): void { @@ -127,6 +113,35 @@ export async function activate(context: vscode.ExtensionContext) { // Create a diagnostic collection. const diagnosticCollection = vscode.languages.createDiagnosticCollection("Cppcheck"); context.subscriptions.push(diagnosticCollection); + + // Create a map for storing all diagnostics, including hidden / filtered diagnostics + const uriDiagnosticsMap = new Map(); + + function filterDisplayedDiagnosticsBasedOnHiddenStatus() { + uriDiagnosticsMap.forEach((diagnostics : vscode.Diagnostic[], uri : vscode.Uri) => { + const filteredDiagnostics = diagnostics?.filter((diagnostic : vscode.Diagnostic) => { + var metadata = diagnosticMetadataStore.get(diagnostic); + if (metadata?.hidden) { + return false; + } + return true; + }); + diagnosticCollection.set(uri, filteredDiagnostics); + }); + } + + function hideDiagnosticsBasedOnSeverityLevel(severity : vscode.DiagnosticSeverity) { + uriDiagnosticsMap.forEach((diagnostics : vscode.Diagnostic[]) => { + diagnostics?.forEach((diagnostic : vscode.Diagnostic) => { + if (severityToNumber(diagnostic.severity) < severityToNumber(severity)) { + setDiagnosticHiddenStatus(diagnostic, true); + } else { + setDiagnosticHiddenStatus(diagnostic, false); + } + }); + }); + filterDisplayedDiagnosticsBasedOnHiddenStatus(); + } // Set up code actions provider context.subscriptions.push( @@ -189,18 +204,17 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand( "cppcheck-official.hideWarning", async (uri : vscode.Uri, diagnosticCode : string, range : vscode.Range) => { - const diagnostics = diagnosticCollection.get(uri); - const filteredDiagnostics = diagnostics?.filter((diagnostic : vscode.Diagnostic) => { + const diagnostics = uriDiagnosticsMap.get(uri); + diagnostics?.forEach((diagnostic : vscode.Diagnostic) => { var code = diagnostic.code; if (typeof(code) === "object" && typeof(code) !== null) { code = code.value; } if (code === diagnosticCode && diagnostic.range.isEqual(range)) { - return false; + setDiagnosticHiddenStatus(diagnostic, true); } - return true; }); - diagnosticCollection.set(uri, filteredDiagnostics); + filterDisplayedDiagnosticsBasedOnHiddenStatus(); } ) ); @@ -210,19 +224,18 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand( "cppcheck-official.hideWarningType", async (diagnosticCode : string) => { - diagnosticCollection.forEach((uri : vscode.Uri, diagnostics : readonly vscode.Diagnostic[], collection : vscode.DiagnosticCollection) => { - const filteredDiagnostics = diagnostics?.filter((diagnostic : vscode.Diagnostic) => { + uriDiagnosticsMap.forEach((diagnostics : readonly vscode.Diagnostic[]) => { + diagnostics?.forEach((diagnostic : vscode.Diagnostic) => { var code = diagnostic.code; if (typeof(code) === "object" && typeof(code) !== null) { code = code.value; } if (code === diagnosticCode) { - return false; + setDiagnosticHiddenStatus(diagnostic, true); } - return true; }); - collection.set(uri, filteredDiagnostics); }); + filterDisplayedDiagnosticsBasedOnHiddenStatus(); } ) ); @@ -315,7 +328,7 @@ export async function activate(context: vscode.ExtensionContext) { ); // Clear diagnostics below severity level selected from the problems tab - filterOutDiagnosticsBelowSeverityLevel(diagnosticCollection, parseSeverity(selection.value)); + hideDiagnosticsBasedOnSeverityLevel(parseSeverity(selection.value)); updateMinSeverityOption(); } @@ -382,7 +395,6 @@ export async function activate(context: vscode.ExtensionContext) { const config = vscode.workspace.getConfiguration(); const isEnabled = config.get("cppcheck-official.enable", true); - const minSevString = config.get("cppcheck-official.minSeverity", "info"); const userPath = config.get("cppcheck-official.path")?.trim() || ""; const commandPath = userPath ? resolvePath(userPath) : "cppcheck"; @@ -425,9 +437,12 @@ export async function activate(context: vscode.ExtensionContext) { document, commandPath, processedArgs, - minSevString, - diagnosticCollection + uriDiagnosticsMap, ); + + // Diagnostics from analysis are stored in DiagnosticCollectionAll, the displayed diagnostic collection + // is diagnosticCollection, which is set by the filter function filterDisplayedDiagnosticsBasedOnHiddenStatus() + filterDisplayedDiagnosticsBasedOnHiddenStatus(); } // Listen for file saves. @@ -496,18 +511,19 @@ async function runCppcheckOnFileXML( document: vscode.TextDocument, commandPath: string, processedArgs: string, - minSevString: string, - diagnosticCollection: vscode.DiagnosticCollection + uriDiagnosticsMap: Map, ): Promise { checksRunning = true; updateProgressIndicator(); // Clear existing diagnostics for this file - diagnosticCollection.delete(document.uri); + uriDiagnosticsMap.delete(document.uri); // Replace backslashes (used in paths in Windows environment) const filePath = document.fileName.replaceAll('\\', '/'); - const minSevNum = parseMinSeverity(minSevString); + + // We always call cppcheck with severity level info, and then filter warnings when displaying them + const minSevNum = SeverityNumber.Info; // Resolve paths for arguments where applicable const argsParsed = processedArgs.split(" ").map((arg) => { @@ -638,7 +654,7 @@ async function runCppcheckOnFileXML( // Save line of code at main location if we can access it const mainLocLine = mainLocDocument?.lineAt(line)?.text ?? ''; - diagnosticMetadataStore.set(diagnostic, {symbolName, mainLocLine}); + diagnosticMetadataStore.set(diagnostic, { symbolName, mainLocLine, hidden: false }); // Related Information const relatedInfos: vscode.DiagnosticRelatedInformation[] = []; @@ -708,11 +724,11 @@ async function runCppcheckOnFileXML( for (const uri of Object.keys(diagnostics)) { var newDiagnostics = diagnostics[uri]; // If file has existing diagnostics from analyzing other files we do not want to overwrite those - const existingDiagnostics = diagnosticCollection.get(vscode.Uri.parse(uri)); + const existingDiagnostics = uriDiagnosticsMap.get(vscode.Uri.parse(uri)); if (existingDiagnostics) { newDiagnostics = diagnosticsUnion(newDiagnostics, existingDiagnostics.flat()); } - diagnosticCollection.set(vscode.Uri.parse(uri), newDiagnostics); + uriDiagnosticsMap.set(vscode.Uri.parse(uri), newDiagnostics); if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { fileRelationMap[uri] = new Set; } diff --git a/src/util/diagnostics.ts b/src/util/diagnostics.ts index 1fd21fb..e5ac63a 100644 --- a/src/util/diagnostics.ts +++ b/src/util/diagnostics.ts @@ -3,6 +3,7 @@ import * as vscode from 'vscode'; interface DiagnosticMetadata { symbolName?: string; mainLocLine?: string; + hidden: boolean; } export class DiagnosticMetadataStore { From 90b44faf16c6fc33589614fd01ab90928ba8127d Mon Sep 17 00:00:00 2001 From: davidramnero Date: Wed, 26 Aug 2026 23:18:35 +0200 Subject: [PATCH 2/5] changed diagnosticMap key to be string instead of uri object --- src/extension.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 8e097b8..eec5a8c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -114,11 +114,11 @@ export async function activate(context: vscode.ExtensionContext) { const diagnosticCollection = vscode.languages.createDiagnosticCollection("Cppcheck"); context.subscriptions.push(diagnosticCollection); - // Create a map for storing all diagnostics, including hidden / filtered diagnostics - const uriDiagnosticsMap = new Map(); + // Create a map for storing all diagnostics, including hidden / filtered diagnostics. Key is file uri as a string + const uriDiagnosticsMap = new Map(); function filterDisplayedDiagnosticsBasedOnHiddenStatus() { - uriDiagnosticsMap.forEach((diagnostics : vscode.Diagnostic[], uri : vscode.Uri) => { + uriDiagnosticsMap.forEach((diagnostics : vscode.Diagnostic[], uri : string) => { const filteredDiagnostics = diagnostics?.filter((diagnostic : vscode.Diagnostic) => { var metadata = diagnosticMetadataStore.get(diagnostic); if (metadata?.hidden) { @@ -126,7 +126,7 @@ export async function activate(context: vscode.ExtensionContext) { } return true; }); - diagnosticCollection.set(uri, filteredDiagnostics); + diagnosticCollection.set(vscode.Uri.parse(uri), filteredDiagnostics); }); } @@ -204,7 +204,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand( "cppcheck-official.hideWarning", async (uri : vscode.Uri, diagnosticCode : string, range : vscode.Range) => { - const diagnostics = uriDiagnosticsMap.get(uri); + const diagnostics = uriDiagnosticsMap.get(uri.toString()); diagnostics?.forEach((diagnostic : vscode.Diagnostic) => { var code = diagnostic.code; if (typeof(code) === "object" && typeof(code) !== null) { @@ -359,8 +359,9 @@ export async function activate(context: vscode.ExtensionContext) { for (const fileUri of Object.keys(fileRelationMap)) { if (fileRelationMap[fileUri].has(doc.uri.toString())) { if (fileRelationMap[fileUri].size <= 1) { - diagnosticCollection.delete(vscode.Uri.parse(fileUri)); + uriDiagnosticsMap.delete(fileUri); fileRelationMap[fileUri].clear(); + filterDisplayedDiagnosticsBasedOnHiddenStatus(); } else { fileRelationMap[fileUri].delete(doc.uri.toString()); } @@ -511,13 +512,13 @@ async function runCppcheckOnFileXML( document: vscode.TextDocument, commandPath: string, processedArgs: string, - uriDiagnosticsMap: Map, + uriDiagnosticsMap: Map, ): Promise { checksRunning = true; updateProgressIndicator(); // Clear existing diagnostics for this file - uriDiagnosticsMap.delete(document.uri); + uriDiagnosticsMap.delete(document.uri.toString()); // Replace backslashes (used in paths in Windows environment) const filePath = document.fileName.replaceAll('\\', '/'); @@ -724,11 +725,11 @@ async function runCppcheckOnFileXML( for (const uri of Object.keys(diagnostics)) { var newDiagnostics = diagnostics[uri]; // If file has existing diagnostics from analyzing other files we do not want to overwrite those - const existingDiagnostics = uriDiagnosticsMap.get(vscode.Uri.parse(uri)); + const existingDiagnostics = uriDiagnosticsMap.get(uri); if (existingDiagnostics) { newDiagnostics = diagnosticsUnion(newDiagnostics, existingDiagnostics.flat()); } - uriDiagnosticsMap.set(vscode.Uri.parse(uri), newDiagnostics); + uriDiagnosticsMap.set(uri, newDiagnostics); if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { fileRelationMap[uri] = new Set; } From 32ea4c56fb36317850453e79be8f49b37824536f Mon Sep 17 00:00:00 2001 From: davidramnero Date: Thu, 27 Aug 2026 08:33:16 +0200 Subject: [PATCH 3/5] promisify child process listener call to avoid async race condition --- src/extension.ts | 309 ++++++++++++++++++++++++----------------------- 1 file changed, 157 insertions(+), 152 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index eec5a8c..920682a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -443,7 +443,8 @@ export async function activate(context: vscode.ExtensionContext) { // Diagnostics from analysis are stored in DiagnosticCollectionAll, the displayed diagnostic collection // is diagnosticCollection, which is set by the filter function filterDisplayedDiagnosticsBasedOnHiddenStatus() - filterDisplayedDiagnosticsBasedOnHiddenStatus(); + const minSevString = config.get("cppcheck-official.minSeverity", "info"); + hideDiagnosticsBasedOnSeverityLevel(parseSeverity(minSevString)); } // Listen for file saves. @@ -567,182 +568,186 @@ async function runCppcheckOnFileXML( cwd, }); - // if spawn fails (e.g. ENOENT or permission denied) - proc.on("error", (err) => { - console.error("Failed to start cppcheck:", err); - vscode.window.showErrorMessage(`Cppcheck failed to start: ${err.message}`); - }); - - let xmlOutput = ""; - let out = ""; - proc.stderr.on("data", d => xmlOutput += d.toString()); - proc.stdout.on("data", d => out += d.toString()); - proc.on("close", code => { - if (code && code > 0) { - // Non-zero code means an error has occured - let errorMessage = `Cppcheck failed with code ${code} (unknown error)`; - if (out.trim().length > 0) { - errorMessage = out.trim(); - } - errorMessage = `${errorMessage}, Command: ${commandPath} ${args.join(' ')}`; - vscode.window.showErrorMessage(errorMessage); - } - const parser = new xml2js.Parser({ explicitArray: true }); - parser.parseString(xmlOutput, async (err, result) => { - if (err) { - console.error("XML parse error:", err); - return; - } - - const errors = result.results?.errors?.[0]?.error || []; - const diagnostics: Record = {}; - for (const e of errors) { - const isCriticalError = criticalWarningTypes.includes(e.$.id); - const locations = e.location || []; - if (!locations.length) { - continue; - } + await new Promise((resolve, reject) => { + // if spawn fails (e.g. ENOENT or permission denied) + proc.on("error", (err) => { + console.error("Failed to start cppcheck:", err); + vscode.window.showErrorMessage(`Cppcheck failed to start: ${err.message}`); + reject(err); + }); - 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; + let xmlOutput = ""; + let out = ""; + proc.stderr.on("data", d => xmlOutput += d.toString()); + proc.stdout.on("data", d => out += d.toString()); + proc.on("close", code => { + if (code && code > 0) { + // Non-zero code means an error has occured + let errorMessage = `Cppcheck failed with code ${code} (unknown error)`; + if (out.trim().length > 0) { + errorMessage = out.trim(); } - - let mainLocDocument : vscode.TextDocument | undefined; - try { - mainLocDocument = await vscode.workspace.openTextDocument(mainLoc.file); - } catch { - // do nothing + errorMessage = `${errorMessage}, Command: ${commandPath} ${args.join(' ')}`; + vscode.window.showErrorMessage(errorMessage); + } + const parser = new xml2js.Parser({ explicitArray: true }); + parser.parseString(xmlOutput, async (err, result) => { + if (err) { + console.error("XML parse error:", err); + return; } - // 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 - if (isNaN(line) || line < 0 || line >= document.lineCount) { - if (isCriticalError) { - line = 0; - } else { + const errors = result.results?.errors?.[0]?.error || []; + const diagnostics: Record = {}; + for (const e of errors) { + const isCriticalError = criticalWarningTypes.includes(e.$.id); + const locations = e.location || []; + if (!locations.length) { continue; } - } - - // Cppcheck col number is 1-indexed, while VS Code uses 0-indexing - let col = Number(mainLoc.column) - 1; - if (isNaN(col) || col < 0 || !mainLocDocument || col > mainLocDocument.lineAt(line).text.length) { - col = 0; - } - const severity = parseSeverity(e.$.severity); - if (!isCriticalError && severityToNumber(severity) < minSevNum) { - continue; - } - - const range = new vscode.Range(line, col, line, mainLocDocument ? mainLocDocument.lineAt(line).text.length : col); - const diagnostic = new vscode.Diagnostic(range, e.$.msg, severity); - diagnostic.source = "cppcheck"; - // If we have a link to documentation, include it - diagnostic.code = documentationLinkMap[e.$.id] ? { - value: e.$.id, - target: vscode.Uri.parse(documentationLinkMap[e.$.id]) - } : getPremiumCertLink(e.$.id) ? { - value: e.$.id, - target: vscode.Uri.parse(getPremiumCertLink(e.$.id)) - } : e.$.id; - - // If warning has a symbol we keep track of it - const symbolName = e.symbol?.[0] ?? ''; - // Save line of code at main location if we can access it - const mainLocLine = mainLocDocument?.lineAt(line)?.text ?? ''; - - diagnosticMetadataStore.set(diagnostic, { symbolName, mainLocLine, hidden: false }); - - // Related Information - const relatedInfos: vscode.DiagnosticRelatedInformation[] = []; - for (let i = 1; i <= locations.length; i++) { - // Related information is ordered in reverse in XML object - const loc = locations[locations.length - i].$; - const msg = loc.info; - const lLine = Number(loc.line) - 1; - const lCol = Number(loc.col) - 1; - - if (msg === null || msg === undefined || isNaN(lLine) || lLine < 0 || lLine >= document.lineCount) { + 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; } - var relatedDocument : vscode.TextDocument | undefined; + let mainLocDocument : vscode.TextDocument | undefined; try { - relatedDocument = await vscode.workspace.openTextDocument(loc.file); + mainLocDocument = await vscode.workspace.openTextDocument(mainLoc.file); } catch { - // Do nothing + // do nothing } - const relatedRange = new vscode.Range( - lLine, lCol, - lLine, relatedDocument ? relatedDocument.lineAt(lLine).text.length : lCol - ); - relatedInfos.push( - new vscode.DiagnosticRelatedInformation( - new vscode.Location(relatedDocument ? relatedDocument.uri : vscode.Uri.file(''), relatedRange), - msg - ) - ); - } - if (relatedInfos.length > 0) { - diagnostic.relatedInformation = relatedInfos; - } - const diagnosticFile = mainLoc.file; - var diagnosticFileIsOpenDocument = diagnosticFile === document.fileName; - if (!diagnosticFile.includes('/')) { - // If we do not have file path but only name we asume diagnosed file is open document if they share name - if (document.fileName.endsWith(diagnosticFile)) { - diagnosticFileIsOpenDocument = true; + + // 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 + if (isNaN(line) || line < 0 || line >= document.lineCount) { + if (isCriticalError) { + line = 0; + } else { + continue; + } } - } - if (diagnosticFileIsOpenDocument) { - const uri = document.uri.toString(); - if (diagnostics[uri] === null || diagnostics[uri] === undefined) { - diagnostics[uri] = []; + + // Cppcheck col number is 1-indexed, while VS Code uses 0-indexing + let col = Number(mainLoc.column) - 1; + if (isNaN(col) || col < 0 || !mainLocDocument || col > mainLocDocument.lineAt(line).text.length) { + col = 0; } - diagnostics[uri].push(diagnostic); - } else { - var relatedDocument : vscode.TextDocument | undefined; - try { - relatedDocument = await vscode.workspace.openTextDocument(mainLoc.file); - } catch { - // Do nothing + + const severity = parseSeverity(e.$.severity); + if (!isCriticalError && severityToNumber(severity) < minSevNum) { + continue; + } + + const range = new vscode.Range(line, col, line, mainLocDocument ? mainLocDocument.lineAt(line).text.length : col); + const diagnostic = new vscode.Diagnostic(range, e.$.msg, severity); + diagnostic.source = "cppcheck"; + // If we have a link to documentation, include it + diagnostic.code = documentationLinkMap[e.$.id] ? { + value: e.$.id, + target: vscode.Uri.parse(documentationLinkMap[e.$.id]) + } : getPremiumCertLink(e.$.id) ? { + value: e.$.id, + target: vscode.Uri.parse(getPremiumCertLink(e.$.id)) + } : e.$.id; + + // If warning has a symbol we keep track of it + const symbolName = e.symbol?.[0] ?? ''; + // Save line of code at main location if we can access it + const mainLocLine = mainLocDocument?.lineAt(line)?.text ?? ''; + + diagnosticMetadataStore.set(diagnostic, { symbolName, mainLocLine, hidden: false }); + + // Related Information + const relatedInfos: vscode.DiagnosticRelatedInformation[] = []; + for (let i = 1; i <= locations.length; i++) { + // Related information is ordered in reverse in XML object + const loc = locations[locations.length - i].$; + const msg = loc.info; + const lLine = Number(loc.line) - 1; + const lCol = Number(loc.col) - 1; + + if (msg === null || msg === undefined || isNaN(lLine) || lLine < 0 || lLine >= document.lineCount) { + continue; + } + + var relatedDocument : vscode.TextDocument | undefined; + try { + relatedDocument = await vscode.workspace.openTextDocument(loc.file); + } catch { + // Do nothing + } + const relatedRange = new vscode.Range( + lLine, lCol, + lLine, relatedDocument ? relatedDocument.lineAt(lLine).text.length : lCol + ); + relatedInfos.push( + new vscode.DiagnosticRelatedInformation( + new vscode.Location(relatedDocument ? relatedDocument.uri : vscode.Uri.file(''), relatedRange), + msg + ) + ); + } + if (relatedInfos.length > 0) { + diagnostic.relatedInformation = relatedInfos; } - if (relatedDocument) { - // Proceed if we are able to open the document - const uri = relatedDocument.uri.toString(); + const diagnosticFile = mainLoc.file; + var diagnosticFileIsOpenDocument = diagnosticFile === document.fileName; + if (!diagnosticFile.includes('/')) { + // If we do not have file path but only name we asume diagnosed file is open document if they share name + if (document.fileName.endsWith(diagnosticFile)) { + diagnosticFileIsOpenDocument = true; + } + } + if (diagnosticFileIsOpenDocument) { + const uri = document.uri.toString(); if (diagnostics[uri] === null || diagnostics[uri] === undefined) { diagnostics[uri] = []; } diagnostics[uri].push(diagnostic); + } else { + var relatedDocument : vscode.TextDocument | undefined; + try { + relatedDocument = await vscode.workspace.openTextDocument(mainLoc.file); + } catch { + // Do nothing + } + if (relatedDocument) { + // Proceed if we are able to open the document + const uri = relatedDocument.uri.toString(); + if (diagnostics[uri] === null || diagnostics[uri] === undefined) { + diagnostics[uri] = []; + } + diagnostics[uri].push(diagnostic); + } } } - } - const sourceDocumentUri = document.uri.toString(); - for (const uri of Object.keys(diagnostics)) { - var newDiagnostics = diagnostics[uri]; - // If file has existing diagnostics from analyzing other files we do not want to overwrite those - const existingDiagnostics = uriDiagnosticsMap.get(uri); - if (existingDiagnostics) { - newDiagnostics = diagnosticsUnion(newDiagnostics, existingDiagnostics.flat()); - } - uriDiagnosticsMap.set(uri, newDiagnostics); - if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { - fileRelationMap[uri] = new Set; + const sourceDocumentUri = document.uri.toString(); + for (const uri of Object.keys(diagnostics)) { + var newDiagnostics = diagnostics[uri]; + // If file has existing diagnostics from analyzing other files we do not want to overwrite those + const existingDiagnostics = uriDiagnosticsMap.get(uri); + if (existingDiagnostics) { + newDiagnostics = diagnosticsUnion(newDiagnostics, existingDiagnostics.flat()); + } + uriDiagnosticsMap.set(uri, newDiagnostics); + if (fileRelationMap[uri] === null ||fileRelationMap[uri] === undefined) { + fileRelationMap[uri] = new Set; + } + // NOTE: uri can be the same as sourceDocumentUri + fileRelationMap[uri].add(sourceDocumentUri); } - // NOTE: uri can be the same as sourceDocumentUri - fileRelationMap[uri].add(sourceDocumentUri); + resolve(); + }); + + // If checks have run without error, save hashed document content to memory + if (!code) { + const hashedContentOfFile = getDocumentSha1(document); + documentHashMemory[document.fileName] = hashedContentOfFile; } }); - - // If checks have run without error, save hashed document content to memory - if (!code) { - const hashedContentOfFile = getDocumentSha1(document); - documentHashMemory[document.fileName] = hashedContentOfFile; - } }); checksRunning = false; From 944654e4b7c73ae28452cfe6f1055baaa5d9d411 Mon Sep 17 00:00:00 2001 From: davidramnero Date: Thu, 27 Aug 2026 08:43:26 +0200 Subject: [PATCH 4/5] updated comment --- src/extension.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 920682a..9353d29 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -441,8 +441,8 @@ export async function activate(context: vscode.ExtensionContext) { uriDiagnosticsMap, ); - // Diagnostics from analysis are stored in DiagnosticCollectionAll, the displayed diagnostic collection - // is diagnosticCollection, which is set by the filter function filterDisplayedDiagnosticsBasedOnHiddenStatus() + // Analysis in runCppcheckOnFileXML populates uriDiagnosticsMap with all warnings, regardless of min severity filter. + // Thus after running analysis we have to apply the severity filter (this also populates DiagnosticCollection, making the diagnostics visible) const minSevString = config.get("cppcheck-official.minSeverity", "info"); hideDiagnosticsBasedOnSeverityLevel(parseSeverity(minSevString)); } From 970f73965cca3af8d9ccf088839731feb46de35c Mon Sep 17 00:00:00 2001 From: davidramnero Date: Thu, 27 Aug 2026 10:12:08 +0200 Subject: [PATCH 5/5] fixed clear diagnostic at closing of file --- src/extension.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extension.ts b/src/extension.ts index 9353d29..483d8ac 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -360,6 +360,7 @@ export async function activate(context: vscode.ExtensionContext) { if (fileRelationMap[fileUri].has(doc.uri.toString())) { if (fileRelationMap[fileUri].size <= 1) { uriDiagnosticsMap.delete(fileUri); + diagnosticCollection.delete(vscode.Uri.parse(fileUri)); fileRelationMap[fileUri].clear(); filterDisplayedDiagnosticsBasedOnHiddenStatus(); } else {