Author: Luan Rabelo Date: 2026-07-11T12:48:47Z New Revision: e490b437555b1f5fce7636d383fc2d7f22097577
URL: https://github.com/llvm/llvm-project/commit/e490b437555b1f5fce7636d383fc2d7f22097577 DIFF: https://github.com/llvm/llvm-project/commit/e490b437555b1f5fce7636d383fc2d7f22097577.diff LOG: [analyzer] Fix invalid HTML nesting for popups at end of line (#207793) The static analyzer's HTML reports contain misnested tags whenever a variable with a `variable_popup` is the last token on a source line. `AddLineNumber` inserts the row-closing `</td></tr>` with `InsertTextBefore`, which places it in front of text previously inserted at the same offset. As a result, the popup's closing `</table></span>` tags and the arrow anchor `</span>` tags end up outside the table row. HTML parsers (jsoup, pup) and validators reject the file from that point on. Before: <span class='variable'>b</td></tr><table class='variable_popup'>...</table></span></span></span> <img width="786" height="414" alt="image" src="https://github.com/user-attachments/assets/023461ad-73e4-424e-a4fb-42faf7a945f0" /> After: <span class='variable'>b<table class='variable_popup'>...</table></span></span></span></td></tr> <img width="877" height="477" alt="image" src="https://github.com/user-attachments/assets/cf8aada4-21c8-4af7-9e07-c2d8cc1d0724" /> The fix inserts `</td></tr>` with `InsertTextAfter` so tags closing at the end-of-line offset stay inside the row. To keep the message bubbles outside the code rows, the line number table is now added before the path pieces are processed, and bubbles are inserted after the newline, between the current and the next row. The pre-existing tests only exercised popups on variables followed by more tokens (`if (b)`), which is why this was never caught; the new test places the variable at the end of the line. This has been broken since at least clang 10; the earlier fix (D73993 / commit 482e236e569e) only covered the macro popup variant. I verified this with the Analysis/html_diagnostics tests, the full clang/test/Analysis suite, and by running generated reports through an HTML parser that checks tag nesting: 4 errors before / 0 after on the reproducer above, and 8 → 0 on a larger file with macro popups, multiple events per line, and mid-line popups. The visible report content is unchanged. Fixes #46089 Added: clang/test/Analysis/html_diagnostics/variable-popups-eol.c Modified: clang/lib/Rewrite/HTMLRewrite.cpp clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp Removed: ################################################################################ diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index 109cdf990543a..37fea7118c91f 100644 --- a/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/clang/lib/Rewrite/HTMLRewrite.cpp @@ -247,7 +247,7 @@ static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, RB.InsertTextBefore(B, OS.str()); } else { RB.InsertTextBefore(B, OS.str()); - RB.InsertTextBefore(E, "</td></tr>"); + RB.InsertTextAfter(E, "</td></tr>"); } } diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 77c1cceb60fe2..04829bffeecd9 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -786,6 +786,10 @@ static void HandlePopUpPieceEndTag(Rewriter &R, void HTMLDiagnostics::RewriteFile(Rewriter &R, const PathPieces &path, FileID FID) { + // Add line numbers first, so that tags inserted later at end-of-line + // offsets (e.g. pop-up closing tags) end up inside the row. + html::EscapeText(R, FID); + html::AddLineNumbers(R, FID); // Process the path. // Maintain the counts of extra note pieces separately. @@ -877,10 +881,6 @@ void HTMLDiagnostics::RewriteFile(Rewriter &R, const PathPieces &path, // Add the <table> start tag of pop-up pieces based on the stored ranges. HandlePopUpPieceStartTag(R, PopUpRanges); - // Add line numbers, header, footer, etc. - html::EscapeText(R, FID); - html::AddLineNumbers(R, FID); - addArrowSVGs(R, FID, ArrowIndices); // If we have a preprocessor, relex the file and syntax highlight. @@ -1096,8 +1096,11 @@ void HTMLDiagnostics::HandlePiece(Rewriter &R, FileID BugFileID, os << "</div></td></tr>"; - // Insert the new html. + // Insert the new html after the newline, so that the bubble's row lands + // between the current line's row and the next line's row. unsigned DisplayPos = LineEnd - FileStart; + if (LineEnd != FileEnd) + ++DisplayPos; SourceLocation Loc = SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos); diff --git a/clang/test/Analysis/html_diagnostics/variable-popups-eol.c b/clang/test/Analysis/html_diagnostics/variable-popups-eol.c new file mode 100644 index 0000000000000..6e6160c92e322 --- /dev/null +++ b/clang/test/Analysis/html_diagnostics/variable-popups-eol.c @@ -0,0 +1,23 @@ +// RUN: rm -fR %t +// RUN: mkdir %t +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html -o %t -verify %s +// RUN: cat %t/report-*.html | FileCheck %s + +void bar(int); + +void foo(void) { + int a; + int b = 1; + if (b + && 1) + bar(a); // expected-warning{{1st function call argument is an uninitialized value}} +} + +// The variable 'b' is the last token on its line, so the popup's closing +// tags and the row's closing </td></tr> are inserted at the same offset. +// The popup table must immediately follow the variable, and the closing +// </span> tags (variable and control-flow arrow anchors) must stay inside +// the row, before </td></tr>. Each directive below matches contiguously. +// CHECK: <span class='variable'>b<table class='variable_popup'><tbody> +// CHECK-SAME: <tr><td valign='top'><div class='PathIndex PathIndexPopUp'>1.1</div></td><td>'b' is 1</td></tr> +// CHECK-SAME: </tbody></table></span></span></span></td></tr> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
