Skip to content

Commit 6070786

Browse files
committed
generator: detailed error on missing path-expr (#252)
1 parent a8ad9ec commit 6070786

File tree

4 files changed

+133
-11
lines changed

4 files changed

+133
-11
lines changed

src/org/intellij/grammar/generator/ParserGenerator.java

+37-9
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@
4949
import static org.intellij.grammar.generator.NameShortener.getRawClassName;
5050
import static org.intellij.grammar.generator.ParserGeneratorUtil.*;
5151
import static org.intellij.grammar.generator.RuleGraphHelper.Cardinality.*;
52-
import static org.intellij.grammar.generator.RuleGraphHelper.getSynonymTargetOrSelf;
53-
import static org.intellij.grammar.generator.RuleGraphHelper.hasPsiClass;
52+
import static org.intellij.grammar.generator.RuleGraphHelper.*;
5453
import static org.intellij.grammar.psi.BnfTypes.*;
5554

5655

@@ -2036,6 +2035,7 @@ private JBIterable<?> resolveUserPsiPathMethods(BnfRule startRule,
20362035
String item = indexStart > -1 ? pathElement.substring(0, indexStart).trim() : pathElement.trim();
20372036

20382037
if (item.isEmpty()) return item;
2038+
if (targetRule[0] == null) return null;
20392039
RuleMethodsHelper.MethodInfo targetInfo = myRulesMethodsHelper.getMethodInfo(targetRule[0], item);
20402040
targetRule[0] = targetInfo == null ? null : targetInfo.rule;
20412041
return targetInfo;
@@ -2057,18 +2057,44 @@ private void generateUserPsiAccessors(BnfRule startRule, RuleMethodsHelper.Metho
20572057
boolean last = i == splitPath.length - 1;
20582058
int indexStart = pathElement.indexOf('[');
20592059
int indexEnd = indexStart > 0 ? pathElement.lastIndexOf(']') : -1;
2060+
String base = (indexStart > -1 ? pathElement.substring(0, indexStart) : pathElement).trim();
20602061
String index = indexEnd > -1 ? pathElement.substring(indexStart + 1, indexEnd).trim() : null;
2061-
if ("first".equals(index)) index = "0";
2062+
20622063

20632064
RuleMethodsHelper.MethodInfo targetInfo = (RuleMethodsHelper.MethodInfo)m;
2064-
if (targetInfo == null ||
2065-
index != null && !targetInfo.cardinality.many() ||
2066-
i > 0 && StringUtil.isEmpty(targetInfo.name) && targetInfo.rule == null) {
2065+
String error;
2066+
if (indexStart > 0 && (indexEnd == -1 || StringUtil.isNotEmpty(pathElement.substring(indexEnd + 1)))) {
2067+
error = "'<name>[<index>]' expected, got '" + pathElement + "'";
2068+
}
2069+
else if (targetInfo == null) {
2070+
Collection<String> available = targetRule == null ? null : myRulesMethodsHelper.getMethodNames(targetRule);
2071+
if (targetRule == null) {
2072+
error = "'" + base + "' not found in '" + splitPath[i - 1] + "' (not a rule)";
2073+
}
2074+
else if (available == null || available.isEmpty()) {
2075+
error = "'" + base + "' not found in '" + targetRule.getName() + "' (available: nothing)";
2076+
}
2077+
else {
2078+
error = "'" + base + "' not found in '" + targetRule.getName() + "' (available: " + String.join(", ", available) + ")";
2079+
}
2080+
}
2081+
else if (index != null && !targetInfo.cardinality.many()) {
2082+
error = "'[" + index + "]' unexpected after '" + base + getCardinalityText(targetInfo.cardinality) + "'";
2083+
}
2084+
else if (!last && index == null && targetInfo.cardinality.many()) {
2085+
error = "'[<index>]' required after '" + base + getCardinalityText(targetInfo.cardinality) + "'";
2086+
}
2087+
else if (i > 0 && StringUtil.isEmpty(targetInfo.name)) {
2088+
error = "'" + base + "' accessor suppressed in '" + splitPath[i - 1] + "'";
2089+
}
2090+
else {
2091+
error = null;
2092+
}
2093+
if (error != null) {
20672094
if (intf) { // warn only once
2068-
addWarning(startRule.getProject(), "incorrect item '" + pathElement + "' in '" + startRule.getName() + "' method " +
2069-
methodInfo.name + "=\"" + methodInfo.path + "\"");
2095+
addWarning(startRule.getProject(), "%s#%s(\"%s\"): %s", startRule.getName(), methodInfo.name, methodInfo.path, error);
20702096
}
2071-
return; // missing rule, unknown or wrong cardinality
2097+
return;
20722098
}
20732099

20742100
boolean many = targetInfo.cardinality.many();
@@ -2105,6 +2131,8 @@ private void generateUserPsiAccessors(BnfRule startRule, RuleMethodsHelper.Metho
21052131

21062132
// list item
21072133
if (index != null) {
2134+
if ("first".equals(index)) index = "0";
2135+
21082136
context += ".";
21092137
boolean isLast = index.equals("last");
21102138
if (isLast) index = context + "size() - 1";

src/org/intellij/grammar/generator/RuleMethodsHelper.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,20 @@ public void buildMaps(Collection<BnfRule> sortedPsiRules) {
6969
}
7070

7171
@NotNull
72-
public Collection<MethodInfo> getFor(BnfRule rule) {
72+
public Collection<MethodInfo> getFor(@NotNull BnfRule rule) {
7373
return myMethods.get(rule).second;
7474
}
7575

7676
@Nullable
77-
public MethodInfo getMethodInfo(BnfRule rule, String name) {
77+
public MethodInfo getMethodInfo(@NotNull BnfRule rule, String name) {
7878
return myMethods.get(rule).first.get(name);
7979
}
8080

81+
@Nullable
82+
public Collection<String> getMethodNames(@NotNull BnfRule rule) {
83+
return myMethods.get(rule).first.keySet();
84+
}
85+
8186
protected void calcMethods(BnfRule rule, Map<String, String> tokensReversed) {
8287
List<MethodInfo> result = new ArrayList<>();
8388

testData/generator/PsiAccessors.PSI.expected.java

+73
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ public interface XBinary extends XComposite {
8787
@Nullable
8888
XValue getBadIndex();
8989

90+
}
91+
// ---- XEmpty.java -----------------
92+
//header.txt
93+
package generated.psi;
94+
95+
import java.util.List;
96+
import org.jetbrains.annotations.*;
97+
import com.intellij.psi.PsiElement;
98+
99+
public interface XEmpty extends XComposite {
100+
90101
}
91102
// ---- XExpression.java -----------------
92103
//header.txt
@@ -136,6 +147,21 @@ public interface XRenameList extends XComposite {
136147
@Nullable
137148
XSomeChild getLast();
138149

150+
}
151+
// ---- XReportSomeBad.java -----------------
152+
//header.txt
153+
package generated.psi;
154+
155+
import java.util.List;
156+
import org.jetbrains.annotations.*;
157+
import com.intellij.psi.PsiElement;
158+
import generated.psi.child.XSomeChild;
159+
160+
public interface XReportSomeBad extends XComposite {
161+
162+
@NotNull
163+
XReportSomeBad getReportSomeBad();
164+
139165
}
140166
// ---- XSomeChild.java -----------------
141167
//header.txt
@@ -356,6 +382,26 @@ public XValue getBadIndex() {
356382
return p3.size() - 1 < wrong_turn ? null : p3.get(wrong_turn);
357383
}
358384

385+
}
386+
// ---- XEmptyImpl.java -----------------
387+
//header.txt
388+
package generated.psi.impl;
389+
390+
import java.util.List;
391+
import org.jetbrains.annotations.*;
392+
import com.intellij.lang.ASTNode;
393+
import com.intellij.psi.PsiElement;
394+
import com.intellij.psi.util.PsiTreeUtil;
395+
import static generated.GeneratedTypes.*;
396+
import com.intellij.extapi.psi.ASTWrapperPsiElement;
397+
import generated.psi.*;
398+
399+
public class XEmptyImpl extends ASTWrapperPsiElement implements XEmpty {
400+
401+
public XEmptyImpl(@NotNull ASTNode node) {
402+
super(node);
403+
}
404+
359405
}
360406
// ---- XExpressionImpl.java -----------------
361407
//header.txt
@@ -452,6 +498,33 @@ public XSomeChild getLast() {
452498
return p1.isEmpty()? null : p1.get(p1.size() - 1);
453499
}
454500

501+
}
502+
// ---- XReportSomeBadImpl.java -----------------
503+
//header.txt
504+
package generated.psi.impl;
505+
506+
import java.util.List;
507+
import org.jetbrains.annotations.*;
508+
import com.intellij.lang.ASTNode;
509+
import com.intellij.psi.PsiElement;
510+
import com.intellij.psi.util.PsiTreeUtil;
511+
import static generated.GeneratedTypes.*;
512+
import com.intellij.extapi.psi.ASTWrapperPsiElement;
513+
import generated.psi.*;
514+
import generated.psi.child.XSomeChild;
515+
516+
public class XReportSomeBadImpl extends ASTWrapperPsiElement implements XReportSomeBad {
517+
518+
public XReportSomeBadImpl(@NotNull ASTNode node) {
519+
super(node);
520+
}
521+
522+
@Override
523+
@NotNull
524+
public XReportSomeBad getReportSomeBad() {
525+
return findNotNullChildByClass(XReportSomeBad.class);
526+
}
527+
455528
}
456529
// ---- XSomeChildImpl.java -----------------
457530
//header.txt

testData/generator/PsiAccessors.bnf

+16
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ operator ::= '+' | '-'
4141

4242
expression ::= value '*' value
4343
value ::= id
44+
fake empty ::=
4445

4546
fake token-defaults ::= UPCASEKWD1 lowcasekwd1 UPCASEKWD2 lowcasekwd2 nodef
4647
fake some-root ::= some-child value {
@@ -72,3 +73,18 @@ fake rename-list ::= some-child * {
7273
last="some-child[last]"
7374
]
7475
}
76+
77+
fake report_some_bad ::= report_some_bad empty some-child * {
78+
methods=[
79+
some-child=""
80+
empty=""
81+
82+
bad0="some-child[0]zzz/"
83+
bad1="some-child[0]/missing-child"
84+
bad2="empty/missing-child"
85+
bad3="some-child/MY_SOMETHING"
86+
bad4="some-child[first]/MY_SOMETHING/BAD"
87+
bad5="report_some_bad[0]/some-child"
88+
bad6="report_some_bad/some-child"
89+
]
90+
}

0 commit comments

Comments
 (0)