|
1 | 1 | /*
|
2 |
| - * Copyright 2009-2020 the original author or authors. |
| 2 | + * Copyright 2009-2021 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
19 | 19 | import java.util.Collection;
|
20 | 20 | import java.util.Collections;
|
21 | 21 | import java.util.HashMap;
|
22 |
| -import java.util.Iterator; |
23 | 22 | import java.util.LinkedHashSet;
|
24 | 23 | import java.util.List;
|
25 | 24 | import java.util.Map;
|
26 | 25 | import java.util.Set;
|
| 26 | +import java.util.function.BiConsumer; |
27 | 27 | import java.util.function.BiPredicate;
|
28 | 28 |
|
29 | 29 | import org.codehaus.groovy.ast.ClassHelper;
|
30 | 30 | import org.codehaus.groovy.ast.ClassNode;
|
31 | 31 | import org.codehaus.groovy.ast.FieldNode;
|
32 | 32 | import org.codehaus.groovy.ast.MethodNode;
|
33 | 33 | import org.codehaus.groovy.ast.ModuleNode;
|
| 34 | +import org.codehaus.groovy.ast.tools.GenericsUtils; |
34 | 35 | import org.codehaus.groovy.eclipse.codeassist.ProposalUtils;
|
35 | 36 | import org.codehaus.groovy.eclipse.codeassist.proposals.AbstractGroovyProposal;
|
36 | 37 | import org.codehaus.groovy.eclipse.codeassist.proposals.IGroovyProposal;
|
@@ -112,7 +113,9 @@ protected Collection<FieldNode> getAllFields(ClassNode thisType, Set<ClassNode>
|
112 | 113 |
|
113 | 114 | Map<String, FieldNode> allFields = new HashMap<>();
|
114 | 115 |
|
115 |
| - Set<ClassNode> types = getAllSupers(thisType, exclude); |
| 116 | + Set<ClassNode> types = new LinkedHashSet<>(); |
| 117 | + VariableScope.createTypeHierarchy(thisType, types, false); |
| 118 | + types.removeAll(exclude); |
116 | 119 |
|
117 | 120 | for (ClassNode type : types) {
|
118 | 121 | List<FieldNode> fields = type.getFields();
|
@@ -140,32 +143,50 @@ protected Collection<FieldNode> getAllFields(ClassNode thisType, Set<ClassNode>
|
140 | 143 | }
|
141 | 144 |
|
142 | 145 | protected Collection<MethodNode> getAllMethods(ClassNode type, Set<ClassNode> exclude) {
|
143 |
| - List<MethodNode> traitMethods = type.redirect().getNodeMetaData("trait.methods"); |
144 |
| - List<MethodNode> allMethods = type.getAllDeclaredMethods(); |
145 |
| - if (traitMethods != null) allMethods.addAll(traitMethods); |
146 |
| - |
147 |
| - if (!exclude.isEmpty()) { |
148 |
| - // remove all methods from classes that have already been visited |
149 |
| - for (Iterator<MethodNode> methodIter = allMethods.iterator(); methodIter.hasNext();) { |
150 |
| - if (exclude.contains(methodIter.next().getDeclaringClass())) { |
151 |
| - methodIter.remove(); |
| 146 | + Map<String, MethodNode> methods = new HashMap<>(); |
| 147 | + |
| 148 | + BiConsumer<MethodNode, Map<String, ClassNode>> mapper = (mn, spec) -> { |
| 149 | + StringBuilder sb = new StringBuilder(mn.getName()); |
| 150 | + sb.append('('); |
| 151 | + for (org.codehaus.groovy.ast.Parameter p : mn.getParameters()) { |
| 152 | + ClassNode pt = p.getOriginType(); |
| 153 | + if (!pt.isGenericsPlaceHolder()) { |
| 154 | + sb.append(pt.getName()); |
| 155 | + } else { |
| 156 | + sb.append(spec.getOrDefault(pt.getUnresolvedName(), pt).getName()); |
| 157 | + } |
| 158 | + sb.append(';'); |
| 159 | + } |
| 160 | + |
| 161 | + methods.merge(sb.toString(), mn, (m1, m2) -> |
| 162 | + // keep override method unless it's synthetic |
| 163 | + !Flags.isSynthetic(m1.getModifiers()) ? m1 : m2); |
| 164 | + }; |
| 165 | + |
| 166 | + if (exclude == null || !exclude.contains(type)) { |
| 167 | + List<MethodNode> traitMethods = type.redirect().getNodeMetaData("trait.methods"); |
| 168 | + if (traitMethods != null && !traitMethods.isEmpty()) { |
| 169 | + for (MethodNode mn : traitMethods) { |
| 170 | + mapper.accept(mn, Collections.emptyMap()); |
152 | 171 | }
|
153 | 172 | }
|
154 | 173 | }
|
155 | 174 |
|
156 |
| - Set<ClassNode> types = getAllSupers(type, exclude); |
| 175 | + Set<ClassNode> types = new LinkedHashSet<>(); |
| 176 | + VariableScope.createTypeHierarchy(type, types, true); |
| 177 | + for (ClassNode cn : types) { |
| 178 | + if ((exclude != null && exclude.contains(cn)) || |
| 179 | + Flags.isSynthetic(cn.getModifiers())) continue; |
157 | 180 |
|
158 |
| - // keep track of the already seen types so that next time, we won't include them |
159 |
| - exclude.addAll(types); |
| 181 | + Map<String, ClassNode> spec = GenericsUtils.createGenericsSpec(cn); |
| 182 | + for (MethodNode mn : cn.getMethods()) { |
| 183 | + mapper.accept(mn, spec); |
| 184 | + } |
| 185 | + } |
160 | 186 |
|
161 |
| - return allMethods; |
162 |
| - } |
| 187 | + if (exclude != null) exclude.addAll(types); // exclude types next time |
163 | 188 |
|
164 |
| - private static Set<ClassNode> getAllSupers(ClassNode type, Set<ClassNode> exclude) { |
165 |
| - Set<ClassNode> superTypes = new LinkedHashSet<>(); |
166 |
| - VariableScope.createTypeHierarchy(type, superTypes, false); |
167 |
| - superTypes.removeAll(exclude); |
168 |
| - return superTypes; |
| 189 | + return methods.values(); |
169 | 190 | }
|
170 | 191 |
|
171 | 192 | protected static boolean leftIsMoreAccessible(FieldNode field, FieldNode existing) {
|
|
0 commit comments