Search in sources :

Example 1 with Expression

use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.

the class QuteCompletions method doComplete.

/**
 * Returns completion list for the given position
 *
 * @param template           the Qute template
 * @param position           the position where completion was triggered
 * @param completionSettings the completion settings.
 * @param formattingSettings the formatting settings.
 * @param cancelChecker      the cancel checker
 * @return completion list for the given position
 */
public CompletableFuture<CompletionList> doComplete(Template template, Position position, QuteCompletionSettings completionSettings, QuteFormattingSettings formattingSettings, CancelChecker cancelChecker) {
    CompletionRequest completionRequest = null;
    try {
        completionRequest = new CompletionRequest(template, position, completionSettings, formattingSettings);
    } catch (BadLocationException e) {
        LOGGER.log(Level.SEVERE, "Creation of CompletionRequest failed", e);
        return EMPTY_FUTURE_COMPLETION;
    }
    Node node = completionRequest.getNode();
    if (node == null) {
        return EMPTY_FUTURE_COMPLETION;
    }
    String text = template.getText();
    int offset = completionRequest.getOffset();
    if (node.getKind() == NodeKind.Expression || node.getKind() == NodeKind.ExpressionParts || node.getKind() == NodeKind.ExpressionPart) {
        Expression expression = null;
        Node nodeExpression = null;
        if (node.getKind() == NodeKind.Expression) {
            expression = (Expression) node;
        } else if (node.getKind() == NodeKind.ExpressionParts) {
            nodeExpression = node;
            expression = ((Parts) node).getParent();
        } else if (node.getKind() == NodeKind.ExpressionPart) {
            nodeExpression = node;
            expression = ((Part) node).getParent().getParent();
        }
        return completionForExpression.doCompleteExpression(completionRequest, expression, nodeExpression, template, offset, completionSettings, formattingSettings, cancelChecker);
    } else if (node.getKind() == NodeKind.Text) {
        // The completion is triggered in text node (before node)
        Section parent = node.getParentSection();
        if (parent != null && (parent.isInEndTagName(offset))) {
            // The completion is triggered inside end tag
            return EMPTY_FUTURE_COMPLETION;
        }
        // The completion is triggered in text node
        // Check if completion is triggered after a start bracket character and if it's
        // a valid expression
        int nbBrackets = 0;
        int bracketOffset = offset - 1;
        char previousChar = text.charAt(bracketOffset);
        if (previousChar == '#') {
            // {#
            bracketOffset--;
        }
        while (bracketOffset >= 0 && text.charAt(bracketOffset) == '{') {
            bracketOffset--;
            nbBrackets++;
        }
        if (nbBrackets > 0) {
            if (nbBrackets % 2 != 0) {
                // The completion is triggered in text node after bracket '{' character
                return completionForExpression.doCompleteExpression(completionRequest, null, node, template, offset, completionSettings, formattingSettings, cancelChecker);
            }
            return EMPTY_FUTURE_COMPLETION;
        }
    } else if (node.getKind() == NodeKind.ParameterDeclaration) {
        return completionsForParameterDeclaration.doCollectJavaClassesSuggestions((ParameterDeclaration) node, template, offset, completionSettings);
    } else if (node.getKind() == NodeKind.Section) {
        // {#|}
        return completionForTagSection.doCompleteTagSection(completionRequest, completionSettings, formattingSettings, cancelChecker);
    }
    return collectSnippetSuggestions(completionRequest);
}
Also used : Expression(com.redhat.qute.parser.template.Expression) QuteCompletionsForExpression(com.redhat.qute.services.completions.QuteCompletionsForExpression) Parts(com.redhat.qute.parser.expression.Parts) Part(com.redhat.qute.parser.expression.Part) Node(com.redhat.qute.parser.template.Node) CompletionRequest(com.redhat.qute.services.completions.CompletionRequest) QuteCompletionForTagSection(com.redhat.qute.services.completions.QuteCompletionForTagSection) Section(com.redhat.qute.parser.template.Section) BadLocationException(com.redhat.qute.ls.commons.BadLocationException)

Example 2 with Expression

use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.

the class QuteDiagnostics method validateMethodPart.

/**
 * Validate the given method part.
 *
 * @param part                     the method part to validate.
 * @param ownerSection             the owner section and null otherwise.
 * @param template                 the template.
 * @param projectUri               the project Uri.
 * @param resolutionContext        the resolution context.
 * @param baseType                 the base object type.
 * @param iterableOfType           the iterable of type.
 * @param diagnostics              the diagnostic list to fill.
 * @param resolvingJavaTypeContext the resolving Java type context.
 *
 * @return the Java type returned by the member part and null otherwise.
 */
private ResolvedJavaTypeInfo validateMethodPart(MethodPart methodPart, Section ownerSection, Template template, String projectUri, QuteValidationSettings validationSettings, ResolutionContext resolutionContext, ResolvedJavaTypeInfo resolvedJavaType, ResolvedJavaTypeInfo iter, List<Diagnostic> diagnostics, ResolvingJavaTypeContext resolvingJavaTypeContext) {
    // Validate parameters of the method part
    boolean undefinedType = false;
    List<ResolvedJavaTypeInfo> parameterTypes = new ArrayList<>();
    for (Parameter parameter : methodPart.getParameters()) {
        ResolvedJavaTypeInfo result = null;
        Expression expression = parameter.getJavaTypeExpression();
        if (expression != null) {
            result = validateExpression(expression, ownerSection, template, validationSettings, resolutionContext, resolvingJavaTypeContext, diagnostics);
        }
        if (result == null) {
            undefinedType = true;
        }
        parameterTypes.add(result);
    }
    if (undefinedType) {
        // One of parameter cannot be resolved as type, teh validation is stopped
        return null;
    }
    // All parameters are resolved, validate the existing of method name according
    // to the computed parameter types
    String methodName = methodPart.getPartName();
    String namespace = methodPart.getNamespace();
    JavaMemberResult result = javaCache.findMethod(resolvedJavaType, namespace, methodName, parameterTypes, projectUri);
    JavaMethodInfo method = (JavaMethodInfo) result.getMember();
    if (method == null) {
        QuteErrorCode errorCode = QuteErrorCode.UnknownMethod;
        String arg = null;
        if (namespace != null) {
            // ex :{config.getXXXX()}
            errorCode = QuteErrorCode.UnknownNamespaceResolverMethod;
            arg = namespace;
        } else {
            // ex : {@org.acme.Item item}
            // {item.getXXXX()}
            arg = resolvedJavaType.getSignature();
            InvalidMethodReason reason = javaCache.getInvalidMethodReason(methodName, resolvedJavaType, projectUri);
            if (reason != null) {
                switch(reason) {
                    case VoidReturn:
                        errorCode = QuteErrorCode.InvalidMethodVoid;
                        break;
                    case Static:
                        errorCode = QuteErrorCode.InvalidMethodStatic;
                        break;
                    case FromObject:
                        errorCode = QuteErrorCode.InvalidMethodFromObject;
                        break;
                    default:
                }
            }
        }
        Range range = QutePositionUtility.createRange(methodPart);
        Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, errorCode, methodName, arg);
        diagnostics.add(diagnostic);
        return null;
    }
    boolean matchVirtualMethod = result.isMatchVirtualMethod();
    if (!matchVirtualMethod) {
        Range range = QutePositionUtility.createRange(methodPart);
        Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, // 
        QuteErrorCode.InvalidVirtualMethod, // 
        method.getName(), // 
        method.getSimpleSourceType(), resolvedJavaType.getJavaElementSimpleType());
        diagnostics.add(diagnostic);
        return null;
    }
    boolean matchParameters = result.isMatchParameters();
    if (!matchParameters) {
        // The method codePointAt(int) in the type String is not applicable for the
        // arguments ()
        StringBuilder expectedSignature = new StringBuilder("(");
        boolean ignoreParameter = method.isVirtual();
        for (JavaParameterInfo parameter : method.getParameters()) {
            if (!ignoreParameter) {
                if (expectedSignature.length() > 1) {
                    expectedSignature.append(", ");
                }
                expectedSignature.append(parameter.getJavaElementSimpleType());
            }
            ignoreParameter = false;
        }
        expectedSignature.append(")");
        expectedSignature.insert(0, method.getName());
        StringBuilder actualSignature = new StringBuilder("(");
        for (ResolvedJavaTypeInfo parameterType : parameterTypes) {
            if (actualSignature.length() > 1) {
                actualSignature.append(", ");
            }
            actualSignature.append(parameterType != null ? parameterType.getJavaElementSimpleType() : parameterType);
        }
        actualSignature.append(")");
        Range range = QutePositionUtility.createRange(methodPart);
        Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, // 
        QuteErrorCode.InvalidMethodParameter, // 
        expectedSignature.toString(), // 
        method.getSimpleSourceType(), /* String */
        actualSignature.toString());
        diagnostics.add(diagnostic);
        return null;
    }
    String memberType = method.resolveJavaElementType(iter);
    return validateJavaTypePart(methodPart, ownerSection, projectUri, diagnostics, resolvingJavaTypeContext, memberType);
}
Also used : JavaMemberResult(com.redhat.qute.project.JavaMemberResult) ResolvedJavaTypeInfo(com.redhat.qute.commons.ResolvedJavaTypeInfo) ArrayList(java.util.ArrayList) DiagnosticDataFactory.createDiagnostic(com.redhat.qute.services.diagnostics.DiagnosticDataFactory.createDiagnostic) Diagnostic(org.eclipse.lsp4j.Diagnostic) Range(org.eclipse.lsp4j.Range) QuteErrorCode(com.redhat.qute.services.diagnostics.QuteErrorCode) JavaMethodInfo(com.redhat.qute.commons.JavaMethodInfo) Expression(com.redhat.qute.parser.template.Expression) Parameter(com.redhat.qute.parser.template.Parameter) InvalidMethodReason(com.redhat.qute.commons.InvalidMethodReason) JavaParameterInfo(com.redhat.qute.commons.JavaParameterInfo)

Example 3 with Expression

use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.

the class QuteDiagnostics method validateDataModel.

private void validateDataModel(Node parent, Template template, QuteValidationSettings validationSettings, ResolvingJavaTypeContext resolvingJavaTypeContext, ResolutionContext currentContext, List<Diagnostic> diagnostics) {
    ResolutionContext previousContext = currentContext;
    List<Node> children = parent.getChildren();
    for (Node node : children) {
        switch(node.getKind()) {
            case ParameterDeclaration:
                {
                    ParameterDeclaration parameter = (ParameterDeclaration) node;
                    String javaTypeToResolve = parameter.getJavaType();
                    if (!StringUtils.isEmpty(javaTypeToResolve)) {
                        String projectUri = template.getProjectUri();
                        if (projectUri != null) {
                            List<JavaTypeRangeOffset> classNameRanges = parameter.getJavaTypeNameRanges();
                            for (RangeOffset classNameRange : classNameRanges) {
                                String className = template.getText(classNameRange);
                                ResolvedJavaTypeInfo resolvedJavaType = resolveJavaType(className, projectUri, resolvingJavaTypeContext);
                                if (resolvedJavaType == null) {
                                    // Java type doesn't exist
                                    Range range = QutePositionUtility.createRange(classNameRange, template);
                                    Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, QuteErrorCode.UnknownType, className);
                                    diagnostics.add(diagnostic);
                                } else if (!isResolvingJavaType(resolvedJavaType)) {
                                    currentContext.put(javaTypeToResolve, resolvedJavaType);
                                }
                            }
                        }
                    }
                    break;
                }
            case Section:
                {
                    Section section = (Section) node;
                    if (canChangeContext(section)) {
                        currentContext = new ResolutionContext(currentContext);
                    }
                    List<Parameter> parameters = section.getParameters();
                    // validate expression parameters
                    for (Parameter parameter : parameters) {
                        Expression expression = parameter.getJavaTypeExpression();
                        if (expression != null) {
                            ResolvedJavaTypeInfo result = validateExpression(expression, section, template, validationSettings, previousContext, resolvingJavaTypeContext, diagnostics);
                            switch(section.getSectionKind()) {
                                case FOR:
                                case EACH:
                                    String alias = ((LoopSection) section).getAlias();
                                    currentContext.put(alias, result);
                                    break;
                                case WITH:
                                    currentContext.setWithObject(result);
                                    break;
                                case LET:
                                case SET:
                                    currentContext.put(parameter.getName(), result);
                                    break;
                                default:
                            }
                        }
                    }
                    switch(section.getSectionKind()) {
                        case INCLUDE:
                            validateIncludeSection((IncludeSection) section, diagnostics);
                            break;
                        default:
                            validateSectionTag(section, template, resolvingJavaTypeContext, diagnostics);
                    }
                    break;
                }
            case Expression:
                {
                    validateExpression((Expression) node, null, template, validationSettings, previousContext, resolvingJavaTypeContext, diagnostics);
                    break;
                }
            default:
        }
        validateDataModel(node, template, validationSettings, resolvingJavaTypeContext, currentContext, diagnostics);
    }
}
Also used : Node(com.redhat.qute.parser.template.Node) ResolvedJavaTypeInfo(com.redhat.qute.commons.ResolvedJavaTypeInfo) DiagnosticDataFactory.createDiagnostic(com.redhat.qute.services.diagnostics.DiagnosticDataFactory.createDiagnostic) Diagnostic(org.eclipse.lsp4j.Diagnostic) Range(org.eclipse.lsp4j.Range) IncludeSection(com.redhat.qute.parser.template.sections.IncludeSection) LoopSection(com.redhat.qute.parser.template.sections.LoopSection) Section(com.redhat.qute.parser.template.Section) Expression(com.redhat.qute.parser.template.Expression) JavaTypeRangeOffset(com.redhat.qute.parser.template.ParameterDeclaration.JavaTypeRangeOffset) RangeOffset(com.redhat.qute.parser.template.RangeOffset) Parameter(com.redhat.qute.parser.template.Parameter) IncludeSection(com.redhat.qute.parser.template.sections.IncludeSection) List(java.util.List) ArrayList(java.util.ArrayList) ParameterDeclaration(com.redhat.qute.parser.template.ParameterDeclaration)

Example 4 with Expression

use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.

the class QuteDiagnostics method validateObjectPart.

private ResolvedJavaTypeInfo validateObjectPart(String namespace, ObjectPart objectPart, Section ownerSection, Template template, String projectUri, QuteValidationSettings validationSettings, ResolutionContext resolutionContext, List<Diagnostic> diagnostics, ResolvingJavaTypeContext resolvingJavaTypeContext) {
    JavaMemberInfo javaMember = resolutionContext.findMemberWithObject(objectPart.getPartName(), projectUri);
    if (javaMember != null) {
        ResolvedJavaTypeInfo resolvedJavaType = resolveJavaType(javaMember.getJavaElementType(), projectUri, resolvingJavaTypeContext);
        if (isResolvingJavaType(resolvedJavaType)) {
            return null;
        }
        return resolvedJavaType;
    }
    JavaTypeInfoProvider javaTypeInfo = objectPart.resolveJavaType();
    if (javaTypeInfo == null) {
        if (!resolvingJavaTypeContext.isDataModelTemplateResolved()) {
            // The data model is not loaded, ignore the error of undefined object
            return null;
        }
        if (UserTagUtils.isUserTag(template)) {
            // Ignore undefined object diagnostic for user tag
            return null;
        }
        // ex : {item} --> undefined object
        DiagnosticSeverity severity = validationSettings.getUndefinedObject().getDiagnosticSeverity();
        if (severity == null) {
            return null;
        }
        Range range = QutePositionUtility.createRange(objectPart);
        Diagnostic diagnostic = createDiagnostic(range, severity, QuteErrorCode.UndefinedObject, objectPart.getPartName());
        // Create data information helpful for code action
        diagnostic.setData(DiagnosticDataFactory.createUndefinedObjectData(objectPart.getPartName(), ownerSection != null && ownerSection.isIterable()));
        diagnostics.add(diagnostic);
        return null;
    }
    String javaTypeToResolve = javaTypeInfo.getJavaType();
    if (javaTypeToResolve == null) {
        // case of (#for item as data.items) where data.items expression must be
        // evaluated
        Expression expression = javaTypeInfo.getJavaTypeExpression();
        if (expression != null) {
            String literalJavaType = expression.getLiteralJavaType();
            if (literalJavaType != null) {
                javaTypeToResolve = literalJavaType;
            } else {
                Part lastPart = expression.getLastPart();
                if (lastPart != null) {
                    ResolvedJavaTypeInfo alias = javaCache.resolveJavaType(lastPart, projectUri).getNow(RESOLVING_JAVA_TYPE);
                    if (isResolvingJavaType(alias)) {
                        return null;
                    }
                    if (alias == null) {
                        if (!resolvingJavaTypeContext.isDataModelTemplateResolved()) {
                            // The data model is not loaded, don't validate the item of items.
                            return null;
                        }
                    } else {
                        javaTypeToResolve = alias.getSignature();
                    }
                }
            }
        }
    }
    return validateJavaTypePart(objectPart, ownerSection, projectUri, diagnostics, resolvingJavaTypeContext, javaTypeToResolve);
}
Also used : JavaMemberInfo(com.redhat.qute.commons.JavaMemberInfo) JavaTypeInfoProvider(com.redhat.qute.parser.template.JavaTypeInfoProvider) DiagnosticSeverity(org.eclipse.lsp4j.DiagnosticSeverity) Expression(com.redhat.qute.parser.template.Expression) MethodPart(com.redhat.qute.parser.expression.MethodPart) Part(com.redhat.qute.parser.expression.Part) PropertyPart(com.redhat.qute.parser.expression.PropertyPart) ObjectPart(com.redhat.qute.parser.expression.ObjectPart) NamespacePart(com.redhat.qute.parser.expression.NamespacePart) ResolvedJavaTypeInfo(com.redhat.qute.commons.ResolvedJavaTypeInfo) DiagnosticDataFactory.createDiagnostic(com.redhat.qute.services.diagnostics.DiagnosticDataFactory.createDiagnostic) Diagnostic(org.eclipse.lsp4j.Diagnostic) Range(org.eclipse.lsp4j.Range)

Example 5 with Expression

use of com.redhat.qute.parser.template.Expression in project quarkus-ls by redhat-developer.

the class QuteHover method doHoverForObjectPart.

private CompletableFuture<Hover> doHoverForObjectPart(Part part, String projectUri, HoverRequest hoverRequest) {
    if (UserTagUtils.isUserTag(hoverRequest.getTemplate())) {
        // It's an user tag
        SectionMetadata specialKey = UserTagUtils.getSpecialKey(part.getPartName());
        if (specialKey != null) {
            // its a special key for user tag ({it} or {nested-content), display the special
            // key documentation.
            boolean hasMarkdown = hoverRequest.canSupportMarkupKind(MarkupKind.MARKDOWN);
            MarkupContent content = DocumentationUtils.getDocumentation(specialKey, hasMarkdown);
            Range range = QutePositionUtility.createRange(part);
            Hover hover = new Hover(content, range);
            return CompletableFuture.completedFuture(hover);
        }
    }
    // Check if part is a literal (ex: true, null, 123, 'abc', etc)
    Expression expression = part.getParent().getParent();
    String literalJavaType = expression.getLiteralJavaType();
    if (literalJavaType != null) {
        return doHoverForJavaType(part, literalJavaType, projectUri, hoverRequest);
    }
    return // 
    javaCache.resolveJavaType(part, projectUri).thenApply(resolvedJavaType -> {
        if (resolvedJavaType != null) {
            SectionMetadata metadata = getMetadata(part);
            boolean hasMarkdown = hoverRequest.canSupportMarkupKind(MarkupKind.MARKDOWN);
            MarkupContent content = DocumentationUtils.getDocumentation(resolvedJavaType, metadata != null ? metadata.getDescription() : null, hasMarkdown);
            Range range = QutePositionUtility.createRange(part);
            return new Hover(content, range);
        }
        return null;
    });
}
Also used : Expression(com.redhat.qute.parser.template.Expression) Hover(org.eclipse.lsp4j.Hover) SectionMetadata(com.redhat.qute.parser.template.SectionMetadata) Range(org.eclipse.lsp4j.Range) MarkupContent(org.eclipse.lsp4j.MarkupContent)

Aggregations

Expression (com.redhat.qute.parser.template.Expression)12 Node (com.redhat.qute.parser.template.Node)8 Parameter (com.redhat.qute.parser.template.Parameter)7 Range (org.eclipse.lsp4j.Range)6 Part (com.redhat.qute.parser.expression.Part)5 Section (com.redhat.qute.parser.template.Section)5 ResolvedJavaTypeInfo (com.redhat.qute.commons.ResolvedJavaTypeInfo)4 ObjectPart (com.redhat.qute.parser.expression.ObjectPart)4 List (java.util.List)4 MethodPart (com.redhat.qute.parser.expression.MethodPart)3 NamespacePart (com.redhat.qute.parser.expression.NamespacePart)3 Parts (com.redhat.qute.parser.expression.Parts)3 DiagnosticDataFactory.createDiagnostic (com.redhat.qute.services.diagnostics.DiagnosticDataFactory.createDiagnostic)3 Diagnostic (org.eclipse.lsp4j.Diagnostic)3 InvalidMethodReason (com.redhat.qute.commons.InvalidMethodReason)2 JavaMemberInfo (com.redhat.qute.commons.JavaMemberInfo)2 BadLocationException (com.redhat.qute.ls.commons.BadLocationException)2 JavaTypeInfoProvider (com.redhat.qute.parser.template.JavaTypeInfoProvider)2 LoopSection (com.redhat.qute.parser.template.sections.LoopSection)2 JavaMemberResult (com.redhat.qute.project.JavaMemberResult)2