blob: 7dd187b9448e3ef1514b2e29e5e89120bc8867cd [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.resolve.processors;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
/**
* @author Maxim.Medvedev
*/
public class AccessorResolverProcessor extends MethodResolverProcessor {
private final String myPropertyName;
private final boolean mySearchForGetter;
private final SubstitutorComputer mySubstitutorComputer;
public AccessorResolverProcessor(@Nullable String accessorName, @NotNull String propertyName, @NotNull PsiElement place, boolean searchForGetter) {
this(accessorName, propertyName, place, searchForGetter, false, null, PsiType.EMPTY_ARRAY);
}
public AccessorResolverProcessor(@Nullable String accessorName,
@NotNull String propertyName,
@NotNull PsiElement place,
boolean searchForGetter,
boolean byShape,
@Nullable PsiType thisType,
@NotNull PsiType[] typeArguments) {
super(accessorName, place, false, thisType, null, typeArguments, false, byShape);
myPropertyName = propertyName;
mySearchForGetter = searchForGetter;
mySubstitutorComputer = byShape ? null : new SubstitutorComputer(thisType, PsiType.EMPTY_ARRAY, typeArguments, place, myPlace);
}
@Override
public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) {
final PsiElement resolveContext = state.get(RESOLVE_CONTEXT);
String importedName = resolveContext instanceof GrImportStatement ? ((GrImportStatement)resolveContext).getImportedName() : null;
if (mySearchForGetter) {
if (element instanceof PsiMethod &&
(importedName != null && GroovyPropertyUtils.isSimplePropertyGetter((PsiMethod)element, null) &&
(isAppropriatePropertyNameForGetter((PsiMethod)element, importedName, myPropertyName) || myPropertyName.equals(importedName)) ||
importedName == null && GroovyPropertyUtils.isSimplePropertyGetter((PsiMethod)element, myPropertyName))) {
return addAccessor((PsiMethod)element, state);
}
}
else {
if (element instanceof PsiMethod &&
(importedName != null && GroovyPropertyUtils.isSimplePropertySetter((PsiMethod)element, null) &&
(isAppropriatePropertyNameForSetter(importedName, myPropertyName) || myPropertyName.equals(importedName)) ||
importedName == null && GroovyPropertyUtils.isSimplePropertySetter((PsiMethod)element, myPropertyName))) {
return addAccessor((PsiMethod)element, state);
}
}
return true;
}
/**
* use only for imported properties
*/
private static boolean isAppropriatePropertyNameForSetter(@NotNull String importedName, @NotNull String propertyName) {
propertyName = GroovyPropertyUtils.decapitalize(propertyName);
return propertyName.equals(GroovyPropertyUtils.getPropertyNameBySetterName(importedName));
}
/**
* use only for imported properties
*/
private static boolean isAppropriatePropertyNameForGetter(@NotNull PsiMethod getter, @NotNull String importedNameForGetter, @NotNull String propertyName) {
propertyName = GroovyPropertyUtils.decapitalize(propertyName);
return propertyName.equals(getPropertyNameByGetter(getter, importedNameForGetter));
}
@Nullable
private static String getPropertyNameByGetter(PsiMethod element, String importedName) {
return GroovyPropertyUtils.getPropertyNameByGetterName(importedName, isBoolean(element));
}
private static boolean isBoolean(PsiMethod method) {
return method.getReturnType() == PsiType.BOOLEAN;
}
private boolean addAccessor(PsiMethod method, ResolveState state) {
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
if (mySubstitutorComputer != null) {
substitutor = mySubstitutorComputer.obtainSubstitutor(substitutor, method, state);
}
boolean isAccessible = isAccessible(method);
final PsiElement resolveContext = state.get(RESOLVE_CONTEXT);
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
boolean isStaticsOK = isStaticsOK(method, resolveContext, false);
final GroovyResolveResultImpl candidate = new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK, true, true);
if (isAccessible && isStaticsOK) {
addCandidate(candidate);
return method instanceof GrGdkMethod; //don't stop searching if we found only gdk method
}
else {
addInapplicableCandidate(candidate);
return true;
}
}
@NotNull
@Override
public GroovyResolveResult[] getCandidates() {
final boolean hasApplicableCandidates = hasApplicableCandidates();
final GroovyResolveResult[] candidates = super.getCandidates();
if (hasApplicableCandidates) {
if (candidates.length <= 1) return candidates;
return new GroovyResolveResult[]{candidates[0]};
}
else {
return candidates;
}
}
}