Skip to content

Commit b347d2b

Browse files
authored
Merge pull request #66 from goblint/messages
Use a TypeAdapter to deserialize Multipiece from json and cleanup
2 parents 8b3f2e3 + fc39dbe commit b347d2b

File tree

4 files changed

+111
-91
lines changed

4 files changed

+111
-91
lines changed

src/main/java/analysis/GoblintAnalysis.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,7 @@ private CompletableFuture<Collection<AnalysisResult>> getComposedAnalysisResults
244244
*/
245245

246246
private Collection<AnalysisResult> convertMessagesFromJson(List<GoblintMessagesResult> response) {
247-
return gobpieConfiguration.explodeGroupWarnings()
248-
? response.stream().map(GoblintMessagesResult::convertExplode).flatMap(List::stream).toList()
249-
: response.stream().map(GoblintMessagesResult::convertNonExplode).flatMap(List::stream).toList();
247+
return response.stream().map(msg -> msg.convert(gobpieConfiguration.explodeGroupWarnings())).flatMap(List::stream).toList();
250248
}
251249

252250
private Collection<AnalysisResult> convertFunctionsFromJson(List<GoblintFunctionsResult> response) {

src/main/java/api/json/GoblintMessageJsonHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ public GsonBuilder getDefaultGsonBuilder() {
3030
.registerTypeAdapterFactory(new TupleTypeAdapters.TwoTypeAdapterFactory())
3131
.registerTypeAdapterFactory(new EnumTypeAdapter.Factory())
3232
.registerTypeAdapterFactory(new GoblintMessageTypeAdapter.Factory(this))
33-
.registerTypeAdapter(GoblintMessagesResult.Tag.class, new GoblintTagInterfaceAdapter());
33+
.registerTypeAdapter(GoblintMessagesResult.Tag.class, new GoblintTagInterfaceAdapter())
34+
.registerTypeAdapter(GoblintMessagesResult.MultiPiece.class, new GoblintMultiPieceInterfaceAdapter());
3435
}
3536

3637
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package api.json;
2+
3+
import api.messages.GoblintMessagesResult;
4+
import com.google.gson.*;
5+
6+
import java.lang.reflect.Type;
7+
8+
/**
9+
* The Class GoblintMultiPieceInterfaceAdapter.
10+
* <p>
11+
* Implements the JsonDeserializer to deserialize json to GoblintResult objects.
12+
* In particular to differentiate between the Group and Piece (Single) classes.
13+
*
14+
* @author Karoliine Holter
15+
* @since 0.0.4
16+
*/
17+
18+
19+
public class GoblintMultiPieceInterfaceAdapter implements JsonDeserializer<Object> {
20+
@Override
21+
public Object deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
22+
JsonObject jsonObject = jsonElement.getAsJsonObject();
23+
if (jsonObject.has("group_text"))
24+
return jsonDeserializationContext.deserialize(jsonObject, GoblintMessagesResult.Group.class);
25+
if (jsonObject.has("text"))
26+
return jsonDeserializationContext.deserialize(jsonObject, GoblintMessagesResult.Piece.class);
27+
return null;
28+
}
29+
}

src/main/java/api/messages/GoblintMessagesResult.java

Lines changed: 79 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class GoblintMessagesResult {
2727
private final String type = getClass().getName();
2828
private final List<Tag> tags = new ArrayList<>();
2929
private String severity;
30-
private Multipiece multipiece;
30+
private MultiPiece multipiece;
3131

3232
public interface Tag {
3333
String toString();
@@ -51,73 +51,96 @@ public String toString() {
5151
}
5252
}
5353

54-
static class Multipiece {
55-
private GoblintLocation loc;
54+
public interface MultiPiece {
55+
List<AnalysisResult> convert(List<Tag> tags, String severity, boolean explode);
56+
}
57+
58+
public static class Piece implements MultiPiece {
5659
private String text;
57-
private String group_text;
58-
private final List<Piece> pieces = new ArrayList<>();
60+
private GoblintLocation loc;
5961

60-
static class Piece {
61-
private String text;
62-
private GoblintLocation loc;
62+
/**
63+
* Converts the Single (Piece type of) Goblint messages from the
64+
* GoblintMessagesResult type to AnalysisResult that are needed for MagPieBridge.
65+
*
66+
* @param tags the tags of the warning given by Goblint
67+
* @param severity the severity of the warning given by Goblint
68+
* @param explode is not used here and is only used for group warnings
69+
* @return A collection of AnalysisResult objects.
70+
*/
71+
public List<AnalysisResult> convert(List<Tag> tags, String severity, boolean explode) {
72+
GoblintPosition pos = getLocation(loc);
73+
String msg = joinTags(tags) + " " + text;
74+
GoblintMessagesAnalysisResult result = new GoblintMessagesAnalysisResult(pos, msg, severity);
75+
return List.of(result);
6376
}
6477
}
6578

66-
public String getType() {
67-
return type;
68-
}
69-
70-
public List<AnalysisResult> convertSingle() {
71-
GoblintMessagesAnalysisResult result = createGoblintAnalysisResult();
72-
return new ArrayList<>(List.of(result));
73-
}
79+
public static class Group implements MultiPiece {
80+
private String group_text;
81+
private GoblintLocation group_loc;
82+
private final List<Piece> pieces = new ArrayList<>();
7483

75-
public List<AnalysisResult> convertGroupToSeparateWarnings() {
76-
List<GoblintMessagesAnalysisResult> resultsWithoutRelated =
77-
multipiece.pieces.stream().map(piece -> createGoblintAnalysisResult(piece, true)).toList();
78-
// Add related warnings to all the pieces in the group
79-
List<GoblintMessagesAnalysisResult> resultsWithRelated = new ArrayList<>();
80-
for (GoblintMessagesAnalysisResult result : resultsWithoutRelated) {
81-
resultsWithRelated.add(
82-
new GoblintMessagesAnalysisResult(
83-
result.position(),
84-
result.group_text() + "\n" + result.text(),
85-
result.severityStr(),
86-
resultsWithoutRelated.stream()
87-
.filter(res -> res != result)
88-
.map(res -> Pair.make(res.position(), res.text()))
89-
.toList()));
84+
/**
85+
* Converts the Group Goblint messages from the
86+
* GoblintMessagesResult type to AnalysisResult that are needed for MagPieBridge.
87+
*
88+
* @param tags the tags of the warning given by Goblint
89+
* @param severity the severity of the warning given by Goblint
90+
* @param explode the group warnings are exploded to have one IDE warning for each piece in the group if true,
91+
* if false, only one warning per one Goblint warning is shown in the IDE
92+
* @return A collection of AnalysisResult objects.
93+
*/
94+
public List<AnalysisResult> convert(List<Tag> tags, String severity, boolean explode) {
95+
return explode
96+
? convertGroupExplode(tags, severity)
97+
: convertGroup(tags, severity);
9098
}
91-
return new ArrayList<>(resultsWithRelated);
92-
}
9399

94-
public List<AnalysisResult> convertGroup() {
95-
List<Pair<Position, String>> relatedFromPieces =
96-
multipiece.pieces.stream()
97-
.map(piece -> createGoblintAnalysisResult(piece, false))
98-
.map(result -> Pair.make(result.position(), result.text()))
99-
.toList();
100-
GoblintMessagesAnalysisResult result = createGoblintAnalysisResult(multipiece, relatedFromPieces);
101-
return new ArrayList<>(List.of(result));
102-
}
100+
public List<AnalysisResult> convertGroupExplode(List<Tag> tags, String severity) {
101+
String groupText = joinTags(tags) + " Group: " + group_text;
102+
List<GoblintMessagesAnalysisResult> resultsWithoutRelated =
103+
pieces.stream().map(piece -> new GoblintMessagesAnalysisResult(getLocation(piece.loc), groupText, piece.text, severity)).toList();
104+
// Add related warnings to all the pieces in the group
105+
List<AnalysisResult> resultsWithRelated = new ArrayList<>();
106+
for (GoblintMessagesAnalysisResult result : resultsWithoutRelated) {
107+
resultsWithRelated.add(
108+
new GoblintMessagesAnalysisResult(
109+
result.position(),
110+
result.group_text() + "\n" + result.text(),
111+
result.severityStr(),
112+
resultsWithoutRelated.stream()
113+
.filter(res -> res != result)
114+
.map(res -> Pair.make(res.position(), res.text()))
115+
.toList()));
116+
}
117+
return resultsWithRelated;
118+
}
103119

104-
public List<AnalysisResult> convertExplode() {
105-
if (multipiece.group_text == null) {
106-
return convertSingle();
107-
} else {
108-
return convertGroupToSeparateWarnings();
120+
public List<AnalysisResult> convertGroup(List<Tag> tags, String severity) {
121+
// Convert all pieces to pairs of position and text to be used as related warnings
122+
List<Pair<Position, String>> relatedFromPieces =
123+
pieces.stream().map(piece -> Pair.make((Position) getLocation(piece.loc), piece.text)).toList();
124+
// Use the group location for the warning if defined, or a random one from one of the pieces otherwise
125+
GoblintPosition pos =
126+
group_loc != null
127+
? group_loc.toPosition()
128+
: pieces.stream()
129+
.filter(piece -> piece.loc != null)
130+
.findFirst()
131+
.map(piece -> piece.loc.toPosition())
132+
.orElse(getLocation(group_loc));
133+
GoblintMessagesAnalysisResult result =
134+
new GoblintMessagesAnalysisResult(pos, joinTags(tags) + " " + group_text, severity, relatedFromPieces);
135+
return List.of(result);
109136
}
110137
}
111138

112-
public List<AnalysisResult> convertNonExplode() {
113-
if (multipiece.group_text == null) {
114-
return convertSingle();
115-
} else {
116-
return convertGroup();
117-
}
139+
private static String joinTags(List<Tag> tags) {
140+
return tags.stream().map(Tag::toString).collect(Collectors.joining(""));
118141
}
119142

120-
public GoblintPosition getLocation(GoblintLocation loc) {
143+
private static GoblintPosition getLocation(GoblintLocation loc) {
121144
try {
122145
return loc == null
123146
? new GoblintPosition(1, 1, 1, new File("").toURI().toURL())
@@ -127,39 +150,8 @@ public GoblintPosition getLocation(GoblintLocation loc) {
127150
}
128151
}
129152

130-
public GoblintPosition getRandomLocation(Multipiece multipiece) {
131-
for (GoblintMessagesResult.Multipiece.Piece piece : multipiece.pieces) {
132-
if (piece.loc != null) return getLocation(piece.loc);
133-
}
134-
return getLocation(multipiece.loc);
153+
public List<AnalysisResult> convert(boolean explode) {
154+
return multipiece.convert(tags, severity, explode);
135155
}
136156

137-
public GoblintMessagesAnalysisResult createGoblintAnalysisResult() {
138-
GoblintPosition pos = getLocation(multipiece.loc);
139-
String msg = tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " " + multipiece.text;
140-
return new GoblintMessagesAnalysisResult(pos, msg, severity);
141-
142-
}
143-
144-
public GoblintMessagesAnalysisResult createGoblintAnalysisResult(Multipiece.Piece piece, boolean addGroupText) {
145-
GoblintPosition pos = getLocation(piece.loc);
146-
return new GoblintMessagesAnalysisResult(
147-
pos,
148-
addGroupText
149-
? tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " Group: " + multipiece.group_text
150-
: "",
151-
piece.text,
152-
severity);
153-
}
154-
155-
public GoblintMessagesAnalysisResult createGoblintAnalysisResult(Multipiece multipiece, List<Pair<Position, String>> related) {
156-
GoblintPosition pos = multipiece.loc != null
157-
? getLocation(multipiece.loc)
158-
: getRandomLocation(multipiece);
159-
return new GoblintMessagesAnalysisResult(
160-
pos,
161-
tags.stream().map(Tag::toString).collect(Collectors.joining("")) + " " + this.multipiece.group_text,
162-
severity,
163-
related);
164-
}
165157
}

0 commit comments

Comments
 (0)