Search in sources :

Example 1 with ElementUtils.isSubtype

use of com.oracle.truffle.dsl.processor.java.ElementUtils.isSubtype 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;
}
Also used : Arrays(java.util.Arrays) Modifier(javax.lang.model.element.Modifier) TypeElement(javax.lang.model.element.TypeElement) ElementUtils.getRepeatedAnnotation(com.oracle.truffle.dsl.processor.java.ElementUtils.getRepeatedAnnotation) ElementUtils.getSimpleName(com.oracle.truffle.dsl.processor.java.ElementUtils.getSimpleName) ElementUtils.getQualifiedName(com.oracle.truffle.dsl.processor.java.ElementUtils.getQualifiedName) Map(java.util.Map) ElementUtils.getTypeId(com.oracle.truffle.dsl.processor.java.ElementUtils.getTypeId) CodeVariableElement(com.oracle.truffle.dsl.processor.java.model.CodeVariableElement) ElementUtils.firstLetterUpperCase(com.oracle.truffle.dsl.processor.java.ElementUtils.firstLetterUpperCase) NodeData(com.oracle.truffle.dsl.processor.model.NodeData) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) ElementUtils.getSuperType(com.oracle.truffle.dsl.processor.java.ElementUtils.getSuperType) CodeTypeElement(com.oracle.truffle.dsl.processor.java.model.CodeTypeElement) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) Element(javax.lang.model.element.Element) Collectors(java.util.stream.Collectors) TypeKind(javax.lang.model.type.TypeKind) List(java.util.List) Entry(java.util.Map.Entry) ElementUtils.isAssignable(com.oracle.truffle.dsl.processor.java.ElementUtils.isAssignable) AnnotationValue(javax.lang.model.element.AnnotationValue) DSLExpression(com.oracle.truffle.dsl.processor.expression.DSLExpression) NodeParser(com.oracle.truffle.dsl.processor.parser.NodeParser) VariableElement(javax.lang.model.element.VariableElement) HashMap(java.util.HashMap) ElementUtils.fromTypeMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashMap(java.util.LinkedHashMap) ElementUtils.findAnnotationMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror) CompilerFactory(com.oracle.truffle.dsl.processor.java.compiler.CompilerFactory) ElementUtils.isSubtype(com.oracle.truffle.dsl.processor.java.ElementUtils.isSubtype) ElementUtils.typeEquals(com.oracle.truffle.dsl.processor.java.ElementUtils.typeEquals) DeclaredType(javax.lang.model.type.DeclaredType) InvalidExpressionException(com.oracle.truffle.dsl.processor.expression.InvalidExpressionException) ElementUtils.getAnnotationValue(com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue) GeneratorUtils(com.oracle.truffle.dsl.processor.generator.GeneratorUtils) ElementFilter(javax.lang.model.util.ElementFilter) LinkedHashSet(java.util.LinkedHashSet) ElementUtils(com.oracle.truffle.dsl.processor.java.ElementUtils) AbstractParser(com.oracle.truffle.dsl.processor.parser.AbstractParser) CodeAnnotationMirror(com.oracle.truffle.dsl.processor.java.model.CodeAnnotationMirror) Iterator(java.util.Iterator) ElementKind(javax.lang.model.element.ElementKind) ElementUtils.elementEquals(com.oracle.truffle.dsl.processor.java.ElementUtils.elementEquals) PUBLIC(javax.lang.model.element.Modifier.PUBLIC) ExecutableElement(javax.lang.model.element.ExecutableElement) ProcessorContext(com.oracle.truffle.dsl.processor.ProcessorContext) CodeAnnotationValue(com.oracle.truffle.dsl.processor.java.model.CodeAnnotationValue) AnnotationMirror(javax.lang.model.element.AnnotationMirror) CodeNames(com.oracle.truffle.dsl.processor.java.model.CodeNames) STATIC(javax.lang.model.element.Modifier.STATIC) TypeMirror(javax.lang.model.type.TypeMirror) ElementUtils.modifiers(com.oracle.truffle.dsl.processor.java.ElementUtils.modifiers) ElementUtils.firstLetterLowerCase(com.oracle.truffle.dsl.processor.java.ElementUtils.firstLetterLowerCase) Collections(java.util.Collections) DSLExpressionResolver(com.oracle.truffle.dsl.processor.expression.DSLExpressionResolver) LinkedHashSet(java.util.LinkedHashSet) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) TypeElement(javax.lang.model.element.TypeElement) CodeVariableElement(com.oracle.truffle.dsl.processor.java.model.CodeVariableElement) CodeExecutableElement(com.oracle.truffle.dsl.processor.java.model.CodeExecutableElement) CodeTypeElement(com.oracle.truffle.dsl.processor.java.model.CodeTypeElement) Element(javax.lang.model.element.Element) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) ElementUtils.fromTypeMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) CodeVariableElement(com.oracle.truffle.dsl.processor.java.model.CodeVariableElement) List(java.util.List) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) CodeAnnotationMirror(com.oracle.truffle.dsl.processor.java.model.CodeAnnotationMirror) TypeElement(javax.lang.model.element.TypeElement) CodeTypeElement(com.oracle.truffle.dsl.processor.java.model.CodeTypeElement) CodeAnnotationValue(com.oracle.truffle.dsl.processor.java.model.CodeAnnotationValue) NodeData(com.oracle.truffle.dsl.processor.model.NodeData) ElementUtils.findAnnotationMirror(com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror) CodeAnnotationMirror(com.oracle.truffle.dsl.processor.java.model.CodeAnnotationMirror) AnnotationMirror(javax.lang.model.element.AnnotationMirror)

Aggregations

ProcessorContext (com.oracle.truffle.dsl.processor.ProcessorContext)1 DSLExpression (com.oracle.truffle.dsl.processor.expression.DSLExpression)1 DSLExpressionResolver (com.oracle.truffle.dsl.processor.expression.DSLExpressionResolver)1 InvalidExpressionException (com.oracle.truffle.dsl.processor.expression.InvalidExpressionException)1 GeneratorUtils (com.oracle.truffle.dsl.processor.generator.GeneratorUtils)1 ElementUtils (com.oracle.truffle.dsl.processor.java.ElementUtils)1 ElementUtils.elementEquals (com.oracle.truffle.dsl.processor.java.ElementUtils.elementEquals)1 ElementUtils.findAnnotationMirror (com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror)1 ElementUtils.firstLetterLowerCase (com.oracle.truffle.dsl.processor.java.ElementUtils.firstLetterLowerCase)1 ElementUtils.firstLetterUpperCase (com.oracle.truffle.dsl.processor.java.ElementUtils.firstLetterUpperCase)1 ElementUtils.fromTypeMirror (com.oracle.truffle.dsl.processor.java.ElementUtils.fromTypeMirror)1 ElementUtils.getAnnotationValue (com.oracle.truffle.dsl.processor.java.ElementUtils.getAnnotationValue)1 ElementUtils.getQualifiedName (com.oracle.truffle.dsl.processor.java.ElementUtils.getQualifiedName)1 ElementUtils.getRepeatedAnnotation (com.oracle.truffle.dsl.processor.java.ElementUtils.getRepeatedAnnotation)1 ElementUtils.getSimpleName (com.oracle.truffle.dsl.processor.java.ElementUtils.getSimpleName)1 ElementUtils.getSuperType (com.oracle.truffle.dsl.processor.java.ElementUtils.getSuperType)1 ElementUtils.getTypeId (com.oracle.truffle.dsl.processor.java.ElementUtils.getTypeId)1 ElementUtils.isAssignable (com.oracle.truffle.dsl.processor.java.ElementUtils.isAssignable)1 ElementUtils.isSubtype (com.oracle.truffle.dsl.processor.java.ElementUtils.isSubtype)1 ElementUtils.modifiers (com.oracle.truffle.dsl.processor.java.ElementUtils.modifiers)1