-
-
Notifications
You must be signed in to change notification settings - Fork 7
Add Problem Reporting API and provide Access Transformer Errors in a Machine Readable Format #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fd7e4bb
89a1b18
60804b6
7c2953d
f76dcdd
10fa1ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,17 +8,30 @@ | |
| import net.neoforged.jst.api.Replacements; | ||
| import net.neoforged.jst.api.SourceTransformer; | ||
| import net.neoforged.jst.api.TransformContext; | ||
| import net.neoforged.problems.Problem; | ||
| import net.neoforged.problems.ProblemGroup; | ||
| import net.neoforged.problems.ProblemId; | ||
| import net.neoforged.problems.ProblemLocation; | ||
| import net.neoforged.problems.ProblemReporter; | ||
| import net.neoforged.problems.ProblemSeverity; | ||
| import picocli.CommandLine; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.UncheckedIOException; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class AccessTransformersTransformer implements SourceTransformer { | ||
|
|
||
| private static final ProblemGroup PROBLEM_GROUP = ProblemGroup.create("access-transformer", "Access Transformers"); | ||
| static final ProblemId INVALID_AT = ProblemId.create("invalid-at", "Invalid", PROBLEM_GROUP); | ||
| private static final ProblemId MISSING_TARGET = ProblemId.create("missing-target", "Missing Target", PROBLEM_GROUP); | ||
|
|
||
| private static final Pattern LINE_PATTERN = Pattern.compile("\\bline\\s+(\\d+)"); | ||
| private static final Pattern ORIGIN_PATTERN = Pattern.compile("(.*):(\\d+)$"); | ||
|
|
||
| @CommandLine.Option(names = "--access-transformer", required = true) | ||
| public List<Path> atFiles; | ||
|
|
||
|
|
@@ -28,19 +41,36 @@ public class AccessTransformersTransformer implements SourceTransformer { | |
| private AccessTransformerFiles ats; | ||
| private Map<Target, Transformation> pendingATs; | ||
| private Logger logger; | ||
| private ProblemReporter problemReporter; | ||
| private volatile boolean errored; | ||
|
|
||
| @Override | ||
| public void beforeRun(TransformContext context) { | ||
| ats = new AccessTransformerFiles(); | ||
| logger = context.logger(); | ||
| problemReporter = context.problemReporter(); | ||
|
|
||
| for (Path path : atFiles) { | ||
| try { | ||
| ats.loadFromPath(path); | ||
| } catch (IOException ex) { | ||
| logger.error("Failed to parse access transformer file %s: %s", path, ex.getMessage()); | ||
| throw new UncheckedIOException(ex); | ||
| } catch (Exception e) { | ||
| logger.error("Failed to parse access transformer file %s: %s", path, e.getMessage()); | ||
|
|
||
| if (e.getMessage() != null) { | ||
| var m = LINE_PATTERN.matcher(e.getMessage()); | ||
| if (m.matches()) { | ||
| // The AT parser internally uses 0-based line numbering, but the problem reporter uses 1-based | ||
| int line = 1 + Integer.parseUnsignedInt(m.group(1)); | ||
| problemReporter.report(INVALID_AT, ProblemSeverity.ERROR, ProblemLocation.ofLocationInFile(path, line), e.getMessage()); | ||
| } else { | ||
| problemReporter.report(INVALID_AT, ProblemSeverity.ERROR, ProblemLocation.ofFile(path), e.getMessage()); | ||
| } | ||
| } | ||
|
|
||
| if (e instanceof RuntimeException re) { | ||
| throw re; | ||
| } | ||
| throw new RuntimeException(e); | ||
|
Comment on lines
+70
to
+73
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would replace this with a sneaky generic throw, not sure if we have a helper for that in JST.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a friend of that hack tbh. Is there a significant issue with this wrapping? |
||
| } | ||
| } | ||
|
|
||
|
|
@@ -55,16 +85,39 @@ public boolean afterRun(TransformContext context) { | |
| // so we don't log the ClassTarget as that will cause duplication | ||
| if (target instanceof Target.ClassTarget && target.className().contains("$")) return; | ||
| logger.error("Access transformer %s, targeting %s did not apply as its target doesn't exist", transformation, target); | ||
|
|
||
| var problem = Problem.builder(MISSING_TARGET) | ||
| .severity(ProblemSeverity.ERROR) | ||
| .contextualLabel("The target " + target + " does not exist.") | ||
| .build(); | ||
| reportProblem(problemReporter, transformation, problem); | ||
| }); | ||
| errored = true; | ||
| } | ||
|
|
||
| return !(errored && validation == AccessTransformerValidation.ERROR); | ||
| } | ||
|
|
||
| static void reportProblem(ProblemReporter problemReporter, Transformation transformation, Problem problem) { | ||
| // Report a problem for each origin of the transform | ||
| for (String origin : transformation.origins()) { | ||
| var m = ORIGIN_PATTERN.matcher(origin); | ||
| ProblemLocation problemLocation; | ||
| if (!m.matches()) { | ||
| problemLocation = ProblemLocation.ofFile(Paths.get(origin)); | ||
| } else { | ||
| var file = Path.of(m.group(1)); | ||
| var line = Integer.parseUnsignedInt(m.group(2)); | ||
| problemLocation = ProblemLocation.ofLocationInFile(file, line); | ||
| } | ||
|
|
||
| problemReporter.report(Problem.builder(problem).location(problemLocation).build()); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void visitFile(PsiFile psiFile, Replacements replacements) { | ||
| var visitor = new ApplyATsVisitor(ats, replacements, pendingATs, logger); | ||
| var visitor = new ApplyATsVisitor(ats, replacements, pendingATs, logger, problemReporter); | ||
| visitor.visitFile(psiFile); | ||
| if (visitor.errored) { | ||
| errored = true; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,9 @@ | ||
| package net.neoforged.jst.api; | ||
|
|
||
| public record TransformContext(IntelliJEnvironment environment, FileSource source, FileSink sink, Logger logger) { | ||
| import net.neoforged.problems.ProblemReporter; | ||
|
|
||
| public record TransformContext(IntelliJEnvironment environment, FileSource source, FileSink sink, Logger logger, ProblemReporter problemReporter) { | ||
| public TransformContext(IntelliJEnvironment environment, FileSource source, FileSink sink, Logger logger) { | ||
| this(environment, source, sink, logger, ProblemReporter.NOOP); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,3 +5,4 @@ picocli_version=4.7.6 | |
| junit_version=5.10.3 | ||
| assertj_version=3.26.0 | ||
| gson_version=2.10.1 | ||
| problems_api_version=3.0.3 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| Access transformer PUBLIC LEAVE {atpath}:1 targeting constructor of AnEnum attempted to make an enum constructor PUBLIC | ||
| Access transformer targeting constructor of AnEnum attempted to make an enum constructor PUBLIC at PUBLIC LEAVE {atpath}:1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| [ | ||
| { | ||
| "problemId": { | ||
| "id": "invalid-at", | ||
| "displayName": "Invalid", | ||
| "group": { | ||
| "id": "access-transformer", | ||
| "displayName": "Access Transformers" | ||
| } | ||
| }, | ||
| "severity": "WARNING", | ||
| "location": { | ||
| "file": "accesstransformer.cfg", | ||
| "line": 1 | ||
| }, | ||
| "contextualLabel": "Access transformer targeting constructor of AnEnum attempted to make an enum constructor PUBLIC" | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| Access transformer PUBLIC LEAVE {atpath}:9 targeting record class PrivateRecord attempts to widen its access without widening the constructor's access. You must AT the constructor too: "public PrivateRecord <init>(I)V" | ||
| Access transformer targeting record class PrivateRecord attempts to widen its access without widening the constructor's access. You must AT the constructor too: "public PrivateRecord <init>(I)V" at PUBLIC LEAVE {atpath}:9 |
Uh oh!
There was an error while loading. Please reload this page.