1 // Copyright 2000-2020 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;
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;
15 import java.io.IOException;
16 import java.util.Collection;
17 import java.util.HashMap;
20 public final class BackwardReferenceIndexUtil {
21 private static final Logger LOG = Logger.getInstance(BackwardReferenceIndexUtil.class);
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) {
31 final int fileId = writer.enumeratePath(filePath);
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<>();
40 final AnonymousClassEnumerator anonymousClassEnumerator = new AnonymousClassEnumerator();
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
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);
55 aClass = anonymousClassEnumerator.addAnonymous(sym.getName(), writer.asClassUsage(classes[0]));
57 aClass = writer.asClassUsage(sym);
59 definitions.put(aClass, null);
61 final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses();
62 for (JavacRef superClass : superClasses) {
63 CompilerRef.JavaCompilerClassRef superClassRef = writer.asClassUsage(superClass);
65 backwardHierarchyMap.computeIfAbsent(superClassRef, k -> new SmartList<>()).add(aClass);
68 else if (def instanceof JavacDef.JavacFunExprDef) {
69 final CompilerRef.JavaCompilerClassRef functionalType = writer.asClassUsage(def.getDefinedElement());
71 CompilerRef.JavaCompilerFunExprDef result = new CompilerRef.JavaCompilerFunExprDef(id);
72 definitions.put(result, null);
74 ContainerUtil.getOrCreate(backwardHierarchyMap, functionalType,
75 (Factory<Collection<CompilerRef>>)() -> new SmartList<>()).add(result);
77 else if (def instanceof JavacDef.JavacMemberDef) {
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);
88 Map<CompilerRef, Integer> convertedRefs = new THashMap<>();
89 IOException[] exception = new IOException[]{null};
90 refs.forEachEntry((ref, count) -> {
91 final CompilerRef compilerRef;
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));
99 catch (IOException e) {
105 if (exception[0] != null) {
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);
117 for (JavacRef ref : implicitToString) {
118 implicitToStringMap.put(writer.asClassUsage(ref), null);
121 writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData, implicitToStringMap));
123 catch (IOException e) {
124 writer.setRebuildCause(e);
128 private static class AnonymousClassEnumerator {
129 private THashMap<String, CompilerRef.CompilerClassHierarchyElementDef> myAnonymousName2Id = null;
131 private CompilerRef.JavaCompilerAnonymousClassRef addAnonymous(String internalName,
132 CompilerRef.JavaCompilerClassRef base) {
133 if (myAnonymousName2Id == null) {
134 myAnonymousName2Id = new THashMap<>();
136 final int anonymousIdx = myAnonymousName2Id.size();
137 myAnonymousName2Id.put(internalName, base);
138 return new CompilerRef.JavaCompilerAnonymousClassRef(anonymousIdx);
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();