Search in sources :

Example 1 with FunctionDefinitionNode

use of org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode in project ballerina by ballerina-lang.

the class BallerinaPsiImplUtil method getStructDefinition.

@Nullable
public static StructDefinitionNode getStructDefinition(@NotNull AssignmentStatementNode assignmentStatementNode, @NotNull IdentifierPSINode structReferenceNode, @NotNull PsiElement definitionNode) {
    // Now we need to know the index of the provided struct reference node in the assignment statement node.
    int index = getVariableIndexFromVarAssignment(assignmentStatementNode, structReferenceNode);
    if (index < 0) {
        return null;
    }
    // Now we get all of the return types from the function.
    List<TypeNameNode> returnTypes = new LinkedList<>();
    if (definitionNode instanceof FunctionDefinitionNode) {
        returnTypes = getReturnTypes(((FunctionDefinitionNode) definitionNode));
    }
    if (definitionNode instanceof ActionDefinitionNode) {
        returnTypes = getReturnTypes(((ActionDefinitionNode) definitionNode));
    }
    // at least 1, etc.
    if (returnTypes.size() <= index) {
        return null;
    }
    // Get the corresponding return type.
    PsiElement elementType = returnTypes.get(index);
    // If this is a struct, we need to resolve it to the definition.
    PsiReference referenceAtElementType = elementType.findReferenceAt(elementType.getTextLength());
    if (referenceAtElementType == null) {
        return null;
    }
    PsiElement resolvedIdentifier = referenceAtElementType.resolve();
    if (resolvedIdentifier != null) {
        // If we can resolve it to a definition, parent should be a struct definition node.
        PsiElement structDefinition = resolvedIdentifier.getParent();
        if (structDefinition instanceof StructDefinitionNode) {
            return (StructDefinitionNode) structDefinition;
        }
    }
    return null;
}
Also used : FunctionDefinitionNode(org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode) StructDefinitionNode(org.ballerinalang.plugins.idea.psi.StructDefinitionNode) BuiltInReferenceTypeNameNode(org.ballerinalang.plugins.idea.psi.BuiltInReferenceTypeNameNode) FunctionTypeNameNode(org.ballerinalang.plugins.idea.psi.FunctionTypeNameNode) TypeNameNode(org.ballerinalang.plugins.idea.psi.TypeNameNode) ValueTypeNameNode(org.ballerinalang.plugins.idea.psi.ValueTypeNameNode) AnonStructTypeNameNode(org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode) ActionDefinitionNode(org.ballerinalang.plugins.idea.psi.ActionDefinitionNode) PsiReference(com.intellij.psi.PsiReference) LinkedList(java.util.LinkedList) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) Nullable(org.jetbrains.annotations.Nullable)

Example 2 with FunctionDefinitionNode

use of org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode in project ballerina by ballerina-lang.

the class BallerinaPsiImplUtil method getType.

/**
 * Returns the type of the provided identifier.
 *
 * @param identifier an identifier
 * @return the type of the identifier. This can be one of {@link ValueTypeNameNode} (for value types like string),
 * {@link BuiltInReferenceTypeNameNode} (for reference types like json) or {@link TypeNameNode} (for arrays).
 */
@Nullable
public static PsiElement getType(@NotNull IdentifierPSINode identifier) {
    PsiElement parent = identifier.getParent();
    // In case of lambda functions or functions attached to types.
    if (parent instanceof FunctionDefinitionNode) {
        CodeBlockParameterNode codeBlockParameterNode = PsiTreeUtil.getChildOfType(parent, CodeBlockParameterNode.class);
        if (codeBlockParameterNode != null) {
            TypeNameNode typeNameNode = PsiTreeUtil.getChildOfType(codeBlockParameterNode, TypeNameNode.class);
            if (typeNameNode != null) {
                return typeNameNode.getFirstChild();
            }
        }
    }
    PsiReference reference = identifier.findReferenceAt(0);
    if (reference != null) {
    // Todo - Do we need to consider this situation?
    }
    VariableDefinitionNode variableDefinitionNode = PsiTreeUtil.getParentOfType(identifier, VariableDefinitionNode.class);
    if (variableDefinitionNode != null) {
        PsiElement typeNode = getType(variableDefinitionNode);
        if (typeNode != null) {
            return typeNode;
        }
    }
    AssignmentStatementNode assignmentStatementNode = PsiTreeUtil.getParentOfType(identifier, AssignmentStatementNode.class);
    if (assignmentStatementNode != null) {
        PsiElement typeNode = getType(assignmentStatementNode, identifier);
        if (typeNode != null) {
            return typeNode;
        }
    }
    ParameterNode parameterNode = PsiTreeUtil.getParentOfType(identifier, ParameterNode.class);
    if (parameterNode != null) {
        PsiElement typeNode = getType(parameterNode);
        if (typeNode != null) {
            return typeNode;
        }
    }
    FieldDefinitionNode fieldDefinitionNode = PsiTreeUtil.getParentOfType(identifier, FieldDefinitionNode.class);
    if (fieldDefinitionNode != null) {
        PsiElement typeNode = getType(fieldDefinitionNode);
        if (typeNode != null) {
            return typeNode;
        }
    }
    return null;
}
Also used : GlobalVariableDefinitionNode(org.ballerinalang.plugins.idea.psi.GlobalVariableDefinitionNode) VariableDefinitionNode(org.ballerinalang.plugins.idea.psi.VariableDefinitionNode) AssignmentStatementNode(org.ballerinalang.plugins.idea.psi.AssignmentStatementNode) ParameterNode(org.ballerinalang.plugins.idea.psi.ParameterNode) ReturnParameterNode(org.ballerinalang.plugins.idea.psi.ReturnParameterNode) CodeBlockParameterNode(org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode) FunctionDefinitionNode(org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode) BuiltInReferenceTypeNameNode(org.ballerinalang.plugins.idea.psi.BuiltInReferenceTypeNameNode) FunctionTypeNameNode(org.ballerinalang.plugins.idea.psi.FunctionTypeNameNode) TypeNameNode(org.ballerinalang.plugins.idea.psi.TypeNameNode) ValueTypeNameNode(org.ballerinalang.plugins.idea.psi.ValueTypeNameNode) AnonStructTypeNameNode(org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode) PsiReference(com.intellij.psi.PsiReference) FieldDefinitionNode(org.ballerinalang.plugins.idea.psi.FieldDefinitionNode) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) CodeBlockParameterNode(org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode) Nullable(org.jetbrains.annotations.Nullable)

Example 3 with FunctionDefinitionNode

use of org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode in project ballerina by ballerina-lang.

the class BallerinaPsiImplUtil method getStructDefinition.

/**
 * Finds a {@link StructDefinitionNode} which corresponds to the provided {@link VariableReferenceNode}.
 *
 * @param variableReferenceNode   an variable reference node in the assignment statement node
 * @param assignmentStatementNode an assignment statement node
 * @param structReferenceNode     an identifier which is a var variable in the assignment node
 * @return
 */
private static StructDefinitionNode getStructDefinition(@NotNull VariableReferenceNode variableReferenceNode, @NotNull AssignmentStatementNode assignmentStatementNode, @NotNull IdentifierPSINode structReferenceNode) {
    InvocationNode invocationNode = PsiTreeUtil.getChildOfType(variableReferenceNode, InvocationNode.class);
    if (invocationNode != null) {
        AnyIdentifierNameNode anyIdentifierNameNode = PsiTreeUtil.getChildOfType(invocationNode, AnyIdentifierNameNode.class);
        if (anyIdentifierNameNode != null) {
            IdentifierPSINode identifier = PsiTreeUtil.getChildOfType(anyIdentifierNameNode, IdentifierPSINode.class);
            if (identifier != null) {
                PsiReference reference = identifier.findReferenceAt(identifier.getTextLength());
                if (reference == null) {
                    return null;
                }
                PsiElement resolvedElement = reference.resolve();
                if (resolvedElement == null) {
                    return null;
                }
                // Check whether the resolved element's parent is a connector definition.
                PsiElement definitionNode = resolvedElement.getParent();
                if (!(definitionNode instanceof ActionDefinitionNode)) {
                    return null;
                }
                return getStructDefinition(assignmentStatementNode, structReferenceNode, definitionNode);
            }
        }
    }
    // Get the first child.
    PsiElement node = variableReferenceNode.getFirstChild();
    // If te first child is a VariableReferenceNode, it can be a function invocation.
    if (node instanceof VariableReferenceNode) {
        // Check whether the node is a function invocation.
        boolean isFunctionInvocation = isFunctionInvocation((VariableReferenceNode) node);
        if (isFunctionInvocation) {
            // If it is a function invocation, the first child node will contain the function name.
            PsiElement functionName = node.getFirstChild();
            // We need to resolve the function name to the corresponding function definition.
            PsiReference reference = functionName.findReferenceAt(functionName.getTextLength());
            if (reference == null) {
                return null;
            }
            PsiElement resolvedFunctionIdentifier = reference.resolve();
            if (resolvedFunctionIdentifier == null) {
                return null;
            }
            // Check whether the resolved element's parent is a function definition.
            PsiElement definitionNode = resolvedFunctionIdentifier.getParent();
            if (!(definitionNode instanceof FunctionDefinitionNode)) {
                return null;
            }
            return getStructDefinition(assignmentStatementNode, structReferenceNode, definitionNode);
        }
    } else if (node instanceof NameReferenceNode) {
        // If the node is a NameReferenceNode, that means RHS contains a variable.
        PsiReference reference = node.findReferenceAt(node.getTextLength());
        if (reference == null) {
            return null;
        }
        // We resolve that variable to the definition.
        PsiElement resolvedDefinition = reference.resolve();
        if (resolvedDefinition == null || !(resolvedDefinition instanceof IdentifierPSINode)) {
            return null;
        }
        // Then recursively call the findStructDefinition method to get the correct definition.
        return findStructDefinition((IdentifierPSINode) resolvedDefinition);
    } else if (node instanceof FunctionInvocationNode) {
        FunctionReferenceNode functionReferenceNode = PsiTreeUtil.getChildOfType(node, FunctionReferenceNode.class);
        if (functionReferenceNode == null) {
            return null;
        }
        PsiReference reference = functionReferenceNode.findReferenceAt(functionReferenceNode.getTextLength());
        if (reference == null) {
            return null;
        }
        PsiElement resolvedDefinition = reference.resolve();
        if (resolvedDefinition == null || !(resolvedDefinition instanceof IdentifierPSINode)) {
            return null;
        }
        PsiElement definitionNode = resolvedDefinition.getParent();
        if (!(definitionNode instanceof FunctionDefinitionNode)) {
            return null;
        }
        return getStructDefinition(assignmentStatementNode, structReferenceNode, definitionNode);
    }
    return null;
}
Also used : AnyIdentifierNameNode(org.ballerinalang.plugins.idea.psi.AnyIdentifierNameNode) FunctionDefinitionNode(org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode) ActionDefinitionNode(org.ballerinalang.plugins.idea.psi.ActionDefinitionNode) IdentifierPSINode(org.ballerinalang.plugins.idea.psi.IdentifierPSINode) PsiReference(com.intellij.psi.PsiReference) VariableReferenceNode(org.ballerinalang.plugins.idea.psi.VariableReferenceNode) FunctionReferenceNode(org.ballerinalang.plugins.idea.psi.FunctionReferenceNode) InvocationNode(org.ballerinalang.plugins.idea.psi.InvocationNode) FunctionInvocationNode(org.ballerinalang.plugins.idea.psi.FunctionInvocationNode) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) NameReferenceNode(org.ballerinalang.plugins.idea.psi.NameReferenceNode) FunctionInvocationNode(org.ballerinalang.plugins.idea.psi.FunctionInvocationNode)

Example 4 with FunctionDefinitionNode

use of org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode in project ballerina by ballerina-lang.

the class BallerinaDocumentationProvider method getSignature.

@NotNull
private static String getSignature(PsiElement element) {
    if (element == null) {
        return "";
    }
    StringBuilder stringBuilder = new StringBuilder();
    // element will be an identifier. So we need to get the parent of the element to identify the type to
    // generate the signature.
    PsiElement parent = element.getParent();
    // Generate the signature according to the parent type.
    if (parent instanceof FunctionDefinitionNode) {
        // Add the function signature.
        stringBuilder.append("function ");
        stringBuilder.append(element.getText());
        // Get parameters.
        String params = getParameterString(parent, false);
        // Add parameters.
        stringBuilder.append("(");
        stringBuilder.append(params);
        stringBuilder.append(")");
        // Get return types. These can be either return types or return parameters.
        List<String> returnParamsList = getReturnTypes(parent);
        String returnParams = StringUtil.join(returnParamsList, ", ");
        if (!returnParams.isEmpty()) {
            // Add return types/parameters.
            stringBuilder.append("(");
            stringBuilder.append(returnParams);
            stringBuilder.append(")");
        }
    } else if (parent instanceof ActionDefinitionNode || parent instanceof AnyIdentifierNameNode) {
        // Add the action signature.
        stringBuilder.append("action ");
        stringBuilder.append(element.getText());
        // Get parameters.
        String params = getParameterString(parent, false);
        // Add parameters.
        stringBuilder.append("(");
        stringBuilder.append(params);
        stringBuilder.append(")");
        // Get return types/parameters.
        List<String> returnParamsList = getReturnTypes(parent);
        String returnParams = StringUtil.join(returnParamsList, ", ");
        if (!returnParams.isEmpty()) {
            // Add return types/parameters.
            stringBuilder.append("(");
            stringBuilder.append(returnParams);
            stringBuilder.append(")");
        }
    } else if (parent instanceof ConnectorDefinitionNode) {
        // Add the connector signature.
        stringBuilder.append("connector ");
        stringBuilder.append(element.getText());
        // Get parameters.
        String params = getParameterString(parent, false);
        // Add parameters.
        stringBuilder.append("(");
        stringBuilder.append(params);
        stringBuilder.append(")");
    } else if (parent instanceof StructDefinitionNode) {
        // Add the function signature.
        stringBuilder.append("struct ");
        stringBuilder.append(element.getText());
        stringBuilder.append(" { }");
    } else if (parent instanceof ConstantDefinitionNode) {
        // Add the function signature.
        stringBuilder.append(parent.getText());
    }
    // If the doc is available, add package to the top.
    if (!stringBuilder.toString().isEmpty()) {
        // Add the containing package to the quick doc if there is any.
        PsiElement packagePathNode = getContainingPackage(element);
        if (packagePathNode != null) {
            stringBuilder.insert(0, packagePathNode.getText() + "<br><br>");
        }
    }
    // Return the signature.
    return stringBuilder.toString();
}
Also used : AnyIdentifierNameNode(org.ballerinalang.plugins.idea.psi.AnyIdentifierNameNode) ConstantDefinitionNode(org.ballerinalang.plugins.idea.psi.ConstantDefinitionNode) FunctionDefinitionNode(org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode) StructDefinitionNode(org.ballerinalang.plugins.idea.psi.StructDefinitionNode) ActionDefinitionNode(org.ballerinalang.plugins.idea.psi.ActionDefinitionNode) LinkedList(java.util.LinkedList) ParameterTypeNameList(org.ballerinalang.plugins.idea.psi.ParameterTypeNameList) List(java.util.List) ConnectorDefinitionNode(org.ballerinalang.plugins.idea.psi.ConnectorDefinitionNode) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with FunctionDefinitionNode

use of org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode in project ballerina by ballerina-lang.

the class BallerinaRecursiveCallMarkerProvider method collectSlowLineMarkers.

@Override
public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
    // This is used to prevent adding multiple line markers to the same line.
    Set<Integer> lines = ContainerUtil.newHashSet();
    for (PsiElement element : elements) {
        // Check whether the current element can be used to add recursive call marker.
        if (!isMatchingElement(element)) {
            continue;
        }
        // Resolve the element to the definition. We use this to get the common context later.
        PsiElement resolvedElement = resolveElement(element);
        if (resolvedElement == null) {
            continue;
        }
        if (!(resolvedElement.getParent() instanceof FunctionDefinitionNode)) {
            continue;
        }
        // Get the document manager;
        PsiDocumentManager documentManager = PsiDocumentManager.getInstance(element.getProject());
        // Get the document.
        Document document = documentManager.getDocument(element.getContainingFile());
        if (document == null) {
            continue;
        }
        // Get the offset of the current element.
        int textOffset = element.getTextOffset();
        // Get the line number of the current element.
        int lineNumber = document.getLineNumber(textOffset);
        // Find the common context. For a recursive call, the common context should be a FunctionDefinitionNode.
        PsiElement commonContext = PsiTreeUtil.findCommonContext(element, resolvedElement);
        if (commonContext instanceof FunctionDefinitionNode && !lines.contains(lineNumber)) {
            // Add the number to the set.
            lines.add(lineNumber);
            // Return a new line marker.
            result.add(new RecursiveMethodCallMarkerInfo(element));
        }
    }
}
Also used : FunctionDefinitionNode(org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode) Document(com.intellij.openapi.editor.Document) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) PsiElement(com.intellij.psi.PsiElement) PsiDocumentManager(com.intellij.psi.PsiDocumentManager)

Aggregations

FunctionDefinitionNode (org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode)12 PsiElement (com.intellij.psi.PsiElement)10 PsiReference (com.intellij.psi.PsiReference)6 LeafPsiElement (com.intellij.psi.impl.source.tree.LeafPsiElement)6 TypeNameNode (org.ballerinalang.plugins.idea.psi.TypeNameNode)6 ActionDefinitionNode (org.ballerinalang.plugins.idea.psi.ActionDefinitionNode)4 AnonStructTypeNameNode (org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode)4 BuiltInReferenceTypeNameNode (org.ballerinalang.plugins.idea.psi.BuiltInReferenceTypeNameNode)4 FunctionTypeNameNode (org.ballerinalang.plugins.idea.psi.FunctionTypeNameNode)4 NameReferenceNode (org.ballerinalang.plugins.idea.psi.NameReferenceNode)4 ServiceDefinitionNode (org.ballerinalang.plugins.idea.psi.ServiceDefinitionNode)4 StructDefinitionNode (org.ballerinalang.plugins.idea.psi.StructDefinitionNode)4 LinkedList (java.util.LinkedList)3 AnyIdentifierNameNode (org.ballerinalang.plugins.idea.psi.AnyIdentifierNameNode)3 AssignmentStatementNode (org.ballerinalang.plugins.idea.psi.AssignmentStatementNode)3 CodeBlockParameterNode (org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode)3 ConnectorDefinitionNode (org.ballerinalang.plugins.idea.psi.ConnectorDefinitionNode)3 ConstantDefinitionNode (org.ballerinalang.plugins.idea.psi.ConstantDefinitionNode)3 FieldDefinitionNode (org.ballerinalang.plugins.idea.psi.FieldDefinitionNode)3 FunctionInvocationNode (org.ballerinalang.plugins.idea.psi.FunctionInvocationNode)3