blob: 41005120e4cfd1b3b55a3347e719fbb59c931ddd [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.impl.auxiliary.modifiers;
import com.intellij.psi.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
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.auxiliary.modifiers.annotation.GrAnnotationArrayInitializer;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationMemberValue;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotationNameValuePair;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class GrAnnotationCollector {
@NotNull
public static GrAnnotation[] getResolvedAnnotations(@NotNull GrModifierList modifierList) {
final GrAnnotation[] rawAnnotations = modifierList.getRawAnnotations();
if (!hasAliases(rawAnnotations)) return rawAnnotations;
List<GrAnnotation> result = ContainerUtil.newArrayList();
for (GrAnnotation annotation : rawAnnotations) {
final PsiAnnotation annotationCollector = findAnnotationCollector(annotation);
if (annotationCollector != null) {
collectAnnotations(result, annotation, annotationCollector);
}
else {
result.add(annotation);
}
}
return result.toArray(new GrAnnotation[result.size()]);
}
private static boolean hasAliases(@NotNull GrAnnotation[] rawAnnotations) {
for (GrAnnotation annotation : rawAnnotations) {
final PsiAnnotation annotationCollector = findAnnotationCollector(annotation);
if (annotationCollector != null) {
return true;
}
}
return false;
}
/**
*
* @param list resulting collection of aliased annotations
* @param alias alias annotation
* @param annotationCollector @AnnotationCollector annotation used in alias declaration
* @return set of used arguments of alias annotation
*/
@NotNull
public static Set<String> collectAnnotations(@NotNull List<GrAnnotation> list,
@NotNull GrAnnotation alias,
@NotNull PsiAnnotation annotationCollector) {
final PsiModifierList modifierList = (PsiModifierList)annotationCollector.getParent();
Map<String, Map<String, PsiNameValuePair>> annotations = ContainerUtil.newHashMap();
collectAliasedAnnotationsFromAnnotationCollectorValueAttribute(annotationCollector, (HashMap<String, Map<String, PsiNameValuePair>>)annotations);
collectAliasedAnnotationsFromAnnotationCollectorAnnotations(modifierList, (HashMap<String, Map<String, PsiNameValuePair>>)annotations);
final PsiManager manager = alias.getManager();
final GrAnnotationNameValuePair[] attributes = alias.getParameterList().getAttributes();
Set<String> allUsedAttrs = ContainerUtil.newHashSet();
for (Map.Entry<String, Map<String, PsiNameValuePair>> entry : annotations.entrySet()) {
final String qname = entry.getKey();
final PsiClass resolved = JavaPsiFacade.getInstance(alias.getProject()).findClass(qname, alias.getResolveScope());
if (resolved == null) continue;
final GrLightAnnotation annotation = new GrLightAnnotation(manager, alias.getLanguage(), qname, modifierList);
Set<String> usedAttrs = ContainerUtil.newHashSet();
for (GrAnnotationNameValuePair attr : attributes) {
final String name = attr.getName() != null ? attr.getName() : "value";
if (resolved.findMethodsByName(name, false).length > 0) {
annotation.addAttribute(attr);
allUsedAttrs.add(name);
usedAttrs.add(name);
}
}
final Map<String, PsiNameValuePair> defaults = entry.getValue();
for (Map.Entry<String, PsiNameValuePair> defa : defaults.entrySet()) {
if (!usedAttrs.contains(defa.getKey())) {
annotation.addAttribute(defa.getValue());
}
}
list.add(annotation);
}
return allUsedAttrs;
}
private static void collectAliasedAnnotationsFromAnnotationCollectorAnnotations(@NotNull PsiModifierList modifierList,
@NotNull HashMap<String, Map<String, PsiNameValuePair>> annotations) {
PsiElement parent = modifierList.getParent();
if (parent instanceof PsiClass &&
GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_DYNAMIC.equals(((PsiClass)parent).getQualifiedName())) {
HashMap<String, PsiNameValuePair> params = ContainerUtil.newHashMap();
annotations.put(GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC, params);
GrAnnotation annotation =
GroovyPsiElementFactory.getInstance(modifierList.getProject()).createAnnotationFromText("@CompileStatic(TypeCheckingMode.SKIP)");
params.put("value", annotation.getParameterList().getAttributes()[0]);
return;
}
PsiAnnotation[] rawAnnotations =
modifierList instanceof GrModifierList ? ((GrModifierList)modifierList).getRawAnnotations() : modifierList.getAnnotations();
for (PsiAnnotation annotation : rawAnnotations) {
final String qname = annotation.getQualifiedName();
if (qname == null || qname.equals(GroovyCommonClassNames.GROOVY_TRANSFORM_ANNOTATION_COLLECTOR)) continue;
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
for (PsiNameValuePair pair : attributes) {
Map<String, PsiNameValuePair> map = annotations.get(qname);
if (map == null) {
map = ContainerUtil.newHashMap();
annotations.put(qname, map);
}
map.put(pair.getName() != null ? pair.getName() : "value", pair);
}
if (attributes.length == 0 && !annotations.containsKey(qname)) {
annotations.put(qname, ContainerUtil.<String, PsiNameValuePair>newHashMap());
}
}
}
private static void collectAliasedAnnotationsFromAnnotationCollectorValueAttribute(@NotNull PsiAnnotation annotationCollector,
@NotNull HashMap<String, Map<String, PsiNameValuePair>> annotations) {
final PsiAnnotationMemberValue annotationsFromValue = annotationCollector.findAttributeValue("value");
if (annotationsFromValue instanceof GrAnnotationArrayInitializer) {
for (GrAnnotationMemberValue member : ((GrAnnotationArrayInitializer)annotationsFromValue).getInitializers()) {
if (member instanceof GrReferenceExpression) {
final PsiElement resolved = ((GrReferenceExpression)member).resolve();
if (resolved instanceof PsiClass && ((PsiClass)resolved).isAnnotationType()) {
annotations.put(((PsiClass)resolved).getQualifiedName(), ContainerUtil.<String, PsiNameValuePair>newHashMap());
}
}
}
}
}
@Nullable
public static PsiAnnotation findAnnotationCollector(@Nullable PsiClass clazz) {
if (clazz != null) {
final PsiModifierList modifierList = clazz.getModifierList();
if (modifierList != null) {
PsiAnnotation[] annotations = modifierList instanceof GrModifierList ? ((GrModifierList)modifierList).getRawAnnotations() : modifierList.getAnnotations();
for (PsiAnnotation annotation : annotations) {
if (GroovyCommonClassNames.GROOVY_TRANSFORM_ANNOTATION_COLLECTOR.equals(annotation.getQualifiedName())) {
return annotation;
}
}
}
}
return null;
}
@Nullable
public static PsiAnnotation findAnnotationCollector(@NotNull GrAnnotation annotation) {
final GrCodeReferenceElement ref = annotation.getClassReference();
final PsiElement resolved = ref.resolve();
if (resolved instanceof PsiClass) {
return findAnnotationCollector((PsiClass)resolved);
}
else {
return null;
}
}
}