blob: 8cde2d7f1bc2b63ce4309fa0f7586d1d451dbce1 [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.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.InferredAnnotationsManager;
import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiFormatUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.util.AsynchConsumer;
import org.jetbrains.annotations.Contract;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
/**
* @author lambdamix
*/
public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestCase {
public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
private InferredAnnotationsManager myInferredAnnotationsManager;
private ExternalAnnotationsManager myExternalAnnotationsManager;
private MessageDigest myMessageDigest;
private List<String> diffs = new ArrayList<String>();
@Override
protected void setUp() throws Exception {
super.setUp();
setUpLibraries();
setUpExternalUpAnnotations();
myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
myExternalAnnotationsManager = ExternalAnnotationsManager.getInstance(myModule.getProject());
myMessageDigest = BytecodeAnalysisConverter.getMessageDigest();
}
private void setUpLibraries() {
VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
assertNotNull(lib);
PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
}
private void setUpExternalUpAnnotations() {
String annotationsPath = PathManagerEx.getTestDataPath() + "/codeInspection/bytecodeAnalysis/annotations";
final VirtualFile annotationsDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(annotationsPath);
assertNotNull(annotationsDir);
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();
}
}
});
VfsUtilCore.visitChildrenRecursively(annotationsDir, new VirtualFileVisitor() { });
annotationsDir.refresh(false, true);
}
public void testSdkAndLibAnnotations() {
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)) {
for (PsiMethod method : aClass.getMethods()) {
checkMethodAnnotations(method);
}
}
}
};
rootPackage.accept(visitor);
assertEmpty(diffs);
}
private void checkMethodAnnotations(PsiMethod method) {
if (ProjectBytecodeAnalysis.getKey(method, myMessageDigest) == null) {
return;
}
String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
{
// @NotNull method
String externalNotNullMethodAnnotation =
myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
String inferredNotNullMethodAnnotation =
myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
if (!externalNotNullMethodAnnotation.equals(inferredNotNullMethodAnnotation)) {
diffs.add(methodKey + ": " + externalNotNullMethodAnnotation + " != " + inferredNotNullMethodAnnotation);
}
}
{
// @Nullable method
String externalNullableMethodAnnotation =
myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
String inferredNullableMethodAnnotation =
myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
if (!externalNullableMethodAnnotation.equals(inferredNullableMethodAnnotation)) {
diffs.add(methodKey + ": " + externalNullableMethodAnnotation + " != " + inferredNullableMethodAnnotation);
}
}
for (PsiParameter parameter : method.getParameterList().getParameters()) {
String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
{
// @NotNull parameter
String externalNotNull =
myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
String inferredNotNull =
myInferredAnnotationsManager.findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
if (!externalNotNull.equals(inferredNotNull)) {
diffs.add(parameterKey + ": " + externalNotNull + " != " + inferredNotNull);
}
}
{
// @Nullable parameter
String externalNullable =
myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
String inferredNullable =
myInferredAnnotationsManager.findInferredAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
if (!externalNullable.equals(inferredNullable)) {
diffs.add(parameterKey + ": " + externalNullable + " != " + inferredNullable);
}
}
}
// @Contract
PsiAnnotation externalContractAnnotation =
myExternalAnnotationsManager.findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
PsiAnnotation inferredContractAnnotation =
myInferredAnnotationsManager.findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
String externalContractAnnotationString =
externalContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(externalContractAnnotation, null) + ")";
String inferredContractAnnotationString =
inferredContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(inferredContractAnnotation, null) + ")";
if (!externalContractAnnotationString.equals(inferredContractAnnotationString)) {
diffs.add(methodKey + ": " + externalContractAnnotationString + " != " + inferredContractAnnotationString);
}
}
}