Search in sources :

Example 1 with VariableDefinitionNode

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.&lt;caret&gt;);
 * }
 *
 * 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;
}
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) Nullable(org.jetbrains.annotations.Nullable)

Example 2 with VariableDefinitionNode

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;
}
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 VariableDefinitionNode

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;
}
Also used : VariableDefinitionNode(org.ballerinalang.plugins.idea.psi.VariableDefinitionNode) GlobalVariableDefinitionNode(org.ballerinalang.plugins.idea.psi.GlobalVariableDefinitionNode) AssignmentStatementNode(org.ballerinalang.plugins.idea.psi.AssignmentStatementNode) StructDefinitionNode(org.ballerinalang.plugins.idea.psi.StructDefinitionNode) IdentifierPSINode(org.ballerinalang.plugins.idea.psi.IdentifierPSINode) FieldDefinitionNode(org.ballerinalang.plugins.idea.psi.FieldDefinitionNode) StructBodyNode(org.ballerinalang.plugins.idea.psi.StructBodyNode) AnonStructTypeNameNode(org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode) GlobalVariableDefinitionNode(org.ballerinalang.plugins.idea.psi.GlobalVariableDefinitionNode) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable)

Example 4 with VariableDefinitionNode

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;
}
Also used : PsiReference(com.intellij.psi.PsiReference) LookupElement(com.intellij.codeInsight.lookup.LookupElement) InvocationNode(org.ballerinalang.plugins.idea.psi.InvocationNode) AnonStructTypeNameNode(org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode) LinkedList(java.util.LinkedList) VariableDefinitionNode(org.ballerinalang.plugins.idea.psi.VariableDefinitionNode) GlobalVariableDefinitionNode(org.ballerinalang.plugins.idea.psi.GlobalVariableDefinitionNode) StructDefinitionNode(org.ballerinalang.plugins.idea.psi.StructDefinitionNode) TypeNameNode(org.ballerinalang.plugins.idea.psi.TypeNameNode) AnonStructTypeNameNode(org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode) IdentifierPSINode(org.ballerinalang.plugins.idea.psi.IdentifierPSINode) FieldDefinitionNode(org.ballerinalang.plugins.idea.psi.FieldDefinitionNode) StructBodyNode(org.ballerinalang.plugins.idea.psi.StructBodyNode) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 5 with VariableDefinitionNode

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);
}
Also used : VariableDefinitionNode(org.ballerinalang.plugins.idea.psi.VariableDefinitionNode) ParameterNode(org.ballerinalang.plugins.idea.psi.ParameterNode) CodeBlockParameterNode(org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode) StructDefinitionNode(org.ballerinalang.plugins.idea.psi.StructDefinitionNode) IdentifierPSINode(org.ballerinalang.plugins.idea.psi.IdentifierPSINode) VariableReferenceNode(org.ballerinalang.plugins.idea.psi.VariableReferenceNode) PsiReference(com.intellij.psi.PsiReference) AssignmentStatementNode(org.ballerinalang.plugins.idea.psi.AssignmentStatementNode) StatementNode(org.ballerinalang.plugins.idea.psi.StatementNode) FieldDefinitionNode(org.ballerinalang.plugins.idea.psi.FieldDefinitionNode) EnumDefinitionNode(org.ballerinalang.plugins.idea.psi.EnumDefinitionNode) PsiElement(com.intellij.psi.PsiElement) NameReferenceNode(org.ballerinalang.plugins.idea.psi.NameReferenceNode) CodeBlockParameterNode(org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode) Nullable(org.jetbrains.annotations.Nullable)

Aggregations

VariableDefinitionNode (org.ballerinalang.plugins.idea.psi.VariableDefinitionNode)14 PsiElement (com.intellij.psi.PsiElement)12 PsiReference (com.intellij.psi.PsiReference)10 IdentifierPSINode (org.ballerinalang.plugins.idea.psi.IdentifierPSINode)10 GlobalVariableDefinitionNode (org.ballerinalang.plugins.idea.psi.GlobalVariableDefinitionNode)9 AssignmentStatementNode (org.ballerinalang.plugins.idea.psi.AssignmentStatementNode)8 FieldDefinitionNode (org.ballerinalang.plugins.idea.psi.FieldDefinitionNode)8 ParameterNode (org.ballerinalang.plugins.idea.psi.ParameterNode)8 StructDefinitionNode (org.ballerinalang.plugins.idea.psi.StructDefinitionNode)8 CodeBlockParameterNode (org.ballerinalang.plugins.idea.psi.CodeBlockParameterNode)6 NotNull (org.jetbrains.annotations.NotNull)6 Nullable (org.jetbrains.annotations.Nullable)6 LinkedList (java.util.LinkedList)5 LookupElement (com.intellij.codeInsight.lookup.LookupElement)4 AnonStructTypeNameNode (org.ballerinalang.plugins.idea.psi.AnonStructTypeNameNode)4 NameReferenceNode (org.ballerinalang.plugins.idea.psi.NameReferenceNode)4 TypeNameNode (org.ballerinalang.plugins.idea.psi.TypeNameNode)4 VariableReferenceNode (org.ballerinalang.plugins.idea.psi.VariableReferenceNode)4 LeafPsiElement (com.intellij.psi.impl.source.tree.LeafPsiElement)3 Collection (java.util.Collection)3