towards indexing

This commit is contained in:
Ilya Klyuchnikov
2014-06-09 17:24:04 +04:00
committed by peter
parent 10fda956d6
commit dabdf64c56
11 changed files with 522 additions and 242 deletions

View File

@@ -18,6 +18,7 @@
<orderEntry type="module" module-name="resources-en" />
<orderEntry type="module" module-name="xml-psi-impl" />
<orderEntry type="library" exported="" name="asm5" level="project" />
<orderEntry type="module" module-name="platform-api" />
</component>
</module>

View File

@@ -0,0 +1,74 @@
/*
* 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.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.util.io.PersistentStringEnumerator;
import java.io.File;
import java.io.IOException;
import java.util.Set;
/**
* @author lambdamix
*/
public class BytecodeAnalysisConverter extends ApplicationComponent.Adapter {
public static BytecodeAnalysisConverter getInstance() {
return ApplicationManager.getApplication().getComponent(BytecodeAnalysisConverter.class);
}
PersistentStringEnumerator internalKeyEnumerator;
private final File myFile = new File(PathManager.getIndexRoot(), "faba.internalIds");
public BytecodeAnalysisConverter() {
try {
internalKeyEnumerator = new PersistentStringEnumerator(myFile);
}
catch (IOException e) {
//e.printStackTrace();
}
}
IntIdEquation enumerate(Equation<Key, Value> equation) throws IOException {
Result<Key, Value> rhs = equation.rhs;
IntIdResult result;
if (rhs instanceof Final) {
result = new IntIdFinal(((Final<Key, Value>)rhs).value);
} else {
Pending<Key, Value> pending = (Pending<Key, Value>)rhs;
Set<Set<Key>> deltaOrig = pending.delta;
IntIdComponent[] components = new IntIdComponent[deltaOrig.size()];
int componentI = 0;
for (Set<Key> keyComponent : deltaOrig) {
int[] ids = new int[keyComponent.size()];
int idI = 0;
for (Key id : keyComponent) {
ids[idI] = internalKeyEnumerator.enumerate(Util.internalKeyString(id));
idI++;
}
IntIdComponent intIdComponent = new IntIdComponent(ids);
components[componentI] = intIdComponent;
componentI++;
}
result = new IntIdPending(pending.infinum, components);
}
int key = internalKeyEnumerator.enumerate(Util.internalKeyString(equation.id));
return new IntIdEquation(key, result);
}
}

View File

@@ -65,8 +65,6 @@ public class BytecodeAnalysisHandler extends AbstractProjectComponent {
private final PsiManager myPsiManager;
private final Enumerators myEnumerators;
private MostlySingularMultiMap<String, AnnotationData> myAnnotations = new MostlySingularMultiMap<String, AnnotationData>();
public BytecodeAnalysisHandler(Project project, PsiManager psiManager) {
@@ -86,15 +84,6 @@ public class BytecodeAnalysisHandler extends AbstractProjectComponent {
doIndex();
}
});
Enumerators enumerators;
try {
enumerators = new Enumerators(getEnumerator(project, "internalKeys"), getEnumerator(project, "annotationKeys"));
}
catch (IOException e) {
LOG.error("Cannot initialize enumerators", e);
enumerators = null;
}
myEnumerators = enumerators;
}
void setAnnotations(MostlySingularMultiMap<String, AnnotationData> annotations) {
@@ -194,9 +183,7 @@ public class BytecodeAnalysisHandler extends AbstractProjectComponent {
}
private void doIndex() {
if (myEnumerators != null) {
DumbService.getInstance(myProject).queueTask(new BytecodeAnalysisTask(myProject, myEnumerators));
}
DumbService.getInstance(myProject).queueTask(new BytecodeAnalysisTask(myProject));
}
}
@@ -245,29 +232,13 @@ class AnnotationData {
}
}
// TODO - this should application-level
class Enumerators {
@NotNull
final PersistentStringEnumerator internalKeyEnumerator;
@NotNull
final PersistentStringEnumerator annotationKeyEnumerator;
Enumerators(@NotNull PersistentStringEnumerator internalKeyEnumerator,
@NotNull PersistentStringEnumerator annotationKeyEnumerator) {
this.internalKeyEnumerator = internalKeyEnumerator;
this.annotationKeyEnumerator = annotationKeyEnumerator;
}
}
class BytecodeAnalysisTask extends DumbModeTask {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisTask");
private final Project myProject;
private long myClassFilesCount = 0;
private final Enumerators myEnumerators;
BytecodeAnalysisTask(Project project, Enumerators enumerators) {
BytecodeAnalysisTask(Project project) {
myProject = project;
myEnumerators = enumerators;
}
private VirtualFileVisitor<?> myClassFilesCounter = new VirtualFileVisitor() {
@@ -299,11 +270,11 @@ class BytecodeAnalysisTask extends DumbModeTask {
}
LOG.info("Found " + myClassFilesCount + " classes to Index");
BytecodeAnalysisHandler handler = myProject.getComponent(BytecodeAnalysisHandler.class);
ClassProcessor myClassProcessor = new ClassProcessor(indicator, myClassFilesCount, myEnumerators);
ClassFileProcessor myClassFileProcessor = new ClassFileProcessor(indicator, myClassFilesCount);
for (VirtualFile classRoot : classRoots) {
VfsUtilCore.visitChildrenRecursively(classRoot, myClassProcessor);
VfsUtilCore.visitChildrenRecursively(classRoot, myClassFileProcessor);
}
handler.setAnnotations(myClassProcessor.annotations());
handler.setAnnotations(myClassFileProcessor.annotations());
}

View File

@@ -0,0 +1,74 @@
/*
* 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.openapi.fileTypes.StdFileTypes;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorIntegerDescriptor;
import com.intellij.util.io.KeyDescriptor;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* @author lambdamix
*/
public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Collection<IntIdEquation>> {
public static final int KEY = 0;
public static final ID<Integer, Collection<IntIdEquation>> NAME = ID.create("bytecodeAnalysis");
private final EquationExternalizer myExternalizer = new EquationExternalizer();
@NotNull
@Override
public ID<Integer, Collection<IntIdEquation>> getName() {
return NAME;
}
@NotNull
@Override
public DataIndexer<Integer, Collection<IntIdEquation>, FileContent> getIndexer() {
return null;
}
@NotNull
@Override
public KeyDescriptor<Integer> getKeyDescriptor() {
return EnumeratorIntegerDescriptor.INSTANCE;
}
@NotNull
@Override
public DataExternalizer<Collection<IntIdEquation>> getValueExternalizer() {
return myExternalizer;
}
@NotNull
@Override
public FileBasedIndex.InputFilter getInputFilter() {
return new DefaultFileTypeSpecificInputFilter(StdFileTypes.CLASS);
}
@Override
public boolean dependsOnFileContent() {
return true;
}
@Override
public int getVersion() {
return 0;
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileContent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* @author lambdamix
*/
public class ClassDataIndexer implements DataIndexer<Integer, Collection<IntIdEquation>, FileContent> {
final BytecodeAnalysisConverter myLowering;
public ClassDataIndexer(BytecodeAnalysisConverter lowering) {
myLowering = lowering;
}
@NotNull
@Override
public Map<Integer, Collection<IntIdEquation>> map(@NotNull FileContent inputData) {
ArrayList<Equation<Key, Value>> rawEquations = ClassProcessing.processClass(new ClassReader(inputData.getContent()));
Collection<IntIdEquation> idEquations = new ArrayList<IntIdEquation>(rawEquations.size());
for (Equation<Key, Value> rawEquation : rawEquations) {
try {
IntIdEquation idEquation = myLowering.enumerate(rawEquation);
idEquations.add(idEquation);
}
catch (IOException e) {
e.printStackTrace();
}
}
return Collections.singletonMap(BytecodeAnalysisIndex.KEY, idEquations);
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.util.containers.MostlySingularMultiMap;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.ClassReader;
import java.io.IOException;
import java.util.ArrayList;
public class ClassFileProcessor extends VirtualFileVisitor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.ClassProcessor");
final static ELattice<Value> valueLattice = new ELattice<Value>(Value.Bot, Value.Top);
final IntIdSolver myIntIdSolver;
final BytecodeAnalysisConverter myLowering;
@NotNull
final ProgressIndicator myProgressIndicator;
private final long totalClassFiles;
long processed = 0;
public ClassFileProcessor(@NotNull ProgressIndicator indicator, long totalClassFiles) {
this.myProgressIndicator = indicator;
this.totalClassFiles = totalClassFiles;
myLowering = BytecodeAnalysisConverter.getInstance();
myIntIdSolver = new IntIdSolver(valueLattice);
}
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory() && "class".equals(file.getExtension())) {
try {
ArrayList<Equation<Key, Value>> equations = ClassProcessing.processClass(new ClassReader(file.contentsToByteArray()));
for (Equation<Key, Value> equation : equations) {
addEquation(equation);
}
}
catch (IOException e) {
LOG.debug("Error when processing " + file.getPresentableUrl(), e);
}
myProgressIndicator.setText2(file.getPresentableUrl());
myProgressIndicator.setFraction(((double) processed++) / totalClassFiles);
}
return true;
}
void addEquation(Equation<Key, Value> equation) {
try {
myIntIdSolver.addEquation(myLowering.enumerate(equation));
}
catch (IOException e) {
// TODO
}
}
// nullity, contracts
MostlySingularMultiMap<String, AnnotationData> annotations() {
TIntObjectHashMap<Value> internalIdSolutions = myIntIdSolver.solve();
return Util.makeAnnotations(internalIdSolutions);
}
}

View File

@@ -0,0 +1,135 @@
/*
* 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.openapi.diagnostic.Logger;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* @author lambdamix
*/
public class ClassProcessing {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.ClassProcessing");
public static ArrayList<Equation<Key, Value>> processClass(final ClassReader classReader) {
final ArrayList<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>();
classReader.accept(new ClassVisitor(Opcodes.ASM5) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MethodNode node = new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions);
return new MethodVisitor(Opcodes.ASM5, node) {
@Override
public void visitEnd() {
super.visitEnd();
processMethod(classReader.getClassName(), node);
}
};
}
void processMethod(String className, MethodNode methodNode) {
Method method = new Method(className, methodNode.name, methodNode.desc);
ControlFlowGraph graph = cfg.buildControlFlowGraph(className, methodNode);
boolean added = false;
Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
Type resultType = Type.getReturnType(methodNode.desc);
int resultSort = resultType.getSort();
boolean isReferenceResult = resultSort == Type.OBJECT || resultSort == Type.ARRAY;
boolean isBooleanResult = Type.BOOLEAN_TYPE == resultType;
if (graph.transitions.length > 0) {
DFSTree dfs = cfg.buildDFSTree(graph.transitions);
boolean reducible = dfs.back.isEmpty() || cfg.reducible(graph, dfs);
if (reducible) {
List<Equation<Key, Value>> toAdd = new LinkedList<Equation<Key, Value>>();
try {
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
int argSort = argType.getSort();
boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
boolean isBooleanArg = Type.BOOLEAN_TYPE.equals(argType);
if (isReferenceArg) {
toAdd.add(new NonNullInAnalysis(new RichControlFlow(graph, dfs), new In(i)).analyze());
}
if (isReferenceResult || isBooleanResult) {
if (isReferenceArg) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.Null)).analyze());
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.NotNull)).analyze());
}
if (isBooleanArg) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.False)).analyze());
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.True)).analyze());
}
}
}
if (isReferenceResult) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new Out()).analyze());
}
added = true;
for (Equation<Key, Value> equation : toAdd) {
addEquation(equation);
}
} catch (AnalyzerException e) {
throw new RuntimeException();
}
} else {
LOG.debug("CFG for " + method + " is not reducible");
}
}
if (!added) {
method = new Method(className, methodNode.name, methodNode.desc);
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
int argSort = argType.getSort();
boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
if (isReferenceArg) {
addEquation(new Equation<Key, Value>(new Key(method, new In(i)), new Final<Key, Value>(Value.Top)));
if (isReferenceResult || isBooleanResult) {
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null)), new Final<Key, Value>(Value.Top)));
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull)), new Final<Key, Value>(Value.Top)));
}
}
if (Type.BOOLEAN_TYPE.equals(argType)) {
if (isReferenceResult || isBooleanResult) {
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False)), new Final<Key, Value>(Value.Top)));
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True)), new Final<Key, Value>(Value.Top)));
}
}
}
if (isReferenceResult) {
addEquation(new Equation<Key, Value>(new Key(method, new Out()), new Final<Key, Value>(Value.Top)));
}
}
}
void addEquation(Equation<Key, Value> equation) {
result.add(equation);
}
}, 0);
return result;
}
}

View File

@@ -1,205 +0,0 @@
/*
* 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.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.util.containers.MostlySingularMultiMap;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class ClassProcessor extends VirtualFileVisitor {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.ClassProcessor");
final static ELattice<Value> valueLattice = new ELattice<Value>(Value.Bot, Value.Top);
final IntIdSolver myIntIdSolver;
@NotNull
final ProgressIndicator myProgressIndicator;
private final long totalClassFiles;
private final Enumerators myEnumerators;
long processed = 0;
public ClassProcessor(@NotNull ProgressIndicator indicator, long totalClassFiles, Enumerators enumerators) {
this.myProgressIndicator = indicator;
this.totalClassFiles = totalClassFiles;
this.myEnumerators = enumerators;
myIntIdSolver = new IntIdSolver(valueLattice);
}
@Override
public boolean visitFile(@NotNull VirtualFile file) {
if (!file.isDirectory() && "class".equals(file.getExtension())) {
try {
processClass(new ClassReader(file.contentsToByteArray()));
}
catch (IOException e) {
LOG.debug("Error when processing " + file.getPresentableUrl(), e);
}
myProgressIndicator.setText2(file.getPresentableUrl());
myProgressIndicator.setFraction(((double) processed++) / totalClassFiles);
}
return true;
}
public void processClass(final ClassReader classReader) {
classReader.accept(new ClassVisitor(Opcodes.ASM5) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MethodNode node = new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions);
return new MethodVisitor(Opcodes.ASM5, node) {
@Override
public void visitEnd() {
super.visitEnd();
processMethod(classReader.getClassName(), node);
}
};
}
}, 0);
}
void processMethod(String className, MethodNode methodNode) {
Method method = new Method(className, methodNode.name, methodNode.desc);
ControlFlowGraph graph = cfg.buildControlFlowGraph(className, methodNode);
boolean added = false;
Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
Type resultType = Type.getReturnType(methodNode.desc);
int resultSort = resultType.getSort();
boolean isReferenceResult = resultSort == Type.OBJECT || resultSort == Type.ARRAY;
boolean isBooleanResult = Type.BOOLEAN_TYPE == resultType;
if (graph.transitions.length > 0) {
DFSTree dfs = cfg.buildDFSTree(graph.transitions);
boolean reducible = dfs.back.isEmpty() || cfg.reducible(graph, dfs);
if (reducible) {
List<Equation<Key, Value>> toAdd = new LinkedList<Equation<Key, Value>>();
try {
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
int argSort = argType.getSort();
boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
boolean isBooleanArg = Type.BOOLEAN_TYPE.equals(argType);
if (isReferenceArg) {
toAdd.add(new NonNullInAnalysis(new RichControlFlow(graph, dfs), new In(i)).analyze());
}
if (isReferenceResult || isBooleanResult) {
if (isReferenceArg) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.Null)).analyze());
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.NotNull)).analyze());
}
if (isBooleanArg) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.False)).analyze());
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new InOut(i, Value.True)).analyze());
}
}
}
if (isReferenceResult) {
toAdd.add(new InOutAnalysis(new RichControlFlow(graph, dfs), new Out()).analyze());
}
added = true;
for (Equation<Key, Value> equation : toAdd) {
addEquation(equation);
}
} catch (AnalyzerException e) {
throw new RuntimeException();
}
} else {
LOG.debug("CFG for " + method + " is not reducible");
}
}
if (!added) {
method = new Method(className, methodNode.name, methodNode.desc);
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
int argSort = argType.getSort();
boolean isReferenceArg = argSort == Type.OBJECT || argSort == Type.ARRAY;
if (isReferenceArg) {
addEquation(new Equation<Key, Value>(new Key(method, new In(i)), new Final<Key, Value>(Value.Top)));
if (isReferenceResult || isBooleanResult) {
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null)), new Final<Key, Value>(Value.Top)));
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull)), new Final<Key, Value>(Value.Top)));
}
}
if (Type.BOOLEAN_TYPE.equals(argType)) {
if (isReferenceResult || isBooleanResult) {
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False)), new Final<Key, Value>(Value.Top)));
addEquation(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True)), new Final<Key, Value>(Value.Top)));
}
}
}
if (isReferenceResult) {
addEquation(new Equation<Key, Value>(new Key(method, new Out()), new Final<Key, Value>(Value.Top)));
}
}
}
void addEquation(Equation<Key, Value> equation) {
try {
myIntIdSolver.addEquation(enumerate(equation));
}
catch (IOException e) {
// TODO
}
}
// turns high-lever equation into low-level one
IntIdEquation enumerate(Equation<Key, Value> equation) throws IOException {
com.intellij.codeInspection.bytecodeAnalysis.Result<Key, Value> rhs = equation.rhs;
IntIdResult result;
if (rhs instanceof Final) {
result = new IntIdFinal(((Final<Key, Value>)rhs).value);
} else {
Pending<Key, Value> pending = (Pending<Key, Value>)rhs;
Set<Set<Key>> deltaOrig = pending.delta;
IntIdComponent[] components = new IntIdComponent[deltaOrig.size()];
int componentI = 0;
for (Set<Key> keyComponent : deltaOrig) {
int[] ids = new int[keyComponent.size()];
int idI = 0;
for (Key id : keyComponent) {
ids[idI] = myEnumerators.internalKeyEnumerator.enumerate(Util.internalKeyString(id));
idI++;
}
IntIdComponent intIdComponent = new IntIdComponent(ids);
components[componentI] = intIdComponent;
componentI++;
}
result = new IntIdPending(pending.infinum, components);
}
int key = myEnumerators.internalKeyEnumerator.enumerate(Util.internalKeyString(equation.id));
return new IntIdEquation(key, result);
}
// nullity, contracts
MostlySingularMultiMap<String, AnnotationData> annotations() {
TIntObjectHashMap<Value> internalIdSolutions = myIntIdSolver.solve();
return Util.makeAnnotations(internalIdSolutions, myEnumerators);
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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.util.io.DataExternalizer;
import com.intellij.util.io.DataInputOutputUtil;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author lambdamix
*/
public class EquationExternalizer implements DataExternalizer<Collection<IntIdEquation>> {
@Override
public void save(@NotNull DataOutput out, Collection<IntIdEquation> equations) throws IOException {
DataInputOutputUtil.writeINT(out, equations.size());
for (IntIdEquation equation : equations) {
out.write(equation.id);
IntIdResult rhs = equation.rhs;
if (rhs instanceof IntIdFinal) {
IntIdFinal finalResult = (IntIdFinal)rhs;
out.writeBoolean(true);
DataInputOutputUtil.writeINT(out, finalResult.value.ordinal());
} else {
IntIdPending pendResult = (IntIdPending)rhs;
out.writeBoolean(false);
DataInputOutputUtil.writeINT(out, pendResult.infinum.ordinal());
out.writeInt(pendResult.delta.length);
for (IntIdComponent component : pendResult.delta) {
int[] ids = component.ids;
DataInputOutputUtil.writeINT(out, ids.length);
for (int id : ids) {
out.writeInt(id);
}
}
}
}
}
@Override
public Collection<IntIdEquation> read(@NotNull DataInput in) throws IOException {
int size = DataInputOutputUtil.readINT(in);
ArrayList<IntIdEquation> result = new ArrayList<IntIdEquation>(size);
for (int x = 0; x < size; x++) {
int equationId = in.readInt();
boolean isFinal = in.readBoolean();
if (isFinal) {
int ordinal = DataInputOutputUtil.readINT(in);
Value value = Value.values()[ordinal];
result.add(new IntIdEquation(equationId, new IntIdFinal(value)));
} else {
int ordinal = DataInputOutputUtil.readINT(in);
Value value = Value.values()[ordinal];
int componentsNumber = DataInputOutputUtil.readINT(in);
IntIdComponent[] components = new IntIdComponent[componentsNumber];
for (int i = 0; i < componentsNumber; i++) {
int componentSize = DataInputOutputUtil.readINT(in);
int[] ids = new int[componentSize];
for (int j = 0; j < componentSize; j++) {
ids[j] = in.readInt();
}
components[i] = new IntIdComponent(ids);
}
result.add(new IntIdEquation(equationId, new IntIdPending(value, components)));
}
}
return result;
}
}

View File

@@ -36,8 +36,8 @@ public class Util {
}
}
public static MostlySingularMultiMap<String, AnnotationData> makeAnnotations(TIntObjectHashMap<Value> internalIdSolutions,
Enumerators enumerators) {
public static MostlySingularMultiMap<String, AnnotationData> makeAnnotations(TIntObjectHashMap<Value> internalIdSolutions) {
BytecodeAnalysisConverter lowering = BytecodeAnalysisConverter.getInstance();
MostlySingularMultiMap<String, AnnotationData> annotations = new MostlySingularMultiMap<String, AnnotationData>();
HashMap<String, StringBuilder> contracts = new HashMap<String, StringBuilder>();
TIntObjectIterator<Value> iterator = internalIdSolutions.iterator();
@@ -50,7 +50,7 @@ public class Util {
}
InternalKey key;
try {
String s = enumerators.internalKeyEnumerator.valueOf(inKey);
String s = lowering.internalKeyEnumerator.valueOf(inKey);
key = readInternalKey(s);
}
catch (IOException e) {

View File

@@ -37,6 +37,10 @@
<component>
<implementation-class>com.intellij.codeInsight.preview.ImageOrColorPreviewManager</implementation-class>
</component>
<component>
<implementation-class>com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter</implementation-class>
</component>
</application-components>
<project-components>