// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.groovy.lang.resolve;

import com.intellij.psi.*;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.testFramework.UsefulTestCase;
import junit.framework.TestCase;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrTraitMethod;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.util.TestUtils;
import org.jetbrains.plugins.groovy.util.ThrowingTransformation;

public class ResolvePropertyTest extends GroovyResolveTestCase {
  public void testParameter1() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    resolve("A.groovy", GrParameter.class);
  }

  public void testClosureParameter1() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    resolve("A.groovy", GrParameter.class);
  }

  public void testClosureOwner() {
    PsiReference ref = configureByFile("closureOwner/A.groovy");
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, PsiMethod.class);
  }

  public void testLocal1() throws Exception {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    doTest("local1/A.groovy");
  }

  public void testField1() throws Exception {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    doTest("field1/A.groovy");
  }

  public void testField2() throws Exception {
    doTest("field2/A.groovy");
  }

  public void testArrayLength() throws Exception {
    doTest("arrayLength/A.groovy");
  }

  public void testFromGetter() {
    PsiReference ref = configureByFile("fromGetter/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrAccessorMethod);
  }

  public void testFromGetter2() {
    PsiReference ref = configureByFile("fromGetter2/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrAccessorMethod);
  }

  public void testFromSetter2() {
    PsiReference ref = configureByFile("fromSetter2/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrAccessorMethod);
  }

  public void testFromSetter() {
    PsiReference ref = configureByFile("fromSetter/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrAccessorMethod);
  }

  public void testCatchParameter() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    resolve("CatchParameter.groovy", GrParameter.class);
  }

  public void testCaseClause() throws Exception {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    doTest("caseClause/CaseClause.groovy");
  }

  public void testGrvy104() throws Exception {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    doTest("grvy104/Test.groovy");
  }

  public void testGrvy270() {
    PsiReference ref = configureByFile("grvy270/Test.groovy");
    TestCase.assertNull(ref.resolve());
  }

  public void testGrvy1483() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    resolve("Test.groovy", GrVariable.class);
  }

  public void testField3() {
    GrReferenceElement ref = (GrReferenceElement)configureByFile("field3/A.groovy").getElement();
    GroovyResolveResult resolveResult = ref.advancedResolve();
    TestCase.assertTrue(resolveResult.getElement() instanceof GrField);
    TestCase.assertFalse(resolveResult.isValidResult());
  }

  public void testToGetter() {
    GrReferenceElement ref = (GrReferenceElement)configureByFile("toGetter/A.groovy").getElement();
    PsiElement resolved = ref.resolve();
    TestCase.assertTrue(resolved instanceof GrMethod);
    TestCase.assertTrue(PropertyUtil.isSimplePropertyGetter((PsiMethod)resolved));
  }

  public void testToSetter() {
    GrReferenceElement ref = (GrReferenceElement)configureByFile("toSetter/A.groovy").getElement();
    PsiElement resolved = ref.resolve();
    TestCase.assertTrue(resolved instanceof GrMethod);
    TestCase.assertTrue(PropertyUtil.isSimplePropertySetter((PsiMethod)resolved));
  }

  public void testUndefinedVar1() {
    PsiReference ref = configureByFile("undefinedVar1/A.groovy");
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrBindingVariable.class);
  }

  public void testRecursive1() {
    PsiReference ref = configureByFile("recursive1/A.groovy");
    PsiElement resolved = ref.resolve();
    TestCase.assertTrue(resolved instanceof GrField);
  }

  public void testRecursive2() {
    PsiReference ref = configureByFile("recursive2/A.groovy");
    PsiElement resolved = ref.resolve();
    TestCase.assertTrue(resolved instanceof GrMethod);
    TestCase.assertEquals(CommonClassNames.JAVA_LANG_OBJECT, ((GrMethod)resolved).getReturnType().getCanonicalText());
  }

  public void testUndefinedVar2() throws Exception {
    doUndefinedVarTest("undefinedVar2/A.groovy");
  }

  public void testUndefinedVar3() {
    resolveByText("""
                    
                      (aa, b) = [1, 4]
                      c = a<caret>a
                     \s\
                    """, GrBindingVariable.class);
  }

  public void testDefinedVar1() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    resolve("A.groovy", GrVariable.class);
  }

  public void testOperatorOverload() throws Exception {
    doTest("operatorOverload/A.groovy");
  }

  public void testEnumConstant() throws Exception {
    PsiReference ref = configureByFile("enumConstant/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrEnumConstant);
  }

  public void testStackOverflow() throws Exception {
    doTest("stackOverflow/A.groovy");
  }

  public void testFromDifferentCaseClause() {
    PsiReference ref = configureByFile("fromDifferentCaseClause/A.groovy");
    TestCase.assertNull(ref.resolve());
  }

  public void testNotSettingProperty() {
    PsiReference ref = configureByFile("notSettingProperty/A.groovy");
    TestCase.assertNull(ref.resolve());
  }

  public void testGrvy633() {
    PsiReference ref = configureByFile("grvy633/A.groovy");
    TestCase.assertNull(ref.resolve());
  }

  public void testGrvy575() throws Exception {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    doTest("grvy575/A.groovy");
  }

  public void testGrvy747() {
    PsiReference ref = configureByFile("grvy747/A.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrField);
  }

  public void testClosureCall() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    PsiReference ref = configureByFile("closureCall/ClosureCall.groovy");
    TestCase.assertTrue(ref.resolve() instanceof GrVariable);
  }

  public void testUnderscoredField() {
    PsiReference ref = configureByFile("underscoredField/UnderscoredField.groovy");
    final GrField field = UsefulTestCase.assertInstanceOf(ref.resolve(), GrField.class);
    TestCase.assertFalse(ref.isReferenceTo(field.getGetters()[0]));
    TestCase.assertTrue(ref.isReferenceTo(field));
  }

  public void testPropertyWithoutField1() {
    PsiReference ref = configureByFile("propertyWithoutField1/PropertyWithoutField1.groovy");
    UsefulTestCase.assertInstanceOf(ref.resolve(), GrMethod.class);
  }

  public void testPropertyWithoutField2() {
    PsiReference ref = configureByFile("propertyWithoutField2/PropertyWithoutField2.groovy");
    UsefulTestCase.assertInstanceOf(ref.resolve(), GrMethod.class);
  }

  public void testFieldAssignedInTheSameMethod() {
    PsiReference ref = configureByFile("fieldAssignedInTheSameMethod/FieldAssignedInTheSameMethod.groovy");
    UsefulTestCase.assertInstanceOf(ref.resolve(), GrField.class);
  }

  public void testPrivateFieldAssignment() {
    myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, """
      
                                  class Aaaaa {
                                    final def aaa
       \s
                                    def foo() {
                                      a<caret>aa = 2
                                    }
                                  }\
      """);
    PsiReference reference = myFixture.getFile().findReferenceAt(myFixture.getEditor().getCaretModel().getOffset());
    UsefulTestCase.assertInstanceOf(reference.resolve(), GrField.class);
  }

  public void testOverriddenGetter() {
    myFixture.configureByText("a.groovy", """
      interface Foo {
                                                      def getFoo()
                                                    }
                                                    interface Bar extends Foo {
                                                      def getFoo()
                                                    }
       \s
                                                    Bar b
                                                    b.fo<caret>o""");
    PsiReference reference = myFixture.getFile().findReferenceAt(myFixture.getEditor().getCaretModel().getOffset());
    TestCase.assertEquals("Bar", UsefulTestCase.assertInstanceOf(reference.resolve(), GrMethod.class).getContainingClass().getName());
  }

  public void testIDEADEV40403() {
    myFixture.configureByFile("IDEADEV40403/A.groovy");
    PsiReference reference = findReference();
    PsiElement resolved = reference.resolve();
    PsiClass clazz = UsefulTestCase.assertInstanceOf(resolved, PsiMethod.class).getContainingClass();
    TestCase.assertEquals("Script", clazz.getName());
  }

  public void testBooleanGetterPropertyAccess() {
    myFixture.configureByText("a.groovy", "print([].em<caret>pty)");
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, PsiMethod.class);
  }

  public PsiReference findReference() { return myFixture.getFile().findReferenceAt(myFixture.getEditor().getCaretModel().getOffset()); }

  public void testTriplePropertyUsages() {
    myFixture.configureByText("a.groovy", """
      
        class Foo {
          def bar
          def zoo = <caret>bar
        }
       \s\
      """);
    PsiReference ref = findReference();
    GrField target = UsefulTestCase.assertInstanceOf(ref.resolve(), GrField.class);
    TestCase.assertTrue(ref.isReferenceTo(target));
    TestCase.assertFalse(ref.isReferenceTo(target.getGetters()[0]));
    TestCase.assertFalse(ref.isReferenceTo(target.getSetter()));
  }

  public void testAliasedStaticImport() {
    myFixture.addClass("""
                         class Main {
                         static def foo=4
                         """);

    myFixture.configureByText("a.groovy", """
      import static Main.foo as bar
      print ba<caret>r
      }
      """);
    PsiReference ref = findReference();
    PsiField target = UsefulTestCase.assertInstanceOf(ref.resolve(), PsiField.class);
    TestCase.assertEquals("foo", target.getName());
  }

  private void doTest(String fileName) {
    PsiReference ref = configureByFile(fileName);
    PsiElement resolved = ref.resolve();
    TestCase.assertTrue(resolved instanceof GrVariable);
  }

  private void doUndefinedVarTest(String fileName) {
    PsiReference ref = configureByFile(fileName);
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrBindingVariable.class);
  }

  public void testBooleanProperty() {
    myFixture.configureByText("Abc.groovy", """
      class A{
         boolean getFoo(){return true}
         boolean isFoo(){return false}
      }
      print new A().f<caret>oo
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    TestCase.assertNotNull(resolved);
    assertEquals("getFoo", ((PsiMethod)resolved).getName());
  }

  public void testExplicitBooleanProperty() {
    myFixture.configureByText("Abc.groovy", """
      class A{
         boolean foo
      }
      print new A().f<caret>oo
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    assertEquals("getFoo", ((PsiMethod)resolved).getName());
  }

  public void testStaticFieldAndNonStaticGetter() {
    myFixture.configureByText("Abc.groovy", "print Float.N<caret>aN");
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, PsiField.class);
  }

  public void testPropertyAndFieldDeclarationInsideClass() {
    myFixture.configureByText("a.groovy", """
       class Foo {
        def foo
        public def foo
        def bar() {
          print fo<caret>o
        }
      }
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrField.class);
    TestCase.assertTrue(((GrField)resolved).getModifierList().hasExplicitVisibilityModifiers());
  }

  public void testPropertyAndFieldDeclarationOutsideClass() {
    myFixture.configureByText("a.groovy", """
      class Foo {
        def foo
        public def foo
      
        def bar() {
          print foo
        }
      }
      print new Foo().fo<caret>o
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testPropertyAndFieldDeclarationWithSuperClass1() {
    myFixture.configureByText("a.groovy", """
      class Bar{
        def foo
      }
      class Foo extends Bar {
        public def foo
      
        def bar() {
          print foo
        }
      }
      print new Foo().fo<caret>o
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testPropertyAndFieldDeclarationWithSuperClass2() {
    myFixture.configureByText("a.groovy", """
      class Bar{
        def foo
      }
      class Foo extends Bar {
        public def foo
      
        def bar() {
          print f<caret>oo
        }
      }
      print new Foo().foo
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrField.class);
    TestCase.assertTrue(((GrField)resolved).getModifierList().hasExplicitVisibilityModifiers());
  }

  public void testPropertyAndFieldDeclarationWithSuperClass3() {
    myFixture.configureByText("a.groovy", """
      class Bar{
        public def foo
      }
      class Foo extends Bar {
        def foo
      
        def bar() {
          print foo
        }
      }
      print new Foo().fo<caret>o
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testPropertyAndFieldDeclarationWithSuperClass4() {
    myFixture.configureByText("a.groovy", """
      class Bar{
        public def foo
      }
      class Foo extends Bar {
        def foo
      
        def bar() {
          print f<caret>oo
        }
      }
      print new Foo().foo
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrField.class);
    TestCase.assertFalse(((GrField)resolved).getModifierList().hasExplicitVisibilityModifiers());
  }

  public void testReadAccessToStaticallyImportedProperty() {

    myFixture.addFileToProject("a.groovy", """
      class Foo {
        static def bar
      }
      """);
    myFixture.configureByText("b.groovy", """
      import static Foo.bar
      print ba<caret>r
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testWriteAccessToStaticallyImportedProperty() {
    myFixture.addFileToProject("a.groovy", """
      class Foo {
        static def bar
      }
      """);
    myFixture.configureByText("b.groovy", """
      import static Foo.bar
      ba<caret>r = 2
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testGetterToStaticallyImportedProperty() {
    myFixture.addFileToProject("a.groovy", """
      class Foo {
        static def bar
      }
      """);
    myFixture.configureByText("b.groovy", """
      import static Foo.bar
      set<caret>Bar(2)
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testPropertyInCallExpression() {
    myFixture.configureByText("a.groovy", """
      class Foo {
        def foo = {
          return {int i -> print i}
        }
      
        def foo(String s){
          print s
        }
      }
      new Foo().fo<caret>o(2)\
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();

    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void test_property_vs_field_in_call_from_outside() {
    GrMethod method = resolveByText("""
                                      class C {
                                        def foo = { 42 }
                                        def getFoo() { return { 43 } }
                                      }
                                      new C().<caret>foo(2)
                                      """, GrMethod.class);
    assertFalse(method instanceof GrAccessorMethod);
  }

  public void testPropertyImportedOnDemand() {
    myFixture.addFileToProject("foo/A.groovy", "package foo; class Foo {static def foo}");
    myFixture.configureByText("B.groovy", """
      package foo
      import static Foo.*
      print fo<caret>o
      """);

    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testSetterToAliasedImportedProperty() {
    myFixture.addFileToProject("a.groovy", """
      class Foo {
        static def bar
      }
      """);
    myFixture.configureByText("b.groovy", """
      import static Foo.bar as foo
      set<caret>Foo(2)
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrAccessorMethod.class);
  }

  public void testPhysicalSetterToStaticallyImportedProperty() {
    myFixture.addFileToProject("a.groovy", """
      class Foo {
        static def bar
        static def setBar(def bar){}
      }
      """);
    myFixture.configureByText("b.groovy", """
      import static Foo.bar as foo
      set<caret>Foo(2)
      """);
    PsiReference ref = findReference();
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrMethod.class);
  }

  public void testPropertyUseInCategory() {
    PsiReference ref = configureByFile("propertyUseInCategory/a.groovy");
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, PsiMethod.class);
  }

  public void testCollectionItemFields() {
    PsiReference ref = configureByFile("collectionItemFields/A.groovy");
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, PsiField.class);
  }

  public void testFieldAccessInStaticContext() {
    PsiReference ref = configureByFile("fieldAccessInStaticContext/A.groovy");
    GroovyResolveResult resolveResult = ((GrReferenceExpression)ref).advancedResolve();
    TestCase.assertFalse(resolveResult.isStaticsOK());
  }

  public void testFieldAccessInClosureVsStaticContext() {
    PsiReference ref = configureByFile("fieldAccessInClosureVsStaticContext/A.groovy");
    GroovyResolveResult resolveResult = ((GrReferenceExpression)ref).advancedResolve();
    TestCase.assertTrue(resolveResult.isStaticsOK());
  }

  public void testUpperCaseFieldAndGetter() {
    TestCase.assertTrue(resolve("A.groovy") instanceof GrField);
  }

  public void testUpperCaseFieldWithoutGetter() {
    UsefulTestCase.assertInstanceOf(resolve("A.groovy"), GrField.class);
  }

  public void testGetterWithUpperCaseFieldReference() {
    TestCase.assertNull(resolve("A.groovy"));
  }

  public void testCommandExpressions() {
    UsefulTestCase.assertInstanceOf(resolve("A.groovy"), GrAccessorMethod.class);
  }

  public void testStaticFieldOfInterface() {
    final GroovyResolveResult result = advancedResolve("A.groovy");
    TestCase.assertTrue(result.isStaticsOK());
  }

  public void testNonStaticFieldInStaticContext() {
    final GroovyResolveResult result = advancedResolve("A.groovy");
    TestCase.assertFalse(result.isStaticsOK());
  }

  public void testPropertyInExprStatement() {
    PsiElement result = resolve("A.groovy");
    UsefulTestCase.assertInstanceOf(result, GrAccessorMethod.class);
  }

  public void testPreferAlias() {
    myFixture.addFileToProject("a/B.groovy", "package a; class B {public static def f1; public static def f2}");
    TestCase.assertEquals("f2", ((GrField)resolve("A.groovy")).getName());
  }

  public void testF1property() {
    UsefulTestCase.assertInstanceOf(resolve("A.groovy"), GrAccessorMethod.class);
  }

  public void testAnonymousClassFieldAndLocalVar() {
    ThrowingTransformation.disableTransformations(getTestRootDisposable());
    final PsiElement resolved = resolve("A.groovy");
    UsefulTestCase.assertInstanceOf(resolved, PsiVariable.class);
    TestCase.assertTrue(PsiUtil.isLocalVariable(resolved));
  }

  public void _testResolveForVarOutsideOfFor() {
    final PsiElement resolved = resolve("A.groovy");
    UsefulTestCase.assertInstanceOf(resolved, GrParameter.class);
  }

  public void testDontResolveForVarOutsideOfFor() {
    TestCase.assertNull(resolve("A.groovy"));
  }

  public void testOperatorOverloading() {
    UsefulTestCase.assertInstanceOf(resolve("A.groovy"), GrAccessorMethod.class);
  }

  public void testResolveClosureOverloader() {
    UsefulTestCase.assertInstanceOf(resolve("A.groovy"), GrAccessorMethod.class);
  }

  public void testJavaLoggingTransform() {
    myFixture.addClass("package groovy.util.logging; public @interface Log { String value() default \"\"; }");
    PsiReference ref = configureByText("@groovy.util.logging.Log class Foo { { lo<caret>g.inf } }");
    assertEquals("java.util.logging.Logger",
                 UsefulTestCase.assertInstanceOf(ref.resolve(), PsiVariable.class).getType().getCanonicalText());
  }

  public void testNonLoggingField() {
    myFixture.addClass("package groovy.util.logging; public @interface Log { String value() default \"\"; }");
    assertNull(configureByText("@groovy.util.logging.Log class Foo { { alo<caret>g.inf } }").resolve());
  }

  public void testJavaLoggingTransformCustomName() {
    myFixture.addClass("package groovy.util.logging; public @interface Log { String value() default \"\"; }");
    PsiReference ref = configureByText("@groovy.util.logging.Log('myLog') class Foo { { myLo<caret>g.inf } }");
    assertEquals("java.util.logging.Logger",
                 UsefulTestCase.assertInstanceOf(ref.resolve(), PsiVariable.class).getType().getCanonicalText());
  }

  public void testCommonsLoggingTransform() {
    myFixture.addClass("package groovy.util.logging; public @interface Commons { String value() default \"\"; }");
    PsiReference ref = configureByText("@groovy.util.logging.Commons('myLog') class Foo { { myLo<caret>g.inf } }");
    assertEquals("org.apache.commons.logging.Log",
                 UsefulTestCase.assertInstanceOf(ref.resolve(), PsiVariable.class).getType().getCanonicalText());
  }

  public void testFieldTransform() {
    addGroovyTransformField();
    PsiReference ref = configureByText("""
                                         @groovy.transform.Field def aaa = 2
                                           def foo() { println <caret>aaa }
                                          \s""");
    assertTrue(ref.resolve() instanceof GrVariable);
  }

  public void testScriptFieldVariableOutside() {
    myFixture.addFileToProject("Foo.groovy", "if (true) { @groovy.transform.Field def a = 2 }");

    PsiReference ref = configureByText("println new Foo().<caret>a");
    assertTrue(ref.resolve() instanceof GrVariable);
  }

  public void testScriptVariableFromScriptMethod() {
    PsiReference ref = configureByText("""
                                         def aaa = 2
                                         def foo() { println <caret>aaa }
                                         """);
    assertNull(ref.resolve());
  }

  public void testConfigObject() {
    PsiReference ref = configureByText("""
                                         def config = new ConfigObject()
                                         print config.config<caret>File
                                         """);
    assertNotNull(ref.resolve());
  }

  public void testResolveInsideWith0() {
    PsiElement resolved = resolve("a.groovy", GrAccessorMethod.class);
    assertEquals("A", ((PsiMember)resolved).getContainingClass().getName());
  }

  public void testResolveInsideWith1() {
    PsiElement resolved = resolve("a.groovy", GrAccessorMethod.class);
    assertEquals("B", ((PsiMember)resolved).getContainingClass().getName());
  }

  public void testLocalVarVsFieldInWithClosure() {
    // TODO disableTransformations getTestRootDisposable()
    PsiReference ref = configureByText("""
                                         class Test {
                                           def var
                                         }
                                         int var = 4
                                         new Test().with() {
                                           print v<caret>ar
                                         }
                                         """);
    TestCase.assertFalse(ref.resolve() instanceof GrField);
    TestCase.assertTrue(ref.resolve() instanceof GrVariable);
  }

  public void testCapitalizedProperty1() {
    PsiReference ref = configureByText("""
                                         class A {
                                           def Prop
                                         }
                                         
                                         new A().Pro<caret>p
                                         """);
    TestCase.assertNotNull(ref.resolve());
  }

  public void testCapitalizedProperty2() {
    PsiReference ref = configureByText("""
                                         class A {
                                           def Prop
                                         }
                                         
                                         new A().pro<caret>p
                                         """);
    TestCase.assertNotNull(ref.resolve());
  }

  public void testCapitalizedProperty3() {
    PsiReference ref = configureByText("""
                                         class A {
                                           def prop
                                         }
                                         
                                         new A().Pro<caret>p
                                         """);
    TestCase.assertNull(ref.resolve());
  }

  public void testCapitalizedProperty4() {
    PsiReference ref = configureByText("""
                                         class A {
                                           def prop
                                         }
                                         
                                         new A().pro<caret>p
                                         """);
    TestCase.assertNotNull(ref.resolve());
  }

  public void testGetChars() {
    PsiReference ref = configureByText("""
                                         'abc'.cha<caret>rs
                                         """);
    PsiElement resolved = ref.resolve();
    UsefulTestCase.assertInstanceOf(resolved, GrGdkMethod.class);
    PsiMethod method = ((GrGdkMethod)resolved).getStaticMethod();

    TestCase.assertEquals("java.lang.CharSequence", method.getParameterList().getParameters()[0].getType().getCanonicalText());
  }

  public void testLocalVarNotAvailableInClass() {
    PsiReference ref = configureByText("""
                                         def aa = 5
                                         
                                         class Inner {
                                           def foo() {
                                             print a<caret>a
                                           }
                                         }
                                         """);
    TestCase.assertNull(ref.resolve());
  }

  public void testLocalVarNotAvailableInMethod() {
    PsiReference ref = configureByText("""
                                         def aa = 5
                                         
                                         def foo() {
                                           print a<caret>a
                                         }
                                         """);
    TestCase.assertNull(ref.resolve());
  }

  public void testScriptFieldNotAvailableInClass() {
    addGroovyTransformField();
    PsiReference ref = configureByText("""
                                         import groovy.transform.Field
                                         
                                         @Field
                                         def aa = 5
                                         
                                         class X {
                                           def foo() {
                                             print a<caret>a
                                           }
                                         }
                                         """);
    TestCase.assertNull(ref.resolve());
  }

  public void testInitializerOfScriptField() {
    addGroovyTransformField();
    PsiReference ref = configureByText("""
                                         import groovy.transform.Field
                                         
                                         def xx = 5
                                         @Field
                                         def aa = 5 + x<caret>x
                                         """);
    TestCase.assertNull(ref.resolve());
  }

  public void testInitializerOfScriptField2() {
    addGroovyTransformField();
    PsiReference ref = configureByText("""
                                         import groovy.transform.Field
                                         
                                         @Field
                                         def xx = 5
                                         
                                         @Field
                                         def aa = 5 + x<caret>x
                                         """);
    UsefulTestCase.assertInstanceOf(ref.resolve(), GrVariable.class);
  }

  public void testAliasedImportedPropertyWithGetterInAlias() {
    myFixture.addFileToProject("Foo.groovy", """
      class Foo {
        static def prop = 2
      }
      """);

    PsiReference ref = configureByText("""
                                         import static Foo.getProp as getOther
                                         
                                         print othe<caret>r
                                         """);

    UsefulTestCase.assertInstanceOf(ref.resolve(), GrAccessorMethod.class);
  }

  public void testPrefLocalVarToScriptName() {
    myFixture.addFileToProject("foo.groovy", "print 2");

    PsiReference ref = configureByText("""
                                         class Bar {
