blob: 4311dd39c2c0f07736225f131766d0e7bec4b044 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.ide.highlighter.JavaClassFileType;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SystemProperties;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.DifferentSerializableBytesImplyNonEqualityPolicy;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author lambdamix
*/
public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Bytes, HEquations> {
public static final ID<Bytes, HEquations> NAME = ID.create("bytecodeAnalysis");
private final HEquationsExternalizer myExternalizer = new HEquationsExternalizer();
private static final ClassDataIndexer INDEXER = new ClassDataIndexer();
private static final HKeyDescriptor KEY_DESCRIPTOR = new HKeyDescriptor();
private static final int ourInternalVersion = 2;
private static boolean ourEnabled = SystemProperties.getBooleanProperty("idea.enable.bytecode.contract.inference", true);
@NotNull
@Override
public ID<Bytes, HEquations> getName() {
return NAME;
}
@NotNull
@Override
public DataIndexer<Bytes, HEquations, FileContent> getIndexer() {
return INDEXER;
}
@NotNull
@Override
public KeyDescriptor<Bytes> getKeyDescriptor() {
return KEY_DESCRIPTOR;
}
@NotNull
@Override
public DataExternalizer<HEquations> getValueExternalizer() {
return myExternalizer;
}
@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return new DefaultFileTypeSpecificInputFilter(JavaClassFileType.INSTANCE) {
@Override
public boolean acceptInput(@NotNull VirtualFile file) {
return ourEnabled && super.acceptInput(file);
}
};
}
@Override
public boolean dependsOnFileContent() {
return true;
}
@Override
public int getVersion() {
return ourInternalVersion + (ourEnabled ? 0xFF : 0);
}
private static class HKeyDescriptor implements KeyDescriptor<Bytes>, DifferentSerializableBytesImplyNonEqualityPolicy {
@Override
public void save(@NotNull DataOutput out, Bytes value) throws IOException {
out.write(value.bytes);
}
@Override
public Bytes read(@NotNull DataInput in) throws IOException {
byte[] bytes = new byte[BytecodeAnalysisConverter.HASH_SIZE];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = in.readByte();
}
return new Bytes(bytes);
}
@Override
public int getHashCode(Bytes value) {
return Arrays.hashCode(value.bytes);
}
@Override
public boolean isEqual(Bytes val1, Bytes val2) {
return Arrays.equals(val1.bytes, val2.bytes);
}
}
public static class HEquationsExternalizer implements DataExternalizer<HEquations>, DifferentSerializableBytesImplyNonEqualityPolicy {
@Override
public void save(@NotNull DataOutput out, HEquations eqs) throws IOException {
out.writeBoolean(eqs.stable);
DataInputOutputUtil.writeINT(out, eqs.results.size());
for (DirectionResultPair pair : eqs.results) {
DataInputOutputUtil.writeINT(out, pair.directionKey);
HResult rhs = pair.hResult;
if (rhs instanceof HFinal) {
HFinal finalResult = (HFinal)rhs;
out.writeBoolean(true); // final flag
DataInputOutputUtil.writeINT(out, finalResult.value.ordinal());
}
else {
HPending pendResult = (HPending)rhs;
out.writeBoolean(false); // pending flag
DataInputOutputUtil.writeINT(out, pendResult.delta.length);
for (HComponent component : pendResult.delta) {
DataInputOutputUtil.writeINT(out, component.value.ordinal());
HKey[] ids = component.ids;
DataInputOutputUtil.writeINT(out, ids.length);
for (HKey hKey : ids) {
out.write(hKey.key);
DataInputOutputUtil.writeINT(out, hKey.dirKey);
out.writeBoolean(hKey.stable);
}
}
}
}
}
@Override
public HEquations read(@NotNull DataInput in) throws IOException {
boolean stable = in.readBoolean();
int size = DataInputOutputUtil.readINT(in);
ArrayList<DirectionResultPair> results = new ArrayList<DirectionResultPair>(size);
for (int k = 0; k < size; k++) {
int directionKey = DataInputOutputUtil.readINT(in);
boolean isFinal = in.readBoolean(); // flag
if (isFinal) {
int ordinal = DataInputOutputUtil.readINT(in);
Value value = Value.values()[ordinal];
results.add(new DirectionResultPair(directionKey, new HFinal(value)));
}
else {
int sumLength = DataInputOutputUtil.readINT(in);
HComponent[] components = new HComponent[sumLength];
for (int i = 0; i < sumLength; i++) {
int ordinal = DataInputOutputUtil.readINT(in);
Value value = Value.values()[ordinal];
int componentSize = DataInputOutputUtil.readINT(in);
HKey[] ids = new HKey[componentSize];
for (int j = 0; j < componentSize; j++) {
byte[] bytes = new byte[BytecodeAnalysisConverter.HASH_SIZE];
for (int bi = 0; bi < bytes.length; bi++) {
bytes[bi] = in.readByte();
}
ids[j] = new HKey(bytes, DataInputOutputUtil.readINT(in), in.readBoolean());
}
components[i] = new HComponent(value, ids);
}
results.add(new DirectionResultPair(directionKey, new HPending(components)));
}
}
return new HEquations(results, stable);
}
}
}