blob: 8cde2d7f1bc2b63ce4309fa0f7586d1d451dbce1 [file] [log] [blame]
Tor Norbye2e5965e2014-07-25 12:24:15 -07001/*
2 * Copyright 2000-2014 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.intellij.codeInspection.bytecodeAnalysis;
17
18import com.intellij.codeInsight.AnnotationUtil;
19import com.intellij.codeInsight.ExternalAnnotationsManager;
20import com.intellij.codeInsight.InferredAnnotationsManager;
21import com.intellij.openapi.application.ex.PathManagerEx;
22import com.intellij.openapi.projectRoots.Sdk;
23import com.intellij.openapi.projectRoots.SdkModificator;
24import com.intellij.openapi.roots.AnnotationOrderRootType;
25import com.intellij.openapi.roots.ModifiableRootModel;
26import com.intellij.openapi.roots.ModuleRootModificationUtil;
27import com.intellij.openapi.roots.libraries.Library;
28import com.intellij.openapi.roots.libraries.LibraryTable;
29import com.intellij.openapi.vfs.LocalFileSystem;
30import com.intellij.openapi.vfs.VfsUtilCore;
31import com.intellij.openapi.vfs.VirtualFile;
32import com.intellij.openapi.vfs.VirtualFileVisitor;
33import com.intellij.psi.*;
34import com.intellij.psi.search.GlobalSearchScope;
35import com.intellij.psi.util.PsiFormatUtil;
36import com.intellij.testFramework.PsiTestUtil;
37import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
38import com.intellij.util.AsynchConsumer;
39import org.jetbrains.annotations.Contract;
40
Tor Norbyec3d3a90f2014-09-04 13:24:04 -070041import java.security.MessageDigest;
Tor Norbye2e5965e2014-07-25 12:24:15 -070042import java.util.ArrayList;
43import java.util.List;
44
45/**
46 * @author lambdamix
47 */
48public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestCase {
49 public static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
50
51 private InferredAnnotationsManager myInferredAnnotationsManager;
52 private ExternalAnnotationsManager myExternalAnnotationsManager;
Tor Norbyec3d3a90f2014-09-04 13:24:04 -070053 private MessageDigest myMessageDigest;
Tor Norbye2e5965e2014-07-25 12:24:15 -070054 private List<String> diffs = new ArrayList<String>();
55
56 @Override
57 protected void setUp() throws Exception {
58 super.setUp();
59
60 setUpLibraries();
61 setUpExternalUpAnnotations();
62
63 myInferredAnnotationsManager = InferredAnnotationsManager.getInstance(myModule.getProject());
64 myExternalAnnotationsManager = ExternalAnnotationsManager.getInstance(myModule.getProject());
Tor Norbyec3d3a90f2014-09-04 13:24:04 -070065 myMessageDigest = BytecodeAnalysisConverter.getMessageDigest();
Tor Norbye2e5965e2014-07-25 12:24:15 -070066 }
67
68 private void setUpLibraries() {
69 VirtualFile lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib");
70 assertNotNull(lib);
71 PsiTestUtil.addLibrary(myModule, "velocity", lib.getPath(), new String[]{"/velocity.jar!/"}, new String[]{});
72 }
73
74 private void setUpExternalUpAnnotations() {
75 String annotationsPath = PathManagerEx.getTestDataPath() + "/codeInspection/bytecodeAnalysis/annotations";
76 final VirtualFile annotationsDir = LocalFileSystem.getInstance().refreshAndFindFileByPath(annotationsPath);
77 assertNotNull(annotationsDir);
78
79 ModuleRootModificationUtil.updateModel(myModule, new AsynchConsumer<ModifiableRootModel>() {
80 @Override
81 public void finished() {
82 }
83
84 @Override
85 public void consume(ModifiableRootModel modifiableRootModel) {
86 final LibraryTable libraryTable = modifiableRootModel.getModuleLibraryTable();
87 Library[] libs = libraryTable.getLibraries();
88 for (Library library : libs) {
89 final Library.ModifiableModel libraryModel = library.getModifiableModel();
90 libraryModel.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
91 libraryModel.commit();
92 }
93 Sdk sdk = modifiableRootModel.getSdk();
94 if (sdk != null) {
95 SdkModificator sdkModificator = sdk.getSdkModificator();
96 sdkModificator.addRoot(annotationsDir, AnnotationOrderRootType.getInstance());
97 sdkModificator.commitChanges();
98 }
99 }
100 });
101
102 VfsUtilCore.visitChildrenRecursively(annotationsDir, new VirtualFileVisitor() { });
103 annotationsDir.refresh(false, true);
104 }
105
106 public void testSdkAndLibAnnotations() {
107
108 final PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
109 assert rootPackage != null;
110
111 final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
112 JavaRecursiveElementVisitor visitor = new JavaRecursiveElementVisitor() {
113 @Override
114 public void visitPackage(PsiPackage aPackage) {
115 for (PsiPackage subPackage : aPackage.getSubPackages(scope)) {
116 visitPackage(subPackage);
117 }
118 for (PsiClass aClass : aPackage.getClasses(scope)) {
119 for (PsiMethod method : aClass.getMethods()) {
120 checkMethodAnnotations(method);
121 }
122 }
123 }
124 };
125
126 rootPackage.accept(visitor);
127 assertEmpty(diffs);
128 }
129
130 private void checkMethodAnnotations(PsiMethod method) {
Tor Norbyec3d3a90f2014-09-04 13:24:04 -0700131
132 if (ProjectBytecodeAnalysis.getKey(method, myMessageDigest) == null) {
133 return;
Tor Norbye2e5965e2014-07-25 12:24:15 -0700134 }
135
Tor Norbye2e5965e2014-07-25 12:24:15 -0700136 String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
137
Tor Norbyee782c572014-09-18 11:43:07 -0700138 {
139 // @NotNull method
140 String externalNotNullMethodAnnotation =
141 myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
142 String inferredNotNullMethodAnnotation =
143 myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
144
145 if (!externalNotNullMethodAnnotation.equals(inferredNotNullMethodAnnotation)) {
146 diffs.add(methodKey + ": " + externalNotNullMethodAnnotation + " != " + inferredNotNullMethodAnnotation);
147 }
148 }
149
150 {
151 // @Nullable method
152 String externalNullableMethodAnnotation =
153 myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
154 String inferredNullableMethodAnnotation =
155 myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
156
157 if (!externalNullableMethodAnnotation.equals(inferredNullableMethodAnnotation)) {
158 diffs.add(methodKey + ": " + externalNullableMethodAnnotation + " != " + inferredNullableMethodAnnotation);
159 }
Tor Norbye2e5965e2014-07-25 12:24:15 -0700160 }
161
162 for (PsiParameter parameter : method.getParameterList().getParameters()) {
163 String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
Tor Norbyec3d3a90f2014-09-04 13:24:04 -0700164
165 {
Tor Norbyee782c572014-09-18 11:43:07 -0700166 // @NotNull parameter
Tor Norbyec3d3a90f2014-09-04 13:24:04 -0700167 String externalNotNull =
168 myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
169 String inferredNotNull =
170 myInferredAnnotationsManager.findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
171 if (!externalNotNull.equals(inferredNotNull)) {
172 diffs.add(parameterKey + ": " + externalNotNull + " != " + inferredNotNull);
173 }
174 }
175
176 {
Tor Norbyee782c572014-09-18 11:43:07 -0700177 // @Nullable parameter
Tor Norbyec3d3a90f2014-09-04 13:24:04 -0700178 String externalNullable =
179 myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
180 String inferredNullable =
181 myInferredAnnotationsManager.findInferredAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
182 if (!externalNullable.equals(inferredNullable)) {
183 diffs.add(parameterKey + ": " + externalNullable + " != " + inferredNullable);
184 }
Tor Norbye2e5965e2014-07-25 12:24:15 -0700185 }
186 }
187
Tor Norbyee782c572014-09-18 11:43:07 -0700188 // @Contract
Tor Norbye2e5965e2014-07-25 12:24:15 -0700189 PsiAnnotation externalContractAnnotation =
190 myExternalAnnotationsManager.findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
191 PsiAnnotation inferredContractAnnotation =
192 myInferredAnnotationsManager.findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
193
194 String externalContractAnnotationString =
195 externalContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(externalContractAnnotation, null) + ")";
196 String inferredContractAnnotationString =
197 inferredContractAnnotation == null ? "null" : "@Contract(" + AnnotationUtil.getStringAttributeValue(inferredContractAnnotation, null) + ")";
198
199 if (!externalContractAnnotationString.equals(inferredContractAnnotationString)) {
200 diffs.add(methodKey + ": " + externalContractAnnotationString + " != " + inferredContractAnnotationString);
201 }
202
203 }
204
205}