Source:
<code>protected void checkFile(@NotNull ErlangFile file, @NotNull ProblemsHolder problemsHolder) { for (ErlangBehaviour behaviour : file.getBehaviours()) { ErlangModuleRef behaviourRef = behaviour.getModuleRef(); ErlangFile behaviourModule = ErlangPsiImplUtil.resolveToFile(behaviourRef); if (behaviourModule == null) continue; List<ErlangCallbackSpec> undefinedCallbacks = ContainerUtil.newArrayList(); Map<String, ErlangCallbackSpec> callbackMap = behaviourModule.getCallbackMap(); for (ErlangCallbackSpec spec : callbackMap.values()) { <START> if (spec.isOptional()) continue; <END> String name = ErlangPsiImplUtil.getCallbackSpecName(spec); int arity = ErlangPsiImplUtil.getCallbackSpecArity(spec); ErlangFunction function = name != null ? file.getFunction(name, arity) : null; if (function == null || !function.isExported()) { undefinedCallbacks.add(spec); } } if (undefinedCallbacks.isEmpty()) continue; boolean multiple = undefinedCallbacks.size() != 1; StringBuilder builder = new StringBuilder(); builder.append("Undefined or non-exported callback function").append(multiple ? "s" : "").append(": "); for (ErlangCallbackSpec spec : undefinedCallbacks) { builder.append("'").append(ErlangPsiImplUtil.createFunctionPresentationFromCallbackSpec(spec)).append("', "); } String message = builder.substring(0, builder.length() - 2); registerProblem(problemsHolder, behaviourRef, message, new CreateAndExportFunctionsFix(undefinedCallbacks, file.getProject())); } }</code><technical_language>Optional callbacks attribute account for release 18.0 above</technical_language>

Target:
protected void checkFile(@NotNull ErlangFile file, @NotNull ProblemsHolder problemsHolder) { ErlangSdkRelease release = ErlangSdkType.getRelease(file); boolean supportOptionalCallbacks = release == null || !ErlangSdkRelease.V_18_0.isNewerThan(release); for (ErlangBehaviour behaviour : file.getBehaviours()) { ErlangModuleRef behaviourRef = behaviour.getModuleRef(); ErlangFile behaviourModule = ErlangPsiImplUtil.resolveToFile(behaviourRef); if (behaviourModule == null) continue; List<ErlangCallbackSpec> undefinedCallbacks = ContainerUtil.newArrayList(); Map<String, ErlangCallbackSpec> callbackMap = behaviourModule.getCallbackMap(); for (ErlangCallbackSpec spec : callbackMap.values()) { if (supportOptionalCallbacks && spec.isOptional()) continue; String name = ErlangPsiImplUtil.getCallbackSpecName(spec); int arity = ErlangPsiImplUtil.getCallbackSpecArity(spec); ErlangFunction function = name != null ? file.getFunction(name, arity) : null; if (function == null || !function.isExported()) { undefinedCallbacks.add(spec); } } if (undefinedCallbacks.isEmpty()) continue; boolean multiple = undefinedCallbacks.size() != 1; StringBuilder builder = new StringBuilder(); builder.append("Undefined or non-exported callback function").append(multiple ? "s" : "").append(": "); for (ErlangCallbackSpec spec : undefinedCallbacks) { builder.append("'").append(ErlangPsiImplUtil.createFunctionPresentationFromCallbackSpec(spec)).append("', "); } String message = builder.substring(0, builder.length() - 2); registerProblem(problemsHolder, behaviourRef, message, new CreateAndExportFunctionsFix(undefinedCallbacks, file.getProject())); } }