Skip to content

Commit ca58806

Browse files
#39: Make proto file node syntax value accessible in errors annotator
1 parent 03517fd commit ca58806

File tree

9 files changed

+138
-53
lines changed

9 files changed

+138
-53
lines changed

build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ buildscript {
22
repositories {
33
jcenter()
44
maven { url 'http://dl.bintray.com/jetbrains/intellij-plugin-service' }
5+
mavenCentral()
56
mavenLocal()
67
}
78
dependencies {
@@ -31,7 +32,7 @@ dependencies {
3132
exclude group: 'com.jetbrains'
3233
}
3334
compile 'com.google.guava:guava:21.0'
34-
compile 'io.protostuff:protostuff-parser:2.0.0-alpha37'
35+
compile 'io.protostuff:protostuff-parser:2.0.0-alpha38'
3536
}
3637

3738
apply plugin: 'idea'

src/main/java/io/protostuff/jetbrains/plugin/ProtoParserDefinition.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
import io.protostuff.jetbrains.plugin.psi.RpcMethodTypeNode;
4949
import io.protostuff.jetbrains.plugin.psi.ServiceNode;
5050
import io.protostuff.jetbrains.plugin.psi.StandardFieldReferenceNode;
51-
import io.protostuff.jetbrains.plugin.psi.SyntaxNode;
51+
import io.protostuff.jetbrains.plugin.psi.SyntaxStatement;
5252
import io.protostuff.jetbrains.plugin.psi.TypeReferenceNode;
5353
import java.util.HashMap;
5454
import java.util.List;
@@ -232,7 +232,7 @@ public class ProtoParserDefinition implements ParserDefinition {
232232
* Create new parser definition.
233233
*/
234234
public ProtoParserDefinition() {
235-
register(ProtoParser.RULE_syntax, SyntaxNode::new);
235+
register(ProtoParser.RULE_syntaxStatement, SyntaxStatement::new);
236236
register(ProtoParser.RULE_packageStatement, PackageStatement::new);
237237
register(ProtoParser.RULE_importStatement, ImportNode::new);
238238
register(ProtoParser.RULE_fileReference, FileReferenceNode::new);

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

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
import com.intellij.lang.annotation.AnnotationHolder;
1010
import com.intellij.lang.annotation.Annotator;
1111
import com.intellij.psi.PsiElement;
12-
import com.intellij.psi.PsiErrorElement;
13-
import com.intellij.psi.PsiRecursiveElementVisitor;
1412
import io.protostuff.compiler.model.Field;
1513
import io.protostuff.jetbrains.plugin.psi.AntlrParserRuleNode;
1614
import io.protostuff.jetbrains.plugin.psi.EnumConstantNode;
1715
import io.protostuff.jetbrains.plugin.psi.EnumNode;
1816
import io.protostuff.jetbrains.plugin.psi.MessageField;
1917
import io.protostuff.jetbrains.plugin.psi.MessageNode;
18+
import io.protostuff.jetbrains.plugin.psi.ProtoRootNode;
2019
import io.protostuff.jetbrains.plugin.psi.RangeNode;
2120
import io.protostuff.jetbrains.plugin.psi.RpcMethodNode;
2221
import io.protostuff.jetbrains.plugin.psi.ServiceNode;
22+
import io.protostuff.jetbrains.plugin.psi.Syntax;
2323
import java.util.Collection;
2424
import java.util.HashMap;
2525
import java.util.List;
@@ -47,28 +47,40 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold
4747
boolean check = hasErrors(element);
4848
if (!check) {
4949
this.holder = holder;
50-
if (element instanceof MessageNode) {
51-
MessageNode message = (MessageNode) element;
52-
Collection<MessageField> fields = message.getFields();
53-
checkInvalidFieldTags(fields);
54-
checkDuplicateFieldTags(fields);
55-
checkDuplicateFieldNames(fields);
56-
checkReservedFieldTags(message, fields);
57-
checkReservedFieldNames(message, fields);
58-
} else if (element instanceof EnumNode) {
59-
EnumNode anEnum = (EnumNode) element;
60-
List<EnumConstantNode> constants = anEnum.getConstants();
61-
checkDuplicateEnumConstantNames(constants);
62-
checkDuplicateEnumConstantValues(anEnum, constants);
63-
} else if (element instanceof ServiceNode) {
64-
ServiceNode service = (ServiceNode) element;
65-
List<RpcMethodNode> rpcMethods = service.getRpcMethods();
66-
checkDuplicateServiceMethodNames(rpcMethods);
50+
ProtoRootNode root = getProtoRoot(element);
51+
if (root != null) {
52+
Syntax syntax = root.getSyntax();
53+
if (element instanceof MessageNode) {
54+
MessageNode message = (MessageNode) element;
55+
Collection<MessageField> fields = message.getFields();
56+
checkInvalidFieldTags(fields);
57+
checkDuplicateFieldTags(fields);
58+
checkDuplicateFieldNames(fields);
59+
checkReservedFieldTags(message, fields);
60+
checkReservedFieldNames(message, fields);
61+
} else if (element instanceof EnumNode) {
62+
EnumNode anEnum = (EnumNode) element;
63+
List<EnumConstantNode> constants = anEnum.getConstants();
64+
checkDuplicateEnumConstantNames(constants);
65+
checkDuplicateEnumConstantValues(anEnum, constants);
66+
} else if (element instanceof ServiceNode) {
67+
ServiceNode service = (ServiceNode) element;
68+
List<RpcMethodNode> rpcMethods = service.getRpcMethods();
69+
checkDuplicateServiceMethodNames(rpcMethods);
70+
}
6771
}
6872
this.holder = null;
6973
}
7074
}
7175

76+
private ProtoRootNode getProtoRoot(PsiElement element) {
77+
PsiElement tmp = element;
78+
while (tmp != null && !(tmp instanceof ProtoRootNode)) {
79+
tmp = tmp.getParent();
80+
}
81+
return (ProtoRootNode) tmp;
82+
}
83+
7284
private void checkDuplicateServiceMethodNames(List<RpcMethodNode> rpcMethods) {
7385
Map<String, RpcMethodNode> methodByName = new HashMap<>();
7486
for (RpcMethodNode methods : rpcMethods) {
@@ -116,14 +128,7 @@ private boolean hasErrors(PsiElement element) {
116128
AntlrParserRuleNode node = (AntlrParserRuleNode) element;
117129
return node.hasSyntaxErrors();
118130
} else {
119-
final boolean[] hasErrors = {false};
120-
new PsiRecursiveElementVisitor() {
121-
@Override
122-
public void visitErrorElement(PsiErrorElement element) {
123-
hasErrors[0] = true;
124-
}
125-
};
126-
return hasErrors[0];
131+
return false;
127132
}
128133
}
129134

src/main/java/io/protostuff/jetbrains/plugin/formatter/BlockFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
import static io.protostuff.compiler.parser.ProtoParser.RULE_serviceBlock;
4848
import static io.protostuff.compiler.parser.ProtoParser.RULE_serviceName;
4949
import static io.protostuff.compiler.parser.ProtoParser.RULE_standardFieldRerefence;
50-
import static io.protostuff.compiler.parser.ProtoParser.RULE_syntax;
50+
import static io.protostuff.compiler.parser.ProtoParser.RULE_syntaxName;
51+
import static io.protostuff.compiler.parser.ProtoParser.RULE_syntaxStatement;
5152
import static io.protostuff.compiler.parser.ProtoParser.RULE_tag;
5253
import static io.protostuff.compiler.parser.ProtoParser.RULE_textFormat;
5354
import static io.protostuff.compiler.parser.ProtoParser.RULE_textFormatEntry;
@@ -101,7 +102,8 @@ class BlockFactory {
101102
register(rule(RULE_reservedFieldRanges), StatementBlock::new);
102103
register(rule(RULE_fieldOptions), StatementBlock::new);
103104
register(rule(RULE_map), StatementBlock::new);
104-
register(rule(RULE_syntax), StatementBlock::new);
105+
register(rule(RULE_syntaxStatement), StatementBlock::new);
106+
register(rule(RULE_syntaxName), LeafBlock::new);
105107
register(rule(RULE_packageStatement), StatementBlock::new);
106108
register(rule(RULE_importStatement), StatementBlock::new);
107109
register(rule(RULE_optionEntry), StatementBlock::new);

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ private PackageStatement getPackageStatement() {
130130
return findChildByClass(PackageStatement.class);
131131
}
132132

133+
@Nullable
134+
public SyntaxStatement getSyntaxStatement() {
135+
return findChildByClass(SyntaxStatement.class);
136+
}
137+
138+
/**
139+
* Returns syntax value for this file, or default to {@link Syntax#DEFAULT}.
140+
*/
141+
public Syntax getSyntax() {
142+
SyntaxStatement statement = getSyntaxStatement();
143+
if (statement != null) {
144+
String syntaxName = statement.getSyntaxName();
145+
return Syntax.forName(syntaxName).orElse(Syntax.DEFAULT);
146+
}
147+
return Syntax.DEFAULT;
148+
}
149+
133150
@Override
134151
public String getNamespace() {
135152
String packageName = getPackageName();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.protostuff.jetbrains.plugin.psi;
2+
3+
import java.util.Optional;
4+
5+
/**
6+
* Proto syntax level.
7+
*
8+
* @author Kostiantyn Shchepanovskyi
9+
*/
10+
public enum Syntax {
11+
PROTO2("proto2"),
12+
PROTO3("proto3");
13+
14+
public static Syntax DEFAULT = PROTO2;
15+
16+
private final String name;
17+
18+
Syntax(String name) {
19+
this.name = name;
20+
}
21+
22+
public String getName() {
23+
return name;
24+
}
25+
26+
/**
27+
* Get syntax by proto syntax name.
28+
*/
29+
public static Optional<Syntax> forName(String name) {
30+
for (Syntax syntax : Syntax.values()) {
31+
if (syntax.getName().equals(name)) {
32+
return Optional.of(syntax);
33+
}
34+
}
35+
return Optional.empty();
36+
}
37+
}

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

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.protostuff.jetbrains.plugin.psi;
2+
3+
import static io.protostuff.compiler.parser.Util.removeFirstAndLastChar;
4+
5+
import com.intellij.lang.ASTNode;
6+
import com.intellij.psi.PsiElement;
7+
import io.protostuff.compiler.parser.ProtoParser;
8+
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
9+
import org.antlr.jetbrains.adapter.psi.AntlrPsiNode;
10+
import org.jetbrains.annotations.NotNull;
11+
import org.jetbrains.annotations.Nullable;
12+
13+
/**
14+
* Syntax node.
15+
*
16+
* @author Kostiantyn Shchepanovskyi
17+
*/
18+
public class SyntaxStatement extends AntlrPsiNode implements KeywordsContainer {
19+
20+
public SyntaxStatement(@NotNull ASTNode node) {
21+
super(node);
22+
}
23+
24+
@Nullable
25+
String getSyntaxName() {
26+
PsiElement syntaxNameNode = findChildByType(ProtoParserDefinition.rule(ProtoParser.RULE_syntaxName));
27+
if (syntaxNameNode != null) {
28+
String text = syntaxNameNode.getText();
29+
if (text.length() > 2
30+
&& (text.startsWith("\"") && text.endsWith("\""))
31+
|| (text.startsWith("'") && text.endsWith("'"))) {
32+
String value = removeFirstAndLastChar(text);
33+
return value;
34+
}
35+
return text;
36+
}
37+
return null;
38+
}
39+
40+
}

src/test/resources/parsing/HeaderAndFooterComments.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ Protobuf File: HeaderAndFooterComments.proto(0,118)
22
PsiComment(LINE_COMMENT)('// Header comment does not belong to 'proto' rule')(0,49)
33
PsiWhiteSpace('\n')(49,50)
44
ProtoRootNode(proto)(50,68)
5-
SyntaxNode(syntax)(50,68)
5+
SyntaxStatement(syntaxStatement)(50,68)
66
PsiElement('syntax')('syntax')(50,56)
77
PsiWhiteSpace(' ')(56,57)
88
PsiElement('=')('=')(57,58)
99
PsiWhiteSpace(' ')(58,59)
10-
PsiElement(STRING_VALUE)('"proto2"')(59,67)
10+
AntlrPsiNode(syntaxName)(59,67)
11+
PsiElement(STRING_VALUE)('"proto2"')(59,67)
1112
PsiElement(';')(';')(67,68)
1213
PsiWhiteSpace('\n')(68,69)
13-
PsiComment(LINE_COMMENT)('// Footer comment does not belong to 'proto' rule')(69,118)
14+
PsiComment(LINE_COMMENT)('// Footer comment does not belong to 'proto' rule')(69,118)

0 commit comments

Comments
 (0)