All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParamsEnhancer Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition groovy-psi library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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.typeEnhancers;

import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
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.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;

import java.util.Collections;
import java.util.List;

/**
 * Created by Max Medvedev on 27/02/14
 */
public class ClosureParamsEnhancer extends AbstractClosureParameterEnhancer {

  @Nullable
  @Override
  protected PsiType getClosureParameterType(GrClosableBlock closure, int index) {
    if (!GroovyConfigUtils.getInstance().isVersionAtLeast(closure, GroovyConfigUtils.GROOVY2_3)) return null;

    final GrParameter[] parameters = closure.getAllParameters();
    if (containsParametersWithDeclaredType(parameters)) {
      return null;
    }

    List fittingSignatures = findFittingSignatures(closure);

    if (fittingSignatures.size() == 1) {
      PsiType[] expectedSignature = fittingSignatures.get(0);
      return expectedSignature[index];
    }

    return null;
  }

  @NotNull
  public static List findFittingSignatures(GrClosableBlock closure) {
    GrCall call = findCall(closure);
    if (call == null) return Collections.emptyList();

    List expectedSignatures = ContainerUtil.newArrayList();

    GroovyResolveResult[] variants = call.getCallVariants(closure);
    for (GroovyResolveResult variant : variants) {
      expectedSignatures.addAll(inferExpectedSignatures(variant, call, closure));
    }

    final GrParameter[] parameters = closure.getAllParameters();
    return ContainerUtil.findAll(expectedSignatures, new Condition() {
      @Override
      public boolean value(PsiType[] types) {
        return types.length == parameters.length;
      }
    });
  }

  private static List inferExpectedSignatures(@NotNull GroovyResolveResult variant, @NotNull GrCall call, @NotNull GrClosableBlock closure) {
    PsiElement element = variant.getElement();

    while (element instanceof PsiMirrorElement) element = ((PsiMirrorElement)element).getPrototype();
    if (!(element instanceof PsiMethod)) return Collections.emptyList();

    List> params = ResolveUtil.collectExpectedParamsByArg(closure,
                                                                                      new GroovyResolveResult[]{variant},
                                                                                      call.getNamedArguments(),
                                                                                      call.getExpressionArguments(),
                                                                                      call.getClosureArguments(), closure);
    if (params.isEmpty()) return Collections.emptyList();

    Pair pair = params.get(0);

    PsiParameter param = pair.getFirst();
    PsiModifierList modifierList = param.getModifierList();
    if (modifierList == null) return Collections.emptyList();

    PsiAnnotation anno = modifierList.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_STC_CLOSURE_PARAMS);
    if (anno == null) return Collections.emptyList();

    PsiClass closureSignatureHint = GrAnnotationUtil.inferClassAttribute(anno, "value");
    if (closureSignatureHint == null) return Collections.emptyList();

    String qnameOfClosureSignatureHint = closureSignatureHint.getQualifiedName();
    if (qnameOfClosureSignatureHint == null) return Collections.emptyList();

    SignatureHintProcessor signatureHintProcessor = SignatureHintProcessor.getHintProcessor(qnameOfClosureSignatureHint);
    if (signatureHintProcessor == null) return Collections.emptyList();

    return signatureHintProcessor.inferExpectedSignatures((PsiMethod)element,
                                                          variant.getSubstitutor(),
                                                          SignatureHintProcessor.buildOptions(anno));
  }

  private static boolean containsParametersWithDeclaredType(GrParameter[] parameters) {
    return ContainerUtil.find(parameters, new Condition() {
      @Override
      public boolean value(GrParameter parameter) {
        return parameter.getDeclaredType() != null;
      }
    }) != null;
  }

  @Nullable
  private static GrCall findCall(@NotNull GrClosableBlock closure) {
    PsiElement parent = closure.getParent();
    if (parent instanceof GrCall && ArrayUtil.contains(closure, ((GrCall)parent).getClosureArguments())) {
      return (GrCall)parent;
    }

    if (parent instanceof GrArgumentList) {
      PsiElement pparent = parent.getParent();
      if (pparent instanceof GrCall) {
        return (GrCall)pparent;
      }
    }

    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy