use of org.ballerinalang.plugins.idea.psi.VariableDefinitionNode in project ballerina by ballerina-lang.
the class BallerinaPsiImplUtil method findStructDefinition.
/**
* Resolves the corresponding struct definition of the provided identifier node if possible.
* Eg:
* <pre>
* function main (string[] args) {
* var person = getData();
* var person2 = person;
* var person3 = person2;
*
* system:println(person3.<caret>);
* }
*
* function getData () (Person) {
* Person person = {name:"Shan", age:26};
* return person;
* }
*
* struct Person {
* string name;
* int age;
* }
* </pre>
* <p>
* From the above caret position, we should be able to get the type of the 'person3'. So we resolve recursively
* until we find the struct definition. If the RHS has a variable, we resolve the definition of the variable and
* call this method again. So in the first call of this function, 'resolvedElement' will be the
* definition of 'person3'. Next, the definition of 'person2' and definition of 'person' after that. At that point,
* we find a function invocation in the RHS. So we get the type from that.
*
* @param resolvedElement element which was resolved from the variable reference
* @return corresponding {@link StructDefinitionNode} if the structName can be resolved, {@code null} otherwise.
*/
@Nullable
public static StructDefinitionNode findStructDefinition(@NotNull IdentifierPSINode resolvedElement) {
// Since this method might get called recursively, it is better to check whether the process is cancelled in the
// beginning.
ProgressManager.checkCanceled();
// Get the assignment statement parent node.
AssignmentStatementNode assignmentStatementNode = PsiTreeUtil.getParentOfType(resolvedElement, AssignmentStatementNode.class);
// count as a definition and does not resolve to it.
if (assignmentStatementNode != null) {
return getStructDefinition(assignmentStatementNode, resolvedElement);
}
// If the resolved element is not in an AssignmentStatement, we check for VariableDefinition parent node.
// If there is a VariableDefinition parent node, finding the type is quite straight forward.
VariableDefinitionNode variableDefinitionNode = PsiTreeUtil.getParentOfType(resolvedElement, VariableDefinitionNode.class);
if (variableDefinitionNode != null) {
return resolveStructFromDefinitionNode(variableDefinitionNode);
}
ParameterNode parameterNode = PsiTreeUtil.getParentOfType(resolvedElement, ParameterNode.class);
if (parameterNode != null) {
return resolveStructFromDefinitionNode(parameterNode);
}
return null;
}
use of org.ballerinalang.plugins.idea.psi.VariableDefinitionNode 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.VariableDefinitionNode in project ballerina by ballerina-lang.
the class RecordKeyReference method resolve.
@Nullable
@Override
public PsiElement resolve() {
IdentifierPSINode identifier = getElement();
VariableDefinitionNode variableDefinitionNode = PsiTreeUtil.getParentOfType(identifier, VariableDefinitionNode.class);
if (variableDefinitionNode != null) {
return resolve(variableDefinitionNode);
}
GlobalVariableDefinitionNode globalVariableDefinitionNode = PsiTreeUtil.getParentOfType(identifier, GlobalVariableDefinitionNode.class);
if (globalVariableDefinitionNode != null) {
return resolve(globalVariableDefinitionNode);
}
AssignmentStatementNode assignmentStatementNode = PsiTreeUtil.getParentOfType(identifier, AssignmentStatementNode.class);
if (assignmentStatementNode != null) {
PsiElement resolvedElement = resolve(assignmentStatementNode);
if (resolvedElement != null) {
return resolvedElement;
}
}
// Try to resolve to fields in anonymous struct.
PsiElement definitionNode = BallerinaPsiImplUtil.resolveAnonymousStruct(identifier);
if (definitionNode == null) {
return null;
}
if (definitionNode instanceof AnonStructTypeNameNode) {
StructBodyNode structBodyNode = PsiTreeUtil.findChildOfType(definitionNode, StructBodyNode.class);
if (structBodyNode == null) {
return null;
}
List<FieldDefinitionNode> fieldDefinitionNodes = PsiTreeUtil.getChildrenOfTypeAsList(structBodyNode, FieldDefinitionNode.class);
for (FieldDefinitionNode fieldDefinitionNode : fieldDefinitionNodes) {
if (fieldDefinitionNode == null) {
continue;
}
IdentifierPSINode fieldName = PsiTreeUtil.getChildOfType(fieldDefinitionNode, IdentifierPSINode.class);
if (fieldName == null) {
continue;
}
if (fieldName.getText().equals(identifier.getText())) {
return fieldName;
}
}
}
if (!(definitionNode instanceof StructDefinitionNode)) {
return null;
}
StructDefinitionNode structDefinitionNode = ((StructDefinitionNode) definitionNode);
IdentifierPSINode structNameNode = PsiTreeUtil.getChildOfType(structDefinitionNode, IdentifierPSINode.class);
if (structNameNode == null) {
return null;
}
Collection<FieldDefinitionNode> fieldDefinitionNodes = PsiTreeUtil.findChildrenOfType(structDefinitionNode, FieldDefinitionNode.class);
for (FieldDefinitionNode fieldDefinitionNode : fieldDefinitionNodes) {
IdentifierPSINode fieldName = PsiTreeUtil.getChildOfType(fieldDefinitionNode, IdentifierPSINode.class);
if (fieldName != null && identifier.getText().equals(fieldName.getText())) {
return fieldName;
}
}
return null;
}
use of org.ballerinalang.plugins.idea.psi.VariableDefinitionNode in project ballerina by ballerina-lang.
the class RecordKeyReference method getVariantsFromCurrentPackage.
@NotNull
private List<LookupElement> getVariantsFromCurrentPackage() {
List<LookupElement> results = new LinkedList<>();
IdentifierPSINode identifier = getElement();
VariableDefinitionNode variableDefinitionNode = PsiTreeUtil.getParentOfType(identifier, VariableDefinitionNode.class);
InvocationNode invocationNode = PsiTreeUtil.getParentOfType(identifier, InvocationNode.class);
if (variableDefinitionNode == null || invocationNode != null) {
StructDefinitionNode structDefinitionNode = resolveStructDefinition(identifier);
if (structDefinitionNode == null) {
// Todo - Check for enclosing {} since the parse errors might cause issues when identifying
// RecordLiteralNode element
// RecordLiteralNode mapStructLiteralNode = PsiTreeUtil.getParentOfType(identifier,
// RecordLiteralNode.class);
// if (mapStructLiteralNode == null) {
// return results;
// }
// Try to get fields from an anonymous struct.
PsiElement definitionNode = BallerinaPsiImplUtil.resolveAnonymousStruct(identifier);
if (definitionNode == null) {
return results;
}
if (definitionNode instanceof AnonStructTypeNameNode) {
StructBodyNode structBodyNode = PsiTreeUtil.findChildOfType(definitionNode, StructBodyNode.class);
if (structBodyNode == null) {
return results;
}
List<FieldDefinitionNode> fieldDefinitionNodes = PsiTreeUtil.getChildrenOfTypeAsList(structBodyNode, FieldDefinitionNode.class);
results = BallerinaCompletionUtils.createFieldLookupElements(fieldDefinitionNodes, PackageCompletionInsertHandler.INSTANCE_WITH_AUTO_POPUP);
return results;
}
structDefinitionNode = ((StructDefinitionNode) definitionNode);
IdentifierPSINode structNameNode = PsiTreeUtil.getChildOfType(structDefinitionNode, IdentifierPSINode.class);
if (structNameNode == null) {
return results;
}
Collection<FieldDefinitionNode> fieldDefinitionNodes = PsiTreeUtil.findChildrenOfType(structDefinitionNode, FieldDefinitionNode.class);
results = BallerinaCompletionUtils.createFieldLookupElements(fieldDefinitionNodes, structNameNode, PackageCompletionInsertHandler.INSTANCE_WITH_AUTO_POPUP);
return results;
}
IdentifierPSINode structNameNode = PsiTreeUtil.getChildOfType(structDefinitionNode, IdentifierPSINode.class);
if (structNameNode == null) {
return results;
}
Collection<FieldDefinitionNode> fieldDefinitionNodes = PsiTreeUtil.findChildrenOfType(structDefinitionNode, FieldDefinitionNode.class);
results = BallerinaCompletionUtils.createFieldLookupElements(fieldDefinitionNodes, structNameNode, PackageCompletionInsertHandler.INSTANCE_WITH_AUTO_POPUP);
} else {
TypeNameNode typeNameNode = PsiTreeUtil.getChildOfType(variableDefinitionNode, TypeNameNode.class);
if (typeNameNode == null) {
return results;
} else {
PsiReference reference = typeNameNode.findReferenceAt(typeNameNode.getTextLength());
if (reference == null) {
return results;
}
PsiElement resolvedElement = reference.resolve();
if (resolvedElement == null) {
return results;
}
PsiElement resolvedElementParent = resolvedElement.getParent();
if (!(resolvedElementParent instanceof StructDefinitionNode)) {
return results;
}
StructBodyNode structBodyNode = PsiTreeUtil.getChildOfType(resolvedElementParent, StructBodyNode.class);
if (structBodyNode == null) {
return results;
}
Collection<FieldDefinitionNode> fieldDefinitionNodes;
if (isInSamePackage(identifier, resolvedElement)) {
fieldDefinitionNodes = PsiTreeUtil.findChildrenOfType(structBodyNode, FieldDefinitionNode.class);
} else {
fieldDefinitionNodes = PsiTreeUtil.getChildrenOfTypeAsList(structBodyNode, FieldDefinitionNode.class);
}
results = BallerinaCompletionUtils.createFieldLookupElements(fieldDefinitionNodes, (IdentifierPSINode) resolvedElement, PackageCompletionInsertHandler.INSTANCE_WITH_AUTO_POPUP);
}
}
return results;
}
use of org.ballerinalang.plugins.idea.psi.VariableDefinitionNode in project ballerina by ballerina-lang.
the class FieldReference method resolve.
@Nullable
@Override
public PsiElement resolve() {
// Get the current element.
IdentifierPSINode identifier = getElement();
// Get the parent element.
PsiElement parent = identifier.getParent();
PsiElement prevSibling;
// resolve multi level structs. Eg: user.name.<caret>
if (parent instanceof StatementNode) {
// Get the previous element.
PsiElement prevVisibleLeaf = PsiTreeUtil.prevVisibleLeaf(parent);
if (prevVisibleLeaf == null) {
return null;
}
// Previous leaf element should be "." if the references are correctly defined.
if (!".".equals(prevVisibleLeaf.getText())) {
return null;
}
// Get the prevSibling. This is used to resolve the current field.
prevSibling = PsiTreeUtil.prevVisibleLeaf(prevVisibleLeaf);
if (prevSibling == null) {
return null;
}
} else if (parent instanceof NameReferenceNode) {
prevSibling = PsiTreeUtil.prevVisibleLeaf(parent);
if (prevSibling != null && ".".equals(prevSibling.getText())) {
prevSibling = PsiTreeUtil.prevVisibleLeaf(prevSibling);
}
} else {
PsiElement parentPrevSibling = parent.getPrevSibling();
if (parentPrevSibling != null) {
if (parentPrevSibling instanceof VariableReferenceNode) {
PsiElement[] children = parentPrevSibling.getChildren();
if (children.length <= 0) {
return null;
}
PsiElement firstChild = children[0].getFirstChild();
if (firstChild == null) {
return null;
}
prevSibling = firstChild;
} else {
return null;
}
} else {
// If the current statement is correctly resolved, that means all the fields are identified properly.
// Get the prevSibling. This is used to resolve the current field.
prevSibling = PsiTreeUtil.prevVisibleLeaf(parent);
}
}
// If the prevSibling is null, we return from this method because we cannot resolve the element.
if (prevSibling == null) {
return null;
}
// We get the reference at end. This is because struct field access can be multiple levels deep.
// Eg: user.name.first - If the current node is 'first', then the previous node will be 'user.name'. If
// we get the reference at the beginning, we we get the reference for 'user'. But we want to resolve the
// 'name' field first. That is why we get the reference at the end.
PsiReference variableReference = prevSibling.findReferenceAt(prevSibling.getTextLength());
if (variableReference == null) {
return null;
}
// Resolve the reference. The resolved element can be an identifier of either a struct of a field
// depending on the current node.
// Eg: user.name.firstName - If the current node is 'name', resolved element will be a struct definition. if
// the current element is 'firstName', then the resolved element will be a field definition.
PsiElement resolvedElement = variableReference.resolve();
if (resolvedElement == null || !(resolvedElement instanceof IdentifierPSINode)) {
return null;
}
// Get the parent of the resolved element.
PsiElement resolvedElementParent = resolvedElement.getParent();
StructDefinitionNode structDefinitionNode = null;
// Resolve the corresponding resolvedElementParent to get the struct definition.
if (resolvedElementParent instanceof VariableDefinitionNode || resolvedElementParent instanceof CodeBlockParameterNode || resolvedElementParent instanceof ParameterNode) {
// Resolve the Type of the VariableDefinitionNode to get the corresponding struct.
// Eg: User user = {}
// In here, "User" is resolved and struct identifier is returned.
structDefinitionNode = BallerinaPsiImplUtil.resolveStructFromDefinitionNode(resolvedElementParent);
} else if (resolvedElementParent instanceof FieldDefinitionNode) {
// If the resolvedElementParent is of type FieldDefinitionNode, that means we need to resolve the type of
// the field to get the struct definition.
// Eg: user.name.firstName - In here, if we want to resolve the 'firstName' we will get the 'Name name;'
// field. So we need to resolve the type of the field which is 'Name'. Then we will get the Name struct.
// Then we need to get the 'firstName' field from that.
structDefinitionNode = BallerinaPsiImplUtil.resolveTypeNodeStruct((resolvedElementParent));
} else if (resolvedElementParent instanceof NameReferenceNode) {
structDefinitionNode = BallerinaPsiImplUtil.findStructDefinition((IdentifierPSINode) resolvedElement);
} else if (resolvedElementParent instanceof EnumDefinitionNode) {
return ((EnumDefinitionNode) resolvedElementParent).resolve(identifier);
}
if (structDefinitionNode == null) {
return null;
}
// Resolve the field and return the resolved element.
return structDefinitionNode.resolve(identifier);
}
Aggregations