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;
}
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;
}
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;
}
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();
}
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));
}
}
}
Aggregations