compound indices in action

This commit is contained in:
Ilya Klyuchnikov
2014-07-10 10:35:36 +02:00
committed by peter
parent ff8433736f
commit 383752b4a0
6 changed files with 264 additions and 337 deletions
@@ -22,8 +22,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MostlySingularMultiMap;
import com.intellij.util.io.DataInputOutputUtil;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentEnumeratorDelegate;
@@ -39,7 +37,6 @@ import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
/**
@@ -53,7 +50,6 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
return ApplicationManager.getApplication().getComponent(BytecodeAnalysisConverter.class);
}
private PersistentStringEnumerator myInternalKeyEnumerator;
private PersistentStringEnumerator myPackageEnumerator;
private PersistentStringEnumerator myNamesEnumerator;
private PersistentEnumeratorDelegate<int[]> myCompoundKeyEnumerator;
@@ -62,11 +58,9 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
public void initComponent() {
try {
File keysDir = new File(PathManager.getIndexRoot(), "bytecodeKeys");
final File internalKeysFile = new File(keysDir, "faba.internalIds");
final File packageKeysFile = new File(keysDir, "faba.packages");
final File namesFile = new File(keysDir, "faba.names1");
final File compoundKeysFile = new File(keysDir, "faba.keys");
myInternalKeyEnumerator = new PersistentStringEnumerator(internalKeysFile);
final File packageKeysFile = new File(keysDir, "packages");
final File namesFile = new File(keysDir, "names");
final File compoundKeysFile = new File(keysDir, "compound");
myPackageEnumerator = new PersistentStringEnumerator(packageKeysFile);
myNamesEnumerator = new PersistentStringEnumerator(namesFile);
myCompoundKeyEnumerator = new PersistentEnumeratorDelegate<int[]>(compoundKeysFile, new IntArrayKeyDescriptor(), 1024 * 4);
@@ -79,7 +73,6 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
@Override
public void disposeComponent() {
try {
myInternalKeyEnumerator.close();
myPackageEnumerator.close();
myNamesEnumerator.close();
myCompoundKeyEnumerator.close();
@@ -109,8 +102,8 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
int[] ids = new int[keyComponent.size()];
int idI = 0;
for (Key id : keyComponent) {
// TODO refactor here
ids[idI] = myInternalKeyEnumerator.enumerate(internalKeyString(id));
int[] compoundKey = mkCompoundKey(id);
ids[idI] = myCompoundKeyEnumerator.enumerate(compoundKey);
idI++;
}
IntIdComponent intIdComponent = new IntIdComponent(ids);
@@ -119,26 +112,17 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
}
result = new IntIdPending(pending.infinum, components);
}
int key = myInternalKeyEnumerator.enumerate(internalKeyString(equation.id));
int key = myCompoundKeyEnumerator.enumerate(mkCompoundKey(equation.id));
return new IntIdEquation(key, result);
}
public static class InternalKey {
final String annotationKey;
final Direction dir;
InternalKey(String annotationKey, Direction dir) {
this.annotationKey = annotationKey;
this.dir = dir;
}
}
@NotNull
public int[] mkCompoundKey(@NotNull Key key) throws IOException {
Direction direction = key.direction;
Method method = key.method;
Type ownerType = Type.getType(method.internalClassName);
Type ownerType = Type.getObjectType(method.internalClassName);
Type[] argTypes = Type.getArgumentTypes(method.methodDesc);
Type returnType = Type.getReturnType(method.methodDesc);
@@ -159,10 +143,23 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
return compoundKey;
}
@Nullable
private static Direction extractDirection(int[] compoundKey) {
switch (compoundKey[0]) {
case Direction.OUT_DIRECTION:
return new Out();
case Direction.IN_DIRECTION:
return new In(compoundKey[1]);
case Direction.INOUT_DIRECTION:
return new InOut(compoundKey[1], Value.values()[compoundKey[2]]);
}
return null;
}
private void writeType(int[] compoundKey, int i, Type type) throws IOException {
String className = type.getClassName();
int dotIndex = className.lastIndexOf('.');
String packageName;
String simpleName;
if (dotIndex > 0) {
@@ -172,44 +169,12 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
packageName = "";
simpleName = className;
}
compoundKey[i] = myPackageEnumerator.enumerate(packageName);
compoundKey[i + 1] = myNamesEnumerator.enumerate(simpleName);
myPackageEnumerator.valueOf(compoundKey[i]);
myNamesEnumerator.valueOf(compoundKey[i + 1]);
}
public String showCompoundKey(@NotNull int[] key) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append(key[0]);
sb.append(", ");
sb.append(key[1]);
sb.append(", ");
sb.append(key[2]);
sb.append(", ");
sb.append(myPackageEnumerator.valueOf(key[3]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[4]));
sb.append(", ");
sb.append(myPackageEnumerator.valueOf(key[5]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[6]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[7]));
sb.append(", ");
sb.append(key[8]);
sb.append(", ");
for (int i = 0; i < key[8]; i++) {
sb.append(myPackageEnumerator.valueOf(key[9 + 2*i]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[9 + 2*i + 1]));
sb.append(", ");
}
return sb.toString();
}
@Nullable
public int[] mkCompoundKey(@NotNull PsiMethod psiMethod, Direction direction) throws IOException {
@@ -256,6 +221,16 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
return compoundKey;
}
public int mkKey(@NotNull PsiMethod psiMethod, Direction direction) throws IOException {
int[] compoundKey = mkCompoundKey(psiMethod, direction);
if (compoundKey == null) {
return -1;
}
else {
return myCompoundKeyEnumerator.enumerate(compoundKey);
}
}
private void writeClass(int[] compoundKey, int i, PsiClass psiClass, int dimensions) throws IOException {
String packageName = "";
@@ -290,6 +265,7 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
}
if (psiType instanceof PsiClassType) {
// no resolve() -> no package/class split
PsiClass psiClass = ((PsiClassType)psiType).resolve();
if (psiClass != null) {
writeClass(compoundKey, i, psiClass, dimensions);
@@ -303,71 +279,88 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
String packageName = "";
String className = psiType.getPresentableText();
compoundKey[i] = myPackageEnumerator.enumerate(packageName);
compoundKey[i + 1] = myNamesEnumerator.enumerate(className);
if (dimensions == 0) {
compoundKey[i + 1] = myNamesEnumerator.enumerate(className);
} else {
StringBuilder sb = new StringBuilder(className);
for (int j = 0; j < dimensions; j++) {
sb.append("[]");
}
compoundKey[i + 1] = myNamesEnumerator.enumerate(sb.toString());
}
return true;
}
return false;
}
public MostlySingularMultiMap<String, AnnotationData> makeAnnotations(TIntObjectHashMap<Value> internalIdSolutions) {
MostlySingularMultiMap<String, AnnotationData> annotations = new MostlySingularMultiMap<String, AnnotationData>();
HashMap<String, StringBuilder> contracts = new HashMap<String, StringBuilder>();
TIntObjectIterator<Value> iterator = internalIdSolutions.iterator();
public Annotations makeAnnotations(TIntObjectHashMap<Value> internalIdSolutions) {
final TIntObjectHashMap<AnnotationData> outs = new TIntObjectHashMap<AnnotationData>();
final TIntObjectHashMap<AnnotationData> params = new TIntObjectHashMap<AnnotationData>();
final TIntObjectHashMap<AnnotationData> contracts = new TIntObjectHashMap<AnnotationData>();
TIntObjectHashMap<StringBuilder> contractBuilders = new TIntObjectHashMap<StringBuilder>();
TIntObjectIterator<Value> solutionsIterator = internalIdSolutions.iterator();
for (int i = internalIdSolutions.size(); i-- > 0;) {
iterator.advance();
int inKey = iterator.key();
Value value = iterator.value();
solutionsIterator.advance();
int key = solutionsIterator.key();
Value value = solutionsIterator.value();
if (value == Value.Top || value == Value.Bot) {
continue;
}
InternalKey key;
int[] compoundKey = null;
try {
String s = myInternalKeyEnumerator.valueOf(inKey);
key = readInternalKey(s);
compoundKey = myCompoundKeyEnumerator.valueOf(key);
}
catch (IOException e) {
throw new RuntimeException(e);
// TODO: question: how to react?
}
if (key != null) {
Direction direction = key.dir;
String baseAnnKey = key.annotationKey;
if (compoundKey != null) {
Direction direction = extractDirection(compoundKey);
if (direction instanceof In && value == Value.NotNull) {
String annKey = baseAnnKey + " " + ((In)direction).paramIndex;
// TODO - here
annotations.add(annKey, new AnnotationData("org.jetbrains.annotations.NotNull", ""));
params.put(key, new AnnotationData("org.jetbrains.annotations.NotNull", ""));
}
else if (direction instanceof Out && value == Value.NotNull) {
// TODO - here
annotations.add(baseAnnKey, new AnnotationData("org.jetbrains.annotations.NotNull", ""));
outs.put(key, new AnnotationData("org.jetbrains.annotations.NotNull", ""));
}
// TODO - sort (normalize) contract clauses
else if (direction instanceof InOut) {
StringBuilder sb = contracts.get(baseAnnKey);
if (sb == null) {
sb = new StringBuilder("\"");
contracts.put(baseAnnKey, sb);
compoundKey[0] = 0;
compoundKey[1] = 0;
compoundKey[2] = 0;
try {
// TODO - sort (normalize) contract clauses
int baseKey = myCompoundKeyEnumerator.enumerate(compoundKey);
StringBuilder sb = contractBuilders.get(baseKey);
if (sb == null) {
sb = new StringBuilder("\"");
contractBuilders.put(baseKey, sb);
}
else {
sb.append(';');
}
int arity = compoundKey[8];
contractElement(sb, arity, (InOut)direction, value);
}
else {
sb.append(';');
catch (IOException e) {
// TODO: question: how to react?
}
contractElement(sb, calculateArity(baseAnnKey), (InOut)direction, value);
}
}
}
for (Map.Entry<String, StringBuilder> contract : contracts.entrySet()) {
if (!annotations.containsKey(contract.getKey())) {
annotations.add(contract.getKey(), new AnnotationData("org.jetbrains.annotations.Contract", contract.getValue().append('"').toString()));
TIntObjectIterator<StringBuilder> buildersIterator = contractBuilders.iterator();
for (int i = contractBuilders.size(); i-- > 0;) {
buildersIterator.advance();
int key = buildersIterator.key();
StringBuilder value = buildersIterator.value();
if (!outs.contains(key)) {
contracts.put(key, new AnnotationData("org.jetbrains.annotations.Contract", value.append('"').toString()));
}
}
return annotations;
}
// TODO - this is a hack for now
static int calculateArity(String annotationKey) {
return annotationKey.split(",").length;
return new Annotations(outs, params, contracts);
}
static String contractValueString(Value v) {
@@ -396,79 +389,34 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
return sb.toString();
}
public static String internalKeyString(Key key) {
return annotationKey(key.method) + ';' + direction2Key(key.direction);
}
public String debugCompoundKey(@NotNull int[] key) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append(key[0]);
sb.append(", ");
sb.append(key[1]);
sb.append(", ");
sb.append(key[2]);
sb.append(", ");
sb.append(myPackageEnumerator.valueOf(key[3]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[4]));
sb.append(", ");
sb.append(myPackageEnumerator.valueOf(key[5]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[6]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[7]));
sb.append(", ");
sb.append(key[8]);
sb.append(", ");
for (int i = 0; i < key[8]; i++) {
sb.append(myPackageEnumerator.valueOf(key[9 + 2*i]));
sb.append(", ");
sb.append(myNamesEnumerator.valueOf(key[9 + 2*i + 1]));
sb.append(", ");
public static String direction2Key(Direction dir) {
if (dir instanceof In) {
return "In:" + ((In)dir).paramIndex;
} else if (dir instanceof Out) {
return "Out";
} else {
InOut inOut = (InOut)dir;
return "InOut:" + inOut.paramIndex + ":" + inOut.inValue.name();
}
}
public static InternalKey readInternalKey(String s) {
String[] parts = s.split(";");
String annKey = parts[0];
String[] dirStrings = parts[1].split(":");
if ("In".equals(dirStrings[0])) {
return new InternalKey(annKey, new In(Integer.valueOf(dirStrings[1])));
} else if ("Out".equals(dirStrings[0])) {
return new InternalKey(annKey, new Out());
} else {
return new InternalKey(annKey, new InOut(Integer.valueOf(dirStrings[1]), Value.valueOf(dirStrings[2])));
}
}
public static String annotationKey(Method method) {
if ("<init>".equals(method.methodName)) {
return canonical(method.internalClassName) + " " +
simpleName(method.internalClassName) +
parameters(method);
} else {
return canonical(method.internalClassName) + " " +
returnType(method) + " " +
method.methodName +
parameters(method);
}
}
private static String returnType(Method method) {
return canonical(Type.getReturnType(method.methodDesc).getClassName());
}
public static String canonical(String internalName) {
return internalName.replace('/', '.').replace('$', '.');
}
private static String simpleName(String internalName) {
String cn = canonical(internalName);
int lastDotIndex = cn.lastIndexOf('.');
if (lastDotIndex == -1) {
return cn;
} else {
return cn.substring(lastDotIndex + 1);
}
}
private static String parameters(Method method) {
Type[] argTypes = Type.getArgumentTypes(method.methodDesc);
StringBuilder sb = new StringBuilder("(");
boolean notFirst = false;
for (Type argType : argTypes) {
if (notFirst) {
sb.append(", ");
}
else {
notFirst = true;
}
sb.append(canonical(argType.getClassName()));
}
sb.append(')');
return sb.toString();
}
@@ -503,5 +451,4 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
}
}
}
@@ -28,24 +28,20 @@ import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.*;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MostlySingularMultiMap;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.util.messages.MessageBusConnection;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -53,28 +49,25 @@ import java.util.List;
public class ProjectBytecodeAnalysis extends AbstractProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis");
private static final List<AnnotationData> NO_DATA = new ArrayList<AnnotationData>(1);
private static final List<AnnotationData> NO_DATA = new ArrayList<AnnotationData>(0);
private final PsiManager myPsiManager;
private MostlySingularMultiMap<String, AnnotationData> myAnnotations = null;
private Annotations myAnnotations = null;
public ProjectBytecodeAnalysis(Project project, PsiManager psiManager) {
super(project);
myPsiManager = psiManager;
// TODO: question: what is a proper way to handle indices changes?
StartupManager.getInstance(project).registerPostStartupActivity(new Runnable() {
@Override
public void run() {
//doIndex();
}
public void run() {}
});
final MessageBusConnection connection = myProject.getMessageBus().connect();
connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
@Override
public void rootsChanged(ModuleRootEvent event) {
//doIndex();
}
public void rootsChanged(ModuleRootEvent event) {}
});
}
@@ -95,24 +88,18 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent {
TIntObjectHashMap<Value> solutions = solver.solve();
LOG.info("equations are solved");
myAnnotations = BytecodeAnalysisConverter.getInstance().makeAnnotations(solutions);
LOG.info("initialized " + myAnnotations.size());
LOG.info("initialized ");
}
// TODO: what follows was just copied/modified from BaseExternalAnnotationsManager
// TODO: refactor?
@Nullable
public PsiAnnotation findInferredAnnotation(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN) {
String key = getExternalName(listOwner);
if (key == null) {
return null;
}
List<AnnotationData> list = collectInferredAnnotations(listOwner);
AnnotationData data = findByFQN(list, annotationFQN);
if (data == null) {
return null;
}
LOG.info("annotation: " + key + " " + data);
return data.getAnnotation(this);
}
@@ -120,15 +107,12 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent {
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
List<AnnotationData> result = collectInferredAnnotations(listOwner);
if (result == null || result.isEmpty()) return null;
PsiAnnotation[] myResult = ContainerUtil.map2Array(result, PsiAnnotation.EMPTY_ARRAY, new Function<AnnotationData, PsiAnnotation>() {
return ContainerUtil.map2Array(result, PsiAnnotation.EMPTY_ARRAY, new Function<AnnotationData, PsiAnnotation>() {
@Override
public PsiAnnotation fun(AnnotationData data) {
return data.getAnnotation(ProjectBytecodeAnalysis.this);
}
});
String key = getExternalName(listOwner);
LOG.info("annotations: " + key + " " + result);
return myResult;
}
@Nullable
@@ -142,28 +126,40 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent {
}
private synchronized List<AnnotationData> collectInferredAnnotations(PsiModifierListOwner listOwner) {
String key = getExternalName(listOwner);
if (key == null) {
return NO_DATA;
}
SmartList<AnnotationData> result = new SmartList<AnnotationData>();
if (myAnnotations == null) {
loadAnnotations();
}
Iterable<AnnotationData> inferred = myAnnotations.get(key);
ContainerUtil.addAll(result, inferred);
return result;
try {
int key = getKey(listOwner);
if (key == -1) {
return NO_DATA;
}
SmartList<AnnotationData> result = new SmartList<AnnotationData>();
ContainerUtil.addIfNotNull(result, myAnnotations.contracts.get(key));
ContainerUtil.addIfNotNull(result, myAnnotations.outs.get(key));
ContainerUtil.addIfNotNull(result, myAnnotations.params.get(key));
return result;
}
catch (IOException e) {
return NO_DATA;
}
}
@Nullable
protected static String getExternalName(@NotNull PsiModifierListOwner listOwner) {
String rawExternalName = PsiFormatUtil.getRawExternalName(listOwner);
if (rawExternalName != null) {
rawExternalName = rawExternalName.replace("...)", "[])");
protected static int getKey(@NotNull PsiModifierListOwner owner) throws IOException {
if (owner instanceof PsiMethod) {
return BytecodeAnalysisConverter.getInstance().mkKey((PsiMethod)owner, new Out());
}
else if (owner instanceof PsiParameter) {
final PsiElement declarationScope = ((PsiParameter)owner).getDeclarationScope();
if (!(declarationScope instanceof PsiMethod)) {
return -1;
}
final PsiMethod psiMethod = (PsiMethod)declarationScope;
final int index = psiMethod.getParameterList().getParameterIndex((PsiParameter)owner);
return BytecodeAnalysisConverter.getInstance().mkKey(psiMethod, new In(index));
} else {
return -1;
}
return rawExternalName;
}
// interner for storing annotation FQN
@@ -190,6 +186,18 @@ public class ProjectBytecodeAnalysis extends AbstractProjectComponent {
}
}
class Annotations {
final TIntObjectHashMap<AnnotationData> outs;
final TIntObjectHashMap<AnnotationData> params;
final TIntObjectHashMap<AnnotationData> contracts;
Annotations(TIntObjectHashMap<AnnotationData> outs, TIntObjectHashMap<AnnotationData> params, TIntObjectHashMap<AnnotationData> contracts) {
this.outs = outs;
this.params = params;
this.contracts = contracts;
}
}
class AnnotationData {
@NotNull final String annotationClassFqName;
@NotNull final String annotationParameters;
@@ -18,9 +18,9 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInspection.bytecodeAnalysis.data.Test01;
import com.intellij.codeInspection.bytecodeAnalysis.data.Test02;
import com.intellij.codeInspection.bytecodeAnalysis.data.Test03;
import com.intellij.codeInspection.bytecodeAnalysis.data.TestConverterData;
import com.intellij.codeInspection.bytecodeAnalysis.data.TestAnnotation;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -29,6 +29,7 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.util.ArrayUtil;
import org.apache.commons.lang.SystemUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.org.objectweb.asm.Type;
import org.junit.Assert;
@@ -57,6 +58,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
myBytecodeAnalysisConverter = BytecodeAnalysisConverter.getInstance();
setUpDataClasses();
setUpVelocityLibrary();
}
@Override
@@ -65,32 +67,31 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
super.tearDown();
}
// TODO - test it, possible solution - via external annotation manager??
/*
// TODO: real integration test (possible solution - via external annotation manager??)
public void testVelocityJar() {
VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
assertNotNull(lib);
PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
PsiClass psiClass = myJavaPsiFacade.findClass(SystemUtils.class.getName(), GlobalSearchScope.moduleWithLibrariesScope(myModule));
assertNotNull(psiClass);
PsiMethod getJavaHomeMethod = psiClass.findMethodsByName("getJavaHome", false)[0];
assertNotNull(InferredAnnotationsManager.getInstance(myModule.getProject()).findInferredAnnotation(getJavaHomeMethod, AnnotationUtil.NOT_NULL));
}
*/
private void setUpVelocityLibrary() {
VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
assertNotNull(lib);
PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
}
public void testInference() throws IOException {
checkAnnotations(Test01.class);
}
public void testCompoundKeys() throws IOException {
public void testConverter() throws IOException {
checkCompoundIds(Test01.class);
checkCompoundIds(Test02.class);
checkCompoundIds(Test02.Inner1.class);
checkCompoundIds(Test02.Inner2.class);
checkCompoundIds(Test03.class);
checkCompoundIds(Test03.Inner1.class);
checkCompoundIds(Test03.Inner2.class);
checkCompoundIds(TestConverterData.class);
checkCompoundIds(TestConverterData.StaticNestedClass.class);
checkCompoundIds(TestConverterData.InnerClass.class);
checkCompoundIds(TestConverterData.GenericStaticNestedClass.class);
checkCompoundIds(TestAnnotation.class);
}
@@ -107,8 +108,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
Annotation[] parameterAnnotations = annotations[i];
PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
for (int j = 0; j < parameterAnnotations.length; j++) {
Annotation parameterAnnotation = parameterAnnotations[j];
for (Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
assertNotNull(inferredAnnotation);
continue params;
@@ -128,7 +128,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
assertEquals(expectedContract == null, actualContractAnnotation == null);
if (expectedAnnotation != null) {
if (expectedContract != null) {
String expectedContractValue = expectedContract.value();
String actualContractValue = AnnotationUtil.getStringAttributeValue(actualContractAnnotation, null);
assertEquals(expectedContractValue, actualContractValue);
@@ -144,14 +144,14 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
System.out.println(javaMethod.getName());
Method method = new Method(Type.getDescriptor(javaClass), javaMethod.getName(), Type.getMethodDescriptor(javaMethod));
Method method = new Method(Type.getType(javaClass).getInternalName(), javaMethod.getName(), Type.getMethodDescriptor(javaMethod));
boolean noKey = javaMethod.getAnnotation(ExpectNoPsiKey.class) != null;
PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
checkCompoundId(method, psiMethod, noKey);
}
for (Constructor<?> constructor : javaClass.getDeclaredConstructors()) {
Method method = new Method(Type.getDescriptor(javaClass), "<init>", Type.getConstructorDescriptor(constructor));
Method method = new Method(Type.getType(javaClass).getInternalName(), "<init>", Type.getConstructorDescriptor(constructor));
boolean noKey = constructor.getAnnotation(ExpectNoPsiKey.class) != null;
PsiMethod[] constructors = psiClass.getConstructors();
PsiMethod psiMethod = constructors[0];
@@ -175,8 +175,8 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
System.out.println(Arrays.toString(asmKey));
System.out.println(Arrays.toString(psiKey));
System.out.println(myBytecodeAnalysisConverter.showCompoundKey(asmKey));
System.out.println(myBytecodeAnalysisConverter.showCompoundKey(psiKey));
System.out.println(myBytecodeAnalysisConverter.debugCompoundKey(asmKey));
System.out.println(myBytecodeAnalysisConverter.debugCompoundKey(psiKey));
Assert.assertArrayEquals(asmKey, psiKey);
}
@@ -187,7 +187,6 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
FileUtil.copyDir(classesDir, destDir);
VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(destDir);
assertNotNull(vFile);
PsiTestUtil.addLibrary(myModule, "dataClasses", vFile.getPath(), new String[]{""}, ArrayUtil.EMPTY_STRING_ARRAY);
}
@@ -1,54 +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.data;
import com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter;
import com.intellij.codeInspection.bytecodeAnalysis.ExpectNoPsiKey;
/**
* @author lambdamix
*/
public class Test02 {
public static class Inner1 {
public Inner1(Object o) {
}
public Inner1[] Inner1test01(Inner1[] tests, Inner1... ellipsis) {
return tests;
}
}
public class Inner2 {
public Inner2(Object o) {
}
public Inner2[] Inner2test01(Inner2[] tests, Inner2... ellipsis) {
return tests;
}
}
public Test02(int x) {}
@ExpectNoPsiKey
public BytecodeAnalysisConverter.InternalKey test01(BytecodeAnalysisConverter.InternalKey converter) {
return converter;
}
public Test02[] test02(Test02[] tests) {
return tests;
}
}
@@ -1,54 +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.data;
import com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter;
import com.intellij.codeInspection.bytecodeAnalysis.ExpectNoPsiKey;
/**
* @author lambdamix
*/
public class Test03<A> {
public static class Inner1 {
public Inner1(Object o) {
}
public Inner1[] Inner1test01(Inner1[] tests, Inner1... ellipsis) {
return tests;
}
}
public class Inner2 {
public Inner2(A o) {
}
public A[] Inner2test01(A[] tests, A... ellipsis) {
return tests;
}
}
public Test03(@TestAnnotation int x) {}
@ExpectNoPsiKey
public BytecodeAnalysisConverter.InternalKey test01(BytecodeAnalysisConverter.InternalKey converter) {
return converter;
}
public Test03[] test02(Test03[] tests) {
return tests;
}
}
@@ -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.data;
import com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter;
import com.intellij.codeInspection.bytecodeAnalysis.ExpectNoPsiKey;
/**
* @author lambdamix
*/
public class TestConverterData {
public static class StaticNestedClass {
public StaticNestedClass(Object o) {
}
public StaticNestedClass[] test01(StaticNestedClass[] ns, StaticNestedClass... ellipsis) {
return ns;
}
}
public class InnerClass {
// a reference to outer class should be inserted when translating PSI -> ASM
public InnerClass(Object o) {}
public InnerClass[] Inner2test01(InnerClass[] tests, InnerClass... ellipsis) {
return tests;
}
}
public static class GenericStaticNestedClass<A> {
public GenericStaticNestedClass(A a) {
}
public GenericStaticNestedClass[] test01(GenericStaticNestedClass[] ns, GenericStaticNestedClass... ellipsis) {
return ns;
}
public GenericStaticNestedClass<A>[] test02(GenericStaticNestedClass<A>[] ns, GenericStaticNestedClass<A>... ellipsis) {
return ns;
}
public class GenericInnerClass<B> {
public GenericInnerClass(B b) {}
public <C> GenericStaticNestedClass<A> test01(GenericInnerClass<C> c) {
return GenericStaticNestedClass.this;
}
}
}
public TestConverterData(int x) {}
// BytecodeAnalysisConverter class is not in the project path, so translation from PSI is impossible
@ExpectNoPsiKey
public BytecodeAnalysisConverter test01(BytecodeAnalysisConverter converter) {
return converter;
}
@TestAnnotation
public TestConverterData[] test02(@TestAnnotation TestConverterData[] tests) throws Exception {
return tests;
}
public boolean[] test03(boolean[] b) {
return b;
}
}