Skip to content

Commit

Permalink
Merge pull request #66 from goblint/messages
Browse files Browse the repository at this point in the history
Use a TypeAdapter to deserialize Multipiece from json and cleanup
  • Loading branch information
karoliineh authored Aug 21, 2023
2 parents 8b3f2e3 + fc39dbe commit b347d2b
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 91 deletions.
4 changes: 1 addition & 3 deletions src/main/java/analysis/GoblintAnalysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,7 @@ private CompletableFuture<Collection<AnalysisResult>> getComposedAnalysisResults
*/

private Collection<AnalysisResult> convertMessagesFromJson(List<GoblintMessagesResult> 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<AnalysisResult> convertFunctionsFromJson(List<GoblintFunctionsResult> response) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/api/json/GoblintMessageJsonHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

}
29 changes: 29 additions & 0 deletions src/main/java/api/json/GoblintMultiPieceInterfaceAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package api.json;

import api.messages.GoblintMessagesResult;
import com.google.gson.*;

import java.lang.reflect.Type;

/**
* The Class GoblintMultiPieceInterfaceAdapter.
* <p>
* 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<Object> {
@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;
}
}
166 changes: 79 additions & 87 deletions src/main/java/api/messages/GoblintMessagesResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class GoblintMessagesResult {
private final String type = getClass().getName();
private final List<Tag> tags = new ArrayList<>();
private String severity;
private Multipiece multipiece;
private MultiPiece multipiece;

public interface Tag {
String toString();
Expand All @@ -51,73 +51,96 @@ public String toString() {
}
}

static class Multipiece {
private GoblintLocation loc;
public interface MultiPiece {
List<AnalysisResult> convert(List<Tag> tags, String severity, boolean explode);
}

public static class Piece implements MultiPiece {
private String text;
private String group_text;
private final List<Piece> 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<AnalysisResult> convert(List<Tag> 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<AnalysisResult> 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<Piece> pieces = new ArrayList<>();

public List<AnalysisResult> convertGroupToSeparateWarnings() {
List<GoblintMessagesAnalysisResult> resultsWithoutRelated =
multipiece.pieces.stream().map(piece -> createGoblintAnalysisResult(piece, true)).toList();
// Add related warnings to all the pieces in the group
List<GoblintMessagesAnalysisResult> 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<AnalysisResult> convert(List<Tag> tags, String severity, boolean explode) {
return explode
? convertGroupExplode(tags, severity)
: convertGroup(tags, severity);
}
return new ArrayList<>(resultsWithRelated);
}

public List<AnalysisResult> convertGroup() {
List<Pair<Position, String>> 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<AnalysisResult> convertGroupExplode(List<Tag> tags, String severity) {
String groupText = joinTags(tags) + " Group: " + group_text;
List<GoblintMessagesAnalysisResult> 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<AnalysisResult> 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<AnalysisResult> convertExplode() {
if (multipiece.group_text == null) {
return convertSingle();
} else {
return convertGroupToSeparateWarnings();
public List<AnalysisResult> convertGroup(List<Tag> tags, String severity) {
// Convert all pieces to pairs of position and text to be used as related warnings
List<Pair<Position, String>> 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<AnalysisResult> convertNonExplode() {
if (multipiece.group_text == null) {
return convertSingle();
} else {
return convertGroup();
}
private static String joinTags(List<Tag> 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())
Expand All @@ -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<AnalysisResult> 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<Pair<Position, String>> 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);
}
}

0 comments on commit b347d2b

Please sign in to comment.