blob: abaca2d9151b265fd002d0c2d6a39d7baa314517 [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.psi.impl.references;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author vlan
*/
public class PyOperatorReference extends PyReferenceImpl {
public PyOperatorReference(PyQualifiedExpression element, @NotNull PyResolveContext context) {
super(element, context);
}
@NotNull
@Override
protected List<RatedResolveResult> resolveInner() {
List<RatedResolveResult> res = new ArrayList<RatedResolveResult>();
if (myElement instanceof PyBinaryExpression) {
final PyBinaryExpression expr = (PyBinaryExpression)myElement;
final String name = expr.getReferencedName();
if (PyNames.CONTAINS.equals(name)) {
res = resolveMember(expr.getRightExpression(), name);
}
else {
if (PyNames.DIV.equals(name) && isTrueDivEnabled(myElement)) {
resolveLeftAndRightOperators(res, expr, PyNames.TRUEDIV);
}
resolveLeftAndRightOperators(res, expr, name);
}
}
else if (myElement instanceof PySubscriptionExpression) {
final PySubscriptionExpression expr = (PySubscriptionExpression)myElement;
res = resolveMember(expr.getOperand(), expr.getReferencedName());
}
else if (myElement instanceof PyPrefixExpression) {
final PyPrefixExpression expr = (PyPrefixExpression)myElement;
res = resolveMember(expr.getOperand(), expr.getReferencedName());
}
return res;
}
@Override
public boolean isReferenceTo(PsiElement element) {
if (element instanceof PyParameter || element instanceof PyTargetExpression) {
return false;
}
return super.isReferenceTo(element);
}
@Override
public String toString() {
return "PyOperatorReference(" + myElement + "," + myContext + ")";
}
public String getReadableOperatorName() {
final String name = myElement.getReferencedName();
if (PyNames.SUBSCRIPTION_OPERATORS.contains(name)) {
return "[]";
}
else {
return getRangeInElement().substring(myElement.getText());
}
}
@Nullable
public PyExpression getReceiver() {
if (myElement instanceof PyBinaryExpression) {
return ((PyBinaryExpression)myElement).getLeftExpression();
}
else if (myElement instanceof PySubscriptionExpression) {
return ((PySubscriptionExpression)myElement).getOperand();
}
else if (myElement instanceof PyPrefixExpression) {
return ((PyPrefixExpression)myElement).getOperand();
}
return null;
}
private static String leftToRightOperatorName(String name) {
return name.replaceFirst("__([a-z]+)__", "__r$1__");
}
private static boolean isTrueDivEnabled(@NotNull PyElement anchor) {
final PsiFile file = anchor.getContainingFile();
if (file instanceof PyFile) {
final PyFile pyFile = (PyFile)file;
return FutureFeature.DIVISION.requiredAt(pyFile.getLanguageLevel()) || pyFile.hasImportFromFuture(FutureFeature.DIVISION);
}
return false;
}
private void resolveLeftAndRightOperators(List<RatedResolveResult> res, PyBinaryExpression expr, String name) {
final TypeEvalContext typeEvalContext = myContext.getTypeEvalContext();
typeEvalContext.trace("Trying to resolve left operator");
typeEvalContext.traceIndent();
try {
res.addAll(resolveMember(expr.getLeftExpression(), name));
}
finally {
typeEvalContext.traceUnindent();
}
typeEvalContext.trace("Trying to resolve right operator");
typeEvalContext.traceIndent();
try {
res.addAll(resolveMember(expr.getRightExpression(), leftToRightOperatorName(name)));
}
finally {
typeEvalContext.traceUnindent();
}
}
@NotNull
private List<RatedResolveResult> resolveMember(@Nullable PyExpression object, @Nullable String name) {
final ArrayList<RatedResolveResult> results = new ArrayList<RatedResolveResult>();
if (object != null && name != null) {
final TypeEvalContext typeEvalContext = myContext.getTypeEvalContext();
final PyType type = typeEvalContext.getType(object);
typeEvalContext.trace("Side text is %s, type is %s", object.getText(), type);
if (type != null) {
List<? extends RatedResolveResult> res = type.resolveMember(name, object, AccessDirection.of(myElement), myContext);
if (res != null && res.size() > 0) {
results.addAll(res);
}
else if (typeEvalContext.tracing()) {
VirtualFile vFile = null;
if (type instanceof PyClassType) {
final PyClass pyClass = ((PyClassType)type).getPyClass();
vFile = pyClass.getContainingFile().getVirtualFile();
}
type.resolveMember(name, object, AccessDirection.of(myElement), myContext);
typeEvalContext.trace("Could not resolve member %s in type %s from file %s", name, type, vFile);
}
}
}
return results;
}
}