| /* |
| * 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); |
| } |
| } |
| } |