diff --git a/src/main/java/analysis/GoblintAnalysis.java b/src/main/java/analysis/GoblintAnalysis.java index 0545683..36e1d95 100644 --- a/src/main/java/analysis/GoblintAnalysis.java +++ b/src/main/java/analysis/GoblintAnalysis.java @@ -244,9 +244,7 @@ private CompletableFuture> getComposedAnalysisResults */ private Collection convertMessagesFromJson(List response) { - return gobpieConfiguration.explodeGroupWarnings() - ? response.stream().map(GoblintMessagesResult::convertExplode).flatMap(List::stream).toList() - : response.stream().map(GoblintMessagesResult::convertNonExplode).flatMap(List::stream).toList(); + return response.stream().map(msg -> msg.convert(gobpieConfiguration.explodeGroupWarnings())).flatMap(List::stream).toList(); } private Collection convertFunctionsFromJson(List response) { diff --git a/src/main/java/api/json/GoblintMessageJsonHandler.java b/src/main/java/api/json/GoblintMessageJsonHandler.java index 8a3e3ab..d1c6f98 100644 --- a/src/main/java/api/json/GoblintMessageJsonHandler.java +++ b/src/main/java/api/json/GoblintMessageJsonHandler.java @@ -30,7 +30,8 @@ public GsonBuilder getDefaultGsonBuilder() { .registerTypeAdapterFactory(new TupleTypeAdapters.TwoTypeAdapterFactory()) .registerTypeAdapterFactory(new EnumTypeAdapter.Factory()) .registerTypeAdapterFactory(new GoblintMessageTypeAdapter.Factory(this)) - .registerTypeAdapter(GoblintMessagesResult.Tag.class, new GoblintTagInterfaceAdapter()); + .registerTypeAdapter(GoblintMessagesResult.Tag.class, new GoblintTagInterfaceAdapter()) + .registerTypeAdapter(GoblintMessagesResult.MultiPiece.class, new GoblintMultiPieceInterfaceAdapter()); } } diff --git a/src/main/java/api/json/GoblintMultiPieceInterfaceAdapter.java b/src/main/java/api/json/GoblintMultiPieceInterfaceAdapter.java new file mode 100644 index 0000000..c42353d --- /dev/null +++ b/src/main/java/api/json/GoblintMultiPieceInterfaceAdapter.java @@ -0,0 +1,29 @@ +package api.json; + +import api.messages.GoblintMessagesResult; +import com.google.gson.*; + +import java.lang.reflect.Type; + +/** + * The Class GoblintMultiPieceInterfaceAdapter. + *

+ * Implements the JsonDeserializer to deserialize json to GoblintResult objects. + * In particular to differentiate between the Group and Piece (Single) classes. + * + * @author Karoliine Holter + * @since 0.0.4 + */ + + +public class GoblintMultiPieceInterfaceAdapter implements JsonDeserializer { + @Override + public Object deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + if (jsonObject.has("group_text")) + return jsonDeserializationContext.deserialize(jsonObject, GoblintMessagesResult.Group.class); + if (jsonObject.has("text")) + return jsonDeserializationContext.deserialize(jsonObject, GoblintMessagesResult.Piece.class); + return null; + } +} diff --git a/src/main/java/api/messages/GoblintMessagesResult.java b/src/main/java/api/messages/GoblintMessagesResult.java index 1c4bdec..f021b3f 100644 --- a/src/main/java/api/messages/GoblintMessagesResult.java +++ b/src/main/java/api/messages/GoblintMessagesResult.java @@ -27,7 +27,7 @@ public class GoblintMessagesResult { private final String type = getClass().getName(); private final List tags = new ArrayList<>(); private String severity; - private Multipiece multipiece; + private MultiPiece multipiece; public interface Tag { String toString(); @@ -51,73 +51,96 @@ public String toString() { } } - static class Multipiece { - private GoblintLocation loc; + public interface MultiPiece { + List convert(List tags, String severity, boolean explode); + } + + public static class Piece implements MultiPiece { private String text; - private String group_text; - private final List pieces = new ArrayList<>(); + private GoblintLocation loc; - static class Piece { - private String text; - private GoblintLocation loc; + /** + * Converts the Single (Piece type of) Goblint messages from the + * GoblintMessagesResult type to AnalysisResult that are needed for MagPieBridge. + * + * @param tags the tags of the warning given by Goblint + * @param severity the severity of the warning given by Goblint + * @param explode is not used here and is only used for group warnings + * @return A collection of AnalysisResult objects. + */ + public List convert(List tags, String severity, boolean explode) { + GoblintPosition pos = getLocation(loc); + String msg = joinTags(tags) + " " + text; + GoblintMessagesAnalysisResult result = new GoblintMessagesAnalysisResult(pos, msg, severity); + return List.of(result); } } - public String getType() { - return type; - } - - public List convertSingle() { - GoblintMessagesAnalysisResult result = createGoblintAnalysisResult(); - return new ArrayList<>(List.of(result)); - } + public static class Group implements MultiPiece { + private String group_text; + private GoblintLocation group_loc; + private final List pieces = new ArrayList<>(); - public List convertGroupToSeparateWarnings() { - List resultsWithoutRelated = - multipiece.pieces.stream().map(piece -> createGoblintAnalysisResult(piece, true)).toList(); - // Add related warnings to all the pieces in the group - List resultsWithRelated = new ArrayList<>(); - for (GoblintMessagesAnalysisResult result : resultsWithoutRelated) { - resultsWithRelated.add( - new GoblintMessagesAnalysisResult( - result.position(), - result.group_text() + "\n" + result.text(), - result.severityStr(), - resultsWithoutRelated.stream() - .filter(res -> res != result) - .map(res -> Pair.make(res.position(), res.text())) - .toList())); + /** + * Converts the Group Goblint messages from the + * GoblintMessagesResult type to AnalysisResult that are needed for MagPieBridge. + * + * @param tags the tags of the warning given by Goblint + * @param severity the severity of the warning given by Goblint + * @param explode the group warnings are exploded to have one IDE warning for each piece in the group if true, + * if false, only one warning per one Goblint warning is shown in the IDE + * @return A collection of AnalysisResult objects. + */ + public List convert(List tags, String severity, boolean explode) { + return explode + ? convertGroupExplode(tags, severity) + : convertGroup(tags, severity); } - return new ArrayList<>(resultsWithRelated); - } - public List convertGroup() { - List> relatedFromPieces = - multipiece.pieces.stream() - .map(piece -> createGoblintAnalysisResult(piece, false)) - .map(result -> Pair.make(result.position(), result.text())) - .toList(); - GoblintMessagesAnalysisResult result = createGoblintAnalysisResult(multipiece, relatedFromPieces); - return new ArrayList<>(List.of(result)); - } + public List convertGroupExplode(List tags, String severity) { + String groupText = joinTags(tags) + " Group: " + group_text; + List resultsWithoutRelated = + pieces.stream().map(piece -> new GoblintMessagesAnalysisResult(getLocation(piece.loc), groupText, piece.text, severity)).toList(); + // Add related warnings to all the pieces in the group + List resultsWithRelated = new ArrayList<>(); + for (GoblintMessagesAnalysisResult result : resultsWithoutRelated) { + resultsWithRelated.add( + new GoblintMessagesAnalysisResult( + result.position(), + result.group_text() + "\n" + result.text(), + result.severityStr(), + resultsWithoutRelated.stream() + .filter(res -> res != result) + .map(res -> Pair.make(res.position(), res.text())) + .toList())); + } + return resultsWithRelated; + } - public List convertExplode() { - if (multipiece.group_text == null) { - return convertSingle(); - } else { - return convertGroupToSeparateWarnings(); + public List convertGroup(List tags, String severity) { + // Convert all pieces to pairs of position and text to be used as related warnings + List> relatedFromPieces = + pieces.stream().map(piece -> Pair.make((Position) getLocation(piece.loc), piece.text)).toList(); + // Use the group location for the warning if defined, or a random one from one of the pieces otherwise + GoblintPosition pos = + group_loc != null + ? group_loc.toPosition() + : pieces.stream() + .filter(piece -> piece.loc != null) + .findFirst() + .map(piece -> piece.loc.toPosition()) + .orElse(getLocation(group_loc)); + GoblintMessagesAnalysisResult result = + new GoblintMessagesAnalysisResult(pos, joinTags(tags) + " " + group_text, severity, relatedFromPieces); + return List.of(result); } } - public List convertNonExplode() { - if (multipiece.group_text == null) { - return convertSingle(); - } else { - return convertGroup(); - } + private static String joinTags(List tags) { + return tags.stream().map(Tag::toString).collect(Collectors.joining("")); } - public GoblintPosition getLocation(GoblintLocation loc) { + private static GoblintPosition getLocation(GoblintLocation loc) { try { return loc == null ? new GoblintPosition(1, 1, 1, new File("").toURI().toURL()) @@ -127,39 +150,8 @@ public GoblintPosition getLocation(GoblintLocation loc) { } } - public GoblintPosition getRandomLocation(Multipiece multipiece) { - for (GoblintMessagesResult.Multipiece.Piece piece : multipiece.pieces) { - if (piece.loc != null) return getLocation(piece.loc); - } - return getLocation(multipiece.loc); + public List convert(boolean explode) { + return multipiece.convert(tags, severity, explode); } - public GoblintMessagesAnalysisResult createGoblintAnalysisResult() { - GoblintPosition pos = getLocation(multipiece.loc); - String msg = tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " " + multipiece.text; - return new GoblintMessagesAnalysisResult(pos, msg, severity); - - } - - public GoblintMessagesAnalysisResult createGoblintAnalysisResult(Multipiece.Piece piece, boolean addGroupText) { - GoblintPosition pos = getLocation(piece.loc); - return new GoblintMessagesAnalysisResult( - pos, - addGroupText - ? tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " Group: " + multipiece.group_text - : "", - piece.text, - severity); - } - - public GoblintMessagesAnalysisResult createGoblintAnalysisResult(Multipiece multipiece, List> related) { - GoblintPosition pos = multipiece.loc != null - ? getLocation(multipiece.loc) - : getRandomLocation(multipiece); - return new GoblintMessagesAnalysisResult( - pos, - tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " " + this.multipiece.group_text, - severity, - related); - } } \ No newline at end of file