803d3e9b371ab265757c47d45fc64f453e2ad121
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / backwardRefs / BackwardReferenceIndexUtil.java
1 // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.jps.backwardRefs;
3
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.util.Factory;
6 import com.intellij.util.SmartList;
7 import com.intellij.util.containers.ContainerUtil;
8 import gnu.trove.THashMap;
9 import gnu.trove.TObjectIntHashMap;
10 import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
11 import org.jetbrains.jps.javac.ast.api.JavacDef;
12 import org.jetbrains.jps.javac.ast.api.JavacRef;
13 import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
14
15 import java.io.IOException;
16 import java.util.Collection;
17 import java.util.HashMap;
18 import java.util.Map;
19
20 public class BackwardReferenceIndexUtil {
21   private static final Logger LOG = Logger.getInstance(BackwardReferenceIndexUtil.class);
22
23   static void registerFile(String filePath,
24                            TObjectIntHashMap<? extends JavacRef> refs,
25                            Collection<? extends JavacDef> defs,
26                            Collection<? extends JavacTypeCast> casts,
27                            Collection<? extends JavacRef> implicitToString,
28                            final JavaBackwardReferenceIndexWriter writer) {
29
30     try {
31       final int fileId = writer.enumeratePath(filePath);
32       int funExprId = 0;
33
34       Map<CompilerRef, Void> definitions = new HashMap<>(defs.size());
35       Map<CompilerRef, Collection<CompilerRef>> backwardHierarchyMap = new HashMap<>();
36       Map<SignatureData, Collection<CompilerRef>> signatureData = new THashMap<>();
37       Map<CompilerRef, Collection<CompilerRef>> castMap = new THashMap<>();
38       Map<CompilerRef, Void> implicitToStringMap = new THashMap<>();
39
40       final AnonymousClassEnumerator anonymousClassEnumerator = new AnonymousClassEnumerator();
41
42       for (JavacDef def : defs) {
43         if (def instanceof JavacDef.JavacClassDef) {
44           JavacRef.JavacClass sym = (JavacRef.JavacClass)def.getDefinedElement();
45           if (sym.isPackageInfo()) {
46             continue; // skip special 'package-info' class
47           }
48           final CompilerRef.CompilerClassHierarchyElementDef aClass;
49           if (sym.isAnonymous()) {
50             final JavacRef[] classes = ((JavacDef.JavacClassDef)def).getSuperClasses();
51             if (classes.length == 0) {
52               LOG.info("Seems that compilation will finish with errors in anonymous class inside file " + filePath);
53               continue;
54             }
55             aClass = anonymousClassEnumerator.addAnonymous(sym.getName(), writer.asClassUsage(classes[0]));
56           } else {
57             aClass = writer.asClassUsage(sym);
58           }
59           definitions.put(aClass, null);
60
61           final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses();
62           for (JavacRef superClass : superClasses) {
63             CompilerRef.JavaCompilerClassRef superClassRef = writer.asClassUsage(superClass);
64
65             backwardHierarchyMap.computeIfAbsent(superClassRef, k -> new SmartList<>()).add(aClass);
66           }
67         }
68         else if (def instanceof JavacDef.JavacFunExprDef) {
69           final CompilerRef.JavaCompilerClassRef functionalType = writer.asClassUsage(def.getDefinedElement());
70           int id = funExprId++;
71           CompilerRef.JavaCompilerFunExprDef result = new CompilerRef.JavaCompilerFunExprDef(id);
72           definitions.put(result, null);
73
74           ContainerUtil.getOrCreate(backwardHierarchyMap, functionalType,
75                                     (Factory<Collection<CompilerRef>>)() -> new SmartList<>()).add(result);
76         }
77         else if (def instanceof JavacDef.JavacMemberDef) {
78           final CompilerRef
79             ref = writer.enumerateNames(def.getDefinedElement(), name -> anonymousClassEnumerator.getCompilerRefIfAnonymous(name));
80           final CompilerRef.JavaCompilerClassRef returnType = writer.asClassUsage(((JavacDef.JavacMemberDef)def).getReturnType());
81           if (ref != null && returnType != null) {
82             final SignatureData data = new SignatureData(returnType.getName(), ((JavacDef.JavacMemberDef)def).getIteratorKind(), ((JavacDef.JavacMemberDef)def).isStatic());
83             signatureData.computeIfAbsent(data, element -> new SmartList<>()).add(ref);
84           }
85         }
86       }
87
88       Map<CompilerRef, Integer> convertedRefs = new THashMap<>();
89       IOException[] exception = new IOException[]{null};
90       refs.forEachEntry((ref, count) -> {
91         final CompilerRef compilerRef;
92         try {
93           compilerRef = writer.enumerateNames(ref, name -> anonymousClassEnumerator.getCompilerRefIfAnonymous(name));
94           if (compilerRef != null) {
95             Integer old = convertedRefs.get(compilerRef);
96             convertedRefs.put(compilerRef, old == null ? count : (old + count));
97           }
98         }
99         catch (IOException e) {
100           exception[0] = e;
101           return false;
102         }
103         return true;
104       });
105       if (exception[0] != null) {
106         throw exception[0];
107       }
108
109       for (JavacTypeCast cast : casts) {
110         CompilerRef enumeratedCastType = writer.enumerateNames(cast.getCastType(), name -> null);
111         if (enumeratedCastType == null) continue;
112         CompilerRef enumeratedOperandType = writer.enumerateNames(cast.getOperandType(), name -> null);
113         if (enumeratedOperandType == null) continue;
114         castMap.computeIfAbsent(enumeratedCastType, t -> new SmartList<>()).add(enumeratedOperandType);
115       }
116
117       for (JavacRef ref : implicitToString) {
118         implicitToStringMap.put(writer.asClassUsage(ref), null);
119       }
120
121       writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData, implicitToStringMap));
122     }
123     catch (IOException e) {
124       writer.setRebuildCause(e);
125     }
126   }
127
128   private static class AnonymousClassEnumerator {
129     private THashMap<String, CompilerRef.CompilerClassHierarchyElementDef> myAnonymousName2Id = null;
130
131     private CompilerRef.JavaCompilerAnonymousClassRef addAnonymous(String internalName,
132                                                                    CompilerRef.JavaCompilerClassRef base) {
133       if (myAnonymousName2Id == null) {
134         myAnonymousName2Id = new THashMap<>();
135       }
136       final int anonymousIdx = myAnonymousName2Id.size();
137       myAnonymousName2Id.put(internalName, base);
138       return new CompilerRef.JavaCompilerAnonymousClassRef(anonymousIdx);
139     }
140
141     private Integer getCompilerRefIfAnonymous(String className) {
142       if (myAnonymousName2Id == null) return null;
143       final CompilerRef.CompilerClassHierarchyElementDef ref = myAnonymousName2Id.get(className);
144       return ref == null ? null : ref.getName();
145     }
146   }
147 }