Files
openide/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
T

290 lines
12 KiB
Java

/*
* 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.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.codeInspection.bytecodeAnalysis.data.Test01;
import com.intellij.codeInspection.bytecodeAnalysis.data.TestAnnotation;
import com.intellij.codeInspection.bytecodeAnalysis.data.TestConverterData;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.util.ArrayUtil;
import com.intellij.util.AsynchConsumer;
import org.apache.commons.lang.SystemUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.org.objectweb.asm.Type;
import org.junit.Assert;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Arrays;
/**
* @author lambdamix
*/
public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private final String myClassesProjectRelativePath = "/classes/" + Test01.class.getPackage().getName().replace('.', '/');
private JavaPsiFacade myJavaPsiFacade;
private InferredAnnotationsManager myInferredAnnotationsManager;
private ExternalAnnotationsManager myExternalAnnotationsManager;
private BytecodeAnalysisConverter myBytecodeAnalysisConverter;
@Override
protected void setUp() throws Exception {
super.setUp();
/*
ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
@Override
public void run() {
myBytecodeAnalysisConverter.disposeComponent();
}
}); */
setUpDataClasses();
setUpVelocityLibrary();
setUpAnnotations();
myJavaPsiFacade = JavaPsiFacade.getInstance(myModule.getProject());
myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
myExternalAnnotationsManager = ExternalAnnotationsManager.getInstance(myModule.getProject());
myBytecodeAnalysisConverter = BytecodeAnalysisConverter.getInstance();
}
public void testVelocityJar() {
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[]{});
}
private void setUpAnnotations() {
final VirtualFile annotationsDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/codeInspection/bytecodeAnalysis/annotations");
ModuleRootModificationUtil.updateModel(myModule, new AsynchConsumer<ModifiableRootModel>() {
@Override
public void finished() {
}
@Override
public void consume(ModifiableRootModel modifiableRootModel) {
final LibraryTable libraryTable = modifiableRootModel.getModuleLibraryTable();
Library[] libs = libraryTable.getLibraries();
for (Library library : libs) {
final Library.ModifiableModel libraryModel = library.getModifiableModel();
libraryModel.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
libraryModel.commit();
}
Sdk sdk = modifiableRootModel.getSdk();
if (sdk != null) {
SdkModificator sdkModificator = sdk.getSdkModificator();
sdkModificator.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
sdkModificator.commitChanges();
}
}
});
}
public void testIntegration() {
PsiClass psiClass = myJavaPsiFacade.findClass(String.class.getName(), GlobalSearchScope.moduleWithLibrariesScope(myModule));
assertNotNull(psiClass);
PsiMethod[] methods = psiClass.getMethods();
for (PsiMethod method : methods) {
PsiAnnotation externalAnnotation = myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL);
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL);
System.out.println(method);
System.out.println(externalAnnotation);
System.out.println(inferredAnnotation);
}
//psiClass
final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
assert rootPackage != null;
final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
JavaRecursiveElementVisitor visitor = new JavaRecursiveElementVisitor() {
@Override
public void visitPackage(PsiPackage aPackage) {
for (PsiPackage subPackage : aPackage.getSubPackages(scope)) {
visitPackage(subPackage);
}
for (PsiClass aClass : aPackage.getClasses(scope)) {
visitClass(aClass);
}
}
@Override
public void visitClass(PsiClass aClass) {
for (PsiMethod method : aClass.getMethods()) {
visitMethod(method);
}
}
@Override
public void visitMethod(PsiMethod method) {
System.out.println(method);
}
};
rootPackage.accept(visitor);
}
public void testInference() throws IOException {
for (OrderEntry entry : ModuleRootManager.getInstance(myModule).getOrderEntries()) {
System.out.println(entry);
final VirtualFile[] files = AnnotationOrderRootType.getFiles(entry);
for (VirtualFile file : files) {
System.out.println("FOUND:" + file.getPath());
}
}
checkAnnotations(Test01.class);
}
public void testConverter() throws IOException {
checkCompoundIds(Test01.class);
checkCompoundIds(TestConverterData.class);
checkCompoundIds(TestConverterData.StaticNestedClass.class);
checkCompoundIds(TestConverterData.InnerClass.class);
checkCompoundIds(TestConverterData.GenericStaticNestedClass.class);
checkCompoundIds(TestAnnotation.class);
}
private void checkAnnotations(Class<?> javaClass) {
PsiClass psiClass = myJavaPsiFacade.findClass(javaClass.getName(), GlobalSearchScope.moduleWithLibrariesScope(myModule));
assertNotNull(psiClass);
for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
PsiMethod psiMethod = psiClass.findMethodsByName(javaMethod.getName(), false)[0];
Annotation[][] annotations = javaMethod.getParameterAnnotations();
// not-null parameters
params: for (int i = 0; i < annotations.length; i++) {
Annotation[] parameterAnnotations = annotations[i];
PsiParameter psiParameter = psiMethod.getParameterList().getParameters()[i];
PsiAnnotation inferredAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiParameter, AnnotationUtil.NOT_NULL);
for (Annotation parameterAnnotation : parameterAnnotations) {
if (parameterAnnotation.annotationType() == ExpectNotNull.class) {
assertNotNull(inferredAnnotation);
continue params;
}
}
assertNull(inferredAnnotation);
}
// not-null result
ExpectNotNull expectedAnnotation = javaMethod.getAnnotation(ExpectNotNull.class);
PsiAnnotation actualAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, AnnotationUtil.NOT_NULL);
assertEquals(expectedAnnotation == null, actualAnnotation == null);
// contracts
ExpectContract expectedContract = javaMethod.getAnnotation(ExpectContract.class);
PsiAnnotation actualContractAnnotation = myInferredAnnotationsManager.findInferredAnnotation(psiMethod, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
assertEquals(expectedContract == null, actualContractAnnotation == null);
if (expectedContract != null) {
String expectedContractValue = expectedContract.value();
String actualContractValue = AnnotationUtil.getStringAttributeValue(actualContractAnnotation, null);
assertEquals(expectedContractValue, actualContractValue);
}
}
}
private void checkCompoundIds(Class<?> javaClass) throws IOException {
String javaClassName = javaClass.getCanonicalName();
System.out.println(javaClassName);
PsiClass psiClass = myJavaPsiFacade.findClass(javaClassName, GlobalSearchScope.moduleWithLibrariesScope(myModule));
assertNotNull(psiClass);
for (java.lang.reflect.Method javaMethod : javaClass.getDeclaredMethods()) {
System.out.println(javaMethod.getName());
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.getType(javaClass).getInternalName(), "<init>", Type.getConstructorDescriptor(constructor));
boolean noKey = constructor.getAnnotation(ExpectNoPsiKey.class) != null;
PsiMethod[] constructors = psiClass.getConstructors();
PsiMethod psiMethod = constructors[0];
checkCompoundId(method, psiMethod, noKey);
}
}
private void checkCompoundId(Method method, PsiMethod psiMethod, boolean noKey) throws IOException {
Direction direction = new Out();
int[] psiKey = myBytecodeAnalysisConverter.mkCompoundKey(psiMethod, direction);
if (noKey) {
assertNull(psiKey);
return;
}
else {
assertNotNull(psiKey);
}
int[] asmKey = myBytecodeAnalysisConverter.mkCompoundKey(new Key(method, direction));
System.out.println(Arrays.toString(asmKey));
System.out.println(Arrays.toString(psiKey));
System.out.println(myBytecodeAnalysisConverter.debugCompoundKey(asmKey));
System.out.println(myBytecodeAnalysisConverter.debugCompoundKey(psiKey));
Assert.assertArrayEquals(asmKey, psiKey);
}
private void setUpDataClasses() throws IOException {
File classesDir = new File(Test01.class.getResource(".").getFile());
File destDir = new File(myModule.getProject().getBaseDir().getPath() + myClassesProjectRelativePath);
FileUtil.copyDir(classesDir, destDir);
VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(destDir);
assertNotNull(vFile);
PsiTestUtil.addLibrary(myModule, "dataClasses", vFile.getPath(), new String[]{""}, ArrayUtil.EMPTY_STRING_ARRAY);
}
}