/* * 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.intellij.plugins.intelliLang.inject.groovy; import com.intellij.lang.injection.MultiHostInjector; import com.intellij.lang.injection.MultiHostRegistrar; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import org.intellij.plugins.intelliLang.Configuration; import org.intellij.plugins.intelliLang.inject.InjectorUtils; import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport; import org.intellij.plugins.intelliLang.inject.config.BaseInjection; import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport; import org.intellij.plugins.intelliLang.util.AnnotationUtilEx; import org.intellij.plugins.intelliLang.util.PsiUtilEx; 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.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; 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.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Max Medvedev */ public class GrConcatenationInjector implements MultiHostInjector { @Override public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context) { assert context instanceof GrLiteral; final GrLiteral literal = (GrLiteral)context; processInPlace(registrar, literal); } public static void processInPlace(MultiHostRegistrar registrar, GrLiteral literal) { BaseInjection injection = findLanguageParams(literal); if (injection != null) { LanguageInjectionSupport support = InjectorUtils.findInjectionSupport(GroovyLanguageInjectionSupport.GROOVY_SUPPORT_ID); InjectorUtils.registerInjectionSimple(literal, injection, support, registrar); } } private static BaseInjection findLanguageParams(PsiElement place) { PsiElement parent = place.getParent(); if (parent instanceof GrAssignmentExpression && ((GrAssignmentExpression)parent).getRValue() == place) { final GrExpression lvalue = ((GrAssignmentExpression)parent).getLValue(); if (lvalue instanceof GrReferenceExpression) { final PsiElement resolved = ((GrReferenceExpression)lvalue).resolve(); if (resolved instanceof PsiModifierListOwner) { return getLanguageParams((PsiModifierListOwner)resolved); } } } else if (parent instanceof GrVariable) { return getLanguageParams((PsiModifierListOwner)parent); } else if (parent instanceof GrArgumentList) { final PsiElement pparent = parent.getParent(); if (pparent instanceof GrCall) { final GrCall call = (GrCall)pparent; final GroovyResolveResult result = call.advancedResolve(); if (result.getElement() != null) { final Map<GrExpression, Pair<PsiParameter, PsiType>> map = GrClosureSignatureUtil .mapArgumentsToParameters(result, place, false, false, call.getNamedArguments(), call.getExpressionArguments(), call.getClosureArguments()); if (map != null) { final Pair<PsiParameter, PsiType> pair = map.get(place); return getLanguageParams(pair.first); } } } } return null; } @Nullable private static BaseInjection getLanguageParams(PsiModifierListOwner annotationOwner) { return CachedValuesManager.getCachedValue(annotationOwner, () -> CachedValueProvider.Result.create(calcLanguageParams(annotationOwner), PsiModificationTracker.MODIFICATION_COUNT)); } @Nullable private static BaseInjection calcLanguageParams(PsiModifierListOwner annotationOwner) { final Pair<String, ? extends Set<String>> pair = Configuration.getInstance().getAdvancedConfiguration().getLanguageAnnotationPair(); final PsiAnnotation[] annotations = getAnnotationFrom(annotationOwner, pair, true, true); if (annotations.length > 0) { String prefix = StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "prefix")); String suffix = StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "suffix")); String id = StringUtil.notNullize(AnnotationUtilEx.calcAnnotationValue(annotations, "value")); if (!StringUtil.isEmpty(id)) { BaseInjection injection = new BaseInjection(GroovyLanguageInjectionSupport.GROOVY_SUPPORT_ID); injection.setPrefix(prefix); injection.setSuffix(suffix); injection.setInjectedLanguageId(id); return injection; } } if (annotationOwner instanceof PsiParameter && annotationOwner.getParent() instanceof PsiParameterList && annotationOwner.getParent().getParent() instanceof PsiMethod) { List<BaseInjection> injections = Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID); for (BaseInjection injection : injections) { if (injection.acceptsPsiElement(annotationOwner)) { return injection; } } } return null; } @NotNull public static PsiAnnotation[] getAnnotationFrom(PsiModifierListOwner owner, Pair<String, ? extends Set<String>> annotationName, boolean allowIndirect, boolean inHierarchy) { if (!isLanguageAnnotationTargetGroovy(owner)) return PsiAnnotation.EMPTY_ARRAY; return AnnotationUtilEx.getAnnotationsFromImpl(owner, annotationName, allowIndirect, inHierarchy); } private static boolean isLanguageAnnotationTargetGroovy(PsiModifierListOwner owner) { return owner instanceof GrMethod && ((GrMethod)owner).getReturnTypeElementGroovy() == null || owner instanceof GrVariable && ((GrVariable)owner).getTypeElementGroovy() == null || PsiUtilEx.isLanguageAnnotationTarget(owner); } @NotNull @Override public List<? extends Class<? extends PsiElement>> elementsToInjectIn() { return Collections.singletonList(GrLiteral.class); } }