blob: 84ae5151e9822ac123a802fd09f819b5e47b12f6 [file] [log] [blame]
/*
* Copyright 2007-2010 Bas Leijdekkers
*
* 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.siyeh.ig.internationalization;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
public class NonNlsUtils {
private static final Key<Boolean> KEY = new Key("IG_NON_NLS_ANNOTATED_USE");
private NonNlsUtils() {
}
@Nullable
public static PsiModifierListOwner getAnnotatableArgument(
PsiMethodCallExpression methodCallExpression) {
final PsiExpressionList argumentList =
methodCallExpression.getArgumentList();
final PsiExpression[] arguments = argumentList.getExpressions();
if (arguments.length < 1) {
return null;
}
final PsiExpression argument = arguments[0];
if (argument instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)argument;
final PsiElement element = referenceExpression.resolve();
if (element instanceof PsiModifierListOwner) {
return (PsiModifierListOwner)element;
}
}
return null;
}
@Nullable
public static PsiModifierListOwner getAnnotatableQualifier(
PsiReferenceExpression expression) {
final PsiExpression qualifierExpression =
expression.getQualifierExpression();
if (qualifierExpression instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)qualifierExpression;
final PsiElement element = referenceExpression.resolve();
if (element instanceof PsiModifierListOwner) {
return (PsiModifierListOwner)element;
}
}
return null;
}
public static boolean isNonNlsAnnotated(
@Nullable PsiExpression expression) {
if (isReferenceToNonNlsAnnotatedElement(expression)) {
return true;
}
if (expression instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression)expression;
final PsiMethod method = methodCallExpression.resolveMethod();
if (isNonNlsAnnotatedModifierListOwner(method)) {
return true;
}
final PsiReferenceExpression methodExpression =
methodCallExpression.getMethodExpression();
final PsiExpression qualifier =
methodExpression.getQualifierExpression();
return isNonNlsAnnotated(qualifier);
}
else if (expression instanceof PsiArrayAccessExpression) {
final PsiArrayAccessExpression arrayAccessExpression =
(PsiArrayAccessExpression)expression;
final PsiExpression arrayExpression =
arrayAccessExpression.getArrayExpression();
return isNonNlsAnnotated(arrayExpression);
}
return false;
}
public static boolean isNonNlsAnnotatedUse(
@Nullable PsiExpression expression) {
if (expression == null) {
return false;
}
final Boolean value = getCachedValue(expression, KEY);
if (value != null) {
return value.booleanValue();
}
final PsiElement element =
PsiTreeUtil.getParentOfType(expression,
PsiExpressionList.class,
PsiAssignmentExpression.class,
PsiVariable.class,
PsiReturnStatement.class);
final boolean result;
if (element instanceof PsiExpressionList) {
final PsiExpressionList expressionList =
(PsiExpressionList)element;
result = isNonNlsAnnotatedParameter(expression, expressionList);
}
else if (element instanceof PsiVariable) {
result = isNonNlsAnnotatedModifierListOwner(element);
}
else if (element instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression =
(PsiAssignmentExpression)element;
result =
isAssignmentToNonNlsAnnotatedVariable(assignmentExpression);
}
else if (element instanceof PsiReturnStatement) {
final PsiMethod method =
PsiTreeUtil.getParentOfType(element, PsiMethod.class);
result = isNonNlsAnnotatedModifierListOwner(method);
}
else {
result = false;
}
putCachedValue(expression, KEY, Boolean.valueOf(result));
return result;
}
private static <T> void putCachedValue(PsiExpression expression,
Key<T> key, T value) {
if (expression instanceof PsiBinaryExpression) {
expression.putUserData(key, value);
}
}
@Nullable
private static <T> T getCachedValue(PsiExpression expression, Key<T> key) {
final T data = expression.getUserData(key);
if (!(expression instanceof PsiBinaryExpression)) {
return data;
}
final PsiBinaryExpression binaryExpression =
(PsiBinaryExpression)expression;
final PsiExpression lhs = binaryExpression.getLOperand();
T childData = null;
if (lhs instanceof PsiBinaryExpression) {
childData = lhs.getUserData(key);
}
if (childData == null) {
final PsiExpression rhs = binaryExpression.getROperand();
if (rhs instanceof PsiBinaryExpression) {
childData = rhs.getUserData(key);
}
}
if (childData != data) {
expression.putUserData(key, childData);
}
return childData;
}
private static boolean isAssignmentToNonNlsAnnotatedVariable(
PsiAssignmentExpression assignmentExpression) {
final PsiExpression lhs = assignmentExpression.getLExpression();
return isReferenceToNonNlsAnnotatedElement(lhs);
}
private static boolean isReferenceToNonNlsAnnotatedElement(
@Nullable PsiExpression expression) {
if (!(expression instanceof PsiReferenceExpression)) {
return false;
}
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)expression;
final PsiElement target = referenceExpression.resolve();
return isNonNlsAnnotatedModifierListOwner(target);
}
private static boolean isNonNlsAnnotatedParameter(
PsiExpression expression,
PsiExpressionList expressionList) {
final PsiElement parent = expressionList.getParent();
final PsiParameterList parameterList;
if (parent instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression =
(PsiMethodCallExpression)parent;
if (isQualifierNonNlsAnnotated(methodCallExpression)) {
return true;
}
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) {
return false;
}
parameterList = method.getParameterList();
}
else if (parent instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)parent;
final PsiMethod constructor = newExpression.resolveConstructor();
if (constructor == null) {
return false;
}
parameterList = constructor.getParameterList();
}
else {
return false;
}
final PsiExpression[] expressions = expressionList.getExpressions();
int index = -1;
for (int i = 0; i < expressions.length; i++) {
final PsiExpression argument = expressions[i];
if (PsiTreeUtil.isAncestor(argument, expression, false)) {
index = i;
}
}
final PsiParameter[] parameters = parameterList.getParameters();
if (parameters.length == 0) {
return false;
}
final PsiParameter parameter;
if (index < parameters.length) {
parameter = parameters[index];
}
else {
parameter = parameters[parameters.length - 1];
}
return isNonNlsAnnotatedModifierListOwner(parameter);
}
private static boolean isQualifierNonNlsAnnotated(
PsiMethodCallExpression methodCallExpression) {
final PsiReferenceExpression methodExpression =
methodCallExpression.getMethodExpression();
final PsiExpression qualifier =
methodExpression.getQualifierExpression();
if (isReferenceToNonNlsAnnotatedElement(qualifier)) {
return true;
}
if (qualifier instanceof PsiMethodCallExpression) {
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) {
return false;
}
if (isChainable(method)) {
final PsiMethodCallExpression expression =
(PsiMethodCallExpression)qualifier;
if (isQualifierNonNlsAnnotated(expression)) {
return true;
}
}
}
return false;
}
private static boolean isChainable(PsiMethod method) {
if (method == null) {
return false;
}
method = (PsiMethod)method.getNavigationElement();
final PsiCodeBlock body = method.getBody();
if (body == null) {
return false;
}
final PsiStatement[] statements = body.getStatements();
if (statements.length == 0) {
return false;
}
final PsiStatement lastStatement = statements[statements.length - 1];
if (!(lastStatement instanceof PsiReturnStatement)) {
return false;
}
final PsiReturnStatement returnStatement =
(PsiReturnStatement)lastStatement;
final PsiExpression returnValue = returnStatement.getReturnValue();
return returnValue instanceof PsiThisExpression;
}
private static boolean isNonNlsAnnotatedModifierListOwner(
@Nullable PsiElement element) {
if (!(element instanceof PsiModifierListOwner)) {
return false;
}
final PsiModifierListOwner variable = (PsiModifierListOwner)element;
return AnnotationUtil.isAnnotated(variable,
AnnotationUtil.NON_NLS, false, false);
}
}