blob: bf75b982cb4e5cfa150dc998670fe6862e43ebcc [file] [log] [blame]
/*
* Copyright 2000-2014 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 org.jetbrains.plugins.groovy.lang.psi.util;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.impl.light.JavaIdentifier;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import gnu.trove.TIntStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocComment;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyLexer;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
import org.jetbrains.plugins.groovy.lang.psi.*;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrSpreadArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrAssertStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrForInClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrPropertySelection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrNamedArgumentsOwner;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.*;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
import java.util.*;
/**
* @author ven
*/
public class PsiUtil {
public static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil");
public static final Key<JavaIdentifier> NAME_IDENTIFIER = new Key<JavaIdentifier>("Java Identifier");
public static final Set<String> OPERATOR_METHOD_NAMES = ContainerUtil.newHashSet(
"plus", "minus", "multiply", "power", "div", "mod", "or", "and", "xor", "next", "previous", "getAt", "putAt", "leftShift", "rightShift",
"isCase", "bitwiseNegate", "negative", "positive", "call"
);
private PsiUtil() {
}
@Nullable
public static PsiElement findModifierInList(@NotNull GrModifierList list, @GrModifier.GrModifierConstant @NotNull String modifier) {
for (PsiElement element : list.getModifiers()) {
if (modifier.equals(element.getText())) return element;
}
return null;
}
@Nullable
public static String getMethodName(GrMethodCall methodCall) {
GrExpression invokedExpression = methodCall.getInvokedExpression();
if (!(invokedExpression instanceof GrReferenceExpression)) return null;
return ((GrReferenceExpression)invokedExpression).getReferenceName();
}
@Nullable
public static String getUnqualifiedMethodName(GrMethodCall methodCall) {
GrExpression invokedExpression = methodCall.getInvokedExpression();
if (!(invokedExpression instanceof GrReferenceExpression)) return null;
if (((GrReferenceExpression)invokedExpression).isQualified()) return null;
return ((GrReferenceExpression)invokedExpression).getReferenceName();
}
@Nullable
public static String getQualifiedReferenceText(GrCodeReferenceElement referenceElement) {
StringBuilder builder = new StringBuilder();
if (!appendName(referenceElement, builder)) return null;
return builder.toString();
}
private static boolean appendName(GrCodeReferenceElement referenceElement, StringBuilder builder) {
String refName = referenceElement.getReferenceName();
if (refName == null) return false;
GrCodeReferenceElement qualifier = referenceElement.getQualifier();
if (qualifier != null) {
appendName(qualifier, builder);
builder.append(".");
}
builder.append(refName);
return true;
}
public static boolean isLValue(GroovyPsiElement element) {
if (element instanceof GrExpression) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class);
if (parent instanceof GrTupleExpression) {
return isLValue((GroovyPsiElement)parent);
}
return parent instanceof GrAssignmentExpression &&
PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false);
}
return false;
}
public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
PsiMethod method,
PsiSubstitutor substitutor,
PsiElement place,
final boolean eraseParameterTypes) {
return isApplicableConcrete(argumentTypes, method, substitutor, place, eraseParameterTypes) !=
GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
}
public static GrClosureSignatureUtil.ApplicabilityResult isApplicableConcrete(@Nullable PsiType[] argumentTypes,
PsiMethod method,
PsiSubstitutor substitutor,
PsiElement place,
final boolean eraseParameterTypes) {
if (argumentTypes == null) return GrClosureSignatureUtil.ApplicabilityResult.canBeApplicable;
GrClosureSignature signature = eraseParameterTypes
? GrClosureSignatureUtil.createSignatureWithErasedParameterTypes(method)
: GrClosureSignatureUtil.createSignature(method, substitutor);
//check for default constructor
if (method.isConstructor()) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == 0 && argumentTypes.length == 1) {
return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP)
? GrClosureSignatureUtil.ApplicabilityResult.applicable
: GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
}
if (parameters.length == 1 &&
argumentTypes.length == 0 &&
InheritanceUtil.isInheritor(parameters[0].getType(), CommonClassNames.JAVA_UTIL_MAP)) {
return GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
}
}
LOG.assertTrue(signature != null);
GrClosureSignatureUtil.ApplicabilityResult result =
GrClosureSignatureUtil.isSignatureApplicableConcrete(signature, argumentTypes, place);
if (result != GrClosureSignatureUtil.ApplicabilityResult.inapplicable) {
return result;
}
if (method instanceof GrBuilderMethod && !((GrBuilderMethod)method).hasObligatoryNamedArguments()) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length > 0 && parameters[0].getType() instanceof GrMapType &&
(argumentTypes.length == 0 || !(argumentTypes[0] instanceof GrMapType))) {
return GrClosureSignatureUtil.isSignatureApplicableConcrete(GrClosureSignatureUtil.removeParam(signature, 0), argumentTypes, place);
}
}
return GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
}
public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
GrClosureType type,
GroovyPsiElement context) {
return isApplicableConcrete(argumentTypes, type, context) != GrClosureSignatureUtil.ApplicabilityResult.inapplicable;
}
public static GrClosureSignatureUtil.ApplicabilityResult isApplicableConcrete(@Nullable PsiType[] argumentTypes,
GrClosureType type,
GroovyPsiElement context) {
if (argumentTypes == null) return GrClosureSignatureUtil.ApplicabilityResult.canBeApplicable;
GrSignature signature = type.getSignature();
return GrClosureSignatureUtil.isSignatureApplicableConcrete(signature, argumentTypes, context);
}
@Nullable
public static GrArgumentList getArgumentsList(@Nullable PsiElement methodRef) {
if (methodRef == null) return null;
if (methodRef instanceof GrEnumConstant) return ((GrEnumConstant)methodRef).getArgumentList();
PsiElement parent = methodRef.getParent();
if (parent instanceof GrCall) {
return ((GrCall)parent).getArgumentList();
}
if (parent instanceof GrAnonymousClassDefinition) {
return ((GrAnonymousClassDefinition)parent).getArgumentListGroovy();
}
return null;
}
@Nullable
public static PsiType[] getArgumentTypes(@Nullable PsiElement place, boolean nullAsBottom) {
return getArgumentTypes(place, nullAsBottom, null, false);
}
@Nullable
public static PsiType[] getArgumentTypes(@Nullable PsiElement place,
boolean nullAsBottom,
@Nullable GrExpression stopAt,
boolean byShape) {
PsiElement parent = place instanceof GrEnumConstant ? place : place != null ? place.getParent() : null;
if (parent instanceof GrIndexProperty) {
GrIndexProperty index = (GrIndexProperty)parent;
PsiType[] argTypes = getArgumentTypes(index.getNamedArguments(), index.getExpressionArguments(), index.getClosureArguments(), nullAsBottom, stopAt, byShape);
if (isLValue(index) && argTypes != null) {
PsiType rawInitializer = TypeInferenceHelper.getInitializerTypeFor(index);
PsiType initializer = notNullizeType(rawInitializer, nullAsBottom, index);
return ArrayUtil.append(argTypes, initializer);
}
else {
return argTypes;
}
}
if (parent instanceof GrCall) {
GrCall call = (GrCall)parent;
GrNamedArgument[] namedArgs = call.getNamedArguments();
GrExpression[] expressions = call.getExpressionArguments();
GrClosableBlock[] closures = call.getClosureArguments();
return getArgumentTypes(namedArgs, expressions, closures, nullAsBottom, stopAt, byShape);
}
else if (parent instanceof GrAnonymousClassDefinition) {
final GrArgumentList argList = ((GrAnonymousClassDefinition)parent).getArgumentListGroovy();
if (argList == null) {
return getArgumentTypes(GrNamedArgument.EMPTY_ARRAY, GrExpression.EMPTY_ARRAY, GrClosableBlock.EMPTY_ARRAY, nullAsBottom, stopAt, byShape);
}
else {
return getArgumentTypes(argList.getNamedArguments(), argList.getExpressionArguments(), GrClosableBlock.EMPTY_ARRAY, nullAsBottom, stopAt, byShape);
}
}
else if (parent instanceof GrBinaryExpression) {
GrExpression right = ((GrBinaryExpression)parent).getRightOperand();
PsiType type = right != null ? right.getType() : null;
return new PsiType[] {notNullizeType(type, nullAsBottom, parent)};
}
return null;
}
@Contract("_, false, _ -> !null; !null, _, _ -> !null; null, true, _ -> null")
private static PsiType notNullizeType(PsiType type, boolean acceptNull, PsiElement context) {
return type != null || acceptNull ? type : TypesUtil.getJavaLangObject(context);
}
@Nullable
public static PsiType[] getArgumentTypes(GrArgumentList argList) {
return getArgumentTypes(argList, false, null, false);
}
@Nullable
public static PsiType[] getArgumentTypes(@NotNull GrNamedArgument[] namedArgs,
@NotNull GrExpression[] expressions,
@NotNull GrClosableBlock[] closures,
boolean nullAsBottom,
@Nullable GrExpression stopAt,
boolean byShape) {
List<PsiType> result = new ArrayList<PsiType>();
if (namedArgs.length > 0) {
GrNamedArgument context = namedArgs[0];
result.add(GrMapType.createFromNamedArgs(context, byShape ? new GrNamedArgument[0] : namedArgs));
}
for (GrExpression expression : expressions) {
PsiType type = expression.getType();
if (expression instanceof GrSpreadArgument) {
if (type instanceof GrTupleType) {
result.addAll(Arrays.asList(((GrTupleType)type).getComponentTypes()));
}
else {
return null;
}
}
else {
if (type == null) {
result.add(nullAsBottom ? null : TypesUtil.getJavaLangObject(expression));
}
else {
if (stopAt == expression) {
type = TypeConversionUtil.erasure(type);
}
result.add(type);
}
}
if (stopAt == expression) {
return result.toArray(PsiType.createArray(result.size()));
}
}
for (GrClosableBlock closure : closures) {
PsiType closureType = closure.getType();
if (closureType != null) {
if (stopAt == closure) {
closureType = TypeConversionUtil.erasure(closureType);
}
result.add(notNullizeType(closureType, nullAsBottom, closure));
}
if (stopAt == closure) {
break;
}
}
return result.toArray(PsiType.createArray(result.size()));
}
@Nullable
public static PsiClass getJavaLangClass(PsiElement resolved, GlobalSearchScope scope) {
return JavaPsiFacade.getInstance(resolved.getProject()).findClass(CommonClassNames.JAVA_LANG_CLASS, scope);
}
public static boolean isValidReferenceName(@NotNull String text) {
final GroovyLexer lexer = new GroovyLexer();
lexer.start(text);
return TokenSets.REFERENCE_NAMES_WITHOUT_NUMBERS.contains(lexer.getTokenType()) && lexer.getTokenEnd() == text.length();
}
public static boolean isAccessible(@NotNull PsiElement place, @NotNull PsiMember member) {
if (member instanceof LightElement) {
return true;
}
if (place instanceof GrReferenceExpression && ((GrReferenceExpression)place).getQualifierExpression() == null) {
if (member.getContainingClass() instanceof GroovyScriptClass) { //calling top level script members from the same script file
return true;
}
}
if (PsiTreeUtil.getParentOfType(place, GrDocComment.class) != null) return true;
return com.intellij.psi.util.PsiUtil.isAccessible(member, place, null);
}
public static void reformatCode(final PsiElement element) {
final TextRange textRange = element.getTextRange();
PsiFile file = element.getContainingFile();
FileViewProvider viewProvider = file.getViewProvider();
if (viewProvider instanceof MultiplePsiFilesPerDocumentFileViewProvider) {
MultiplePsiFilesPerDocumentFileViewProvider multiProvider = (MultiplePsiFilesPerDocumentFileViewProvider)viewProvider;
file = multiProvider.getPsi(multiProvider.getBaseLanguage());
LOG.assertTrue(file != null, element + " " + multiProvider.getBaseLanguage());
}
try {
CodeStyleManager.getInstance(element.getProject())
.reformatText(file, textRange.getStartOffset(), textRange.getEndOffset());
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
public static Iterable<PsiClass> iterateSupers(@NotNull final PsiClass psiClass, final boolean includeSelf) {
return new Iterable<PsiClass>() {
@Override
public Iterator<PsiClass> iterator() {
return new Iterator<PsiClass>() {
TIntStack indices = new TIntStack();
Stack<PsiClassType[]> superTypesStack = new Stack<PsiClassType[]>();
PsiClass current;
boolean nextObtained;
Set<PsiClass> visited = new HashSet<PsiClass>();
{
if (includeSelf) {
current = psiClass;
nextObtained = true;
}
else {
current = null;
nextObtained = false;
}
pushSuper(psiClass);
}
@Override
public boolean hasNext() {
nextElement();
return current != null;
}
private void nextElement() {
if (nextObtained) return;
nextObtained = true;
while (!superTypesStack.empty()) {
assert indices.size() > 0;
int i = indices.pop();
PsiClassType[] superTypes = superTypesStack.peek();
while (i < superTypes.length) {
PsiClass clazz = superTypes[i].resolve();
if (clazz != null && !visited.contains(clazz)) {
current = clazz;
visited.add(clazz);
indices.push(i + 1);
pushSuper(clazz);
return;
}
i++;
}
superTypesStack.pop();
}
current = null;
}
private void pushSuper(PsiClass clazz) {
superTypesStack.push(clazz.getSuperTypes());
indices.push(0);
}
@Override
@NotNull
public PsiClass next() {
nextElement();
nextObtained = false;
if (current == null) throw new NoSuchElementException();
return current;
}
@Override
public void remove() {
throw new IllegalStateException("should not be called");
}
};
}
};
}
@Nullable
public static PsiClass getContextClass(@Nullable PsiElement context) {
while (context != null) {
if (context instanceof PsiClass && !isInDummyFile(context)) {
return (PsiClass)context;
}
else if (context instanceof GroovyFileBase && !isInDummyFile(context)) {
return ((GroovyFileBase)context).getScriptClass();
}
context = context.getContext();
}
return null;
}
public static boolean isInDummyFile(@NotNull PsiElement context) {
PsiFile file = context.getContainingFile();
if (file == null) return false;
String name = file.getName();
return name.startsWith(GroovyPsiElementFactory.DUMMY_FILE_NAME);
}
@Nullable
public static GroovyPsiElement getFileOrClassContext(PsiElement context) {
while (context != null) {
if (context instanceof GrTypeDefinition) {
return (GroovyPsiElement)context;
}
else if (context instanceof GroovyFileBase && context.isPhysical()) {
return (GroovyPsiElement)context;
}
context = context.getContext();
}
return null;
}
public static boolean mightBeLValue(@Nullable GrExpression expr) {
if (expr instanceof GrParenthesizedExpression) return mightBeLValue(((GrParenthesizedExpression)expr).getOperand());
if (expr instanceof GrTupleExpression ||
expr instanceof GrReferenceExpression ||
expr instanceof GrIndexProperty ||
expr instanceof GrPropertySelection) {
return true;
}
if ((isThisOrSuperRef(expr)) &&
GroovyConfigUtils.getInstance().isVersionAtLeast(expr, GroovyConfigUtils.GROOVY1_8)) {
return true;
}
return false;
}
public static boolean isRawMethodCall(GrMethodCallExpression call) {
final GroovyResolveResult result = call.advancedResolve();
final PsiElement element = result.getElement();
if (element == null) return false;
if (element instanceof PsiMethod) {
PsiType returnType = getSmartReturnType((PsiMethod)element);
final GrExpression expression = call.getInvokedExpression();
if (expression instanceof GrReferenceExpression && result.isInvokedOnProperty()) {
if (returnType instanceof GrClosureType) {
return isRawClosureCall(call, result, (GrClosureType)returnType);
}
}
else {
return isRawType(returnType, result.getSubstitutor());
}
}
if (element instanceof PsiVariable) {
GrExpression expression = call.getInvokedExpression();
final PsiType type = expression.getType();
if (type instanceof GrClosureType) {
return isRawClosureCall(call, result, (GrClosureType)type);
}
}
return false;
}
private static boolean isRawClosureCall(GrMethodCallExpression call, GroovyResolveResult result, GrClosureType returnType) {
final GrSignature signature = returnType.getSignature();
GrClosureSignature _signature;
if (signature instanceof GrClosureSignature) {
_signature = (GrClosureSignature)signature;
}
else {
final PsiType[] types = getArgumentTypes(call.getInvokedExpression(), true);
final Trinity<GrClosureSignature, GrClosureSignatureUtil.ArgInfo<PsiType>[], GrClosureSignatureUtil.ApplicabilityResult>
resultTrinity = types != null ? GrClosureSignatureUtil.getApplicableSignature(signature, types, call) : null;
_signature = resultTrinity != null ? resultTrinity.first : null;
}
if (_signature != null) {
return isRawType(_signature.getReturnType(), TypesUtil.composeSubstitutors(_signature.getSubstitutor(), result.getSubstitutor()));
}
return false;
}
public static boolean isRawFieldAccess(GrReferenceExpression ref) {
PsiElement element = null;
final GroovyResolveResult[] resolveResults = ref.multiResolve(false);
if (resolveResults.length == 0) return false;
final GroovyResolveResult resolveResult = resolveResults[0];
if (resolveResult != null) {
element = resolveResult.getElement();
}
if (element instanceof PsiField) {
return isRawType(((PsiField)element).getType(), resolveResult.getSubstitutor());
}
else if (element instanceof GrAccessorMethod) {
return isRawType(((GrAccessorMethod)element).getReturnType(), resolveResult.getSubstitutor());
}
return false;
}
private static boolean isRawIndexPropertyAccess(GrIndexProperty expr) {
final GrExpression qualifier = expr.getInvokedExpression();
final PsiType qualifierType = qualifier.getType();
if (qualifierType instanceof PsiClassType) {
if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_LIST)) {
return com.intellij.psi.util.PsiUtil.extractIterableTypeParameter(qualifierType, false) == null;
}
if (InheritanceUtil.isInheritor(qualifierType, CommonClassNames.JAVA_UTIL_MAP)) {
return com.intellij.psi.util.PsiUtil.substituteTypeParameter(qualifierType, CommonClassNames.JAVA_UTIL_MAP, 1, false) == null;
}
PsiClassType classType = (PsiClassType)qualifierType;
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
GrExpression[] arguments = expr.getArgumentList().getExpressionArguments();
PsiType[] argTypes = PsiType.createArray(arguments.length);
for (int i = 0; i < arguments.length; i++) {
PsiType argType = arguments[i].getType();
if (argType == null) argType = TypesUtil.getJavaLangObject(expr);
argTypes[i] = argType;
}
MethodResolverProcessor processor = new MethodResolverProcessor("getAt", expr, false, qualifierType, argTypes, PsiType.EMPTY_ARRAY);
final PsiClass qClass = resolveResult.getElement();
final ResolveState state = ResolveState.initial().put(PsiSubstitutor.KEY, PsiSubstitutor.EMPTY);
if (qClass != null) {
qClass.processDeclarations(processor, state, null, expr);
}
ResolveUtil.processNonCodeMembers(qualifierType, processor, qualifier, state);
final GroovyResolveResult[] candidates = processor.getCandidates();
PsiType type = null;
if (candidates.length == 1) {
final PsiElement element = candidates[0].getElement();
if (element instanceof PsiMethod) {
type = getSmartReturnType((PsiMethod)element);
}
}
return isRawType(type, resolveResult.getSubstitutor());
}
return false;
}
public static boolean isRawClassMemberAccess(GrExpression expr) {
expr = (GrExpression)skipParentheses(expr, false);
if (expr instanceof GrMethodCallExpression) {
return isRawMethodCall((GrMethodCallExpression)expr);
}
if (expr instanceof GrReferenceExpression) {
return isRawFieldAccess((GrReferenceExpression)expr);
}
if (expr instanceof GrIndexProperty) {
return isRawIndexPropertyAccess((GrIndexProperty)expr);
}
return false;
}
public static boolean isRawType(@Nullable PsiType type, @NotNull PsiSubstitutor substitutor) {
if (type instanceof PsiClassType) {
final PsiClass returnClass = ((PsiClassType)type).resolve();
if (returnClass instanceof PsiTypeParameter) {
final PsiTypeParameter typeParameter = (PsiTypeParameter)returnClass;
return substitutor.substitute(typeParameter) == null;
}
}
return false;
}
public static boolean isNewLine(PsiElement element) {
if (element == null) return false;
ASTNode node = element.getNode();
if (node == null) return false;
IElementType elementType = node.getElementType();
return elementType == GroovyTokenTypes.mNLS || elementType == TokenType.WHITE_SPACE && element.getText().contains("\n");
}
@Nullable
public static PsiElement getPrevNonSpace(@NotNull final PsiElement elem) {
PsiElement prevSibling = elem.getPrevSibling();
while (prevSibling instanceof PsiWhiteSpace) {
prevSibling = prevSibling.getPrevSibling();
}
return prevSibling;
}
@Nullable
public static PsiElement getNextNonSpace(final PsiElement elem) {
PsiElement nextSibling = elem.getNextSibling();
while (nextSibling instanceof PsiWhiteSpace) {
nextSibling = nextSibling.getNextSibling();
}
return nextSibling;
}
@NotNull
public static PsiIdentifier getJavaNameIdentifier(@NotNull GrNamedElement namedElement) {
final PsiElement element = namedElement.getNameIdentifierGroovy();
JavaIdentifier identifier = element.getUserData(NAME_IDENTIFIER);
if (identifier == null) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (element) {
identifier = element.getUserData(NAME_IDENTIFIER);
if (identifier != null) {
return identifier;
}
identifier = new JavaIdentifier(element.getManager(), element);
element.putUserData(NAME_IDENTIFIER, identifier);
}
}
return identifier;
}
@Nullable
public static GrStatement findEnclosingStatement(@Nullable PsiElement context) {
while (context != null) {
if (isExpressionStatement(context)) return (GrStatement)context;
context = PsiTreeUtil.getParentOfType(context, GrStatement.class, true);
}
return null;
}
public static boolean isMethodCall(GrMethodCall call, String methodName) {
final GrExpression expression = call.getInvokedExpression();
return expression instanceof GrReferenceExpression && methodName.equals(expression.getText().trim());
}
public static boolean hasEnclosingInstanceInScope(@NotNull PsiClass clazz, @Nullable PsiElement scope, boolean isSuperClassAccepted) {
return findEnclosingInstanceClassInScope(clazz, scope, isSuperClassAccepted) != null;
}
public static PsiClass findEnclosingInstanceClassInScope(@NotNull PsiClass clazz, @Nullable PsiElement scope, boolean isInheritorOfClazzAccepted) {
PsiElement place = scope;
while (place != null && place != clazz && !(place instanceof PsiFile && place.isPhysical())) {
if (place instanceof PsiClass) {
if (isInheritorOfClazzAccepted) {
if (InheritanceUtil.isInheritorOrSelf((PsiClass)place, clazz, true)) return (PsiClass)place;
}
else {
if (clazz.getManager().areElementsEquivalent(place, clazz)) return (PsiClass)place;
}
}
if (place instanceof PsiModifierListOwner && ((PsiModifierListOwner)place).hasModifierProperty(PsiModifier.STATIC)) return null;
place = place.getContext();
}
if (clazz instanceof GroovyScriptClass && place == clazz.getContainingFile() || place == clazz) {
return clazz;
}
return null;
}
@Nullable
public static PsiElement skipWhitespacesAndComments(@Nullable PsiElement elem, boolean forward, boolean skipNLs) {
return skipSet(elem, forward, TokenSets.WHITE_SPACES_OR_COMMENTS, skipNLs);
}
@Nullable
public static PsiElement skipWhitespacesAndComments(@Nullable PsiElement elem, boolean forward) {
return skipSet(elem, forward, TokenSets.WHITE_SPACES_OR_COMMENTS, true);
}
private static PsiElement skipSet(PsiElement elem, boolean forward, TokenSet set, boolean skipNLs) {
while (elem != null &&
elem.getNode() != null &&
set.contains(elem.getNode().getElementType()) &&
(skipNLs || elem.getText().indexOf('\n') == -1)) {
if (forward) {
elem = elem.getNextSibling();
}
else {
elem = elem.getPrevSibling();
}
}
return elem;
}
@Nullable
public static PsiElement skipWhitespaces(@Nullable PsiElement elem, boolean forward) {
return skipSet(elem, forward, TokenSets.WHITE_SPACES_SET, true);
}
@Nullable
public static PsiType getSmartReturnType(@NotNull PsiMethod method) {
if (method instanceof GrMethod) {
return ((GrMethod)method).getInferredReturnType();
}
else if (method instanceof GrAccessorMethod) {
return ((GrAccessorMethod)method).getInferredReturnType();
}
else if (method instanceof GrGdkMethod) {
return getSmartReturnType(((GrGdkMethod)method).getStaticMethod());
}
else {
return method.getReturnType();
}
}
public static boolean isClosurePropertyGetter(PsiMethod method) {
String methodName = method.getName();
if (methodName.startsWith("get") && GroovyPropertyUtils.isGetterName(methodName)) { // exclude isXXX()
PsiModifierList modifiers = method.getModifierList();
if (!modifiers.hasModifierProperty(PsiModifier.STATIC)
&& !modifiers.hasModifierProperty(PsiModifier.PRIVATE)
&& !modifiers.hasModifierProperty(PsiModifier.PROTECTED)
&& method.getParameterList().getParametersCount() == 0) {
final PsiType type = getSmartReturnType(method);
if (type != null && (TypesUtil.isClassType(type, CommonClassNames.JAVA_LANG_OBJECT) || TypesUtil.isClassType(type,
GroovyCommonClassNames.GROOVY_LANG_CLOSURE))) {
return true;
}
}
}
return false;
}
public static boolean isMethodUsage(PsiElement element) {
if (element instanceof GrEnumConstant) return true;
if (!(element instanceof GrReferenceElement)) return false;
PsiElement parent = element.getParent();
if (parent instanceof GrCall) {
return true;
}
else if (parent instanceof GrAnonymousClassDefinition) {
return element.equals(((GrAnonymousClassDefinition)parent).getBaseClassReferenceGroovy());
}
return false;
}
@NotNull
public static GroovyResolveResult[] getConstructorCandidates(@NotNull PsiElement place,
@NotNull GroovyResolveResult classCandidate,
@Nullable PsiType[] argTypes) {
final PsiElement element = classCandidate.getElement();
if (!(element instanceof PsiClass)) return GroovyResolveResult.EMPTY_ARRAY;
PsiClass clazz = (PsiClass)element;
PsiSubstitutor substitutor = classCandidate.getSubstitutor();
return ResolveUtil.getAllClassConstructors(clazz, substitutor, argTypes, place);
}
public static boolean isAccessedForReading(GrExpression expr) {
return !isLValue(expr);
}
public static boolean isAccessedForWriting(GrExpression expr) {
return isLValue(expr) || isUsedInIncOrDec(expr);
}
public static boolean isUsedInIncOrDec(GrExpression expr) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, GrParenthesizedExpression.class);
if (parent instanceof GrUnaryExpression) {
IElementType tokenType = ((GrUnaryExpression)parent).getOperationTokenType();
return tokenType == GroovyTokenTypes.mINC || tokenType == GroovyTokenTypes.mDEC;
}
return false;
}
public static GrReferenceExpression qualifyMemberReference(GrReferenceExpression refExpr, PsiMember member, String name) {
assert refExpr.getQualifierExpression() == null;
final PsiClass clazz = member.getContainingClass();
assert clazz != null;
final PsiElement replaced;
if (member.hasModifierProperty(PsiModifier.STATIC)) {
final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
.createReferenceExpressionFromText(clazz.getQualifiedName() + "." + name);
replaced = refExpr.replace(newRefExpr);
}
else {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class);
if (member.getManager().areElementsEquivalent(containingClass, clazz)) {
final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
.createReferenceExpressionFromText("this." + name);
replaced = refExpr.replace(newRefExpr);
}
else {
final GrReferenceExpression newRefExpr = GroovyPsiElementFactory.getInstance(member.getProject())
.createReferenceExpressionFromText(clazz.getName() + ".this." + name);
replaced = refExpr.replace(newRefExpr);
}
}
return (GrReferenceExpression)replaced;
}
public static GroovyResolveResult[] getConstructorCandidates(PsiClassType classType, PsiType[] argTypes, GroovyPsiElement context) {
final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
final PsiClass psiClass = resolveResult.getElement();
final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
if (psiClass == null) {
return GroovyResolveResult.EMPTY_ARRAY;
}
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
? (GroovyResolveResult)resolveResult
: new GroovyResolveResultImpl(psiClass, context, null, substitutor, true, true);
return getConstructorCandidates(context, grResult, argTypes);
}
@Nullable
public static PsiElement skipParentheses(@Nullable PsiElement element, boolean up) {
if (element == null) return null;
if (up) {
PsiElement parent;
while ((parent = element.getParent()) instanceof GrParenthesizedExpression) {
element = parent;
}
return element;
}
else {
while (element instanceof GrParenthesizedExpression) {
element = ((GrParenthesizedExpression)element).getOperand();
}
return element;
}
}
@NotNull
public static PsiElement skipParenthesesIfSensibly(@NotNull PsiElement element, boolean up) {
PsiElement res = skipParentheses(element, up);
return res == null ? element : res;
}
@Nullable
public static PsiElement getNamedArgumentValue(GrNamedArgument otherNamedArgument, String argumentName) {
PsiElement parent = otherNamedArgument.getParent();
if (!(parent instanceof GrNamedArgumentsOwner)) return null;
GrNamedArgument namedArgument = ((GrNamedArgumentsOwner)parent).findNamedArgument(argumentName);
if (namedArgument == null) return null;
return namedArgument.getExpression();
}
@NotNull
public static PsiClass getOriginalClass(@NotNull PsiClass aClass) {
PsiFile file = aClass.getContainingFile();
if (file == null) return aClass;
PsiFile originalFile = file.getOriginalFile();
if (originalFile == file) return aClass;
if (!(originalFile instanceof PsiClassOwner)) return aClass;
String name = aClass.getName();
if (name == null) return aClass;
for (PsiClass originalClass : ((PsiClassOwner)originalFile).getClasses()) {
if (name.equals(originalClass.getName())) {
return originalClass;
}
}
return aClass;
}
private static final String[] visibilityModifiers = new String[]{PsiModifier.PRIVATE, PsiModifier.PROTECTED, PsiModifier.PUBLIC};
public static void escalateVisibility(PsiMember owner, PsiElement place) {
PsiModifierList modifierList = owner.getModifierList();
LOG.assertTrue(modifierList != null);
final String visibilityModifier = VisibilityUtil.getVisibilityModifier(modifierList);
int index;
for (index = 0; index < visibilityModifiers.length; index++) {
String modifier = visibilityModifiers[index];
if (modifier.equals(visibilityModifier)) break;
}
for (; index < visibilityModifiers.length && !isAccessible(place, owner); index++) {
@PsiModifier.ModifierConstant
String modifier = visibilityModifiers[index];
com.intellij.psi.util.PsiUtil.setModifierProperty(owner, modifier, true);
}
}
public static int getArgumentIndex(@NotNull GrCall call, @NotNull PsiElement argument) {
GrArgumentList argumentList = call.getArgumentList();
if (argumentList == null) return -1;
GrExpression[] expressionArguments = argumentList.getExpressionArguments();
for (int i = 0; i < expressionArguments.length; i++) {
if (argument.equals(expressionArguments[i])) {
int res = i;
if (argumentList.getNamedArguments().length > 0) {
res++; // first argument is map defined by named arguments
}
return res;
}
}
if (argument instanceof GrClosableBlock) {
GrClosableBlock[] closureArgs = call.getClosureArguments();
for (int i = 0; i < closureArgs.length; i++) {
if (argument.equals(closureArgs[i])) {
int res = i + expressionArguments.length;
if (argumentList.getNamedArguments().length > 0) {
res++; // first argument is map defined by named arguments
}
return res;
}
}
}
return -1;
}
/**
* Returns all arguments passed to method. First argument is null if Named Arguments is present.
*/
public static GrExpression[] getAllArguments(@NotNull GrCall call) {
GrArgumentList argumentList = call.getArgumentList();
if (argumentList == null) return GrExpression.EMPTY_ARRAY;
GrClosableBlock[] closureArguments = call.getClosureArguments();
GrExpression[] expressionArguments = argumentList.getExpressionArguments();
GrNamedArgument[] namedArguments = argumentList.getNamedArguments();
int length = expressionArguments.length + closureArguments.length;
int k = 0;
if (namedArguments.length > 0) {
length++;
k = 1;
}
GrExpression[] res = new GrExpression[length];
for (GrExpression expressionArgument : expressionArguments) {
res[k++] = expressionArgument;
}
for (GrClosableBlock closureArgument : closureArguments) {
res[k++] = closureArgument;
}
return res;
}
public static GrNamedArgument[] getFirstMapNamedArguments(@NotNull GrCall grCall) {
GrNamedArgument[] res = grCall.getNamedArguments();
if (res.length > 0) return res;
GrExpression[] arguments = grCall.getExpressionArguments();
if (arguments.length == 0) return GrNamedArgument.EMPTY_ARRAY;
PsiElement firstArg = arguments[0];
if (!(firstArg instanceof GrListOrMap)) return GrNamedArgument.EMPTY_ARRAY;
return ((GrListOrMap)firstArg).getNamedArguments();
}
public static boolean isExpressionStatement(@NotNull PsiElement expr) {
if (!(expr instanceof GrStatement)) return false;
final PsiElement parent = expr.getParent();
if (parent instanceof GrControlFlowOwner || parent instanceof GrCaseSection) return true;
if (parent instanceof GrLabeledStatement) return true;
if (parent instanceof GrIfStatement &&
(expr == ((GrIfStatement)parent).getThenBranch() || expr == ((GrIfStatement)parent).getElseBranch())) {
return true;
}
if (parent instanceof GrWhileStatement && expr == ((GrWhileStatement)parent).getBody()) {
return true;
}
return false;
}
@Nullable
public static GrMethodCall getMethodCallByNamedParameter(GrNamedArgument namedArgument) {
GrCall res = getCallByNamedParameter(namedArgument);
if (res instanceof GrMethodCall) return (GrMethodCall)res;
return null;
}
@Nullable
public static GrCall getCallByNamedParameter(GrNamedArgument namedArgument) {
PsiElement parent = namedArgument.getParent();
PsiElement eMethodCall;
if (parent instanceof GrArgumentList) {
eMethodCall = parent.getParent();
}
else {
if (!(parent instanceof GrListOrMap)) return null;
PsiElement eArgumentList = parent.getParent();
if (!(eArgumentList instanceof GrArgumentList)) return null;
GrArgumentList argumentList = (GrArgumentList)eArgumentList;
if (argumentList.getNamedArguments().length > 0) return null;
if (argumentList.getExpressionArgumentIndex((GrListOrMap)parent) != 0) return null;
eMethodCall = eArgumentList.getParent();
}
if (!(eMethodCall instanceof GrCall)) return null;
return (GrCall)eMethodCall;
}
public static String getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, String defaultValue) {
PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName);
if (value instanceof GrExpression) {
Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value);
if (o instanceof String) {
return (String)o;
}
}
return defaultValue;
}
public static boolean getAnnoAttributeValue(@NotNull PsiAnnotation annotation, final String attributeName, boolean defaultValue) {
PsiAnnotationMemberValue value = annotation.findAttributeValue(attributeName);
if (value instanceof GrExpression) {
Object o = GroovyConstantExpressionEvaluator.evaluate((GrExpression)value);
if (o instanceof Boolean) {
return (Boolean)o;
}
}
return defaultValue;
}
public static boolean isExpressionUsed(PsiElement expr) {
while (expr.getParent() instanceof GrParenthesizedExpression) expr = expr.getParent();
final PsiElement parent = expr.getParent();
if (parent instanceof GrBinaryExpression ||
parent instanceof GrUnaryExpression ||
parent instanceof GrConditionalExpression ||
parent instanceof GrAssignmentExpression ||
parent instanceof GrInstanceOfExpression ||
parent instanceof GrSafeCastExpression ||
parent instanceof GrTupleExpression ||
parent instanceof GrArgumentList ||
parent instanceof GrReturnStatement ||
parent instanceof GrAssertStatement ||
parent instanceof GrThrowStatement ||
parent instanceof GrSwitchStatement ||
parent instanceof GrVariable) {
return true;
}
return isReturnStatement(expr);
}
public static boolean isReturnStatement(@NotNull PsiElement statement) {
final GrControlFlowOwner controlFlowOwner = ControlFlowUtils.findControlFlowOwner(statement);
if (controlFlowOwner instanceof GrOpenBlock) {
final PsiElement controlFlowOwnerParent = controlFlowOwner.getParent();
if (controlFlowOwnerParent instanceof GrMethod && ((GrMethod)controlFlowOwnerParent).isConstructor()) {
return false;
}
else if (controlFlowOwnerParent instanceof PsiMethod && ((PsiMethod)controlFlowOwnerParent).getReturnType() == PsiType.VOID) {
return false;
}
}
//noinspection SuspiciousMethodCalls
return ControlFlowUtils.collectReturns(controlFlowOwner, true).contains(statement);
}
@Nullable
public static PsiClass getContainingNotInnerClass(@Nullable PsiElement element) {
PsiClass domainClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
if (domainClass == null) return null;
while (true) {
PsiClass c = domainClass.getContainingClass();
if (c == null) return domainClass;
domainClass = c;
}
}
@NotNull
public static ResolveResult getAccessObjectClass(GrExpression expression) {
if (isThisOrSuperRef(expression)) return GroovyResolveResult.EMPTY_RESULT;
PsiType type = expression.getType();
if (type instanceof PsiClassType) {
return ((PsiClassType)type).resolveGenerics();
}
if (type == null && expression instanceof GrReferenceExpression) {
GroovyResolveResult resolveResult = ((GrReferenceExpression)expression).advancedResolve();
if (resolveResult.getElement() instanceof PsiClass) {
return resolveResult;
}
}
return GroovyResolveResult.EMPTY_RESULT;
}
public static boolean isReferenceWithoutQualifier(@Nullable PsiElement element, @NotNull String name) {
if (!(element instanceof GrReferenceExpression)) return false;
GrReferenceExpression ref = (GrReferenceExpression)element;
return !ref.isQualified() && name.equals(ref.getReferenceName());
}
public static boolean isProperty(@NotNull GrField field) {
final PsiClass clazz = field.getContainingClass();
if (clazz == null) return false;
if (clazz.isInterface() && !GrTraitUtil.isTrait(clazz)) return false;
final GrModifierList modifierList = field.getModifierList();
return modifierList == null || !modifierList.hasExplicitVisibilityModifiers();
}
public static boolean isConstructorHasRequiredParameters(@NotNull PsiMethod constructor) {
LOG.assertTrue(constructor.isConstructor());
final PsiParameter[] parameters = constructor.getParameterList().getParameters();
for (PsiParameter parameter : parameters) {
if (!(parameter instanceof GrParameter && ((GrParameter)parameter).isOptional())) return true;
}
return false;
}
public static boolean isInMethodCallContext(PsiElement context) {
return getArgumentsList(context) != null;
}
@NotNull
public static List<GrImportStatement> getValidImportStatements(final GroovyFile file) {
final List<GrImportStatement> oldImports = new ArrayList<GrImportStatement>();
for (GrImportStatement statement : file.getImportStatements()) {
if (!ErrorUtil.containsError(statement)) {
oldImports.add(statement);
}
}
return oldImports;
}
public static boolean isCompileStatic(PsiElement e) {
PsiMember containingMember = PsiTreeUtil.getParentOfType(e, PsiMember.class, false, GrAnnotation.class);
return containingMember != null && GroovyPsiManager.getInstance(containingMember.getProject()).isCompileStatic(containingMember);
}
@Nullable
public static PsiType extractIteratedType(GrForInClause forIn) {
GrExpression iterated = forIn.getIteratedExpression();
if (iterated == null) return null;
return ClosureParameterEnhancer.findTypeForIteration(iterated, forIn);
}
public static boolean isThisReference(@Nullable PsiElement expression) {
return isThisOrSuperRef(expression, GroovyTokenTypes.kTHIS, false);
}
public static boolean isSuperReference(@Nullable PsiElement expression) {
return isThisOrSuperRef(expression, GroovyTokenTypes.kSUPER, true);
}
private static boolean isThisOrSuperRef(PsiElement expression, IElementType token, boolean superClassAccepted) {
if (!(expression instanceof GrReferenceExpression)) return false;
GrReferenceExpression ref = (GrReferenceExpression)expression;
PsiElement nameElement = ref.getReferenceNameElement();
if (nameElement == null) return false;
IElementType type = nameElement.getNode().getElementType();
if (type != token) return false;
GrExpression qualifier = ref.getQualifier();
if (qualifier == null) {
return true;
}
else {
PsiElement resolved = ref.resolve();
if (resolved instanceof PsiClass) {
if (hasEnclosingInstanceInScope(((PsiClass)resolved), ref, superClassAccepted)) return true;
if (superClassAccepted && GrTraitUtil.isTrait((PsiClass)resolved) && scopeClassImplementsTrait(((PsiClass)resolved), ref)) return true;
}
return false;
}
}
public static boolean scopeClassImplementsTrait(@NotNull final PsiClass trait, @NotNull final PsiElement place) {
GrTypeDefinition scopeClass = PsiTreeUtil.getParentOfType(place, GrTypeDefinition.class, true);
return scopeClass != null && ContainerUtil.find(scopeClass.getSuperTypes(), new Condition<PsiClassType>() {
@Override
public boolean value(PsiClassType type) {
return place.getManager().areElementsEquivalent(type.resolve(), trait);
}
}) != null;
}
public static boolean isThisOrSuperRef(@Nullable PsiElement qualifier) {
return qualifier instanceof GrReferenceExpression && (isThisReference(qualifier) || isSuperReference(qualifier));
}
public static boolean isInstanceThisRef(PsiElement qualifier) {
if (isThisReference(qualifier)) {
GrReferenceExpression ref = (GrReferenceExpression)qualifier;
PsiElement resolved = ref.resolve();
if (resolved == null) return false;
return hasEnclosingInstanceInScope((PsiClass)resolved, qualifier, false);
}
return false;
}
public static boolean isLineFeed(@Nullable PsiElement e) {
return e != null &&
PsiImplUtil.isWhiteSpaceOrNls(e) &&
(e.getText().indexOf('\n') >= 0 || e.getText().indexOf('\r') >= 0);
}
public static boolean isSingleBindingVariant(GroovyResolveResult[] candidates) {
return candidates.length == 1 && candidates[0].getElement() instanceof GrBindingVariable;
}
@Nullable
public static GrConstructorInvocation getConstructorInvocation(@NotNull GrMethod constructor) {
assert constructor.isConstructor();
final GrOpenBlock body = constructor.getBlock();
if (body == null) return null;
final GrStatement[] statements = body.getStatements();
if (statements.length > 0 && statements[0] instanceof GrConstructorInvocation) {
return ((GrConstructorInvocation)statements[0]);
}
else {
return null;
}
}
public static boolean isDGMMethod(@Nullable PsiElement element) {
if (!(element instanceof PsiMethod)) return false;
final PsiMethod method = element instanceof GrGdkMethod ? ((GrGdkMethod)element).getStaticMethod() : (PsiMethod)element;
final PsiClass aClass = method.getContainingClass();
if (aClass == null) return false;
final String qname = aClass.getQualifiedName();
return GroovyCommonClassNames.GROOVY_EXTENSION_CLASSES.contains(qname);
}
public static boolean isVoidMethodCall(@Nullable GrExpression expression) {
if (expression instanceof GrMethodCall && PsiType.NULL.equals(expression.getType())) {
final GroovyResolveResult resolveResult = ((GrMethodCall)expression).advancedResolve();
final PsiType[] args = getArgumentTypes(((GrMethodCall)expression).getInvokedExpression(), true);
return PsiType.VOID.equals(ResolveUtil.extractReturnTypeFromCandidate(resolveResult, expression, args));
}
return false;
}
public static boolean isVoidMethod(@NotNull PsiMethod method) {
if (PsiType.VOID.equals(method.getReturnType())) {
return true;
}
if (method instanceof GrMethod && ((GrMethod)method).getReturnTypeElementGroovy() == null) {
GrOpenBlock block = ((GrMethod)method).getBlock();
if (block != null && isBlockReturnVoid(block)) {
return true;
}
}
return false;
}
public static boolean isBlockReturnVoid(@NotNull final GrCodeBlock block) {
return CachedValuesManager.getCachedValue(block, new CachedValueProvider<Boolean>() {
@Nullable
@Override
public Result<Boolean> compute() {
return Result.create(ControlFlowUtils.visitAllExitPoints(block, new ControlFlowUtils.ExitPointVisitor() {
@Override
public boolean visitExitPoint(Instruction instruction, @Nullable GrExpression returnValue) {
return returnValue == null || !(returnValue instanceof GrLiteral);
}
}), PsiModificationTracker.MODIFICATION_COUNT);
}
});
}
public static boolean checkPsiElementsAreEqual(PsiElement l, PsiElement r) {
if (!l.getText().equals(r.getText())) return false;
if (l.getNode().getElementType() != r.getNode().getElementType()) return false;
final PsiElement[] lChildren = l.getChildren();
final PsiElement[] rChildren = r.getChildren();
if (lChildren.length != rChildren.length) return false;
for (int i = 0; i < rChildren.length; i++) {
if (!checkPsiElementsAreEqual(lChildren[i], rChildren[i])) return false;
}
return true;
}
public static boolean isCall(GrReferenceExpression referenceExpression) {
return referenceExpression.getParent() instanceof GrCall;
}
public static boolean isLocalVariable(@Nullable PsiElement variable) {
return variable instanceof GrVariable && !(variable instanceof GrField || variable instanceof GrParameter);
}
@Nullable
public static PsiElement getPreviousNonWhitespaceToken(PsiElement e) {
PsiElement next = PsiTreeUtil.prevLeaf(e);
while (next != null && next.getNode().getElementType() == TokenType.WHITE_SPACE) next = PsiTreeUtil.prevLeaf(next);
return next;
}
}