[workspace model] migrate ExternalAnnotationsManager (IDEA-295111)

GitOrigin-RevId: 49ab4d729342875a697b8612a04c27c7aeb3981f
This commit is contained in:
Anna Kozlova
2022-05-31 15:19:33 +00:00
committed by intellij-monorepo-bot
parent 2ff41b74ef
commit 51fb599b8f
5 changed files with 119 additions and 7 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight;
import com.intellij.CommonBundle;
@@ -46,6 +46,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.NlsActions;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
@@ -73,7 +74,15 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.OptionsMessageDialog;
import com.intellij.workspaceModel.ide.WorkspaceModelChangeListener;
import com.intellij.workspaceModel.ide.WorkspaceModelTopics;
import com.intellij.workspaceModel.storage.EntityChange;
import com.intellij.workspaceModel.storage.VersionedStorageChange;
import com.intellij.workspaceModel.storage.WorkspaceEntity;
import com.intellij.workspaceModel.storage.bridgeEntities.api.LibraryEntity;
import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleCustomImlDataEntity;
import one.util.streamex.StreamEx;
import org.jdom.Element;
import org.jetbrains.annotations.*;
import org.xml.sax.SAXParseException;
@@ -85,6 +94,7 @@ import java.nio.file.Path;
import java.util.List;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -104,9 +114,12 @@ public final class ExternalAnnotationsManagerImpl extends ReadableExternalAnnota
myBus = project.getMessageBus();
MessageBusConnection connection = myBus.connect(this);
WorkspaceModelTopics.getInstance(project).subscribeAfterModuleLoading(connection, new ExternalAnnotationsRootListener());
connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
@Override
public void rootsChanged(@NotNull ModuleRootEvent event) {
if (event.isCausedByWorkspaceModelChangesOnly()) return;
dropAnnotationsCache();
}
});
@@ -1110,4 +1123,59 @@ public final class ExternalAnnotationsManagerImpl extends ReadableExternalAnnota
}
}
}
private class ExternalAnnotationsRootListener implements WorkspaceModelChangeListener {
@Override
public void changed(@NotNull VersionedStorageChange event) {
if (hasAnnotationRootInChanges(event, LibraryEntity.class, this::hasAnnotationRoot) ||
hasAnnotationRootInChanges(event, ModuleCustomImlDataEntity.class, this::hasAnnotationRoot)) {
dropAnnotationsCache();
}
}
private <T extends WorkspaceEntity> boolean hasAnnotationRootInChanges(@NotNull VersionedStorageChange event,
@NotNull Class<T> entityClass,
@NotNull Predicate<T> hasAnnotationRoot) {
for (EntityChange<T> change : event.getChanges(entityClass)) {
if (change instanceof EntityChange.Added<?>) {
if (hasAnnotationRoot.test(((EntityChange.Added<T>)change).getEntity())) {
return true;
}
}
else if (change instanceof EntityChange.Removed<?>) {
if (hasAnnotationRoot.test(((EntityChange.Removed<T>)change).getEntity())) {
return true;
}
}
else if (change instanceof EntityChange.Replaced<?>) {
if (hasAnnotationRoot.test(((EntityChange.Replaced<T>)change).getOldEntity()) ||
hasAnnotationRoot.test(((EntityChange.Replaced<T>)change).getNewEntity())) {
return true;
}
}
}
return false;
}
private boolean hasAnnotationRoot(LibraryEntity e) {
return e.getRoots().stream().anyMatch(root -> "ANNOTATIONS".equals(root.getType().getName()));
}
private boolean hasAnnotationRoot(ModuleCustomImlDataEntity e) {
String tagCustomData = e.getRootManagerTagCustomData();
if (tagCustomData != null) {
try {
Element element = JDOMUtil.load(tagCustomData);
Element child = element.getChild("annotation-paths");
if (child != null && !child.getChildren("root").isEmpty()) {
return true;
}
}
catch (Throwable ex) {
return false;
}
}
return false;
}
}
}
@@ -0,0 +1,5 @@
<root>
<item name='rootRemoved.Foo'>
<annotation name='java.lang.Deprecated'/>
</item>
</root>
@@ -0,0 +1,3 @@
package rootRemoved;
public class Foo {
}
@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight;
import com.intellij.codeInsight.AnnotationUtil;
@@ -15,10 +15,7 @@ import com.intellij.openapi.application.ex.PathManagerEx;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Disposer;
@@ -384,6 +381,27 @@ public class AddAnnotationFixTest extends UsefulTestCase {
file.refresh(false, false);
});
stopListeningAndCheckEvents();
}
public void testLibraryAnnotationRootsChanged() throws IOException {
addDefaultLibrary();
myFixture.configureByFiles("content/anno/p/annotations.xml");
PsiFile[] files = myFixture.configureByFiles("lib/p/TestDeannotation.java");
PsiClass aClass = ((PsiJavaFile)files[0]).getClasses()[0];
assertNotNull(aClass);
assertTrue(AnnotationUtil.isAnnotated(aClass.getMethods()[0], AnnotationUtil.NOT_NULL, AnnotationUtil.CHECK_EXTERNAL));
ModuleRootModificationUtil.updateModel(myFixture.getModule(), model -> {
final LibraryTable libraryTable = model.getModuleLibraryTable();
Library library = libraryTable.getModifiableModel().getLibraryByName("test");
Library.ModifiableModel libraryModifiableModel = library.getModifiableModel();
libraryModifiableModel.removeRoot(VfsUtilCore.pathToUrl(myFixture.getTempDirPath() + "/content/anno"),
AnnotationOrderRootType.getInstance());
libraryModifiableModel.commit();
});
assertFalse(AnnotationUtil.isAnnotated(aClass.getMethods()[0], AnnotationUtil.NOT_NULL, AnnotationUtil.CHECK_EXTERNAL));
}
public void testAnnotationsUpdatedWhenFileEdited() {
@@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
@@ -11,13 +11,17 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.JavaModuleExternalPaths;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.*;
import com.intellij.util.ArrayUtil;
public class ExternalAnnotationsTest extends UsefulTestCase {
private CodeInsightTestFixture myFixture;
@@ -116,4 +120,18 @@ public class ExternalAnnotationsTest extends UsefulTestCase {
true);
}
public void testExternalAnnotationsRootRemoved() {
myFixture.configureByFiles("src/rootRemoved/Foo.java", "content/anno/rootRemoved/annotations.xml");
Project project = myFixture.getProject();
PsiClass aClass = JavaPsiFacade.getInstance(project)
.findClass("rootRemoved.Foo", GlobalSearchScope.projectScope(project));
assertNotNull(aClass);
assertTrue(aClass.isDeprecated());
ModuleRootModificationUtil.updateModel(myFixture.getModule(), model -> {
final JavaModuleExternalPaths extension = model.getModuleExtension(JavaModuleExternalPaths.class);
extension.setExternalAnnotationUrls(ArrayUtil.EMPTY_STRING_ARRAY);
});
assertFalse(aClass.isDeprecated());
}
}