blob: 0fbb0f946c995d5b5e86db4f2a3b6da4ccef9d13 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.codeInsight;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.*;
import com.intellij.psi.util.QualifiedName;
import com.jetbrains.python.psi.resolve.QualifiedNameResolver;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public abstract class PyPsiPath {
@Nullable
public abstract PsiElement resolve(PsiElement module);
public static class ToFile extends PyPsiPath {
private final QualifiedName myQualifiedName;
public ToFile(String qualifiedName) {
myQualifiedName = QualifiedName.fromDottedString(qualifiedName);
}
@Nullable
@Override
public PsiElement resolve(PsiElement context) {
PyPsiFacade pyPsiFacade = PyPsiFacade.getInstance(context.getProject());
QualifiedNameResolver visitor = pyPsiFacade.qualifiedNameResolver(myQualifiedName).fromElement(context);
return visitor.firstResult();
}
}
public static class ToClassQName extends PyPsiPath {
private final QualifiedName myQualifiedName;
public ToClassQName(String qualifiedName) {
myQualifiedName = QualifiedName.fromDottedString(qualifiedName);
}
@Nullable
@Override
public PsiElement resolve(PsiElement context) {
return PyPsiFacade.getInstance(context.getProject()).findClass(myQualifiedName.toString());
}
}
public static class ToClass extends PyPsiPath {
private final PyPsiPath myParent;
private final String myClassName;
public ToClass(PyPsiPath parent, String className) {
myParent = parent;
myClassName = className;
}
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (parent == null) {
return null;
}
if (parent instanceof PyFile) {
return ((PyFile) parent).findTopLevelClass(myClassName);
}
if (parent instanceof PyClass) {
for (PsiElement element : parent.getChildren()) {
if (element instanceof PyClass && myClassName.equals(((PyClass)element).getName())) {
return element;
}
}
}
ClassFinder finder = new ClassFinder(myClassName);
parent.acceptChildren(finder);
return finder.myResult != null ? finder.myResult : parent;
}
}
private static class ClassFinder extends PyRecursiveElementVisitor {
private final String myName;
private PyClass myResult;
public ClassFinder(String name) {
myName = name;
}
@Override
public void visitPyClass(PyClass node) {
super.visitPyClass(node);
if (myName.equals(node.getName())) {
myResult = node;
}
}
}
public static class ToFunction extends PyPsiPath {
private final PyPsiPath myParent;
private final String myFunctionName;
public ToFunction(PyPsiPath parent, String functionName) {
myParent = parent;
myFunctionName = functionName;
}
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (parent == null) {
return null;
}
if (parent instanceof PyFile) {
return ((PyFile) parent).findTopLevelFunction(myFunctionName);
}
if (parent instanceof PyClass) {
return ((PyClass) parent).findMethodByName(myFunctionName, false);
}
for (PsiElement element : parent.getChildren()) {
if (element instanceof PyFunction && myFunctionName.equals(((PyFunction)element).getName())) {
return element;
}
}
return parent;
}
}
private static class FunctionFinder extends PyRecursiveElementVisitor {
private final String myName;
private PyFunction myResult;
public FunctionFinder(String name) {
myName = name;
}
@Override
public void visitPyFunction(PyFunction node) {
super.visitPyFunction(node);
if (myName.equals(node.getName())) {
myResult = node;
}
}
}
public static class ToFunctionRecursive extends PyPsiPath {
private final PyPsiPath myParent;
private final String myFunctionName;
public ToFunctionRecursive(PyPsiPath parent, String functionName) {
myParent = parent;
myFunctionName = functionName;
}
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (parent == null) {
return null;
}
FunctionFinder finder = new FunctionFinder(myFunctionName);
parent.acceptChildren(finder);
return finder.myResult != null ? finder.myResult : parent;
}
}
public static class ToClassAttribute extends PyPsiPath {
private final PyPsiPath myParent;
private final String myAttributeName;
public ToClassAttribute(PyPsiPath parent, String attributeName) {
myAttributeName = attributeName;
myParent = parent;
}
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (!(parent instanceof PyClass)) {
return null;
}
return ((PyClass)parent).findClassAttribute(myAttributeName, true);
}
}
public static class ToCall extends PyPsiPath {
private final PyPsiPath myParent;
private final String myCallName;
private final String[] myArgs;
public ToCall(PyPsiPath parent, String callName, String... args) {
myParent = parent;
myCallName = callName;
myArgs = args;
}
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (parent == null) {
return null;
}
CallFinder finder = new CallFinder(myCallName, myArgs);
parent.accept(finder);
return finder.myResult != null ? finder.myResult : parent;
}
}
private static class CallFinder extends PyRecursiveElementVisitor {
private PsiElement myResult;
private final String myCallName;
private final String[] myArgs;
public CallFinder(String callName, String[] args) {
myCallName = callName;
myArgs = args;
}
@Override
public void visitPyCallExpression(PyCallExpression node) {
if (myResult != null) {
return;
}
super.visitPyCallExpression(node);
final PyExpression callee = node.getCallee();
if (callee instanceof PyReferenceExpression) {
String calleeName = ((PyReferenceExpression) callee).getReferencedName();
if (myCallName.equals(calleeName)) {
final PyExpression[] args = node.getArguments();
if (myArgs.length <= args.length) {
boolean argsMatch = true;
for (int i = 0; i < myArgs.length; i++) {
if (!(args[i] instanceof PyStringLiteralExpression) ||
!myArgs [i].equals(((PyStringLiteralExpression)args[i]).getStringValue())) {
argsMatch = false;
break;
}
}
if (argsMatch) {
myResult = node;
}
}
}
}
}
}
public static class ToAssignment extends PyPsiPath {
private final PyPsiPath myParent;
private final String myAssignee;
public ToAssignment(PyPsiPath parent, String assignee) {
myParent = parent;
myAssignee = assignee;
}
@Nullable
@Override
public PsiElement resolve(PsiElement context) {
PsiElement parent = myParent.resolve(context);
if (parent == null) {
return null;
}
AssignmentFinder finder = new AssignmentFinder(myAssignee);
parent.accept(finder);
return finder.myResult != null ? finder.myResult : parent;
}
}
private static class AssignmentFinder extends PyRecursiveElementVisitor {
private final String myAssignee;
private PsiElement myResult;
public AssignmentFinder(String assignee) {
myAssignee = assignee;
}
@Override
public void visitPyAssignmentStatement(PyAssignmentStatement node) {
PyExpression lhs = node.getLeftHandSideExpression();
if (lhs != null && myAssignee.equals(lhs.getText())) {
myResult = node;
}
}
}
}