2 * Copyright 2000-2017 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.jetbrains.jps.backwardRefs;
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.util.Factory;
20 import com.intellij.util.SmartList;
21 import com.intellij.util.containers.ContainerUtil;
22 import gnu.trove.THashMap;
23 import gnu.trove.TObjectIntHashMap;
24 import org.jetbrains.jps.backwardRefs.index.CompiledFileData;
25 import org.jetbrains.jps.javac.ast.api.JavacDef;
26 import org.jetbrains.jps.javac.ast.api.JavacRef;
27 import org.jetbrains.jps.javac.ast.api.JavacTypeCast;
29 import java.io.IOException;
30 import java.util.Collection;
31 import java.util.HashMap;
34 public class BackwardReferenceIndexUtil {
35 private static final Logger LOG = Logger.getInstance(BackwardReferenceIndexUtil.class);
37 static void registerFile(String filePath,
38 TObjectIntHashMap<? extends JavacRef> refs,
39 Collection<JavacDef> defs,
40 Collection<JavacTypeCast> casts,
41 final BackwardReferenceIndexWriter writer) {
44 final int fileId = writer.enumeratePath(filePath);
47 Map<LightRef, Void> definitions = new HashMap<>(defs.size());
48 Map<LightRef, Collection<LightRef>> backwardHierarchyMap = new HashMap<>();
49 Map<SignatureData, Collection<LightRef>> signatureData = new THashMap<>();
50 THashMap<LightRef, Collection<LightRef>> castMap = new THashMap<>();
53 final AnonymousClassEnumerator anonymousClassEnumerator = new AnonymousClassEnumerator();
55 for (JavacDef def : defs) {
56 if (def instanceof JavacDef.JavacClassDef) {
57 JavacRef.JavacClass sym = (JavacRef.JavacClass)def.getDefinedElement();
59 final LightRef.LightClassHierarchyElementDef aClass;
60 if (sym.isAnonymous()) {
61 final JavacRef[] classes = ((JavacDef.JavacClassDef)def).getSuperClasses();
62 if (classes.length == 0) {
63 LOG.info("Seems that compilation will finish with errors in anonymous class inside file " + filePath);
66 aClass = anonymousClassEnumerator.addAnonymous(sym.getName(), writer.asClassUsage(classes[0]));
68 aClass = writer.asClassUsage(sym);
70 definitions.put(aClass, null);
72 final JavacRef[] superClasses = ((JavacDef.JavacClassDef)def).getSuperClasses();
73 for (JavacRef superClass : superClasses) {
74 LightRef.JavaLightClassRef superClassRef = writer.asClassUsage(superClass);
76 backwardHierarchyMap.computeIfAbsent(superClassRef, k -> new SmartList<>()).add(aClass);
79 else if (def instanceof JavacDef.JavacFunExprDef) {
80 final LightRef.JavaLightClassRef functionalType = writer.asClassUsage(def.getDefinedElement());
82 LightRef.JavaLightFunExprDef result = new LightRef.JavaLightFunExprDef(id);
83 definitions.put(result, null);
85 ContainerUtil.getOrCreate(backwardHierarchyMap, functionalType,
86 (Factory<Collection<LightRef>>)() -> new SmartList<>()).add(result);
88 else if (def instanceof JavacDef.JavacMemberDef) {
89 final LightRef ref = writer.enumerateNames(def.getDefinedElement(), name -> anonymousClassEnumerator.getLightRefIfAnonymous(name));
90 final LightRef.JavaLightClassRef returnType = writer.asClassUsage(((JavacDef.JavacMemberDef)def).getReturnType());
91 if (ref != null && returnType != null) {
92 final SignatureData data = new SignatureData(returnType.getName(), ((JavacDef.JavacMemberDef)def).getIteratorKind(), ((JavacDef.JavacMemberDef)def).isStatic());
93 signatureData.computeIfAbsent(data, element -> new SmartList<>()).add(ref);
98 Map<LightRef, Integer> convertedRefs = new THashMap<>();
99 IOException[] exception = new IOException[]{null};
100 refs.forEachEntry((ref, count) -> {
101 final LightRef lightRef;
103 lightRef = writer.enumerateNames(ref, name -> anonymousClassEnumerator.getLightRefIfAnonymous(name));
104 if (lightRef != null) {
105 Integer old = convertedRefs.get(lightRef);
106 convertedRefs.put(lightRef, old == null ? count : (old + count));
109 catch (IOException e) {
115 if (exception[0] != null) {
119 for (JavacTypeCast cast : casts) {
120 LightRef enumeratedCastType = writer.enumerateNames(cast.getCastType(), name -> null);
121 if (enumeratedCastType == null) continue;
122 LightRef enumeratedOperandType = writer.enumerateNames(cast.getOperandType(), name -> null);
123 if (enumeratedOperandType == null) continue;
124 castMap.computeIfAbsent(enumeratedCastType, t -> new SmartList<>()).add(enumeratedOperandType);
127 writer.writeData(fileId, new CompiledFileData(backwardHierarchyMap, castMap, convertedRefs, definitions, signatureData));
129 catch (IOException e) {
130 writer.setRebuildCause(e);
134 private static class AnonymousClassEnumerator {
135 private THashMap<String, LightRef.LightClassHierarchyElementDef> myAnonymousName2Id = null;
137 private LightRef.JavaLightAnonymousClassRef addAnonymous(String internalName,
138 LightRef.JavaLightClassRef base) {
139 if (myAnonymousName2Id == null) {
140 myAnonymousName2Id = new THashMap<>();
142 final int anonymousIdx = myAnonymousName2Id.size();
143 myAnonymousName2Id.put(internalName, base);
144 return new LightRef.JavaLightAnonymousClassRef(anonymousIdx);
147 private Integer getLightRefIfAnonymous(String className) {
148 if (myAnonymousName2Id == null) return null;
149 final LightRef.LightClassHierarchyElementDef ref = myAnonymousName2Id.get(className);
150 return ref == null ? null : ref.getName();