constructor reference: don't ignore constructor parameters during method reference...
[idea/community.git] / java / java-impl / src / com / intellij / codeInsight / template / macro / DescendantClassesEnumMacro.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInsight.template.macro;
17
18 import com.intellij.codeInsight.CodeInsightBundle;
19 import com.intellij.codeInsight.lookup.LookupElement;
20 import com.intellij.codeInsight.lookup.LookupElementBuilder;
21 import com.intellij.codeInsight.template.*;
22 import com.intellij.psi.*;
23 import com.intellij.psi.search.GlobalSearchScope;
24 import com.intellij.psi.search.PsiElementProcessor;
25 import com.intellij.psi.search.PsiElementProcessorAdapter;
26 import com.intellij.psi.search.searches.ClassInheritorsSearch;
27 import org.jetbrains.annotations.NotNull;
28 import org.jetbrains.annotations.Nullable;
29
30 import java.util.ArrayList;
31 import java.util.LinkedHashSet;
32 import java.util.List;
33 import java.util.Set;
34
35 public class DescendantClassesEnumMacro extends Macro {
36   @Override
37   public String getName() {
38     return "descendantClassesEnum";
39   }
40
41   @Override
42   public String getPresentableName() {
43     return CodeInsightBundle.message("macro.descendant.classes.enum");
44   }
45
46   @Override
47   public Result calculateResult(@NotNull Expression[] params, ExpressionContext context) {
48     final List<PsiClass> classes = findDescendants(context, params);
49     if (classes == null || classes.size() == 0) return null;
50     Result[] results = calculateResults(classes);
51
52     return results[0];
53   }
54
55   private static Result[] calculateResults(final List<? extends PsiClass> classes) {
56     Result[] results = new Result[classes.size()];
57     int i = 0;
58
59     for (final PsiClass aClass : classes) {
60       results[i++] = new JavaPsiElementResult(aClass);
61     }
62     return results;
63   }
64
65   @Nullable
66   private static List<PsiClass> findDescendants(ExpressionContext context, Expression[] params) {
67     if (params == null || params.length == 0) return null;
68     PsiManager instance = PsiManager.getInstance(context.getProject());
69
70     Result result = params[0].calculateResult(context);
71     if (result == null) return null;
72     
73     final String paramResult = result.toString();
74     if (paramResult == null) return null;
75
76     final boolean isAllowAbstract = isAllowAbstract(context, params);
77     final PsiClass myBaseClass =
78       JavaPsiFacade.getInstance(instance.getProject()).findClass(paramResult, GlobalSearchScope.allScope(context.getProject()));
79
80     if (myBaseClass != null) {
81       final List<PsiClass> classes = new ArrayList<>();
82
83       ClassInheritorsSearch.search(myBaseClass).forEach(new PsiElementProcessorAdapter<>(new PsiElementProcessor<PsiClass>() {
84         @Override
85         public boolean execute(@NotNull PsiClass element) {
86           if (isAllowAbstract || !isAbstractOrInterface(element)) {
87             classes.add(element);
88           }
89           return true;
90         }
91       }));
92
93       return classes;
94     }
95
96     return null;
97   }
98
99   @Override
100   public Result calculateQuickResult(@NotNull Expression[] params, ExpressionContext context) {
101     final List<PsiClass> classes = findDescendants(context, params);
102     if (classes == null || classes.size() == 0) return null;
103     Result[] results = calculateResults(classes);
104
105     return results[0];
106   }
107
108   @Override
109   public LookupElement[] calculateLookupItems(@NotNull Expression[] params, ExpressionContext context) {
110     final List<PsiClass> classes = findDescendants(context, params);
111     if (classes == null || classes.size() == 0) return null;
112
113     Set<LookupElement> set = new LinkedHashSet<>();
114     boolean isShortName = params.length > 1 && !Boolean.valueOf(params[1].calculateResult(context).toString());
115
116     for (PsiClass object : classes) {
117       final String name = isShortName ? object.getName() : object.getQualifiedName();
118       if (name != null && name.length() > 0) {
119         set.add(LookupElementBuilder.create(name));
120       }
121     }
122
123     return set.toArray(LookupElement.EMPTY_ARRAY);
124   }
125
126   private static boolean isAbstractOrInterface(final PsiClass psiClass) {
127     final PsiModifierList modifierList = psiClass.getModifierList();
128
129     return psiClass.isInterface() || (modifierList != null && modifierList.hasModifierProperty(PsiModifier.ABSTRACT));
130   }
131
132   private static boolean isAllowAbstract(final ExpressionContext context, final Expression[] params) {
133       return params.length > 2 ? Boolean.valueOf(params[2].calculateResult(context).toString()) : true;
134   }
135
136   @Override
137   public boolean isAcceptableInContext(TemplateContextType context) {
138     return context instanceof JavaCodeContextType;
139   }
140
141 }