Skip to content

Commit a5752e3

Browse files
GH-129: Validation for duplicate oneof node names
1 parent 9552488 commit a5752e3

File tree

7 files changed

+78
-2
lines changed

7 files changed

+78
-2
lines changed

src/main/java/io/protostuff/jetbrains/plugin/annotator/ProtoErrorsAnnotator.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold
8282
checkInvalidFieldTags(fields);
8383
checkDuplicateFieldTags(fields);
8484
checkDuplicateFieldNames(fields);
85+
Collection<OneOfNode> oneOfNodes = message.getOneOfNodes();
86+
checkDuplicateOneofNames(oneOfNodes);
87+
checkDuplicateFieldOneofNames(oneOfNodes, fields);
8588
checkReservedFieldTags(message, fields);
8689
checkReservedFieldNames(message, fields);
8790
}
@@ -387,7 +390,7 @@ private void checkDuplicateFieldTags(Collection<MessageField> fields) {
387390
int tag = field.getTag();
388391
if (fieldByTag.containsKey(tag)) {
389392
String message = message("error.duplicate.field.tag", tag);
390-
markError(field.getNode(), fieldByTag.get(tag).getTagNode(), message);
393+
markError(fieldByTag.get(tag).getNode(), fieldByTag.get(tag).getTagNode(), message);
391394
markError(field.getNode(), field.getTagNode(), message);
392395
}
393396
fieldByTag.put(tag, field);
@@ -400,10 +403,39 @@ private void checkDuplicateFieldNames(Collection<MessageField> fields) {
400403
String name = field.getFieldName();
401404
if (fieldByName.containsKey(name)) {
402405
String message = message("error.duplicate.field.name", name);
403-
markError(field.getNode(), fieldByName.get(name).getFieldNameNode(), message);
406+
markError(fieldByName.get(name).getNode(), fieldByName.get(name).getFieldNameNode(), message);
404407
markError(field.getNode(), field.getFieldNameNode(), message);
405408
}
406409
fieldByName.put(name, field);
407410
}
408411
}
412+
413+
private void checkDuplicateOneofNames(Collection<OneOfNode> fields) {
414+
Map<String, OneOfNode> fieldByName = new HashMap<>();
415+
for (OneOfNode oneOfNode : fields) {
416+
String name = oneOfNode.getName();
417+
if (fieldByName.containsKey(name)) {
418+
String message = message("error.duplicate.name", name);
419+
markError(fieldByName.get(name).getNode(), fieldByName.get(name).getOneofNameNode(), message);
420+
markError(oneOfNode.getNode(), oneOfNode.getOneofNameNode(), message);
421+
}
422+
fieldByName.put(name, oneOfNode);
423+
}
424+
}
425+
426+
private void checkDuplicateFieldOneofNames(Collection<OneOfNode> oneOfNodes, Collection<MessageField> fields) {
427+
Map<String, MessageField> fieldByName = new HashMap<>();
428+
for (MessageField field : fields) {
429+
String name = field.getFieldName();
430+
fieldByName.put(name, field);
431+
}
432+
for (OneOfNode oneOfNode : oneOfNodes) {
433+
String name = oneOfNode.getName();
434+
if (fieldByName.containsKey(name)) {
435+
String message = message("error.duplicate.name", name);
436+
markError(fieldByName.get(name).getNode(), fieldByName.get(name).getFieldNameNode(), message);
437+
markError(oneOfNode.getNode(), oneOfNode.getOneofNameNode(), message);
438+
}
439+
}
440+
}
409441
}

src/main/java/io/protostuff/jetbrains/plugin/psi/MessageNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,8 @@ public boolean hasSyntaxErrors() {
110110
return syntaxErrors;
111111
}
112112

113+
public Collection<OneOfNode> getOneOfNodes() {
114+
OneOfNode[] oneOfs = findChildrenByClass(OneOfNode.class);
115+
return Arrays.asList(oneOfs);
116+
}
113117
}

src/main/java/io/protostuff/jetbrains/plugin/psi/OneOfNode.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,15 @@ public Collection<MessageField> getFields() {
2525
public DataType[] getDeclaredDataTypes() {
2626
return findChildrenByClass(DataType.class);
2727
}
28+
29+
/**
30+
* Returns name node, if present, null otherwise.
31+
*/
32+
public ASTNode getOneofNameNode() {
33+
GenericNameNode nameIdentifier = getNameIdentifier();
34+
if (nameIdentifier == null) {
35+
return null;
36+
}
37+
return nameIdentifier.getNode();
38+
}
2839
}

src/main/resources/io/protostuff/protobuf-jetbrains-plugin/messages/ProtostuffBundle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@ error.illegal.oneof.field.label=Oneof field cannot have label
3333
error.unresolved.reference=Unresolved reference
3434
error.file.not.found=File not found
3535
error.expected.identifier=Identifier expected
36+
error.duplicate.name=Duplicate name: {0}
37+
error.duplicate.value=Duplicate value: {0}

src/test/java/io/protostuff/jetbrains/plugin/annotator/ProtoErrorsAnnotatorTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ public void testDuplicateFieldName() {
3030
check();
3131
}
3232

33+
public void testDuplicateFieldName_asOneofName() {
34+
check();
35+
}
36+
37+
public void testDuplicateOneofName() {
38+
check();
39+
}
40+
3341
public void testDuplicateTagValue() {
3442
check();
3543
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
syntax = "proto3";
2+
3+
package annotator;
4+
5+
message TestMessage {
6+
oneof <error descr="Duplicate name: value">value</error> {
7+
int32 <error descr="Duplicate name: value">value</error> = 1;
8+
}
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
syntax = "proto3";
2+
3+
package annotator;
4+
5+
message TestMessage {
6+
oneof <error descr="Duplicate name: value">value</error> {
7+
}
8+
oneof <error descr="Duplicate name: value">value</error> {
9+
}
10+
}

0 commit comments

Comments
 (0)