IAR: Add post-processing step in C-STAT outputs

Harmonize IAR C-STAT headers between the first-time analysis
and subsequent builds, which uses cached results.

It also removes spurious relative paths such as `"../` and
`..\` that might appear after a new line followed by a double quote.
Effectively this will display paths relative to CMAKE_SOURCE_DIR,
similarly to the IDE, which display paths relative to $PROJ_DIR$.

Update the IAR tests to match the new C-STAT outputs.
This commit is contained in:
Felipe Torrezan
2026-08-26 23:10:43 +02:00
parent 4a8aeff8e4
commit a17cbbee93
6 changed files with 72 additions and 19 deletions
+41 -4
View File
@@ -654,13 +654,50 @@ int HandleIcstat(std::string const& runCmd, std::string const& sourceFile,
// Run the IAR C-STAT command line. Capture its output.
if (!cmSystemTools::RunSingleCommand(icstat_cmd, &stdOut, &stdErr, &ret,
nullptr, cmSystemTools::OUTPUT_NONE)) {
std::cerr << "Error running '" << icstat_cmd[0] << "': " << stdOut << '\n';
std::cerr << "C-STAT: Error running '" << icstat_cmd[0] << "': " << stdOut
<< '\n';
return 1;
}
// Post-process successful output for consistent messaging and path cleanup.
if (ret == 0) {
std::cerr << "Warning: C-STAT static analysis reported diagnostics:\n";
} else {
std::cerr << "Error: C-STAT static analysis reported failure:\n";
// Harmonize IAR C-STAT headers between the first-time analysis
// and subsequent builds that use cached results.
std::cerr << "C-STAT: ";
if (stdOut.find("Analyzing") == std::string::npos) {
std::string prepend;
prepend =
cmStrCat("Analyzing ", cmSystemTools::GetFilenameName(sourceFile),
" (cached)\n");
stdOut.insert(0, prepend);
}
// Single-pass removal of consecutive spurious relative paths,
// `"../` or `"..\`, that might appear after a newline followed by
// an opening quote, effectively displaying paths relative to
// CMAKE_SOURCE_DIR.
// Example: `\n"../../../src/file.c` -> `\n"src/file.c`
std::string cleaned;
size_t const n = stdOut.size();
cleaned.reserve(n);
size_t pos = 0;
while (pos < n) {
if (pos + 1 < n && stdOut[pos] == '\n' && stdOut[pos + 1] == '"') {
cleaned += "\n\"";
pos += 2; // skip `\n"`
while (pos + 2 < n && stdOut[pos] == '.' && stdOut[pos + 1] == '.' &&
(stdOut[pos + 2] == '/' || stdOut[pos + 2] == '\\')) {
pos += 3; // skip `../` or `..\`
}
} else {
cleaned += stdOut[pos];
++pos;
}
}
stdOut.swap(cleaned);
} else if (ret != 0) {
std::cerr << "C-STAT ";
}
std::cerr << stdOut;
std::cerr << stdErr;
@@ -1,3 +1,3 @@
Error: C-STAT static analysis reported failure:
stdout from bad command line arg '-bad'
stderr from bad command line arg '-bad'
C-STAT Command line error: Unexpected command line arguments:
-bad
-bad
+1 -2
View File
@@ -1,2 +1 @@
Warning: C-STAT static analysis reported diagnostics.*C-STAT analyze source: [^
]*module\.c.*Severity
C-STAT: Analyzing module.c.*Severity
@@ -1,3 +1,3 @@
Error: C-STAT static analysis reported failure:
stdout from bad command line arg '-bad'
stderr from bad command line arg '-bad'
C-STAT Command line error: Unexpected command line arguments:
-bad
-bad
+1 -2
View File
@@ -1,2 +1 @@
Warning: C-STAT static analysis reported diagnostics.*C-STAT analyze source: [^
]*module\.cxx.*Severity
C-STAT: Analyzing module.cxx.*Severity
+23 -5
View File
@@ -2,6 +2,21 @@
#include <stdlib.h>
#include <string.h>
char const* get_filename(char const* path)
{
// Find the last occurrence of '/'
char const* last_slash = strrchr(path, '/');
// If not found, try finding the last occurrence of '\'
if (!last_slash) {
last_slash = strrchr(path, '\\');
}
// If a separator was found, return the character after it
// Otherwise, return the original path (no directory component)
return last_slash ? last_slash + 1 : path;
}
int main(int argc, char* argv[])
{
int i;
@@ -9,15 +24,18 @@ int main(int argc, char* argv[])
char const* source = "";
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-bad") == 0) {
fprintf(stdout, "stdout from bad command line arg '-bad'\n");
fprintf(stderr, "stderr from bad command line arg '-bad'\n");
fprintf(
stdout,
"C-STAT Command line error: Unexpected command line arguments:\n");
fprintf(stdout, " -bad\n");
fprintf(stderr, " -bad\n");
return 1;
}
if (strcmp(argv[i], "analyze") == 0 && i + 1 < argc) {
source = argv[++i];
if (strcmp(argv[i], "--silent") == 0 && (i + 1) < argc) {
source = get_filename(argv[++i]);
}
}
fprintf(stderr, "C-STAT analyze source: %s\n", source);
fprintf(stderr, "C-STAT: Analyzing %s\n", source);
fprintf(stderr,
"\"foo/bar.c\",2 Severity-High[SPC-uninit-var-some]:"
"Variable `i' may be uninitialized.\n\n");