/* * 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 diffs = new ArrayList(); @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() { @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); } } }