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

Reply via email to