Skip to content

[DO NOT MERGE] Add project-wide semantic analysis report - #6306

Open
alban-auzeill wants to merge 9 commits into
masterfrom
alban/SemanticReport
Open

alban-auzeill wants to merge 9 commits into
masterfrom
alban/SemanticReport

Conversation

@alban-auzeill

@alban-auzeill alban-auzeill commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary by Gitar

  • New Feature:
    • Added SemanticReportScanner to generate project-wide semantic analysis reports in JSON format via sonar.java.internal.semantic.report property.

This will update automatically on new commits.

Comment on lines +62 to 64
context.config().get(SonarComponents.SONAR_SEMANTIC_REPORT)
.ifPresent(path -> semanticReportScanner.writeReport(Path.of(path), context.fileSystem().baseDir().toPath()));
recordSpringTelemetry();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: Report write failure fails the analysis and skips telemetry

ProjectEndOfAnalysisSensor.execute calls writeReport before recordSpringTelemetry() and before telemetry is sent. writeReport turns any IOException into an UncheckedIOException. The path comes from Path.of(path), so a relative path resolves against the JVM working directory rather than the project base dir, and a parent directory that doesn't exist makes Files.newBufferedWriter throw. In either case, a misconfigured optional internal diagnostic property fails the whole project analysis and drops all telemetry. Catch the exception and log it, or write the report after telemetry. Resolving relative paths against baseDir would also help.

Resolve against the base dir and log failures instead of propagating them:

context.config().get(SonarComponents.SONAR_SEMANTIC_REPORT).ifPresent(path -> {
  Path baseDir = context.fileSystem().baseDir().toPath();
  try {
    semanticReportScanner.writeReport(baseDir.resolve(path), baseDir);
  } catch (UncheckedIOException e) {
    LOG.warn("Unable to write semantic report", e);
  }
});
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

@datadog-sonarsource

This comment has been minimized.

Comment thread java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java Outdated
@gitar-bot

gitar-bot Bot commented Oct 6, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 2 closed / 3 findings

🟡 Medium risk · Adds opt-in project-wide identifier analysis and JSON report generation

Adds project-wide semantic analysis reporting with path normalization and filtering for unnamed variables. Consider catching report write exceptions and ensuring they don't suppress telemetry or fail analysis—handle relative path resolution and ensure robust error handling.

💡 Quality: Report write failure fails the analysis and skips telemetry

📄 sonar-java-plugin/src/main/java/org/sonar/plugins/java/ProjectEndOfAnalysisSensor.java:62-64 📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:61 📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:79-81

ProjectEndOfAnalysisSensor.execute calls writeReport before recordSpringTelemetry() and before telemetry is sent. writeReport turns any IOException into an UncheckedIOException. The path comes from Path.of(path), so a relative path resolves against the JVM working directory rather than the project base dir, and a parent directory that doesn't exist makes Files.newBufferedWriter throw. In either case, a misconfigured optional internal diagnostic property fails the whole project analysis and drops all telemetry. Catch the exception and log it, or write the report after telemetry. Resolving relative paths against baseDir would also help.

Resolve against the base dir and log failures instead of propagating them
context.config().get(SonarComponents.SONAR_SEMANTIC_REPORT).ifPresent(path -> {
  Path baseDir = context.fileSystem().baseDir().toPath();
  try {
    semanticReportScanner.writeReport(baseDir.resolve(path), baseDir);
  } catch (UncheckedIOException e) {
    LOG.warn("Unable to write semantic report", e);
  }
});
✅ 2 closed
✅ Edge Case: Root and file paths are normalized differently before relativize

📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:56 📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:63 📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:73 📄 java-frontend/src/test/java/org/sonar/java/JavaFrontendTest.java:255-269
This commit changes the project root to toRealPath(NOFOLLOW_LINKS), but the file keys in scanFile still go through toAbsolutePath().normalize() only. On Windows, toRealPath turns 8.3 short names into long names and fixes letter case (e.g. C:\Users\RUNNER~1\... becomes C:\Users\runneradmin\...), while the file keys keep the spelling that came from the URI. When the two disagree, relativize returns paths like ../../../RUNNER~1/AppData/.../A.java instead of A.java. semantic_report_uses_file_uri_for_project_relative_path hits this case: it builds the URI from the raw temp.resolve("A.java") but passes temp as the root. On a Windows runner whose TEMP uses a short name, that test fails, which is the platform this commit is meant to fix. Fix: normalize the file keys the same way as the root, for example by calling toRealPath(LinkOption.NOFOLLOW_LINKS) with a fallback to toAbsolutePath().normalize() when the file can't be resolved. At minimum, make the test pass file.toRealPath(...).toUri().

✅ Edge Case: Unnamed variables _ are counted as unknown identifiers

📄 java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:47-52
SemanticReportScanner counts an identifier as unknown when tree.symbol().isUnknown(). IdentifierTreeImpl.symbol() returns Symbol.UNKNOWN_SYMBOL whenever isUnnamedVariable is true, even when the binding resolved (if (binding != null && !isUnnamedVariable)). So every _ (unnamed variable or pattern, Java 22+) in fully resolved code adds to numberOfUnknownIdentifier and pushes up the unknown percentage, which makes the report's semantic-quality metric wrong. Skip unnamed variables in the counter. You can either leave them out of both counts or count them as known.

🤖 Prompt for agents
Code Review: Adds project-wide semantic analysis reporting with path normalization and filtering for unnamed variables. Consider catching report write exceptions and ensuring they don't suppress telemetry or fail analysis—handle relative path resolution and ensure robust error handling.

1. 💡 Quality: Report write failure fails the analysis and skips telemetry
   Files: sonar-java-plugin/src/main/java/org/sonar/plugins/java/ProjectEndOfAnalysisSensor.java:62-64, java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:61, java-frontend/src/main/java/org/sonar/java/SemanticReportScanner.java:79-81

   `ProjectEndOfAnalysisSensor.execute` calls `writeReport` before `recordSpringTelemetry()` and before telemetry is sent. `writeReport` turns any `IOException` into an `UncheckedIOException`. The path comes from `Path.of(path)`, so a relative path resolves against the JVM working directory rather than the project base dir, and a parent directory that doesn't exist makes `Files.newBufferedWriter` throw. In either case, a misconfigured optional internal diagnostic property fails the whole project analysis and drops all telemetry. Catch the exception and log it, or write the report after telemetry. Resolving relative paths against `baseDir` would also help.

   Fix (Resolve against the base dir and log failures instead of propagating them):
   context.config().get(SonarComponents.SONAR_SEMANTIC_REPORT).ifPresent(path -> {
     Path baseDir = context.fileSystem().baseDir().toPath();
     try {
       semanticReportScanner.writeReport(baseDir.resolve(path), baseDir);
     } catch (UncheckedIOException e) {
       LOG.warn("Unable to write semantic report", e);
     }
   });

Review coverage

🧪 Functional validation No results

📋 Rules No rules evaluated

Cross-repo coverage 1 repository selected

Cross-repo inspection is incomplete. Unread code may contain additional impacts.

🤖 Auto-approval Not enabled · Set up

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

sonarqube-next Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant