in src/org/intellij/grammar/generator/ParserGenerator.java [1891:2031]
private void generateUserPsiAccessors(BnfRule startRule, RuleMethodsHelper.MethodInfo methodInfo, boolean intf, boolean mixedAST) {
StringBuilder sb = new StringBuilder();
BnfRule targetRule = startRule;
Cardinality cardinality = REQUIRED;
String context = "";
String[] splitPath = methodInfo.path.split("/");
int i = -1, count = 1;
boolean totalNullable = false;
for (Object m : resolveUserPsiPathMethods(startRule, splitPath)) {
String pathElement = splitPath[++i];
if (m instanceof String) continue;
boolean last = i == splitPath.length - 1;
int indexStart = pathElement.indexOf('[');
int indexEnd = indexStart > 0 ? pathElement.lastIndexOf(']') : -1;
String base = (indexStart > -1 ? pathElement.substring(0, indexStart) : pathElement).trim();
String index = indexEnd > -1 ? pathElement.substring(indexStart + 1, indexEnd).trim() : null;
RuleMethodsHelper.MethodInfo targetInfo = (RuleMethodsHelper.MethodInfo)m;
String error;
if (indexStart > 0 && (indexEnd == -1 || StringUtil.isNotEmpty(pathElement.substring(indexEnd + 1)))) {
error = "'<name>[<index>]' expected, got '" + pathElement + "'";
}
else if (targetInfo == null) {
Collection<String> available = targetRule == null ? null : myRulesMethodsHelper.getMethodNames(targetRule);
if (targetRule == null) {
error = "'" + base + "' not found in '" + splitPath[i - 1] + "' (not a rule)";
}
else if (available == null || available.isEmpty()) {
error = "'" + base + "' not found in '" + targetRule.getName() + "' (available: nothing)";
}
else {
error = "'" + base + "' not found in '" + targetRule.getName() + "' (available: " + String.join(", ", available) + ")";
}
}
else if (index != null && !targetInfo.cardinality.many()) {
error = "'[" + index + "]' unexpected after '" + base + getCardinalityText(targetInfo.cardinality) + "'";
}
else if (!last && index == null && targetInfo.cardinality.many()) {
error = "'[<index>]' required after '" + base + getCardinalityText(targetInfo.cardinality) + "'";
}
else if (i > 0 && StringUtil.isEmpty(targetInfo.name)) {
error = "'" + base + "' accessor suppressed in '" + splitPath[i - 1] + "'";
}
else {
error = null;
}
if (error != null) {
if (intf) { // warn only once
addWarning(format("%s#%s(\"%s\"): %s", startRule.getName(), methodInfo.name, methodInfo.path, error));
}
return;
}
boolean many = targetInfo.cardinality.many();
String className = shorten(targetInfo.rule == null ? C.PsiElementClass : getAccessorType(targetInfo.rule));
String type = (many ? shorten(CommonClassNames.JAVA_UTIL_LIST) + "<" : "") + className + (many ? "> " : " ");
String curId = N.psiLocal + (count++);
if (!context.isEmpty()) {
if (cardinality.optional()) {
sb.append("if (").append(context).append(" == null) return null;\n");
}
context += ".";
}
if (last && index == null) {
sb.append("return ");
}
else {
sb.append(type).append(curId).append(" = ");
}
String targetCall;
if (StringUtil.isNotEmpty(targetInfo.name)) {
targetCall = targetInfo.generateGetterName() + "()";
}
else {
targetCall = generatePsiAccessorImplCall(startRule, targetInfo, mixedAST);
}
sb.append(context).append(targetCall).append(";\n");
context = curId;
targetRule = targetInfo.rule; // next accessors
cardinality = targetInfo.cardinality;
totalNullable |= cardinality.optional();
// list item
if (index != null) {
if ("first".equals(index)) index = "0";
context += ".";
boolean isLast = index.equals("last");
if (isLast) index = context + "size() - 1";
curId = N.psiLocal + (count++);
if (last) {
sb.append("return ");
}
else {
sb.append(className).append(" ").append(curId).append(" = ");
}
if (cardinality != AT_LEAST_ONE || !index.equals("0")) { // range check
if (isLast) {
sb.append(context).append("isEmpty()? null : ");
}
else {
int val = StringUtil.parseInt(index, Integer.MAX_VALUE);
sb.append(context).append("size()").append(val == Integer.MAX_VALUE ? " - 1 < " + index : " < " + (val + 1))
.append(" ? null : ");
}
}
sb.append(context).append("get(").append(index).append(");\n");
context = curId;
cardinality = cardinality == AT_LEAST_ONE && index.equals("0") ? REQUIRED : OPTIONAL;
totalNullable |= cardinality.optional();
}
}
if (!intf) out(shorten(OVERRIDE_ANNO));
if (!cardinality.many() && cardinality == REQUIRED && !totalNullable) {
out(shorten(NOTNULL_ANNO));
}
else {
out(shorten(NULLABLE_ANNO));
}
boolean many = cardinality.many();
String s = targetRule == null ? C.PsiElementClass : getAccessorType(targetRule);
String className = shorten(s);
String getterName = getGetterName(methodInfo.name);
String tail = intf ? "();" : "() {";
out((intf ? "" : "public ") + (many ? shorten(CommonClassNames.JAVA_UTIL_LIST) + "<" : "") + className + (many ? "> " : " ") + getterName + tail);
if (!intf) {
out(sb.toString());
out("}");
}
newLine();
}