[java-tests] Convert Groovy to Java; restore copyrights

GitOrigin-RevId: 2c1ab0479b2f26bc51926f0a78663436b9bf5852
This commit is contained in:
Tagir Valeev
2024-02-21 17:28:38 +01:00
committed by intellij-monorepo-bot
parent 4942586999
commit b4d12c1883
8 changed files with 735 additions and 736 deletions

View File

@@ -1,148 +1,135 @@
// 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-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.psi package com.intellij.java.psi;
import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.psi.* import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.impl.source.tree.java.JavaFileElement import com.intellij.psi.impl.source.tree.java.JavaFileElement;
import com.intellij.psi.impl.source.tree.java.MethodElement import com.intellij.psi.impl.source.tree.java.MethodElement;
import com.intellij.psi.impl.source.tree.java.ParameterElement import com.intellij.psi.impl.source.tree.java.ParameterElement;
import com.intellij.testFramework.LeakHunter import com.intellij.testFramework.LeakHunter;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import com.intellij.util.ref.GCWatcher import com.intellij.util.ref.GCWatcher;
import java.util.function.Predicate public class AstLeaksTest extends LightJavaCodeInsightFixtureTestCase {
public void test_AST_should_be_on_a_soft_reference__for_changed_files_as_well() {
final PsiFile file = myFixture.addClass("class Foo {}").getContainingFile();
assertTrue(file.findElementAt(0) instanceof PsiKeyword);
LeakHunter.checkLeak(file, JavaFileElement.class, e -> e.getPsi().equals(file));
class AstLeaksTest extends LightJavaCodeInsightFixtureTestCase { WriteCommandAction.runWriteCommandAction(getProject(), () -> {
file.getViewProvider().getDocument().insertString(0, " ");
void "test AST should be on a soft reference, for changed files as well"() { PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
def file = myFixture.addClass('class Foo {}').containingFile });
assert file.findElementAt(0) instanceof PsiKeyword assertTrue(file.findElementAt(0) instanceof PsiWhiteSpace);
LeakHunter.checkLeak(file, JavaFileElement) { e -> e.psi == file } LeakHunter.checkLeak(file, JavaFileElement.class, e -> e.getPsi().equals(file));
WriteCommandAction.runWriteCommandAction project, {
file.viewProvider.document.insertString(0, ' ')
PsiDocumentManager.getInstance(project).commitAllDocuments()
}
assert file.findElementAt(0) instanceof PsiWhiteSpace
LeakHunter.checkLeak(file, JavaFileElement) { e -> e.psi == file }
} }
void "test super methods held via their signatures in class user data"() { public void test_super_methods_held_via_their_signatures_in_class_user_data() {
def superClass = myFixture.addClass('class Super { void foo() {} }') final PsiClass superClass = myFixture.addClass("class Super { void foo() {} }");
superClass.text // load AST assertNotNull(superClass.getText()); // load AST
def file = myFixture.addFileToProject('Main.java', 'class Main extends Super { void foo() { System.out.println("hello"); } }') PsiFile file = myFixture.addFileToProject("Main.java", "class Main extends Super { void foo() { System.out.println(\"hello\"); } }");
myFixture.configureFromExistingVirtualFile(file.virtualFile) myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
myFixture.doHighlighting() myFixture.doHighlighting();
def mainClass = ((PsiJavaFile)file).classes[0] PsiClass mainClass = ((PsiJavaFile)file).getClasses()[0];
LeakHunter.checkLeak(mainClass, MethodElement) { MethodElement node -> LeakHunter.checkLeak(mainClass, MethodElement.class, node -> superClass.equals(node.getPsi().getParent()));
superClass == node.psi.parent
}
} }
void "test no hard refs to AST after highlighting"() { public void test_no_hard_refs_to_AST_after_highlighting() {
def sup = myFixture.addFileToProject('sup.java', 'class Super { Super() {} }') final PsiFile sup = myFixture.addFileToProject("sup.java", "class Super { Super() {} }");
assert sup.findElementAt(0) // load AST assertNotNull(sup.findElementAt(0));// load AST
assert !((PsiFileImpl)sup).stub assertNull(((PsiFileImpl)sup).getStub());
LeakHunter.checkLeak(sup, MethodElement, { it.psi.containingFile == sup }) LeakHunter.checkLeak(sup, MethodElement.class, it -> it.getPsi().getContainingFile().equals(sup));
def foo = myFixture.addFileToProject('a.java', 'class Foo extends Super { void bar() { bar(); } }') final PsiFile foo = myFixture.addFileToProject("a.java", "class Foo extends Super { void bar() { bar(); } }");
myFixture.configureFromExistingVirtualFile(foo.virtualFile) myFixture.configureFromExistingVirtualFile(foo.getVirtualFile());
myFixture.doHighlighting() myFixture.doHighlighting();
assert !((PsiFileImpl)foo).stub assertNull(((PsiFileImpl)foo).getStub());
assert ((PsiFileImpl)foo).treeElement assertNotNull(((PsiFileImpl)foo).getTreeElement());
LeakHunter.checkLeak(foo, MethodElement, { it.psi.containingFile == foo }) LeakHunter.checkLeak(foo, MethodElement.class, it -> it.getPsi().getContainingFile().equals(foo));
LeakHunter.checkLeak(sup, MethodElement, { it.psi.containingFile == sup }) LeakHunter.checkLeak(sup, MethodElement.class, it -> it.getPsi().getContainingFile().equals(sup));
} }
void "test no hard refs to AST via class reference type"() { public void test_no_hard_refs_to_AST_via_class_reference_type() {
def cls = myFixture.addClass("class Foo { Object bar() {} }") final PsiClass cls = myFixture.addClass("class Foo { Object bar() {} }");
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
cls.node assertNotNull(cls.getNode());
def type = cls.methods[0].returnType PsiType type = cls.getMethods()[0].getReturnType();
assert type instanceof PsiClassReferenceType assertTrue(type instanceof PsiClassReferenceType);
LeakHunter.checkLeak(type, MethodElement, { MethodElement node -> LeakHunter.checkLeak(type, MethodElement.class, node -> node.getPsi().equals(cls.getMethods()[0]));
node.psi == cls.methods[0]
})
GCWatcher.tracking(cls.node).ensureCollected() GCWatcher.tracking(cls.getNode()).ensureCollected();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert type.equalsToText(Object.name) assertTrue(type.equalsToText(Object.class.getName()));
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
@SuppressWarnings('CStyleArrayDeclaration') @SuppressWarnings("CStyleArrayDeclaration")
void "test no hard refs to AST via class reference type of c-style array"() { public void test_no_hard_refs_to_AST_via_class_reference_type_of_c_style_array() {
def cls = myFixture.addClass("class Foo { static void main(String args[]) {} }") final PsiClass cls = myFixture.addClass("class Foo { static void main(String args[]) {} }");
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
cls.node assertNotNull(cls.getNode());
def type = cls.methods[0].parameterList.parameters[0].typeElement.type PsiType type = cls.getMethods()[0].getParameterList().getParameters()[0].getTypeElement().getType();
assert type instanceof PsiClassReferenceType assertTrue(type instanceof PsiClassReferenceType);
LeakHunter.checkLeak(type, ParameterElement, { ParameterElement node -> LeakHunter.checkLeak(type, ParameterElement.class,
node.psi == cls.methods[0].parameterList.parameters[0] node -> node.getPsi().equals(cls.getMethods()[0].getParameterList().getParameters()[0]));
})
GCWatcher.tracking(cls.node).ensureCollected() GCWatcher.tracking(cls.getNode()).ensureCollected();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert type.equalsToText(String.name) assertTrue(type.equalsToText(String.class.getName()));
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
void "test no hard refs to AST via array component type"() { public void test_no_hard_refs_to_AST_via_array_component_type() {
def cls = myFixture.addClass("class Foo { Object[] bar() {} }") final PsiClass cls = myFixture.addClass("class Foo { Object[] bar() {} }");
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
cls.node assertNotNull(cls.getNode());
def type = cls.methods[0].returnType PsiType type = cls.getMethods()[0].getReturnType();
assert type instanceof PsiArrayType assertTrue(type instanceof PsiArrayType);
def componentType = type.getComponentType() PsiType componentType = ((PsiArrayType)type).getComponentType();
assert componentType instanceof PsiClassReferenceType assertTrue(componentType instanceof PsiClassReferenceType);
LeakHunter.checkLeak(type, MethodElement, { MethodElement node -> LeakHunter.checkLeak(type, MethodElement.class, node -> node.getPsi().equals(cls.getMethods()[0]));
node.psi == cls.methods[0]
})
GCWatcher.tracking(cls.node).ensureCollected() GCWatcher.tracking(cls.getNode()).ensureCollected();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert componentType.equalsToText(Object.name) assertTrue(componentType.equalsToText(Object.class.getName()));
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
void "test no hard refs to AST via generic component type"() { public void test_no_hard_refs_to_AST_via_generic_component_type() {
def cls = myFixture.addClass("class Foo { java.util.Map<String[], ? extends CharSequence> bar() {} }") final PsiClass cls = myFixture.addClass("class Foo { java.util.Map<String[], ? extends CharSequence> bar() {} }");
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
cls.node assertNotNull(cls.getNode());
def type = cls.methods[0].returnType PsiType type = cls.getMethods()[0].getReturnType();
assert type instanceof PsiClassReferenceType assertTrue(type instanceof PsiClassReferenceType);
def parameters = (type as PsiClassReferenceType).getParameters() PsiType[] parameters = ((PsiClassReferenceType)type).getParameters();
assert parameters.length == 2 assertEquals(2, parameters.length);
assert parameters[0] instanceof PsiArrayType assertTrue(parameters[0] instanceof PsiArrayType);
def componentType = parameters[0].getDeepComponentType() PsiType componentType = parameters[0].getDeepComponentType();
assert componentType instanceof PsiClassReferenceType assertTrue(componentType instanceof PsiClassReferenceType);
assert parameters[1] instanceof PsiWildcardType assertTrue(parameters[1] instanceof PsiWildcardType);
def bound = (parameters[1] as PsiWildcardType).getExtendsBound() PsiType bound = ((PsiWildcardType)parameters[1]).getExtendsBound();
assert bound instanceof PsiClassReferenceType assertTrue(bound instanceof PsiClassReferenceType);
LeakHunter.checkLeak(type, MethodElement, { MethodElement node -> LeakHunter.checkLeak(type, MethodElement.class, node -> node.getPsi().equals(cls.getMethods()[0]));
node.psi == cls.methods[0]
})
GCWatcher.tracking(cls.node).ensureCollected() GCWatcher.tracking(cls.getNode()).ensureCollected();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert componentType.equalsToText(String.name) assertTrue(componentType.equalsToText(String.class.getName()));
assert bound.equalsToText(CharSequence.name) assertTrue(bound.equalsToText(CharSequence.class.getName()));
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
} }

View File

@@ -1,518 +1,505 @@
// 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-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.psi package com.intellij.java.psi;
import com.intellij.codeInsight.AnnotationTargetUtil import com.intellij.codeInsight.AnnotationTargetUtil;
import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil;
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.psi.* import com.intellij.openapi.editor.Document;
import com.intellij.psi.impl.source.PsiClassImpl import com.intellij.openapi.util.Computable;
import com.intellij.psi.impl.source.PsiFieldImpl import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.impl.source.PsiFieldImpl;
import com.intellij.psi.search.PsiShortNamesCache import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.search.searches.AnnotatedElementsSearch import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.search.searches.AnnotatedElementsSearch;
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiUtil import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.testFramework.PsiTestUtil import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase import com.intellij.psi.util.PsiUtil;
import groovy.transform.CompileStatic import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import java.util.concurrent.Callable import java.util.concurrent.ExecutionException;
@CompileStatic public class JavaStubsTest extends LightJavaCodeInsightFixtureTestCase {
class JavaStubsTest extends LightJavaCodeInsightFixtureTestCase { public void test_resolve_from_annotation_method_default() {
PsiClass cls = myFixture.addClass("""
public @interface BrokenAnnotation {
enum Foo {DEFAULT, OTHER}
Foo value() default Foo.DEFAULT;
}""");
void "test resolve from annotation method default"() { PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
def cls = myFixture.addClass("""\ assertNotNull(file.getStub());
public @interface BrokenAnnotation {
enum Foo {DEFAULT, OTHER}
Foo value() default Foo.DEFAULT;
}
""".stripIndent())
def file = cls.containingFile as PsiFileImpl PsiAnnotationMemberValue ref = (((PsiAnnotationMethod)cls.getMethods()[0])).getDefaultValue();
assert file.stub assertNotNull(file.getStub());
def ref = (cls.methods[0] as PsiAnnotationMethod).defaultValue assertTrue(ref instanceof PsiReferenceExpression);
assert file.stub assertEquals(((PsiReferenceExpression)ref).resolve(), cls.getInnerClasses()[0].getFields()[0]);
assertNotNull(file.getStub());
assert ref instanceof PsiReferenceExpression
assert ref.resolve() == cls.innerClasses[0].fields[0]
assert file.stub
} }
void "test literal annotation value"() { public void test_literal_annotation_value() {
def cls = myFixture.addClass("""\ PsiClass cls = myFixture.addClass("""
class Foo { class Foo {
@org.jetbrains.annotations.Contract(pure=true) @org.jetbrains.annotations.Contract(pure=true)
native int foo(); native int foo();
} }""");
""".stripIndent())
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
assert JavaMethodContractUtil.isPure(cls.methods[0]) assertTrue(JavaMethodContractUtil.isPure(cls.getMethods()[0]));
assert file.stub assertNotNull(file.getStub());
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
void "test local variable annotation doesn't cause stub-ast switch"() { public void test_local_variable_annotation_doesn_t_cause_stub_ast_switch() {
def cls = myFixture.addClass(""" PsiClass cls = myFixture.addClass("""
class Foo { class Foo {
@Anno int foo() { @Anno int foo() {
@Anno int var = 2; @Anno int var = 2;
} }
} }
@interface Anno {} @interface Anno {}""");
""")
def file = cls.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
assert AnnotatedElementsSearch.searchPsiMethods(myFixture.findClass("Anno"), GlobalSearchScope.allScope(project)).size() == 1 assertEquals(1, AnnotatedElementsSearch.searchPsiMethods(myFixture.findClass("Anno"), GlobalSearchScope.allScope(getProject()))
assert file.stub .findAll().size());
assert !file.contentsLoaded assertNotNull(file.getStub());
assertFalse(file.isContentsLoaded());
} }
void "test applying type annotations"() { public void test_applying_type_annotations() {
def cls = myFixture.addClass("""\ PsiClass cls = myFixture.addClass("""
import java.lang.annotation.*; import java.lang.annotation.*;
class Foo { class Foo {
@Target(ElementType.TYPE_USE) @Target(ElementType.TYPE_USE)
@interface TA { String value(); } @interface TA { String value(); }
private @TA String f1; private @TA String f1;
private static @TA int m1(@TA int p1) { return 0; } private static @TA int m1(@TA int p1) { return 0; }
} }""");
""".stripIndent())
def f1 = cls.fields[0].type PsiType f1 = cls.getFields()[0].getType();
def m1 = cls.methods[0].returnType PsiType m1 = cls.getMethods()[0].getReturnType();
def p1 = cls.methods[0].parameterList.parameters[0].type PsiType p1 = cls.getMethods()[0].getParameterList().getParameters()[0].getType();
assert (cls as PsiClassImpl).stub assertNotNull(((PsiClassImpl)cls).getStub());
assert f1.getCanonicalText(true) == "java.lang.@Foo.TA String" assertEquals("java.lang.@Foo.TA String", f1.getCanonicalText(true));
assert m1.getCanonicalText(true) == "@Foo.TA int" assertEquals("@Foo.TA int", m1.getCanonicalText(true));
assert p1.getCanonicalText(true) == "@Foo.TA int" assertEquals("@Foo.TA int", p1.getCanonicalText(true));
} }
void "test containing class of a local class is null"() { public void test_containing_class_of_a_local_class_is_null() {
def foo = myFixture.addClass("""\ PsiClass foo = myFixture.addClass("""
class Foo { class Foo {
static { class Bar extends Foo { } } static { class Bar extends Foo { } }
}""".stripIndent()) }""");
def bar = ClassInheritorsSearch.search(foo).findFirst() PsiClass bar = ClassInheritorsSearch.search(foo).findFirst();
def file = (PsiFileImpl)foo.containingFile PsiFileImpl file = (PsiFileImpl)foo.getContainingFile();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert bar.containingClass == null assertNull(bar.getContainingClass());
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
bar.node assertNotNull(bar.getNode());
assert bar.containingClass == null assertNull(bar.getContainingClass());
assert file.contentsLoaded assertTrue(file.isContentsLoaded());
} }
void "test stub-based super class type parameter resolve"() { public void test_stub_based_super_class_type_parameter_resolve() throws ExecutionException, InterruptedException {
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
def foo = myFixture.addClass("class Foo$i<T> {}") PsiClass foo = myFixture.addClass("class Foo" + i + "<T> {}");
def bar = myFixture.addClass("class Bar$i<T> extends Foo$i<T> {}") final PsiClass bar = myFixture.addClass("class Bar" + i + "<T> extends Foo" + i + "<T> {}");
def app = ApplicationManager.application Application app = ApplicationManager.getApplication();
app.executeOnPooledThread({ ReadAction.compute { bar.node } }) app.executeOnPooledThread(() -> ReadAction.compute(() -> bar.getNode()));
def superType = app.executeOnPooledThread({ ReadAction.compute { bar.superTypes[0] }} as Callable<PsiClassType>).get() PsiClassType superType = app.executeOnPooledThread(() -> ReadAction.compute(() -> bar.getSuperTypes()[0])).get();
assert foo == superType.resolve() assertEquals(foo, superType.resolve());
assert bar.typeParameters[0] == PsiUtil.resolveClassInClassTypeOnly(superType.parameters[0]) assertEquals(bar.getTypeParameters()[0], PsiUtil.resolveClassInClassTypeOnly(superType.getParameters()[0]));
} }
} }
void "test default annotation attribute name"() { public void test_default_annotation_attribute_name() {
def cls = myFixture.addClass('@Anno("foo") class Foo {}') PsiClass cls = myFixture.addClass("@Anno(\"foo\") class Foo {}");
def file = (PsiFileImpl)cls.containingFile PsiFileImpl file = (PsiFileImpl)cls.getContainingFile();
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
def attr = cls.modifierList.annotations[0].parameterList.attributes[0] PsiNameValuePair attr = cls.getModifierList().getAnnotations()[0].getParameterList().getAttributes()[0];
assert attr.name == null assertNull(attr.getName());
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
attr.node assertNotNull(attr.getNode());
assert attr.name == null assertNull(attr.getName());
} }
void "test determine annotation target without AST"() { public void test_determine_annotation_target_without_AST() {
def cls = myFixture.addClass("""\ PsiClass cls = myFixture.addClass("""
import java.lang.annotation.*; import java.lang.annotation.*;
@Anno class Some {} @Anno class Some {}
@Target(ElementType.METHOD) @interface Anno {}""".stripIndent()) @Target(ElementType.METHOD) @interface Anno {}""");
assert "Some" == cls.name assertEquals("Some", cls.getName());
assert !AnnotationTargetUtil.isTypeAnnotation(cls.modifierList.annotations[0]) assertFalse(AnnotationTargetUtil.isTypeAnnotation(cls.getModifierList().getAnnotations()[0]));
assert !((PsiFileImpl) cls.containingFile).contentsLoaded assertFalse(((PsiFileImpl)cls.getContainingFile()).isContentsLoaded());
} }
void "test parameter list count"() { public void test_parameter_list_count() {
myFixture.addFileToProject("a.java", "class Cls { void foo(a) {} }") myFixture.addFileToProject("a.java", "class Cls { void foo(a) {} }");
def list = myFixture.findClass("Cls").methods[0].parameterList PsiParameterList list = myFixture.findClass("Cls").getMethods()[0].getParameterList();
assert list.parametersCount == list.parameters.size() assertEquals(list.getParametersCount(), list.getParameters().length);
} }
void "test deprecated enum constant"() { public void test_deprecated_enum_constant() {
def cls = myFixture.addClass("enum Foo { c1, @Deprecated c2, /** @deprecated */ c3 }") PsiClass cls = myFixture.addClass("enum Foo { c1, @Deprecated c2, /** @deprecated */ c3 }");
assert !((PsiFileImpl) cls.containingFile).contentsLoaded assertFalse(((PsiFileImpl)cls.getContainingFile()).isContentsLoaded());
assert !cls.fields[0].deprecated assertFalse(cls.getFields()[0].isDeprecated());
assert cls.fields[1].deprecated assertTrue(cls.getFields()[1].isDeprecated());
assert cls.fields[2].deprecated assertTrue(cls.getFields()[2].isDeprecated());
assert !((PsiFileImpl) cls.containingFile).contentsLoaded assertFalse(((PsiFileImpl)cls.getContainingFile()).isContentsLoaded());
} }
void "test breaking and adding import does not cause stub AST mismatch"() { public void test_breaking_and_adding_import_does_not_cause_stub_AST_mismatch() {
def file = myFixture.addFileToProject("a.java", "import foo.*; import bar.*; class Foo {}") as PsiJavaFile PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "import foo.*; import bar.*; class Foo {}");
def another = myFixture.addClass("package zoo; public class Another {}") PsiClass another = myFixture.addClass("package zoo; public class Another {}");
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(getProject(), (Computable<Boolean>)() -> {
file.viewProvider.document.insertString(file.text.indexOf("import"), "x") file.getViewProvider().getDocument().insertString(file.getText().indexOf("import"), "x");
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
file.importClass(another) return file.importClass(another);
} });
PsiTestUtil.checkStubsMatchText(file) PsiTestUtil.checkStubsMatchText(file);
} }
void "test removing import in broken code does not cause stub AST mismatch"() { public void test_removing_import_in_broken_code_does_not_cause_stub_AST_mismatch() {
def file = myFixture.addFileToProject("a.java", "import foo..module.SomeClass; class Foo {}") as PsiJavaFile PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "import foo..module.SomeClass; class Foo {}");
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(getProject(), () -> file.getImportList().getImportStatements()[0].delete());
file.importList.importStatements[0].delete() PsiTestUtil.checkStubsMatchText(file);
}
PsiTestUtil.checkStubsMatchText(file)
} }
void "test adding type before method call does not cause stub AST mismatch"() { public void test_adding_type_before_method_call_does_not_cause_stub_AST_mismatch() {
def file = myFixture.addFileToProject("a.java", """\ final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", """
class Foo { class Foo {
void foo() { void foo() {
something(); something();
call(); call();
} }
}""".stripIndent()) as PsiJavaFile }""");
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(getProject(), () -> {
file.viewProvider.document.insertString(file.text.indexOf("call"), "char ") file.getViewProvider().getDocument().insertString(file.getText().indexOf("call"), "char ");
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiTestUtil.checkStubsMatchText(file) PsiTestUtil.checkStubsMatchText(file);
} });
} }
void "test inserting class keyword"() { public void test_inserting_class_keyword() {
String text = "class Foo { void foo() { return; } }" final String text = "class Foo { void foo() { return; } }";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) PsiFile psiFile = myFixture.addFileToProject("a.java", text);
Document document = psiFile.getViewProvider().getDocument() final Document document = psiFile.getViewProvider().getDocument();
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(
document.insertString(text.indexOf("return"), "class ") getProject(), () -> document.insertString(text.indexOf("return"), "class "));
} PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments() PsiTestUtil.checkStubsMatchText(psiFile);
PsiTestUtil.checkStubsMatchText(psiFile)
} }
void "test inserting enum keyword"() { public void test_inserting_enum_keyword() {
String text = "class Foo { void foo() { return; } }" final String text = "class Foo { void foo() { return; } }";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) PsiFile psiFile = myFixture.addFileToProject("a.java", text);
Document document = psiFile.getViewProvider().getDocument() final Document document = psiFile.getViewProvider().getDocument();
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(
document.insertString(text.indexOf("return"), "enum Foo") getProject(), () -> document.insertString(text.indexOf("return"), "enum Foo"));
} PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments() PsiTestUtil.checkStubsMatchText(psiFile);
PsiTestUtil.checkStubsMatchText(psiFile)
} }
void "test type arguments without type in a method"() { public void test_type_arguments_without_type_in_a_method() {
String text = "class Foo { { final Collection<String> contexts; f instanceof -> } }" String text = "class Foo { { final Collection<String> contexts; f instanceof -> } }";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) final PsiFile psiFile = myFixture.addFileToProject("a.java", text);
WriteCommandAction.runWriteCommandAction(project) { deleteString(psiFile, "Collection") } WriteCommandAction.runWriteCommandAction(getProject(), () -> deleteString(psiFile, "Collection"));
PsiDocumentManager.getInstance(getProject()).commitAllDocuments() PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiTestUtil.checkStubsMatchText(psiFile) PsiTestUtil.checkStubsMatchText(psiFile);
} }
private static void deleteString(PsiFile file, String fragment) { private static void deleteString(PsiFile file, String fragment) {
def document = file.viewProvider.document Document document = file.getViewProvider().getDocument();
def index = document.text.indexOf(fragment) int index = document.getText().indexOf(fragment);
document.deleteString(index, index + fragment.size()) document.deleteString(index, index + fragment.length());
} }
void "test remove class literal qualifier"() { public void test_remove_class_literal_qualifier() {
String text = "class Foo { { foo(String.class); } }" final String text = "class Foo { { foo(String.class); } }";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) final PsiFile psiFile = myFixture.addFileToProject("a.java", text);
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(
psiFile.viewProvider.document.insertString(text.indexOf(");"), " x") getProject(), () -> {
WriteCommandAction.runWriteCommandAction(project) { deleteString(psiFile, "String") } psiFile.getViewProvider().getDocument().insertString(text.indexOf(");"), " x");
} WriteCommandAction.runWriteCommandAction(getProject(), () -> deleteString(psiFile, "String"));
PsiDocumentManager.getInstance(getProject()).commitAllDocuments() });
PsiTestUtil.checkStubsMatchText(psiFile) PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiTestUtil.checkStubsMatchText(psiFile);
} }
void "test annotation stub without reference"() { public void test_annotation_stub_without_reference() {
PsiFile psiFile = myFixture.addFileToProject("a.java", "@() class Foo { } }") PsiFile psiFile = myFixture.addFileToProject("a.java", "@() class Foo { } }");
assert ((PsiJavaFile) psiFile).classes[0].modifierList.annotations[0].nameReferenceElement == null assertNull(((PsiJavaFile)psiFile).getClasses()[0].getModifierList().getAnnotations()[0].getNameReferenceElement());
assert !((PsiFileImpl) psiFile).contentsLoaded assertFalse(((PsiFileImpl)psiFile).isContentsLoaded());
} }
void "test anonymous class stubs see method type parameters"() { public void test_anonymous_class_stubs_see_method_type_parameters() {
PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("A.java", """\ PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("A.java", """
class A { class A {
<V> Object foo() { <V> Object foo() {
return new I<V>(){}; return new I<V>(){};
} }
} }
interface I<T> {} interface I<T> {}""");
""".stripIndent())
PsiClass a = ((PsiJavaFile) file).classes[0] PsiClass a = ((PsiJavaFile)file).getClasses()[0];
PsiClass i = ((PsiJavaFile) file).classes[1] PsiClass i = ((PsiJavaFile)file).getClasses()[1];
PsiAnonymousClass anon = assertOneElement(DirectClassInheritorsSearch.search(i).findAll()) as PsiAnonymousClass PsiAnonymousClass anon = (PsiAnonymousClass)UsefulTestCase.assertOneElement(DirectClassInheritorsSearch.search(i).findAll());
assert i == anon.baseClassType.resolve() assertEquals(i, anon.getBaseClassType().resolve());
assert a.methods[0].typeParameters[0] == PsiUtil.resolveClassInClassTypeOnly(anon.baseClassType.parameters[0]) assertEquals(a.getMethods()[0].getTypeParameters()[0], PsiUtil.resolveClassInClassTypeOnly(anon.getBaseClassType().getParameters()[0]));
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
void "test anonymous class stubs see local classes"() { public void test_anonymous_class_stubs_see_local_classes() {
PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("A.java", """\ PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("A.java", """
class A { class A {
void foo() { void foo() {
class Local {} class Local {}
new I<Local>(){}; new I<Local>(){};
} }
} }
interface I<T> {} interface I<T> {}""");
""".stripIndent())
PsiClass i = ((PsiJavaFile) file).classes[1] PsiClass i = ((PsiJavaFile)file).getClasses()[1];
PsiAnonymousClass anon = assertOneElement(DirectClassInheritorsSearch.search(i).findAll()) as PsiAnonymousClass PsiAnonymousClass anon = (PsiAnonymousClass)UsefulTestCase.assertOneElement(DirectClassInheritorsSearch.search(i).findAll());
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert i == anon.baseClassType.resolve() assertEquals(i, anon.getBaseClassType().resolve());
assert PsiUtil.resolveClassInClassTypeOnly(anon.baseClassType.parameters[0])?.name == "Local" final PsiClass only = PsiUtil.resolveClassInClassTypeOnly(anon.getBaseClassType().getParameters()[0]);
assertEquals("Local", (only == null ? null : only.getName()));
} }
void "test local class stubs see other local classes"() { public void test_local_class_stubs_see_other_local_classes() {
PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("A.java", """\ PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("A.java", """
class A { class A {
void foo() { void foo() {
class Local1 {} class Local1 {}
class Local2 extends Local1 {} class Local2 extends Local1 {}
} }
} }""");
""".stripIndent())
def cache = PsiShortNamesCache.getInstance(project) PsiShortNamesCache cache = PsiShortNamesCache.getInstance(getProject());
def local1 = cache.getClassesByName("Local1", GlobalSearchScope.allScope(project))[0] PsiClass local1 = cache.getClassesByName("Local1", GlobalSearchScope.allScope(getProject()))[0];
def local2 = cache.getClassesByName("Local2", GlobalSearchScope.allScope(project))[0] PsiClass local2 = cache.getClassesByName("Local2", GlobalSearchScope.allScope(getProject()))[0];
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
assert local1 == local2.superClass assertEquals(local1, local2.getSuperClass());
} }
void "test local class stubs do not load AST for inheritance checking when possible"() { public void test_local_class_stubs_do_not_load_AST_for_inheritance_checking_when_possible() {
PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("A.java", """\ PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("A.java", """
class A { class A {
void foo() { void foo() {
class UnrelatedLocal {} class UnrelatedLocal {}
class Local extends A {} class Local extends A {}
} }
} }""");
""".stripIndent())
def local = PsiShortNamesCache.getInstance(project).getClassesByName("Local", GlobalSearchScope.allScope(project))[0] PsiClass local = PsiShortNamesCache.getInstance(getProject()).getClassesByName("Local", GlobalSearchScope.allScope(getProject()))[0];
assert "A" == local.superClass.name assertEquals("A", local.getSuperClass().getName());
assert !file.contentsLoaded assertFalse(file.isContentsLoaded());
} }
void "test broken anonymous"() { public void test_broken_anonymous() {
String text = """\ final String text = """
class A { class A {
public GroupDescriptor[] getGroupDescriptors() { public GroupDescriptor[] getGroupDescriptors() {
return new ThreadGroup(Descriptor[]{ return new ThreadGroup(Descriptor[]{
new GroupDescriptor(groupId, "test") new GroupDescriptor(groupId, "test")
}; };
} }
}""".stripIndent() }""";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) final PsiFile psiFile = myFixture.addFileToProject("a.java", text);
WriteCommandAction.runWriteCommandAction(project) { WriteCommandAction.runWriteCommandAction(
psiFile.viewProvider.document.insertString(text.indexOf("]{"), "x") getProject(), () -> psiFile.getViewProvider().getDocument().insertString(text.indexOf("]{"), "x"));
} PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
PsiDocumentManager.getInstance(getProject()).commitAllDocuments() PsiTestUtil.checkStubsMatchText(psiFile);
PsiTestUtil.checkStubsMatchText(psiFile)
} }
void "test broken nested anonymous"() { public void test_broken_nested_anonymous() {
PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", "class A { { new A(new B[a]{b}); } }")) PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", "class A { { new A(new B[a]{b}); } }"));
} }
void "test lone angle brackets"() { public void test_lone_angle_brackets() {
String text = """\ String text = """
class A { class A {
{ {
PsiLanguageInjectionHost host = PsiTreeUtil.getParentOfType(element, .class); PsiLanguageInjectionHost host = PsiTreeUtil.getParentOfType(element, .class);
final <PsiElement, TextRange> pair; final <PsiElement, TextRange> pair;
}
}""".stripIndent()
PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", text))
}
void "test incomplete static import does not cause CCE"() {
def file = myFixture.addFileToProject("a.java", "import static foo.bar.") as PsiJavaFile
assert ((PsiFileImpl)file).stub
assert file.node
def staticImport = ((PsiJavaFile)file).importList.importStaticStatements[0]
assert staticImport.referenceName == null
assert !staticImport.resolveTargetClass()
}
void "test adding import to broken file with type parameters"() {
def file = myFixture.addFileToProject("a.java", "A<B>") as PsiJavaFile
WriteCommandAction.runWriteCommandAction(project) {
file.importClass(myFixture.findClass(CommonClassNames.JAVA_UTIL_LIST))
}
PsiTestUtil.checkStubsMatchText(file)
}
void "test remove extends reference before dot"() {
def file = myFixture.addFileToProject("a.java", "class A extends B. { int a; }")
WriteCommandAction.runWriteCommandAction(project) {
def javaFile = file as PsiJavaFile
def clazz = (javaFile.classes[0] as PsiImplicitClass).innerClasses[0]
clazz.extendsList.referenceElements[0].delete()
}
PsiTestUtil.checkStubsMatchText(file)
}
void "test remove type argument list after space"() {
def file = myFixture.addFileToProject("a.java", "class A { A <B>a; }")
WriteCommandAction.runWriteCommandAction(project) {
myFixture.findClass("A").fields[0].typeElement.innermostComponentReferenceElement.parameterList.delete()
}
PsiTestUtil.checkStubsMatchText(file)
PsiTestUtil.checkFileStructure(file)
}
void "test remove modifier making a comment a class javadoc"() {
def file = myFixture.addFileToProject("a.java", "import foo; final /** @deprecated */ public class A { }")
WriteCommandAction.runWriteCommandAction(project) {
def clazz = myFixture.findClass("A")
def children = clazz.modifierList.children
assert children.length != 0 : clazz.containingFile.text + ";" + clazz.containingFile.virtualFile.path
children[0].delete()
}
PsiTestUtil.checkFileStructure(file)
PsiTestUtil.checkStubsMatchText(file)
}
void "test add reference into broken extends list"() {
def file = myFixture.addFileToProject("a.java", "class A extends.ends Foo { int a; }")
WriteCommandAction.runWriteCommandAction(project) {
def javaFile = file as PsiJavaFile
def clazz = (javaFile.classes[0] as PsiImplicitClass).innerClasses[0]
clazz.extendsList.add(JavaPsiFacade.getElementFactory(project).createReferenceElementByFQClassName(CommonClassNames.JAVA_LANG_OBJECT, file.resolveScope))
}
PsiTestUtil.checkStubsMatchText(file)
}
void "test identifier dot before class"() {
def file = myFixture.addFileToProject("a.java", "class A {{ public id.class B {}}}")
PsiTestUtil.checkStubsMatchText(file)
}
void "test removing orphan annotation"() {
String text = """\
public class Foo {
public Foo() {
}
@Override
public void initSteps {
} }
}""".stripIndent() }""";
PsiFile psiFile = myFixture.addFileToProject("a.java", text) PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", text));
WriteCommandAction.runWriteCommandAction(project) {
PsiTreeUtil.findChildOfType(psiFile, PsiAnnotation).delete()
}
PsiTestUtil.checkStubsMatchText(psiFile)
} }
void "test local record"() { public void test_incomplete_static_import_does_not_cause_CCE() {
PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", """\ PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "import static foo.bar.");
class A { assertNotNull(((PsiFileImpl)file).getStub());
void test() { assertNotNull(file.getNode());
record A(String s) { } PsiImportStaticStatement staticImport = file.getImportList().getImportStaticStatements()[0];
} assertNull(staticImport.getReferenceName());
} assertNull(staticImport.resolveTargetClass());
""".stripIndent()))
} }
void "test field with missing initializer"() { public void test_adding_import_to_broken_file_with_type_parameters() {
def file = myFixture.addFileToProject("a.java", "class A { int a = ; } ") final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "A<B>");
def clazz = myFixture.findClass("A") WriteCommandAction.runWriteCommandAction(
assert PsiFieldImpl.getDetachedInitializer(clazz.fields[0]) == null getProject(), (Computable<Boolean>)() -> file.importClass(myFixture.findClass(CommonClassNames.JAVA_UTIL_LIST)));
assert !(file as PsiFileImpl).contentsLoaded PsiTestUtil.checkStubsMatchText(file);
} }
void "test implicit class"() { public void test_remove_extends_reference_before_dot() {
final PsiFile file = myFixture.addFileToProject("a.java", "class A extends B. { int a; }");
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
PsiJavaFile javaFile = (PsiJavaFile)file;
PsiClass clazz = javaFile.getClasses()[0].getInnerClasses()[0];
clazz.getExtendsList().getReferenceElements()[0].delete();
});
PsiTestUtil.checkStubsMatchText(file);
}
def psiFile = myFixture.addFileToProject("a.java", """\ public void test_remove_type_argument_list_after_space() {
PsiFile file = myFixture.addFileToProject("a.java", "class A { A <B>a; }");
WriteCommandAction.runWriteCommandAction(
getProject(),
() -> myFixture.findClass("A").getFields()[0].getTypeElement().getInnermostComponentReferenceElement().getParameterList().delete());
PsiTestUtil.checkStubsMatchText(file);
PsiTestUtil.checkFileStructure(file);
}
public void test_remove_modifier_making_a_comment_a_class_javadoc() {
PsiFile file = myFixture.addFileToProject("a.java", "import foo; final /** @deprecated */ public class A { }");
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
PsiClass clazz = myFixture.findClass("A");
PsiElement[] children = clazz.getModifierList().getChildren();
assertTrue(clazz.getContainingFile().getText() + ";" + clazz.getContainingFile().getVirtualFile().getPath(),
children.length != 0);
children[0].delete();
});
PsiTestUtil.checkFileStructure(file);
PsiTestUtil.checkStubsMatchText(file);
}
public void test_add_reference_into_broken_extends_list() {
final PsiFile file = myFixture.addFileToProject("a.java", "class A extends.ends Foo { int a; }");
WriteCommandAction.runWriteCommandAction(getProject(), (Computable<PsiElement>)() -> {
PsiJavaFile javaFile = (PsiJavaFile)file;
PsiClass clazz = javaFile.getClasses()[0].getInnerClasses()[0];
return clazz.getExtendsList().add(JavaPsiFacade.getElementFactory(getProject())
.createReferenceElementByFQClassName(CommonClassNames.JAVA_LANG_OBJECT,
file.getResolveScope()));
});
PsiTestUtil.checkStubsMatchText(file);
}
public void test_identifier_dot_before_class() {
PsiFile file = myFixture.addFileToProject("a.java", "class A {{ public id.class B {}}}");
PsiTestUtil.checkStubsMatchText(file);
}
public void test_removing_orphan_annotation() {
String text = """
public class Foo {
public Foo() {
}
@Override
public void initSteps {
}
}""";
final PsiFile psiFile = myFixture.addFileToProject("a.java", text);
WriteCommandAction.runWriteCommandAction(getProject(), () -> PsiTreeUtil.findChildOfType(psiFile, PsiAnnotation.class).delete());
PsiTestUtil.checkStubsMatchText(psiFile);
}
public void test_local_record() {
PsiTestUtil.checkStubsMatchText(myFixture.addFileToProject("a.java", """
class A {
void test() {
record A(String s) { }
}
}"""));
}
public void test_field_with_missing_initializer() {
PsiFile file = myFixture.addFileToProject("a.java", "class A { int a = ; } ");
PsiClass clazz = myFixture.findClass("A");
assertNull(PsiFieldImpl.getDetachedInitializer(clazz.getFields()[0]));
assertFalse(((PsiFileImpl)file).isContentsLoaded());
}
public void test_implicit_class() {
PsiFile psiFile = myFixture.addFileToProject("a.java", """
void test() { void test() {
} }
String s = "foo"; String s = "foo";
int i = 10; int i = 10;
static {} // not allowed by spec, but we parse static {} // not allowed by spec, but we parse""");
""".stripIndent()) PsiTestUtil.checkStubsMatchText(psiFile);
PsiTestUtil.checkStubsMatchText(psiFile)
} }
void "test array type use annotation stubbing"() { public void test_array_type_use_annotation_stubbing() {
myFixture.addClass("""\ myFixture.addClass("""
import java.lang.annotation.*; import java.lang.annotation.*;
@Target(ElementType.TYPE_USE) @Target(ElementType.TYPE_USE)
@interface Anno { int value(); }""".stripIndent()) @interface Anno { int value(); }""");
PsiClass clazz = myFixture.addClass("""\ PsiClass clazz = myFixture.addClass("""
class Foo { class Foo {
<T> @Anno(0) String @Anno(1) [] @Anno(2) [] foo(@Anno(3) byte @Anno(4) [] data) {} <T> @Anno(0) String @Anno(1) [] @Anno(2) [] foo(@Anno(3) byte @Anno(4) [] data) {}
List<String> @Anno(5) [] field; List<String> @Anno(5) [] field;
}""".stripIndent()) }""");
def method = clazz.methods[0] PsiMethod method = clazz.getMethods()[0];
def field = clazz.fields[0] PsiField field = clazz.getFields()[0];
def parameter = method.parameterList.parameters[0] PsiParameter parameter = method.getParameterList().getParameters()[0];
def parameterAnnotations = parameter.type.annotations PsiAnnotation[] parameterAnnotations = parameter.getType().getAnnotations();
def parameterComponentAnnotations = (parameter.type as PsiArrayType).componentType.annotations PsiAnnotation[] parameterComponentAnnotations = ((PsiArrayType)parameter.getType()).getComponentType().getAnnotations();
def methodAnnotations = method.returnType.annotations PsiAnnotation[] methodAnnotations = method.getReturnType().getAnnotations();
def methodComponentAnnotations = (method.returnType as PsiArrayType).componentType.annotations PsiAnnotation[] methodComponentAnnotations = ((PsiArrayType)method.getReturnType()).getComponentType().getAnnotations();
def methodDeepComponentAnnotations = method.returnType.deepComponentType.annotations PsiAnnotation[] methodDeepComponentAnnotations = method.getReturnType().getDeepComponentType().getAnnotations();
def fieldAnnotations = field.type.annotations PsiAnnotation[] fieldAnnotations = field.getType().getAnnotations();
assert !(clazz.containingFile as PsiFileImpl).contentsLoaded assertFalse(((PsiFileImpl)clazz.getContainingFile()).isContentsLoaded());
assertAnnotationValueText methodDeepComponentAnnotations, "0" assertAnnotationValueText(methodDeepComponentAnnotations, "0");
assertAnnotationValueText methodAnnotations, "1" assertAnnotationValueText(methodAnnotations, "1");
assertAnnotationValueText methodComponentAnnotations, "2" assertAnnotationValueText(methodComponentAnnotations, "2");
assertAnnotationValueText parameterComponentAnnotations, "3" assertAnnotationValueText(parameterComponentAnnotations, "3");
assertAnnotationValueText parameterAnnotations, "4" assertAnnotationValueText(parameterAnnotations, "4");
assertAnnotationValueText fieldAnnotations, "5" assertAnnotationValueText(fieldAnnotations, "5");
assert !(clazz.containingFile as PsiFileImpl).contentsLoaded assertFalse(((PsiFileImpl)clazz.getContainingFile()).isContentsLoaded());
assert clazz.node // load AST assertNotNull(clazz.getNode());// load AST
assert parameter.type.annotations.size() == 1 assertEquals(1, parameter.getType().getAnnotations().length);
} }
private static void assertAnnotationValueText(PsiAnnotation[] annotations, String text) { private static void assertAnnotationValueText(PsiAnnotation[] annotations, String text) {
assert annotations.size() == 1 assertEquals(1, annotations.length);
assert annotations[0].findAttributeValue("value").text == text assertEquals(annotations[0].findAttributeValue("value").getText(), text);
} }
} }

View File

@@ -1,334 +1,354 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. // Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.psi package com.intellij.java.psi;
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.editor.Document;
import com.intellij.psi.* import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes import com.intellij.openapi.util.Computable;
import com.intellij.psi.impl.source.DummyHolder import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.psi.impl.source.PsiClassImpl import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiFileImpl import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.source.PsiJavaFileImpl import com.intellij.psi.impl.source.DummyHolder;
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.search.searches.OverridingMethodsSearch import com.intellij.psi.impl.source.PsiJavaFileImpl;
import com.intellij.psi.stubs.StubElement import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubTree import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.testFramework.LeakHunter import com.intellij.psi.stubs.StubElement;
import com.intellij.testFramework.SkipSlowTestLocally import com.intellij.psi.stubs.StubTree;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ref.GCUtil import com.intellij.testFramework.LeakHunter;
import com.intellij.util.ref.GCWatcher import com.intellij.testFramework.SkipSlowTestLocally;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ref.GCUtil;
import com.intellij.util.ref.GCWatcher;
import junit.framework.TestCase;
import one.util.streamex.IntStreamEx;
import java.lang.ref.SoftReference import java.io.IOException;
import java.util.concurrent.Callable import java.lang.ref.SoftReference;
import java.util.concurrent.CountDownLatch import java.util.ArrayList;
import java.util.concurrent.Future import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.IntStream;
import static org.junit.Assert.assertNotEquals;
@SuppressWarnings("CallToSystemGC")
@SkipSlowTestLocally @SkipSlowTestLocally
class StubAstSwitchTest extends LightJavaCodeInsightFixtureTestCase { public class StubAstSwitchTest extends LightJavaCodeInsightFixtureTestCase {
public void test_modifying_file_with_stubs_via_VFS() throws IOException {
final PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("Foo.java", "class Foo {}");
assertNotNull(file.getStub());
PsiClass cls = ((PsiJavaFile)file).getClasses()[0];
assertNotNull(file.getStub());
void "test modifying file with stubs via VFS"() { long oldCount = getPsiManager().getModificationTracker().getModificationCount();
PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject('Foo.java', 'class Foo {}')
assert file.stub
def cls = ((PsiJavaFile)file).classes[0]
assert file.stub
def oldCount = psiManager.modificationTracker.modificationCount WriteAction.run(() -> file.getVirtualFile().setBinaryContent(file.getVirtualFile().contentsToByteArray()));
ApplicationManager.application.runWriteAction { file.virtualFile.setBinaryContent(file.virtualFile.contentsToByteArray()) } assertTrue(getPsiManager().getModificationTracker().getModificationCount() != oldCount);
assert psiManager.modificationTracker.modificationCount != oldCount assertFalse(cls.isValid());
assertNotNull(file.getStub());
assert !cls.valid assertNotEquals(cls, PsiTreeUtil.findElementOfClassAtOffset(file, 1, PsiClass.class, false));
assert file.stub assertNull(file.getStub());
assert cls != PsiTreeUtil.findElementOfClassAtOffset(file, 1, PsiClass, false)
assert !file.stub
} }
void "test reachable psi classes remain valid when nothing changes"() { public void test_reachable_psi_classes_remain_valid_when_nothing_changes() {
int count = 1000 int count = 1000;
List<SoftReference<PsiClass>> classList = (0..<count).collect { new SoftReference<PsiClass>(myFixture.addClass("class Foo$it {}")) } List<SoftReference<PsiClass>> classList = IntStream.range(0, count)
System.gc() .mapToObj(n -> new SoftReference<>(myFixture.addClass("class Foo" + n + " {}"))).toList();
System.gc() System.gc();
System.gc() System.gc();
assert classList.every { System.gc();
def cls = it.get() assertTrue(ContainerUtil.all(classList, ref -> {
if (!cls || cls.valid) return true PsiClass cls = ref.get();
cls.text //load AST if (cls == null || cls.isValid()) return true;
return cls.valid assertNotNull(cls.getText());//load AST
} //noinspection ConstantValue
return cls.isValid();
}));
} }
void "test traversing PSI and switching concurrently"() { public void test_traversing_PSI_and_switching_concurrently() throws InterruptedException {
int count = 100 int count = 100;
List<PsiClass> classList = (0..<count).collect { List<PsiClass> classList = IntStream.range(0, count)
myFixture.addClass("class Foo$it { " + .mapToObj(num -> myFixture.addClass(
"void foo$it(" + "class Foo" + num + " {\n" +
(0..250).collect { "int i$it"}.join(", ") + "void foo" + num + "(" + IntStreamEx.range(0, 250).mapToObj(parNum -> "int i" + parNum).joining(", ") + ") {}\n" +
") {}" + "}")).toList();
" }") final CountDownLatch latch = new CountDownLatch(count);
} for (PsiClass c : classList) {
CountDownLatch latch = new CountDownLatch(count) ApplicationManager.getApplication().executeOnPooledThread(() -> {
for (c in classList) { Thread.yield();
ApplicationManager.application.executeOnPooledThread { ReadAction.compute(() -> c.getText());
Thread.yield() latch.countDown();
ApplicationManager.application.runReadAction { });
c.text for (PsiMethod m : c.getMethods()) {
} PsiParameter[] parameters = m.getParameterList().getParameters();
latch.countDown() for (int i = 0; i < parameters.length; i++) {
} assertEquals(i, m.getParameterList().getParameterIndex(parameters[i]));
for (m in c.methods) {
def parameters = m.parameterList.parameters
for (i in 0..<parameters.size()) {
assert i == m.parameterList.getParameterIndex(parameters[i])
} }
} }
} }
latch.await()
latch.await();
} }
void "test smart pointer survives an external modification of a stubbed file"() { public void test_smart_pointer_survives_an_external_modification_of_a_stubbed_file() throws IOException {
PsiFile file = myFixture.addFileToProject("A.java", "class A {}") final PsiFile file = myFixture.addFileToProject("A.java", "class A {}");
def oldClass = JavaPsiFacade.getInstance(project).findClass("A", GlobalSearchScope.allScope(project)) PsiClass oldClass = JavaPsiFacade.getInstance(getProject()).findClass("A", GlobalSearchScope.allScope(getProject()));
def pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(oldClass) SmartPsiElementPointer<PsiClass> pointer = SmartPointerManager.getInstance(getProject()).createSmartPsiElementPointer(oldClass);
def document = FileDocumentManager.instance.getDocument(file.virtualFile) Document document = FileDocumentManager.getInstance().getDocument(file.getVirtualFile());
assert document assertNotNull(document);
assert file == PsiDocumentManager.getInstance(project).getCachedPsiFile(document) assertEquals(file, PsiDocumentManager.getInstance(getProject()).getCachedPsiFile(document));
assert document == PsiDocumentManager.getInstance(project).getCachedDocument(file) assertEquals(document, PsiDocumentManager.getInstance(getProject()).getCachedDocument(file));
assert ((PsiFileImpl)file).stub assertNotNull(((PsiFileImpl)file).getStub());
ApplicationManager.application.runWriteAction { VfsUtil.saveText(file.virtualFile, "import java.util.*; class A {}; class B {}") } WriteAction.run(() -> VfsUtil.saveText(file.getVirtualFile(), "import java.util.*; class A {}; class B {}"));
assert pointer.element == oldClass assertEquals(pointer.getElement(), oldClass);
} }
void "test do not parse when resolving references inside an anonymous class"() { public void test_do_not_parse_when_resolving_references_inside_an_anonymous_class() {
PsiFileImpl file = (PsiFileImpl) myFixture.addFileToProject("A.java", """ PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("A.java", """
class A {
Object field = new B() { class A {
void foo(Object o) { Object field = new B() {
void foo(Object o) {
}
class MyInner extends Inner {}
};
Runnable r = () -> { new B() {}; };
Runnable r2 = (new B(){})::hashCode();
} }
class MyInner extends Inner {} class B {
}; void foo(Object o) {}
Runnable r = () -> { new B() {}; }; static class Inner {}
Runnable r2 = (new B(){})::hashCode(); }
} """);
assertFalse(file.isContentsLoaded());
PsiClass bClass = ((PsiJavaFile)file).getClasses()[1];
assertEquals(3, DirectClassInheritorsSearch.search(bClass).findAll().size());
assertFalse(file.isContentsLoaded());
class B { PsiMethod fooMethod = bClass.getMethods()[0];
void foo(Object o) {} assertFalse(file.isContentsLoaded());
static class Inner {}
}
""")
assert !file.contentsLoaded
PsiClass bClass = ((PsiJavaFile) file).classes[1]
assert DirectClassInheritorsSearch.search(bClass).findAll().size() == 3
assert !file.contentsLoaded
def fooMethod = bClass.methods[0] PsiMethod override = OverridingMethodsSearch.search(fooMethod).findFirst();
assert !file.contentsLoaded assertNotNull(override);
assertFalse(file.isContentsLoaded());
def override = OverridingMethodsSearch.search(fooMethod).findAll().first() assertTrue(override.getContainingClass() instanceof PsiAnonymousClass);
assert override assertFalse(file.isContentsLoaded());
assert !file.contentsLoaded
assert override.containingClass instanceof PsiAnonymousClass assertEquals(bClass, override.getContainingClass().getSuperClass());
assert !file.contentsLoaded assertEquals(bClass.getInnerClasses()[0], override.getContainingClass().getInnerClasses()[0].getSuperClass());
assertFalse(file.isContentsLoaded());
assert bClass == override.containingClass.superClass
assert bClass.innerClasses[0] == override.containingClass.innerClasses[0].superClass
assert !file.contentsLoaded
} }
void "test AST can be gc-ed and recreated"() { public void test_AST_can_be_gc_ed_and_recreated() {
def psiClass = myFixture.addClass("class Foo {}") PsiClass psiClass = myFixture.addClass("class Foo {}");
def file = psiClass.containingFile as PsiFileImpl PsiFileImpl file = (PsiFileImpl)psiClass.getContainingFile();
assert file.stub assertNotNull(file.getStub());
assert psiClass.nameIdentifier assertNotNull(psiClass.getNameIdentifier());
assert !file.stub assertNull(file.getStub());
assert file.treeElement assertNotNull(file.getTreeElement());
GCUtil.tryGcSoftlyReachableObjects() GCUtil.tryGcSoftlyReachableObjects();
assert !file.treeElement assertNull(file.getTreeElement());
assert file.stub assertNotNull(file.getStub());
assert psiClass.nameIdentifier assertNotNull(psiClass.getNameIdentifier());
assert !file.stub assertNull(file.getStub());
assert file.treeElement assertNotNull(file.getTreeElement());
} }
void "test no AST loading on file rename"() { public void test_no_AST_loading_on_file_rename() {
PsiJavaFile file = (PsiJavaFile) myFixture.addFileToProject('a.java', 'class Foo {}') final PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "class Foo {}");
assert file.classes.length == 1 assertEquals(1, file.getClasses().length);
assert ((PsiFileImpl)file).stub assertNotNull(((PsiFileImpl)file).getStub());
WriteCommandAction.runWriteCommandAction project, { file.setName('b.java') } WriteCommandAction.runWriteCommandAction(getProject(), (Computable<PsiElement>)() -> file.setName("b.java"));
assert file.classes.length == 1 assertEquals(1, file.getClasses().length);
assert ((PsiFileImpl)file).stub assertNotNull(((PsiFileImpl)file).getStub());
assert file.classes[0].nameIdentifier.text == 'Foo' assertEquals("Foo", file.getClasses()[0].getNameIdentifier().getText());
assert ((PsiFileImpl)file).contentsLoaded assertTrue(((PsiFileImpl)file).isContentsLoaded());
} }
void "test use green stub after AST loaded and gc-ed"() { public void test_use_green_stub_after_AST_loaded_and_gc_ed() {
PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "class A{public static void foo() { }}") PsiJavaFile file = (PsiJavaFile)myFixture.addFileToProject("a.java", "class A{public static void foo() { }}");
//noinspection GroovyUnusedAssignment assertNotNull(((PsiFileImpl)file).getStubTree());
StubTree stubHardRef = ((PsiFileImpl)file).stubTree
assert file.classes[0].nameIdentifier assertNotNull(file.getClasses()[0].getNameIdentifier());
loadAndGcAst(file) loadAndGcAst(file);
assertNoStubLoaded(file) assertNoStubLoaded(file);
assert file.classes[0].methods[0].modifierList.hasExplicitModifier(PsiModifier.STATIC) assertTrue(file.getClasses()[0].getMethods()[0].getModifierList().hasExplicitModifier(PsiModifier.STATIC));
assert !((PsiFileImpl)file).getTreeElement() assertNull(((PsiFileImpl)file).getTreeElement());
} }
void "test use green stub after building it from AST"() { public void test_use_green_stub_after_building_it_from_AST() {
PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}") PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}");
PsiClass psiClass = ((PsiJavaFile)file).classes[0] PsiClass psiClass = ((PsiJavaFile)file).getClasses()[0];
assert psiClass.nameIdentifier assertNotNull(psiClass.getNameIdentifier());
loadAndGcAst(file) loadAndGcAst(file);
assertNoStubLoaded(file) assertNoStubLoaded(file);
StubElement hardRefToStub = file.greenStub StubElement<?> hardRefToStub = file.getGreenStub();
assert hardRefToStub assertNotNull(hardRefToStub);
assert hardRefToStub == file.stub assertEquals(hardRefToStub, file.getStub());
loadAndGcAst(file) loadAndGcAst(file);
assert hardRefToStub.is(file.greenStub) assertSame(hardRefToStub, file.getGreenStub());
assert psiClass.typeParameters.length == 1 assertEquals(1, psiClass.getTypeParameters().length);
assert !file.treeElement assertNull(file.getTreeElement());
} }
private static void loadAndGcAst(PsiFile file) { private static void loadAndGcAst(PsiFile file) {
GCWatcher.tracking(file.node).ensureCollected() GCWatcher.tracking(file.getNode()).ensureCollected();
assert !((PsiFileImpl)file).treeElement assertNull(((PsiFileImpl)file).getTreeElement());
} }
private static assertNoStubLoaded(PsiFile file) { private static void assertNoStubLoaded(final PsiFile file) {
LeakHunter.checkLeak(file, StubTree) { candidate -> candidate.root.psi == file } LeakHunter.checkLeak(file, StubTree.class, candidate -> candidate.getRoot().getPsi().equals(file));
} }
void "test node has same PSI when loaded in green stub presence"() { public void test_node_has_same_PSI_when_loaded_in_green_stub_presence() {
PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}") PsiFileImpl file = (PsiFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}");
def stubTree = file.stubTree StubTree stubTree = file.getStubTree();
PsiClass psiClass = ((PsiJavaFile)file).classes[0] PsiClass psiClass = ((PsiJavaFile)file).getClasses()[0];
assert psiClass.nameIdentifier assertNotNull(psiClass.getNameIdentifier());
GCUtil.tryGcSoftlyReachableObjects() GCUtil.tryGcSoftlyReachableObjects();
assert stubTree.is(file.greenStubTree) assertSame(stubTree, file.getGreenStubTree());
assert file.node.lastChildNode.psi.is(psiClass) assertSame(file.getNode().getLastChildNode().getPsi(), psiClass);
} }
void "test load stub from non-file PSI after AST is unloaded"() { public void test_load_stub_from_non_file_PSI_after_AST_is_unloaded() {
PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}") PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A<T>{}");
def cls = file.classes[0] PsiClass cls = file.getClasses()[0];
assert cls.nameIdentifier assertNotNull(cls.getNameIdentifier());
loadAndGcAst(file) loadAndGcAst(file);
assert ((PsiClassImpl) cls).stub assertNotNull(((PsiClassImpl)cls).getStub());
} }
void "test load PSI via stub when AST is gc-ed but PSI exists that was loaded via AST but knows its stub index"() { public void test_load_PSI_via_stub_when_AST_is_gc_ed_but_PSI_exists_that_was_loaded_via_AST_but_knows_its_stub_index() {
PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}") PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}");
def cls = file.lastChild PsiElement cls = file.getLastChild();
assert cls instanceof PsiClass assertTrue(cls instanceof PsiClass);
GCUtil.tryGcSoftlyReachableObjects() GCUtil.tryGcSoftlyReachableObjects();
assert file.treeElement // we still hold a strong reference to AST assertNotNull(file.getTreeElement());// we still hold a strong reference to AST
assertEquals(cls, myFixture.findClass("A"));
assert cls == myFixture.findClass('A')
// now we know stub index and can GC AST // now we know stub index and can GC AST
GCUtil.tryGcSoftlyReachableObjects() GCUtil.tryGcSoftlyReachableObjects();
assert !file.treeElement assertNull(file.getTreeElement());
assertEquals(cls, myFixture.findClass("A"));
assert cls == myFixture.findClass('A') assertNull(file.getTreeElement());
assert !file.treeElement
} }
void "test bind stubs to AST after AST has been loaded and gc-ed"() { public void test_bind_stubs_to_AST_after_AST_has_been_loaded_and_gc_ed() {
PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}") PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}");
loadAndGcAst(file) loadAndGcAst(file);
def cls1 = file.classes[0] PsiClass cls1 = file.getClasses()[0];
def cls2 = file.lastChild PsiElement cls2 = file.getLastChild();
assert cls1 == cls2 assertEquals(cls1, cls2);
} }
void "test concurrent stub and AST reloading"() { public void test_concurrent_stub_and_AST_reloading() throws ExecutionException, InterruptedException {
def fileNumbers = 0..<3 int maxFile = 3;
List<PsiJavaFileImpl> files = fileNumbers.collect { final List<PsiJavaFileImpl> files = IntStream.range(0, maxFile).mapToObj(
(PsiJavaFileImpl)myFixture.addFileToProject("a${it}.java", "import foo.bar; class A{}") num -> (PsiJavaFileImpl)myFixture.addFileToProject("a" + num + ".java", "import foo.bar; class A{}"))
} .toList();
for (iteration in 0..<3) { for (int iteration = 0; iteration <= 3; iteration++) {
GCWatcher.tracking(files.collect { it.node }).ensureCollected() GCWatcher.tracking(ContainerUtil.map(files, PsiFileImpl::getNode)).ensureCollected();
files.each { assert !it.treeElement } for (PsiJavaFileImpl file : files) {
assertNull(file.getTreeElement());
List<Future<PsiImportList>> stubFutures = []
List<Future<PsiImportList>> astFutures = []
for (i in fileNumbers) {
def file = files[i]
stubFutures << ApplicationManager.application.executeOnPooledThread({ ReadAction.compute {
file.importList
} } as Callable)
astFutures << ApplicationManager.application.executeOnPooledThread({ ReadAction.compute {
PsiTreeUtil.findElementOfClassAtOffset(file, 0, PsiImportList, false)
} } as Callable)
} }
GCUtil.tryGcSoftlyReachableObjects()
for (i in fileNumbers) { List<Future<PsiImportList>> stubFutures = new ArrayList<>();
def stubImport = stubFutures[i].get() List<Future<PsiImportList>> astFutures = new ArrayList<>();
def astImport = astFutures[i].get()
if (stubImport != astImport) { for (int i = 0; i < 3; i++) {
fail("Different import psi in ${files[i].name}: stub=$stubImport, ast=$astImport") final PsiJavaFileImpl file = files.get(i);
stubFutures.add(ApplicationManager.getApplication()
.executeOnPooledThread(() -> ReadAction.compute(() -> file.getImportList())));
astFutures.add(ApplicationManager.getApplication()
.executeOnPooledThread(
() -> ReadAction.compute(() -> PsiTreeUtil.findElementOfClassAtOffset(file, 0, PsiImportList.class, false))));
}
GCUtil.tryGcSoftlyReachableObjects();
for (int i = 0; i < maxFile; i++) {
PsiImportList stubImport = stubFutures.get(i).get();
PsiImportList astImport = astFutures.get(i).get();
if (!stubImport.equals(astImport)) {
TestCase.fail("Different import psi in " +
files.get(i).getName() +
": stub=" +
stubImport +
", ast=" +
astImport);
} }
} }
} }
} }
void "test DummyHolder calcStubTree does not fail"() { public void test_DummyHolder_calcStubTree_does_not_fail() {
def text = "{ new Runnable() { public void run() {} }; }" String text = "{ new Runnable() { public void run() {} }; }";
def file = JavaPsiFacade.getElementFactory(project).createCodeBlockFromText(text, null).containingFile PsiFile file = JavaPsiFacade.getElementFactory(getProject()).createCodeBlockFromText(text, null).getContainingFile();
// main thing is it doesn't fail; DummyHolder.calcStubTree can be changed to null in future if we decide we don't need it // The main thing is it doesn't fail; DummyHolder.calcStubTree can be changed to null in future if we decide we don't need it
def stubTree = assertInstanceOf(file, DummyHolder).calcStubTree() StubTree stubTree = UsefulTestCase.assertInstanceOf(file, DummyHolder.class).calcStubTree();
assert stubTree.plainList.find { it.stubType == JavaStubElementTypes.ANONYMOUS_CLASS } assertTrue(ContainerUtil.exists(stubTree.getPlainList(),
it -> JavaStubElementTypes.ANONYMOUS_CLASS.equals(it.getStubType())));
} }
void "test stub index is cleared on AST change"() { public void test_stub_index_is_cleared_on_AST_change() {
def clazz = myFixture.addClass("class Foo { int a; }") PsiClass clazz = myFixture.addClass("class Foo { int a; }");
def field = clazz.fields[0] PsiField field = clazz.getFields()[0];
def file = clazz.containingFile as PsiFileImpl final PsiFileImpl file = (PsiFileImpl)clazz.getContainingFile();
WriteCommandAction.runWriteCommandAction(project, { WriteCommandAction.runWriteCommandAction(getProject(), () -> {
file.viewProvider.document.insertString(0, ' ') file.getViewProvider().getDocument().insertString(0, " ");
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
}) });
assert file.calcStubTree()
WriteCommandAction.runWriteCommandAction(project, { assertNotNull(file.calcStubTree());
file.viewProvider.document.insertString(file.text.indexOf('int'), 'void foo();')
PsiDocumentManager.getInstance(project).commitAllDocuments()
})
GCUtil.tryGcSoftlyReachableObjects()
assert file.calcStubTree() WriteCommandAction.runWriteCommandAction(getProject(), () -> {
file.getViewProvider().getDocument().insertString(file.getText().indexOf("int"), "void foo();");
assert field.valid PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
assert field.name == 'a' });
GCUtil.tryGcSoftlyReachableObjects();
assertNotNull(file.calcStubTree());
assertTrue(field.isValid());
assertEquals("a", field.getName());
} }
} }

View File

@@ -1,3 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.refactoring; package com.intellij.java.refactoring;
import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.TargetElementUtil;

View File

@@ -1,3 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.run; package com.intellij.java.run;
import com.intellij.application.options.PathMacrosCollector; import com.intellij.application.options.PathMacrosCollector;

View File

@@ -1,3 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.impl.source.tree.java; package com.intellij.psi.impl.source.tree.java;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;

View File

@@ -1,3 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.unscramble; package com.intellij.unscramble;
import junit.framework.TestCase; import junit.framework.TestCase;

View File

@@ -1,3 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.unscramble; package com.intellij.unscramble;
import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PlatformTestUtil;