2 * Copyright 2000-2016 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.util.SystemProperties;
19 import com.sun.tools.javac.code.Symbol;
20 import gnu.trove.TIntHashSet;
21 import gnu.trove.TIntProcedure;
22 import org.jetbrains.annotations.NotNull;
23 import org.jetbrains.jps.builders.java.JavaBuilderUtil;
24 import org.jetbrains.jps.builders.storage.BuildDataCorruptedException;
25 import org.jetbrains.jps.incremental.CompileContext;
26 import org.jetbrains.jps.incremental.java.JavaBuilder;
27 import org.jetbrains.jps.incremental.storage.BuildDataManager;
28 import org.jetbrains.jps.javac.ast.api.JavacRefSymbol;
29 import org.jetbrains.jps.model.java.compiler.JavaCompilers;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.Collection;
38 public class BackwardReferenceIndexWriter {
39 public static final String PROP_KEY = "ref.index.builder";
41 private static volatile BackwardReferenceIndexWriter ourInstance;
43 private final CompilerBackwardReferenceIndex myIndex;
44 private final boolean myRebuild;
46 private BackwardReferenceIndexWriter(CompilerBackwardReferenceIndex index, boolean rebuild) {
51 static BackwardReferenceIndexWriter getInstance() {
55 static void initialize(@NotNull CompileContext context) {
57 final BuildDataManager dataManager = context.getProjectDescriptor().dataManager;
58 final File buildDir = dataManager.getDataPaths().getDataStorageRoot();
59 boolean isRebuild = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context);
61 if (!JavaCompilers.JAVAC_ID.equals(JavaBuilder.getUsedCompilerId(context))) {
62 CompilerBackwardReferenceIndex.removeIndexFiles(buildDir);
66 CompilerBackwardReferenceIndex.removeIndexFiles(buildDir);
68 else if (CompilerBackwardReferenceIndex.versionDiffers(buildDir)) {
69 throw new BuildDataCorruptedException(new IOException("backward reference index should be updated to actual version"));
72 if (CompilerBackwardReferenceIndex.exist(buildDir) || isRebuild) {
73 ourInstance = new BackwardReferenceIndexWriter(new CompilerBackwardReferenceIndex(buildDir), isRebuild);
78 static boolean isEnabled() {
79 return SystemProperties.getBooleanProperty(PROP_KEY, false);
86 synchronized void writeReferences(JavaFileObject file, Set<JavacRefSymbol> refs) {
87 final LightUsage[] usages = new LightUsage[refs.size()];
89 final ByteArrayEnumerator byteSeqEum = myIndex.getByteSeqEum();
90 for (JavacRefSymbol ref : refs) {
91 usages[idx++] = LightUsage.fromSymbol(ref.getSymbol(), byteSeqEum);
94 final int fileId = enumerateFile(file);
96 for (LightUsage usage : usages) {
97 myIndex.getBackwardReferenceMap().put(usage, fileId);
98 myIndex.getReferenceMap().put(fileId, usage);
102 updateReferenceIndicesIncrementally(fileId, usages);
106 private void updateReferenceIndicesIncrementally(int fileId, LightUsage[] usages) {
107 final Collection<LightUsage> rawOldUsages = myIndex.getReferenceMap().get(fileId);
108 Collection<LightUsage> oldUsages = rawOldUsages == null ? null : new ArrayList<LightUsage>(rawOldUsages);
109 for (LightUsage usage : usages) {
110 if (oldUsages == null || !oldUsages.remove(usage)) {
111 myIndex.getBackwardReferenceMap().put(usage, fileId);
112 myIndex.getReferenceMap().put(fileId, usage);
115 if (oldUsages != null && !oldUsages.isEmpty()) {
116 myIndex.getReferenceMap().removeAll(fileId, oldUsages);
117 for (LightUsage usage : oldUsages) {
118 myIndex.getBackwardReferenceMap().removeFrom(usage, fileId);
123 synchronized void writeHierarchy(Symbol name, Symbol[] supers) {
124 if (supers.length == 0) {
127 final int classId = classId(name);
128 final int[] superIds = new int[supers.length];
129 for (int i = 0; i < supers.length; i++) {
130 superIds[i] = classId(supers[i]);
134 directlyWriteHierarchyIndices(classId, superIds);
137 updateHierarchyIndicesIncrementally(classId, superIds);
141 private void directlyWriteHierarchyIndices(int classId, int[] superIds) {
142 for (int superId : superIds) {
143 myIndex.getBackwardHierarchyMap().put(superId, classId);
144 myIndex.getHierarchyMap().put(classId, superId);
148 private void updateHierarchyIndicesIncrementally(final int classId, int[] superIds) {
149 final TIntHashSet rawOldSupers = myIndex.getHierarchyMap().get(classId);
150 TIntHashSet oldSuperClasses = rawOldSupers == null ? null : new TIntHashSet(rawOldSupers);
151 for (int superId: superIds) {
152 if (oldSuperClasses == null || !oldSuperClasses.remove(superId)) {
153 myIndex.getBackwardHierarchyMap().put(superId, classId);
154 myIndex.getHierarchyMap().put(classId, superId);
157 if (oldSuperClasses != null && !oldSuperClasses.isEmpty()) {
158 myIndex.getHierarchyMap().removeAll(classId, oldSuperClasses);
159 oldSuperClasses.forEach(new TIntProcedure() {
161 public boolean execute(int oldSuperId) {
162 myIndex.getBackwardHierarchyMap().put(oldSuperId, classId);
169 private int classId(Symbol name) {
170 return myIndex.getByteSeqEum().enumerate(LightUsage.bytes(name));
173 private int enumerateFile(JavaFileObject file) {
175 return myIndex.getFilePathEnumerator().enumerate(file.getName());
177 catch (IOException e) {
178 throw new BuildDataCorruptedException(e);