use of com.oracle.truffle.dsl.processor.java.ElementUtils.getSimpleName in project graal by oracle.
the class NodeParser method initializeFallbackReachability.
private static void initializeFallbackReachability(NodeData node) {
TruffleTypes types = ProcessorContext.getInstance().getTypes();
List<SpecializationData> specializations = node.getSpecializations();
SpecializationData fallback = null;
for (int i = specializations.size() - 1; i >= 0; i--) {
SpecializationData specialization = specializations.get(i);
if (specialization.isFallback() && specialization.getMethod() != null) {
fallback = specialization;
break;
}
}
if (fallback == null) {
// no need to compute reachability
return;
}
for (int index = 0; index < specializations.size(); index++) {
SpecializationData specialization = specializations.get(index);
SpecializationData lastReachable = specialization;
for (int searchIndex = index + 1; searchIndex < specializations.size(); searchIndex++) {
SpecializationData search = specializations.get(searchIndex);
if (search == fallback) {
// reached the end of the specialization
break;
}
assert lastReachable != search;
if (!lastReachable.isReachableAfter(search)) {
lastReachable = search;
} else if (search.getReplaces().contains(specialization)) {
lastReachable = search;
}
}
specialization.setReachesFallback(lastReachable == specialization);
List<SpecializationData> failedSpecializations = null;
if (specialization.isReachesFallback() && !specialization.getCaches().isEmpty() && !specialization.getGuards().isEmpty()) {
boolean failed = false;
if (specialization.getMaximumNumberOfInstances() > 1) {
for (GuardExpression guard : specialization.getGuards()) {
if (specialization.isGuardBoundWithCache(guard)) {
failed = true;
break;
}
}
}
for (CacheExpression cache : specialization.getCaches()) {
if (cache.isWeakReferenceGet()) {
failed = true;
break;
}
}
if (failed) {
if (failedSpecializations == null) {
failedSpecializations = new ArrayList<>();
}
failedSpecializations.add(specialization);
}
}
if (failedSpecializations != null) {
List<String> specializationIds = failedSpecializations.stream().map((e) -> e.getId()).collect(Collectors.toList());
fallback.addError("Some guards for the following specializations could not be negated for the @%s specialization: %s. " + "Guards cannot be negated for the @%s when they bind @%s parameters and the specialization may consist of multiple instances or if any of the @%s parameters is configured as weak. " + "To fix this limit the number of instances to '1' or " + "introduce a more generic specialization declared between this specialization and the fallback. " + "Alternatively the use of @%s can be avoided by declaring a @%s with manually specified negated guards.", ElementUtils.getSimpleName(types.Fallback), specializationIds, ElementUtils.getSimpleName(types.Fallback), ElementUtils.getSimpleName(types.Cached), ElementUtils.getSimpleName(types.Cached), ElementUtils.getSimpleName(types.Fallback), ElementUtils.getSimpleName(types.Specialization));
}
}
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.getSimpleName in project graal by oracle.
the class ExportsParser method parse.
@Override
protected ExportsData parse(Element element, List<AnnotationMirror> elementMirrors) {
TypeElement type = (TypeElement) element;
ExportsData model = parseExports(type, elementMirrors);
if (model.hasErrors()) {
return model;
}
// set of types that contribute members
Set<TypeElement> declaringTypes = new HashSet<>();
Set<TypeElement> declaringInTemplateTypes = new HashSet<>();
declaringInTemplateTypes.add(type);
for (ExportsLibrary library : model.getExportedLibraries().values()) {
declaringTypes.addAll(library.getDeclaringTypes());
if (library.isDeclaredInTemplate()) {
declaringInTemplateTypes.addAll(library.getDeclaringTypes());
}
}
Element packageElement = ElementUtils.findPackageElement(type);
for (TypeElement currentType : declaringInTemplateTypes) {
if (ElementUtils.elementEquals(currentType, element)) {
// current type always visible
continue;
}
List<Element> foundInvisibleMembers = new ArrayList<>();
List<? extends Element> superTypeMembers = loadMembers(null, currentType);
for (Element superTypeMember : superTypeMembers) {
List<AnnotationMirror> exportedMessages = getRepeatedAnnotation(superTypeMember.getAnnotationMirrors(), types.ExportMessage);
if (!exportedMessages.isEmpty()) {
if (!ElementUtils.isVisible(packageElement, superTypeMember)) {
foundInvisibleMembers.add(superTypeMember);
} else if (superTypeMember.getKind().isClass()) {
for (Element specializationMember : loadMembers(null, (TypeElement) superTypeMember)) {
if (ElementUtils.findAnnotationMirror(specializationMember, types.Specialization) != null && !ElementUtils.isVisible(packageElement, specializationMember)) {
foundInvisibleMembers.add(specializationMember);
}
}
}
}
}
if (!foundInvisibleMembers.isEmpty()) {
StringBuilder b = new StringBuilder();
for (Element invisibleMember : foundInvisibleMembers) {
b.append(System.lineSeparator()).append(" - ");
b.append(ElementUtils.getReadableReference(element, invisibleMember));
}
model.addError("Found invisible exported elements in super type '%s': %s%nIncrease their visibility to resolve this problem.", ElementUtils.getSimpleName(currentType), b.toString());
}
}
if (model.getExportedLibraries().isEmpty()) {
for (Element member : loadMembers(null, type)) {
List<AnnotationMirror> exportedMessageMirrors = getRepeatedAnnotation(member.getAnnotationMirrors(), types.ExportMessage);
if (!exportedMessageMirrors.isEmpty()) {
model.addError(//
"Class declares @%s annotations but does not export any libraries. " + //
"Exported messages cannot be resoved without exported library. " + "Add @%s(MyLibrary.class) to the class ot resolve this.", getSimpleName(types.ExportMessage), getSimpleName(types.ExportLibrary));
return model;
}
}
}
List<? extends Element> members = loadMembers(declaringInTemplateTypes, type);
/*
* First pass: element creation
*/
Map<String, List<Element>> potentiallyMissedOverrides = new LinkedHashMap<>();
List<ExportMessageData> exportedElements = new ArrayList<>();
for (Element member : members) {
List<AnnotationMirror> exportedMessageMirrors = getRepeatedAnnotation(member.getAnnotationMirrors(), types.ExportMessage);
if (exportedMessageMirrors.isEmpty()) {
boolean isMethod = isMethodElement(member);
boolean isNode = isNodeElement(member);
String name = null;
if (isMethod) {
name = member.getSimpleName().toString();
} else if (isNode) {
name = inferNodeMessageName((TypeElement) member);
}
if (isMethod || isNode) {
Element enclosingType = member.getEnclosingElement();
if (elementEquals(model.getTemplateType(), enclosingType)) {
potentiallyMissedOverrides.computeIfAbsent(name, (n) -> new ArrayList<>()).add(member);
}
}
} else {
for (AnnotationMirror exportMessage : exportedMessageMirrors) {
exportedElements.addAll(parseExportedMessage(model, member, exportMessage));
}
}
}
for (ExportMessageData exportedMessage : exportedElements) {
Element member = exportedMessage.getMessageElement();
String messageName = exportedMessage.getResolvedMessage().getName();
Map<String, ExportMessageData> exportedMessages = exportedMessage.getExportsLibrary().getExportedMessages();
ExportMessageData existing = exportedMessages.get(messageName);
if (existing != null) {
Element existingEnclosingElement = existing.getMessageElement().getEnclosingElement();
Element currentEnclosingElement = exportedMessage.getMessageElement().getEnclosingElement();
if (ElementUtils.elementEquals(existingEnclosingElement, currentEnclosingElement)) {
String error = String.format("Duplicate exported library message %s.", messageName);
model.addError(member, error);
model.addError(existing.getMessageElement(), error);
} else if (ElementUtils.isSubtype(currentEnclosingElement.asType(), existingEnclosingElement.asType())) {
// new message is more concrete
exportedMessages.put(messageName, exportedMessage);
existing.setOverriden(true);
} else {
// keep existing exported message
exportedMessage.setOverriden(true);
}
} else {
exportedMessages.put(messageName, exportedMessage);
}
}
/*
* Generate synthetic exports for export delegation.
*/
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (!exportsLibrary.hasExportDelegation()) {
continue;
}
ExportMessageData accepts = exportsLibrary.getExportedMessages().get("accepts");
if (accepts == null) {
String delegateName = exportsLibrary.getDelegationVariable().getSimpleName().toString();
CodeAnnotationMirror annotation = new CodeAnnotationMirror(types.CachedLibrary);
annotation.setElementValue(ElementUtils.findExecutableElement(types.CachedLibrary, "value"), new CodeAnnotationValue("receiver_." + delegateName));
CodeExecutableElement executable = CodeExecutableElement.clone(ElementUtils.findMethod(types.Library, "accepts"));
executable.changeTypes(exportsLibrary.getReceiverType());
executable.renameArguments("receiver_");
executable.getModifiers().add(Modifier.STATIC);
CodeVariableElement var = new CodeVariableElement(exportsLibrary.getLibrary().getTemplateType().asType(), delegateName);
var.addAnnotationMirror(annotation);
executable.setEnclosingElement(exportsLibrary.getTemplateType());
executable.getParameters().add(var);
LibraryMessage message = null;
for (LibraryMessage libMessage : exportsLibrary.getLibrary().getMethods()) {
if (libMessage.getName().equals("accepts")) {
message = libMessage;
break;
}
}
accepts = new ExportMessageData(exportsLibrary, message, executable, annotation);
exportsLibrary.getExportedMessages().put("accepts", accepts);
exportedElements.add(accepts);
} else {
accepts.addError("Exporting a custom accepts method is currently not supported when export delegation is used in @%s. " + "Remove delegateTo from all exports or remove the accepts export to resolve this.", getSimpleName(types.ExportLibrary));
}
}
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (!exportsLibrary.isDeclaredInTemplate()) {
for (ExportMessageData message : exportsLibrary.getExportedMessages().values()) {
if (elementEquals(message.getMessageElement().getEnclosingElement(), type)) {
message.addError(//
"The @%s declaration is missing for this exported message. " + "Add @%s(%s.class) to the enclosing class %s to resolve this.", getSimpleName(types.ExportLibrary), getSimpleName(types.ExportLibrary), getSimpleName(exportsLibrary.getLibrary().getTemplateType()), getSimpleName(type));
}
}
}
}
// avoid removal of elements if errors occured.
if (model.hasErrors()) {
return model;
}
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (exportsLibrary.isBuiltinDefaultExport()) {
// we don't print unused warnings for builtin defaults.
continue;
}
if (exportsLibrary.isDeclaredInTemplate()) {
boolean foundDeclared = false;
for (ExportMessageData message : exportsLibrary.getExportedMessages().values()) {
if (message.isDeclared()) {
foundDeclared = true;
break;
}
}
if (!foundDeclared) {
exportsLibrary.addWarning("Exported library %s does not export any messages and therefore has no effect. Remove the export declaration to resolve this.", getSimpleName(exportsLibrary.getLibrary().getTemplateType()));
}
}
}
// avoid removal of elements if errors occured.
if (model.hasErrors()) {
return model;
}
/*
* filter elements that come from exports not relevant for this class. Remove all export
* declarations not relevant for this type.
*/
Predicate<? super ExportsLibrary> filterpredicate = (library -> {
if (library.isDynamicDispatchTarget()) {
// Implicitly export super's library if dynamic dispatched.
return true;
}
return library.isDeclaredInTemplate();
});
Set<ExportsLibrary> declaredExports = model.getExportedLibraries().values().stream().filter(filterpredicate).collect(Collectors.toSet());
model.getExportedLibraries().values().removeIf((e) -> !declaredExports.contains(e));
exportedElements = exportedElements.stream().filter((e) -> declaredExports.contains(e.getExportsLibrary())).collect(Collectors.toList());
/*
* Third pass: initialize and further parsing that need both method and node to be
* available.
*/
for (ExportsLibrary exportsLibrary : declaredExports) {
// recreate cache for every exports library to not confuse exports configuration
Map<String, NodeData> parsedNodeCache = new HashMap<>();
for (ExportMessageData exportedElement : exportsLibrary.getExportedMessages().values()) {
if (exportedElement.isOverriden()) {
// gets confused.
continue;
}
Element member = exportedElement.getMessageElement();
if (isMethodElement(member)) {
initializeExportedMethod(parsedNodeCache, model, exportedElement);
} else if (isNodeElement(member)) {
initializeExportedNode(parsedNodeCache, exportedElement);
} else {
throw new AssertionError("should not be reachable");
}
}
}
TypeMirror receiverClass = null;
for (Entry<String, ExportsLibrary> entry : model.getExportedLibraries().entrySet()) {
ExportsLibrary exportLib = entry.getValue();
if (exportLib.hasErrors()) {
continue;
}
if (receiverClass == null) {
receiverClass = exportLib.getReceiverType();
} else if (!typeEquals(exportLib.getReceiverType(), receiverClass)) {
exportLib.addError("All receiver classes must match for a declared java type. Found '%s' and '%s'.", getSimpleName(receiverClass), getSimpleName(exportLib.getReceiverType()));
continue;
}
Set<LibraryMessage> missingAbstractMessage = new LinkedHashSet<>();
for (LibraryMessage message : exportLib.getLibrary().getMethods()) {
List<Element> elementsWithSameName = potentiallyMissedOverrides.getOrDefault(message.getName(), Collections.emptyList());
if (!elementsWithSameName.isEmpty()) {
for (Element overridingElement : elementsWithSameName) {
if (ElementUtils.findAnnotationMirror(overridingElement, types.ExportMessage_Ignore) == null) {
exportLib.addError(overridingElement, "The method has the same name '%s' as a message in the exported library %s. Did you forget to export it? " + "Use @%s to export the message, @%s to ignore this warning, rename the method or reduce the visibility of the method to private to resolve this warning.", overridingElement.getSimpleName().toString(), getSimpleName(exportLib.getLibrary().getTemplateType()), types.ExportMessage.asElement().getSimpleName().toString(), types.ExportMessage_Ignore.asElement().getSimpleName().toString());
}
}
}
if (message.isAbstract() && !message.getName().equals("accepts")) {
ExportMessageData exportMessage = exportLib.getExportedMessages().get(message.getName());
if (exportMessage == null || exportMessage.getResolvedMessage() != message) {
boolean isAbstract;
if (!message.getAbstractIfExported().isEmpty()) {
isAbstract = false;
for (LibraryMessage abstractIfExported : message.getAbstractIfExported()) {
if (exportLib.getExportedMessages().containsKey(abstractIfExported.getName())) {
isAbstract = true;
break;
}
}
} else {
isAbstract = !exportLib.hasExportDelegation();
}
if (isAbstract) {
missingAbstractMessage.add(message);
}
}
}
}
if (!missingAbstractMessage.isEmpty()) {
StringBuilder msg = new StringBuilder(String.format("The following message(s) of library %s are abstract and must be exported using:%n", getSimpleName(exportLib.getLibrary().getTemplateType())));
for (LibraryMessage message : missingAbstractMessage) {
msg.append(" ").append(generateExpectedSignature(type, message, exportLib.getExplicitReceiver())).append(" {");
if (!ElementUtils.isVoid(message.getExecutable().getReturnType())) {
msg.append(" return ").append(ElementUtils.defaultValue(message.getExecutable().getReturnType()));
msg.append(";");
}
msg.append(" }%n");
}
exportLib.addError(msg.toString());
}
}
for (ExportsLibrary libraryExports : model.getExportedLibraries().values()) {
List<NodeData> cachedSharedNodes = new ArrayList<>();
List<ExportMessageData> exportedMessages = new ArrayList<>();
for (ExportMessageData export : libraryExports.getExportedMessages().values()) {
if (export.getSpecializedNode() != null) {
cachedSharedNodes.add(export.getSpecializedNode());
exportedMessages.add(export);
}
}
libraryExports.setSharedExpressions(NodeParser.computeSharing(libraryExports.getTemplateType(), cachedSharedNodes, true));
// JDT will otherwise just ignore those messages and not display anything.
for (int i = 0; i < cachedSharedNodes.size(); i++) {
NodeData nodeData = cachedSharedNodes.get(i);
ExportMessageData exportedMessage = exportedMessages.get(i);
if (nodeData.hasErrorsOrWarnings()) {
nodeData.redirectMessagesOnGeneratedElements(exportedMessage);
}
nodeData.setGenerateUncached(false);
}
}
for (ExportMessageData message : exportedElements) {
if (!elementEquals(message.getMessageElement().getEnclosingElement(), model.getTemplateType())) {
message.redirectMessages(message.getExportsLibrary());
}
}
if (isGenerateSlowPathOnly(type)) {
for (ExportsLibrary libraryExports : model.getExportedLibraries().values()) {
for (ExportMessageData export : libraryExports.getExportedMessages().values()) {
if (export.isClass() && export.getSpecializedNode() != null) {
NodeParser.removeFastPathSpecializations(export.getSpecializedNode());
}
}
}
}
return model;
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.getSimpleName in project graal by oracle.
the class ExportsParser method parseExports.
private ExportsData parseExports(TypeElement type, List<AnnotationMirror> elementMirrors) {
ExportsData model = new ExportsData(context, type, null);
if (type.getKind().isInterface()) {
model.addError("@%s is not supported for interfaces at the moment.", types.ExportLibrary.asElement().getSimpleName().toString());
return model;
}
if (ElementUtils.getVisibility(type.getModifiers()) == Modifier.PRIVATE) {
model.addError("The exported type must not be private. " + "Increase visibility to resolve this.");
return model;
}
Map<AnnotationMirror, TypeElement> mirrors = new LinkedHashMap<>();
for (AnnotationMirror annotationMirror : elementMirrors) {
mirrors.put(annotationMirror, type);
}
TypeElement superType = type;
while ((superType = getSuperType(superType)) != null) {
for (AnnotationMirror mirror : getRepeatedAnnotation(superType.getAnnotationMirrors(), types.ExportLibrary)) {
mirrors.put(mirror, superType);
}
}
Map<String, List<AnnotationMirror>> mappedMirrors = new LinkedHashMap<>();
for (AnnotationMirror mirror : mirrors.keySet()) {
TypeMirror library = getAnnotationValue(TypeMirror.class, mirror, "value");
mappedMirrors.computeIfAbsent(getTypeId(library), (id) -> new ArrayList<>()).add(mirror);
}
for (Entry<String, List<AnnotationMirror>> entry : mappedMirrors.entrySet()) {
String libraryId = entry.getKey();
List<AnnotationMirror> annotationMirrors = entry.getValue();
AnnotationMirror annotationMirror = annotationMirrors.get(0);
TypeMirror libraryMirror = getAnnotationValue(TypeMirror.class, annotationMirror, "value");
AnnotationValue receiverClassValue = getAnnotationValue(annotationMirror, "receiverType");
boolean explicitReceiver;
TypeMirror receiverClass = getAnnotationValue(TypeMirror.class, annotationMirror, "receiverType", false);
if (receiverClass == null) {
explicitReceiver = false;
receiverClass = type.asType();
} else {
explicitReceiver = true;
}
Map<TypeElement, LibraryData> libraryCache = ProcessorContext.getInstance().getCacheMap(LibraryParser.class);
LibraryData libraryData = libraryCache.computeIfAbsent(fromTypeMirror(libraryMirror), (t) -> new LibraryParser().parse(t));
ExportsLibrary lib = new ExportsLibrary(context, type, annotationMirror, model, libraryData, receiverClass, explicitReceiver);
ExportsLibrary otherLib = model.getExportedLibraries().get(libraryId);
for (AnnotationMirror mirror : annotationMirrors) {
lib.getDeclaringTypes().add(mirrors.get(mirror));
}
model.getExportedLibraries().put(libraryId, lib);
Integer priority = getAnnotationValue(Integer.class, annotationMirror, "priority", false);
if (priority == null && lib.needsDefaultExportProvider()) {
lib.addError(//
"The priority property must be set for default exports based on service providers. " + "See @%s(priority=...) for details.", getSimpleName(types.ExportLibrary));
continue;
} else if (priority != null) {
int prio = priority;
AnnotationValue annotationValue = getAnnotationValue(annotationMirror, "priority");
if (prio < 0) {
LibraryDefaultExportData builtinDefaultExport = libraryData.getBuiltinDefaultExport(receiverClass);
if (builtinDefaultExport != null) {
lib.addError(annotationValue, //
"The provided export receiver type '%s' is not reachable with the given priority. " + //
"The '%s' library specifies @%s(%s) which has receiver type '%s' and that shadows this export. " + "Increase the priority to a positive integer to resolve this.", getSimpleName(receiverClass), getSimpleName(libraryData.getTemplateType()), getSimpleName(types.GenerateLibrary_DefaultExport), getSimpleName(builtinDefaultExport.getImplType()), getSimpleName(builtinDefaultExport.getReceiverType()));
continue;
}
}
if (prio == 0) {
lib.addError(annotationValue, "The set priority must be either positive or negative, but must not be 0.");
continue;
}
lib.setDefaultExportPriority(priority);
}
if (ElementUtils.isPrimitive(receiverClass)) {
lib.addError(annotationMirror, receiverClassValue, "Primitive receiver types are not supported yet.");
continue;
}
if (libraryData == null) {
lib.addError("Class '%s' is not a library annotated with @%s.", getSimpleName(libraryMirror), types.GenerateLibrary.asElement().getSimpleName().toString());
continue;
} else if (libraryData.hasErrors()) {
lib.addError("Library specification %s has errors. Please resolve them first.", getSimpleName(libraryMirror));
continue;
}
if (otherLib != null) {
String message = String.format("Duplicate library specified %s.", getSimpleName(libraryMirror));
otherLib.addError(message);
lib.addError(message);
continue;
}
lib.setUseForAOT(ElementUtils.getAnnotationValue(Boolean.class, annotationMirror, "useForAOT"));
if (libraryData.isGenerateAOT()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
if (useForAOT == null) {
lib.addError(annotationMirror, useForAOT, //
"The useForAOT property needs to be declared for exports of libraries annotated with @%s. " + "Declare the useForAOT property to resolve this problem.", getSimpleName(types.GenerateAOT));
}
Integer useForAOTPriority = getAnnotationValue(Integer.class, annotationMirror, "useForAOTPriority", false);
if (useForAOTPriority == null && lib.isUseForAOT()) {
lib.addError(//
"The useForAOTPriority property must also be set for libraries used for AOT. " + "See @%s(useForAOTPriority=...) for details.", getSimpleName(types.ExportLibrary));
continue;
} else if (useForAOTPriority != null) {
lib.setUseForAOTPriority(useForAOTPriority);
}
}
if (lib.isUseForAOT() && !lib.isFinalReceiver()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, //
"If useForAOT is set to true the receiver type must be a final. " + //
"The compiled code would otherwise cause performance warnings. " + "Add the final modifier to the receiver class or set useForAOT to false to resolve this.");
} else if (lib.isUseForAOT() && lib.isDynamicDispatchTarget()) {
AnnotationMirror dynamicDispatchExportMirror = lib.getReceiverDynamicDispatchExport();
if (dynamicDispatchExportMirror == null) {
throw new AssertionError("Should not reach here. isDynamicDispatchTarget should not return true");
}
if (!ElementUtils.getAnnotationValue(Boolean.class, dynamicDispatchExportMirror, "useForAOT")) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, "The dynamic dispatch target must set useForAOT to true also for the DynamicDispatch export of the receiver type %s. ", getSimpleName(lib.getReceiverType()));
}
}
if (lib.isUseForAOT() && !libraryData.isGenerateAOT() && !libraryData.isDynamicDispatch()) {
AnnotationValue useForAOT = getAnnotationValue(annotationMirror, "useForAOT", false);
lib.addError(annotationMirror, useForAOT, "The exported library does not support AOT. Add the @%s annotation to the library class %s to resolve this.", getSimpleName(types.GenerateAOT), getQualifiedName(libraryData.getTemplateType()));
}
if (explicitReceiver) {
TypeMirror receiverTypeErasure = context.getEnvironment().getTypeUtils().erasure(libraryData.getSignatureReceiverType());
if (!isSubtype(receiverClass, receiverTypeErasure)) {
lib.addError(annotationMirror, receiverClassValue, "The export receiver type %s is not compatible with the library receiver type '%s' of library '%s'. ", getSimpleName(receiverClass), getSimpleName(libraryData.getSignatureReceiverType()), getSimpleName(libraryData.getTemplateType().asType()));
}
} else {
if (!isSubtype(type.asType(), libraryData.getExportsReceiverType())) {
lib.addError("Type %s is not compatible with the receiver type '%s' of exported library '%s'. " + "Inhert from type '%s' to resolve this.", getSimpleName(type.asType()), getSimpleName(libraryData.getExportsReceiverType()), getSimpleName(libraryData.getTemplateType().asType()), getSimpleName(libraryData.getExportsReceiverType()));
}
}
String transitionLimit = ElementUtils.getAnnotationValue(String.class, annotationMirror, "transitionLimit", false);
if (transitionLimit != null) {
DSLExpressionResolver resolver = new DSLExpressionResolver(context, model.getTemplateType(), NodeParser.importVisibleStaticMembers(model.getTemplateType(), model.getTemplateType(), false));
try {
DSLExpression expression = DSLExpression.parse(transitionLimit);
expression.accept(resolver);
lib.setTransitionLimit(expression);
} catch (InvalidExpressionException e) {
AnnotationValue allowTransition = ElementUtils.getAnnotationValue(annotationMirror, "transitionLimit");
model.addError(annotationMirror, allowTransition, "Error parsing expression '%s': %s", transitionLimit, e.getMessage());
}
}
String delegateTo = ElementUtils.getAnnotationValue(String.class, annotationMirror, "delegateTo", false);
if (delegateTo != null) {
AnnotationValue delegateToValue = ElementUtils.getAnnotationValue(annotationMirror, "delegateTo");
if (receiverClass.getKind() != TypeKind.DECLARED) {
lib.addError(delegateToValue, "The receiver type must be declared type for delegation.");
continue;
}
VariableElement delegateVar = ElementUtils.findVariableElement((DeclaredType) receiverClass, delegateTo);
if (delegateVar == null) {
lib.addError(delegateToValue, "The delegation variable with name '%s' could not be found in type '%s'. " + "Declare a field 'final Object %s' in '%s' to resolve this problem.", delegateTo, ElementUtils.getSimpleName(receiverClass), delegateTo, ElementUtils.getSimpleName(receiverClass));
continue;
}
if (!delegateVar.getModifiers().contains(Modifier.FINAL)) {
lib.addError(delegateToValue, "The delegation variable with name '%s' in type '%s' must be have the modifier final. " + "Make the variable final to resolve the problem.", delegateTo, ElementUtils.getSimpleName(receiverClass));
continue;
}
Element packageElement = ElementUtils.findPackageElement(lib.getTemplateType());
if (!ElementUtils.isVisible(packageElement, delegateVar)) {
lib.addError(delegateToValue, "The delegation variable with name '%s' in type '%s' is not visible in package '%s'. " + "Increase the visibility to resolve this problem.", delegateTo, ElementUtils.getSimpleName(receiverClass), ElementUtils.getPackageName(packageElement));
continue;
}
TypeMirror delegateType = delegateVar.asType();
TypeMirror exportsReceiverType = lib.getLibrary().getSignatureReceiverType();
if (!ElementUtils.isAssignable(delegateType, exportsReceiverType)) {
lib.addError(delegateToValue, "The type of export delegation field '%s' is not assignable to the expected type '%s'. " + "Change the field type to '%s' to resolve this.", ElementUtils.getSimpleName(receiverClass) + "." + delegateTo, ElementUtils.getSimpleName(exportsReceiverType), ElementUtils.getSimpleName(exportsReceiverType));
continue;
}
lib.setDelegationVariable(delegateVar);
}
for (LibraryMessage message : libraryData.getMethods()) {
model.getLibraryMessages().computeIfAbsent(message.getName(), (n) -> new ArrayList<>()).add(message);
}
}
// initialize dynamic dispatch
for (ExportsLibrary exportedLibrary : model.getExportedLibraries().values()) {
if (exportedLibrary.hasErrors()) {
continue;
}
boolean explicitReceiver = exportedLibrary.isExplicitReceiver();
int dynamicDispatchEnabledCount = 0;
for (ExportsLibrary library : model.getExportedLibraries().values()) {
if (library.getLibrary().isDynamicDispatchEnabled()) {
dynamicDispatchEnabledCount++;
}
}
if (exportedLibrary.getLibrary().isDynamicDispatch() && dynamicDispatchEnabledCount > 0) {
exportedLibrary.addError("@%s cannot be used for other libraries if the %s library is exported. " + "Using dynamic dispatch and other libraries is mutually exclusive. " + "To resolve this use the dynamic dispatch mechanism of the receiver type instead to export libraries.", types.ExportLibrary.asElement().getSimpleName().toString(), types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
} else if (explicitReceiver && !exportedLibrary.getLibrary().isDefaultExportLookupEnabled() && !exportedLibrary.isDynamicDispatchTarget() && !exportedLibrary.isBuiltinDefaultExport()) {
String dynamicDispatchDisabled = "";
if (!exportedLibrary.getLibrary().isDynamicDispatchEnabled()) {
dynamicDispatchDisabled = String.format("Note that dynamic dispatch is disabled for the exported library '%s'.%n", ElementUtils.getSimpleName(exportedLibrary.getLibrary().getTemplateType()));
}
//
exportedLibrary.addError(//
exportedLibrary.getTemplateTypeAnnotation(), getAnnotationValue(exportedLibrary.getTemplateTypeAnnotation(), "receiverType"), "Using explicit receiver types is only supported for default exports or types that export %s.%n" + // dynamic dispatch disabled
"%s" + "To resolve this use one of the following strategies:%n" + " - Make the receiver type implicit by applying '@%s(%s.class)' to the receiver type '%s' instead.%n" + " - Declare a default export on the '%s' library with '@%s(%s.class)'%n" + " - Enable default exports with service providers using @%s(defaultExportLookupEnabled=true) on the library and specify an export priority%n" + " - Enable dynamic dispatch by annotating the receiver type with '@%s(%s.class)'.", types.DynamicDispatchLibrary.asElement().getSimpleName().toString(), dynamicDispatchDisabled, types.ExportLibrary.asElement().getSimpleName().toString(), exportedLibrary.getLibrary().getTemplateType().getSimpleName().toString(), ElementUtils.getSimpleName(exportedLibrary.getExplicitReceiver()), exportedLibrary.getLibrary().getTemplateType().getSimpleName().toString(), types.GenerateLibrary_DefaultExport.asElement().getSimpleName().toString(), ElementUtils.getSimpleName(exportedLibrary.getTemplateType().asType()), ElementUtils.getSimpleName(types.GenerateLibrary), types.ExportLibrary.asElement().getSimpleName().toString(), types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
} else {
if (explicitReceiver && !exportedLibrary.isBuiltinDefaultExport()) {
boolean foundInvalidExportsOnReceiver = false;
superType = ElementUtils.castTypeElement(exportedLibrary.getExplicitReceiver());
while (superType != null) {
List<AnnotationMirror> exports = getRepeatedAnnotation(superType.getAnnotationMirrors(), types.ExportLibrary);
for (AnnotationMirror export : exports) {
TypeMirror exportedLibraryType = getAnnotationValue(TypeMirror.class, export, "value");
if (!ElementUtils.typeEquals(exportedLibraryType, types.DynamicDispatchLibrary)) {
foundInvalidExportsOnReceiver = true;
break;
}
}
superType = getSuperType(superType);
}
if (foundInvalidExportsOnReceiver) {
AnnotationValue receiverClassValue = getAnnotationValue(exportedLibrary.getMessageAnnotation(), "receiverType");
exportedLibrary.addError(exportedLibrary.getMessageAnnotation(), receiverClassValue, "An export that is used for dynamic dispatch must not export any libraries other than %s with the receiver type.", types.DynamicDispatchLibrary.asElement().getSimpleName().toString());
continue;
}
}
}
}
return model;
}
Aggregations