124 lines
4.8 KiB
Plaintext
124 lines
4.8 KiB
Plaintext
$ErrorActionPreference = "Stop"
|
|
$inputDirs = @PSC_CPPCHECK_INPUT_DIRS@
|
|
$excludeDirs = @PSC_CPPCHECK_EXCLUDE_DIRS@
|
|
$enabledChecks = @PSC_CPPCHECK_ENABLE@
|
|
$suppressions = @PSC_CPPCHECK_SUPPRESSIONS@
|
|
$outputDir = "@PSC_CPPCHECK_OUTPUT_DIR@"
|
|
$compileCommands = "@PSC_CPPCHECK_COMPILE_COMMANDS@"
|
|
$configuredCppcheck = "@PSC_CPPCHECK_EXECUTABLE@"
|
|
$checkLevel = "@PSC_CPPCHECK_CHECK_LEVEL@"
|
|
$jobs = [int]"@PSC_CPPCHECK_JOBS@"
|
|
function Resolve-Tool([string]$Configured, [string]$Name, [string[]]$Fallbacks) {
|
|
if ($Configured -and (Test-Path -LiteralPath $Configured)) {
|
|
return (Resolve-Path -LiteralPath $Configured).Path
|
|
}
|
|
$command = Get-Command $Name -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($command) {
|
|
return $command.Source
|
|
}
|
|
foreach ($fallback in $Fallbacks) {
|
|
if (Test-Path -LiteralPath $fallback) {
|
|
return (Resolve-Path -LiteralPath $fallback).Path
|
|
}
|
|
}
|
|
throw "$Name executable was not found"
|
|
}
|
|
function Normalize-Path([string]$Path) {
|
|
return [IO.Path]::GetFullPath($Path).Replace("\", "/").TrimEnd("/")
|
|
}
|
|
function Test-InRoots([string]$Path, [string[]]$Roots) {
|
|
$normalized = Normalize-Path $Path
|
|
foreach ($root in $Roots) {
|
|
if ($normalized.StartsWith($root + "/", [StringComparison]::OrdinalIgnoreCase) -or $normalized.Equals($root, [StringComparison]::OrdinalIgnoreCase)) {
|
|
return $true
|
|
}
|
|
}
|
|
return $false
|
|
}
|
|
$cppcheck = Resolve-Tool $configuredCppcheck "cppcheck" @("C:\Program Files\Cppcheck\cppcheck.exe")
|
|
if (!(Test-Path -LiteralPath $compileCommands)) {
|
|
throw "compile_commands.json was not found at $compileCommands"
|
|
}
|
|
$roots = @($inputDirs | ForEach-Object { Normalize-Path $_ })
|
|
$excludes = @($excludeDirs | ForEach-Object { Normalize-Path $_ })
|
|
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
|
|
$database = Get-Content -LiteralPath $compileCommands -Raw | ConvertFrom-Json
|
|
$selected = @($database | Where-Object {
|
|
$file = Normalize-Path $_.file
|
|
(Test-InRoots $file $roots) -and !(Test-InRoots $file $excludes) -and [IO.Path]::GetExtension($file) -in @(".c", ".cc", ".cpp", ".cxx")
|
|
})
|
|
if ($selected.Count -eq 0) {
|
|
throw "No translation units matched the configured input directories"
|
|
}
|
|
$filteredDatabase = Join-Path $outputDir "compile_commands.json"
|
|
[IO.File]::WriteAllText($filteredDatabase, ($selected | ConvertTo-Json -Depth 8), [Text.UTF8Encoding]::new($false))
|
|
$xmlPath = Join-Path $outputDir "cppcheck.xml"
|
|
$cacheDir = Join-Path $outputDir "cache"
|
|
New-Item -ItemType Directory -Force -Path $cacheDir | Out-Null
|
|
$arguments = @(
|
|
"--project=$filteredDatabase",
|
|
"--enable=$($enabledChecks -join ',')",
|
|
"--check-level=$checkLevel",
|
|
"--std=c++20",
|
|
"--inconclusive",
|
|
"--inline-suppr",
|
|
"--output-format=xmlv3",
|
|
"--output-file=$xmlPath",
|
|
"--cppcheck-build-dir=$cacheDir"
|
|
"-j"
|
|
$jobs
|
|
)
|
|
foreach ($suppression in $suppressions) {
|
|
$arguments += "--suppress=$suppression"
|
|
}
|
|
& $cppcheck @arguments
|
|
$toolExitCode = $LASTEXITCODE
|
|
if (!(Test-Path -LiteralPath $xmlPath)) {
|
|
throw "Cppcheck did not produce $xmlPath"
|
|
}
|
|
[xml]$xml = Get-Content -LiteralPath $xmlPath -Raw
|
|
$records = [Collections.Generic.List[object]]::new()
|
|
foreach ($errorNode in $xml.results.errors.error) {
|
|
$locations = @($errorNode.location)
|
|
if ($locations.Count -eq 0) {
|
|
$records.Add([pscustomobject]@{
|
|
Severity = [string]$errorNode.severity
|
|
Id = [string]$errorNode.id
|
|
Message = [string]$errorNode.msg
|
|
File = ""
|
|
Line = 0
|
|
Column = 0
|
|
})
|
|
continue
|
|
}
|
|
foreach ($location in $locations) {
|
|
$locationFile = [string]$location.file
|
|
if ($locationFile -and (!(Test-InRoots $locationFile $roots) -or (Test-InRoots $locationFile $excludes))) {
|
|
continue
|
|
}
|
|
$records.Add([pscustomobject]@{
|
|
Severity = [string]$errorNode.severity
|
|
Id = [string]$errorNode.id
|
|
Message = [string]$errorNode.msg
|
|
File = $locationFile
|
|
Line = [int]$location.line
|
|
Column = [int]$location.column
|
|
})
|
|
}
|
|
}
|
|
$records | Export-Csv -LiteralPath (Join-Path $outputDir "cppcheck.csv") -NoTypeInformation -Encoding UTF8
|
|
$severity = @($records | Group-Object Severity | Sort-Object Count -Descending | ForEach-Object {
|
|
[pscustomobject]@{ severity = $_.Name; count = $_.Count }
|
|
})
|
|
$summary = [ordered]@{
|
|
tool = "cppcheck"
|
|
version = (& $cppcheck --version | Select-Object -First 1).Trim()
|
|
translation_units = $selected.Count
|
|
tool_exit_code = $toolExitCode
|
|
findings = $records.Count
|
|
severity = $severity
|
|
top = @($records | Select-Object -First 100)
|
|
}
|
|
[IO.File]::WriteAllText((Join-Path $outputDir "summary.json"), ($summary | ConvertTo-Json -Depth 8), [Text.UTF8Encoding]::new($false))
|
|
Write-Output "Cppcheck report: $outputDir"
|