type casts in relevant method chain completion: various renames
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / backwardRefs / BackwardReferenceIndexUtil.java
1 /*
2  * Copyright 2000-2017 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 org.jetbrains.jps.backwardRefs;
17
18 import com.intellij.openapi.util.Factory;
19 import com.intellij.util.SmartList;
20 import com.intellij.util.containers.ContainerUtil;
21 import gnu.trove.THashMap;
22 import gnu.trove.TObjectIntHashMap;
23 import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
24 import org.jetbrains.jps.javac.ast.api.JavacDef;
25 import org.jetbrains.jps.javac.ast.api.JavacRef;
26 import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
27
28 import java.io.IOException;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.Map;
32
33 public class BackwardReferenceIndexUtil {
34   static void registerFile(String filePath,
35                            TObjectIntHashMap<? extends JavacRef> refs,
36                            Collection<JavacDef> defs,
37                            Collection<JavacTypeCast> casts,
38                            final BackwardReferenceIndexWriter writer) {
39
40     try {
41       final int fileId = writer.enumeratePath(filePath);
42       int funExprId = 0;
43
44       Map<LightRef, Void> definitions = new HashMap<>(defs.size());
45       Map<LightRef, Collection<LightRef>> backwardHierarchyMap = new HashMap<>();
46       Map<SignatureData, Collection<LightRef>> signatureData = new THashMap<>();
47       THashMap<LightRef, Collection<LightRef>> castMap = new THashMap<>();
48
49
50       final AnonymousClassEnumerator anonymousClassEnumerator = new AnonymousClassEnumerator();
51
52       for (JavacDef def : defs) {
53         if (def instanceof JavacDef.JavacClassDef) {
54           JavacRef.JavacClass sym = (JavacRef.JavacClass)def.getDefinedElement();
55
56           final LightRef.LightClassHierarchyElementDef aClass;
57           if (sym.isAnonymous()) {
58             final JavacRef[] classes = ((JavacDef.JavacClassDef)def).getSuperClasses();
59             aClass = anonymousClassEnumerator.addAnonymous(sym.getName(), writer.asClassUsage(classes[0]));
60           } else {
61             aClass = writer.asClassUsage(sym);
62           }
63           definitions.put(aClass, null);
64
65           final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses();
66           for (JavacRef superClass : superClasses) {
67             LightRef.JavaLightClassRef superClassRef = writer.asClassUsage(superClass);
68
69             backwardHierarchyMap.computeIfAbsent(superClassRef, k -> new SmartList<>()).add(aClass);
70           }
71         }
72         else if (def instanceof JavacDef.JavacFunExprDef) {
73           final LightRef.JavaLightClassRef functionalType = writer.asClassUsage(def.getDefinedElement());
74           int id = funExprId++;
75           LightRef.JavaLightFunExprDef result = new LightRef.JavaLightFunExprDef(id);
76           definitions.put(result, null);
77
78           ContainerUtil.getOrCreate(backwardHierarchyMap, functionalType,
79                                     (Factory<Collection<LightRef>>)() -> new SmartList<>()).add(result);
80         }
81         else if (def instanceof JavacDef.JavacMemberDef) {
82           final LightRef ref = writer.enumerateNames(def.getDefinedElement(), name -> anonymousClassEnumerator.getLightRefIfAnonymous(name));
83           final LightRef.JavaLightClassRef returnType = writer.asClassUsage(((JavacDef.JavacMemberDef)def).getReturnType());
84           if (ref != null && returnType != null) {
85             final SignatureData data = new SignatureData(returnType.getName(), ((JavacDef.JavacMemberDef)def).getIteratorKind(), ((JavacDef.JavacMemberDef)def).isStatic());
86             signatureData.computeIfAbsent(data, element -> new SmartList<>()).add(ref);
87           }
88         }
89       }
90
91       Map<LightRef, Integer> convertedRefs = new THashMap<>();
92       IOException[] exception = new IOException[]{null};
93       refs.forEachEntry((ref, count) -> {
94         final LightRef lightRef;
95         try {
96           lightRef = writer.enumerateNames(ref, name -> anonymousClassEnumerator.getLightRefIfAnonymous(name));
97           if (lightRef != null) {
98             Integer old = convertedRefs.get(lightRef);
99             convertedRefs.put(lightRef, old == null ? count : (old + count));
100           }
101         }
102         catch (IOException e) {
103           exception[0] = e;
104           return false;
105         }
106         return true;
107       });
108       if (exception[0] != null) {
109         throw exception[0];
110       }
111
112       for (JavacTypeCast cast : casts) {
113         LightRef enumeratedCastType = writer.enumerateNames(cast.getCastType(), name -> null);
114         if (enumeratedCastType == null) continue;
115         LightRef enumeratedOperandType = writer.enumerateNames(cast.getOperandType(), name -> null);
116         if (enumeratedOperandType == null) continue;
117         castMap.computeIfAbsent(enumeratedCastType, t -> new SmartList<>()).add(enumeratedOperandType);
118       }
119
120       writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData));
121     }
122     catch (IOException e) {
123       writer.setRebuildCause(e);
124     }
125   }
126
127   private static class AnonymousClassEnumerator {
128     private THashMap<String, LightRef.LightClassHierarchyElementDef> myAnonymousName2Id = null;
129
130     private LightRef.JavaLightAnonymousClassRef addAnonymous(String internalName,
131                                                              LightRef.JavaLightClassRef base) {
132       if (myAnonymousName2Id == null) {
133         myAnonymousName2Id = new THashMap<>();
134       }
135       final int anonymousIdx = myAnonymousName2Id.size();
136       myAnonymousName2Id.put(internalName, base);
137       return new LightRef.JavaLightAnonymousClassRef(anonymousIdx);
138     }
139
140     private Integer getLightRefIfAnonymous(String className) {
141       if (myAnonymousName2Id == null) return null;
142       final LightRef.LightClassHierarchyElementDef ref = myAnonymousName2Id.get(className);
143       return ref == null ? null : ref.getName();
144     }
145   }
146 }