blob: fdf13f4caaaab5d33d5c8a73fa4dc96b06dd0e0f [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.dsl.dsltop;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.dsl.GdslMembersHolderConsumer;
import org.jetbrains.plugins.groovy.dsl.holders.DelegatedMembersHolder;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
/**
* @author ilyas
*/
@SuppressWarnings({"MethodMayBeStatic", "UnusedDeclaration"})
public class GroovyDslDefaultMembers implements GdslMembersProvider {
/**
* Find a class by its full-qualified name
*
* @param fqn
* @return
*/
@Nullable
public PsiClass findClass(String fqn, GdslMembersHolderConsumer consumer) {
final JavaPsiFacade facade = JavaPsiFacade.getInstance(consumer.getProject());
return facade.findClass(fqn, GlobalSearchScope.allScope(consumer.getProject()));
}
/**
* **********************************************************************************
* Methods and properties of the GroovyDSL language
* **********************************************************************************
*/
public void delegatesTo(@Nullable PsiElement elem, GdslMembersHolderConsumer consumer) {
if (elem instanceof PsiClass) {
final PsiClass clazz = (PsiClass)elem;
final DelegatedMembersHolder holder = new DelegatedMembersHolder();
if (clazz instanceof GrTypeDefinition) {
final PsiClassType type = JavaPsiFacade.getElementFactory(consumer.getProject()).createType(clazz);
final ResolverProcessor processor = CompletionProcessor.createPropertyCompletionProcessor(clazz);
final GroovyPsiElement context = (GroovyPsiElement)clazz;
ResolveUtil.processAllDeclarations(type, processor, ResolveState.initial(), context);
for (GroovyResolveResult result : processor.getCandidates()) {
final PsiElement element = result.getElement();
if (element instanceof PsiMethod && !((PsiMethod)element).isConstructor() || element instanceof PsiField) {
holder.addMember((PsiMember)element);
}
}
}
else {
for (PsiMethod method : clazz.getAllMethods()) {
if (!method.isConstructor()) holder.addMember(method);
}
for (PsiField field : clazz.getAllFields()) {
holder.addMember(field);
}
}
consumer.addMemberHolder(holder);
}
else if (elem instanceof GrExpression) {
GrExpression expr = (GrExpression)elem;
final PsiType type = expr.getType();
if (type instanceof PsiClassType) {
PsiClassType ctype = (PsiClassType)type;
delegatesTo(ctype.resolve(), consumer);
}
}
}
/**
* Add a member to a context's ctype
*
* @param member
*/
public PsiMember add(PsiMember member, GdslMembersHolderConsumer consumer) {
final DelegatedMembersHolder holder = new DelegatedMembersHolder();
holder.addMember(member);
consumer.addMemberHolder(holder);
return member;
}
/**
* Returns enclosing method call of a given context's place
*/
@Nullable
public GrCall enclosingCall(String name, GdslMembersHolderConsumer consumer) {
final PsiElement place = consumer.getPlace();
if (place == null) return null;
GrCall call = PsiTreeUtil.getParentOfType(place, GrCall.class, true);
if (call == null) return null;
while (call != null && !name.equals(getInvokedMethodName(call))) {
call = PsiTreeUtil.getParentOfType(call, GrCall.class, true);
}
if (call == null) return null;
final GrArgumentList argumentList = call.getArgumentList();
if (argumentList != null) {
for (GrExpression arg : argumentList.getExpressionArguments()) {
if (arg instanceof GrClosableBlock && PsiTreeUtil.findCommonParent(place, arg) == arg) {
return call;
}
}
}
if (call instanceof GrMethodCallExpression) {
for (GrExpression arg : call.getClosureArguments()) {
if (arg instanceof GrClosableBlock && PsiTreeUtil.findCommonParent(place, arg) == arg) {
return call;
}
}
}
return null;
}
@Nullable
public PsiMethod enclosingMethod(GdslMembersHolderConsumer consumer) {
final PsiElement place = consumer.getPlace();
if (place == null) return null;
return PsiTreeUtil.getParentOfType(place, PsiMethod.class, true);
}
@Nullable
public PsiMember enclosingMember(GdslMembersHolderConsumer consumer) {
final PsiElement place = consumer.getPlace();
if (place == null) return null;
final PsiMember member = PsiTreeUtil.getParentOfType(place, PsiMember.class, true);
if (member instanceof PsiClass) return null;
return member;
}
@Nullable
public PsiClass enclosingClass(GdslMembersHolderConsumer consumer) {
final PsiElement place = consumer.getPlace();
if (place == null) return null;
return PsiTreeUtil.getParentOfType(place, PsiClass.class, true);
}
@Nullable
private static String getInvokedMethodName(GrCall call) {
if (call instanceof GrMethodCall) {
final GrExpression expr = ((GrMethodCall)call).getInvokedExpression();
if (expr instanceof GrReferenceExpression) {
return ((GrReferenceExpression)expr).getReferenceName();
}
}
return null;
}
}