| /* |
| * 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); |
| } |
| |
| } |
| |
| } |