/* * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.idea.javaFacade; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.LightProjectDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.asJava.LightClassUtil; import org.jetbrains.kotlin.asJava.classes.KtLightClass; import org.jetbrains.kotlin.asJava.elements.KtLightMethod; import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase; import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; import org.jetbrains.kotlin.idea.test.PluginTestCaseBase; import org.jetbrains.kotlin.name.SpecialNames; import org.jetbrains.kotlin.psi.*; import static org.jetbrains.kotlin.asJava.LightClassUtilsKt.toLightClass; public class KotlinJavaFacadeTest extends KotlinLightCodeInsightFixtureTestCase { @NotNull @Override protected LightProjectDescriptor getProjectDescriptor() { return KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE; } @Override protected String getTestDataPath() { return PluginTestCaseBase.getTestDataPathBase() + "/javaFacade"; } public void testDoNotWrapFunFromLocalClass() { doTestWrapMethod(true); } public void testObjectSubclassing() { doTestWrapMethod(true); } public void testDoNotWrapFunInAnonymousObject() { doTestWrapMethod(true); } public void testWrapFunInClassWithoutBody() { doTestWrapMethod(true); } public void testLocalClassSubclass() { doTestWrapClass(); } public void testClassWithObjectLiteralInClassObjectField() { doTestWrapClass(); } public void testClassWithObjectLiteralInConstructorProperty() { doTestWrapClass(); } public void testClassWithObjectLiteralInFun() { doTestWrapClass(); } public void testClassWithObjectLiteralInField() { doTestWrapClass(); } public void testWrapFunInClassObject() { doTestWrapMethod(true); } public void testWrapTopLevelFun() { doTestWrapMethod(true); } public void testWrapFunWithDefaultParam() { doTestWrapMethod(true); } public void testWrapFunWithImplInTrait() { doTestWrapMethod(true); } public void testWrapFunWithoutImplInTrait() { doTestWrapMethod(true); } public void testWrapFunInObject() { doTestWrapMethod(true); } public void testWrapFunInObjectInObject() { doTestWrapMethod(true); } public void testKt2764() { doTestWrapClass(); } public void testEa37034() { doTestWrapClass(); } public void testEa46019() { doTestWrapClass(); } public void testEa68569() { doTestWrapClass(); } public void testWrapTopLevelFunWithDefaultParams() { doTestWrapMethod(true); } public void testWrapValTopLevelProperty() { doTestWrapProperty(true, false); } public void testWrapVarPropertyInClass() { doTestWrapProperty(true, true); } public void testWrapVarPropertyWithAccessorsInTrait() { doTestWrapProperty(true, true); } public void testWrapVarTopLevelProperty() { doTestWrapProperty(true, true); } public void testWrapVarPropertyInLocalClass() { doTestWrapProperty(true, true); } public void testWrapVarTopLevelAccessor() { doTestWrapPropertyAccessor(true); } public void testWrapConstructorField() { doTestWrapParameter(true, true); } public void testWrapConstructorParameter() { doTestWrapParameter(false, false); } public void testWrapFunctionParameter() { doTestWrapParameter(false, false); } public void testInnerClass() throws Exception { myFixture.configureByFile(fileName()); JavaPsiFacade facade = myFixture.getJavaFacade(); PsiClass mirrorClass = facade.findClass("foo.Outer.Inner", GlobalSearchScope.allScope(getProject())); assertNotNull(mirrorClass); PsiMethod[] fun = mirrorClass.findMethodsByName("innerFun", false); assertEquals(fun[0].getReturnType(), PsiType.VOID); } public void testClassObject() throws Exception { myFixture.configureByFile(fileName()); JavaPsiFacade facade = myFixture.getJavaFacade(); PsiClass theClass = facade.findClass("foo.TheClass", GlobalSearchScope.allScope(getProject())); assertNotNull(theClass); PsiField classobjField = theClass.findFieldByName("$classobj", false); assertNull(classobjField); String defaultCompanionObjectName = SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT.asString(); PsiClass classObjectClass = theClass.findInnerClassByName(defaultCompanionObjectName, false); assertNotNull(classObjectClass); assertEquals("foo.TheClass." + defaultCompanionObjectName, classObjectClass.getQualifiedName()); assertTrue(classObjectClass.hasModifierProperty(PsiModifier.STATIC)); PsiField instance = theClass.findFieldByName(defaultCompanionObjectName, false); assertNotNull(instance); assertEquals("foo.TheClass." + defaultCompanionObjectName, instance.getType().getCanonicalText()); assertTrue(instance.hasModifierProperty(PsiModifier.PUBLIC)); assertTrue(instance.hasModifierProperty(PsiModifier.STATIC)); assertTrue(instance.hasModifierProperty(PsiModifier.FINAL)); PsiMethod[] methods = classObjectClass.findMethodsByName("getOut", false); assertEquals("java.io.PrintStream", methods[0].getReturnType().getCanonicalText()); } public void testLightClassIsNotCreatedForBuiltins() throws Exception { myFixture.configureByFile(fileName()); PsiReference reference = myFixture.getFile().findReferenceAt(myFixture.getCaretOffset()); assert reference != null; PsiElement element = reference.resolve(); assertInstanceOf(element, KtClass.class); KtClass aClass = (KtClass) element; PsiClass createdByWrapDelegate = toLightClass(aClass); assertNull(createdByWrapDelegate); } private void doTestWrapMethod(boolean shouldBeWrapped) { KtNamedFunction jetFunction = getPreparedElement(KtNamedFunction.class); // Should not fail! PsiMethod psiMethod = LightClassUtil.INSTANCE.getLightClassMethod(jetFunction); checkDeclarationMethodWrapped(shouldBeWrapped, jetFunction, psiMethod); } private void doTestWrapParameter(boolean shouldWrapGetter, boolean shouldWrapSetter) { KtParameter jetParameter = getPreparedElement(KtParameter.class); // Should not fail! LightClassUtil.PropertyAccessorsPsiMethods propertyAccessors = LightClassUtil.INSTANCE.getLightClassPropertyMethods(jetParameter); checkDeclarationMethodWrapped(shouldWrapGetter, jetParameter, propertyAccessors.getGetter()); checkDeclarationMethodWrapped(shouldWrapSetter, jetParameter, propertyAccessors.getSetter()); } private void doTestWrapProperty(boolean shouldWrapGetter, boolean shouldWrapSetter) { KtProperty jetProperty = getPreparedElement(KtProperty.class); // Should not fail! LightClassUtil.PropertyAccessorsPsiMethods propertyAccessors = LightClassUtil.INSTANCE.getLightClassPropertyMethods(jetProperty); checkDeclarationMethodWrapped(shouldWrapGetter, jetProperty, propertyAccessors.getGetter()); checkDeclarationMethodWrapped(shouldWrapSetter, jetProperty, propertyAccessors.getSetter()); } private void doTestWrapPropertyAccessor(boolean shouldWrapAccessor) { KtPropertyAccessor jetPropertyAccessor = getPreparedElement(KtPropertyAccessor.class); // Should not fail! PsiMethod propertyAccessors = LightClassUtil.INSTANCE.getLightClassAccessorMethod(jetPropertyAccessor); checkDeclarationMethodWrapped(shouldWrapAccessor, PsiTreeUtil.getParentOfType(jetPropertyAccessor, KtProperty.class), propertyAccessors); } @NotNull private <T extends KtElement> T getPreparedElement(Class<T> elementClass) { myFixture.configureByFile(fileName()); int offset = myFixture.getEditor().getCaretModel().getOffset(); PsiElement elementAt = myFixture.getFile().findElementAt(offset); assertNotNull("Caret should be set for tested file", elementAt); T caretElement = PsiTreeUtil.getParentOfType(elementAt, elementClass); assertNotNull( String.format("Caret should be placed to element of type: %s, but was at element '%s' of type %s", elementClass, elementAt, elementAt.getClass()), caretElement); return caretElement; } private static void checkDeclarationMethodWrapped(boolean shouldBeWrapped, KtDeclaration declaration, PsiMethod psiMethod) { if (shouldBeWrapped) { assertNotNull(String.format("Failed to wrap declaration '%s' to method", declaration.getText()), psiMethod); assertInstanceOf(psiMethod, KtLightMethod.class); assertEquals("Invalid original element for generated method", ((KtLightMethod) psiMethod).getKotlinOrigin(), declaration); } else { assertNull("There should be no wrapper for given method", psiMethod); } } private void doTestWrapClass() { myFixture.configureByFile(fileName()); int offset = myFixture.getEditor().getCaretModel().getOffset(); PsiElement elementAt = myFixture.getFile().findElementAt(offset); assertNotNull("Caret should be set for tested file", elementAt); KtClass ktClass = PsiTreeUtil.getParentOfType(elementAt, KtClass.class); assertNotNull("Caret should be placed to class definition", ktClass); // Should not fail! KtLightClass lightClass = toLightClass(ktClass); assertNotNull(String.format("Failed to wrap jetClass '%s' to class", ktClass.getText()), lightClass); // This invokes codegen with ClassBuilderMode = LIGHT_CLASSES // No exception/error should happen here lightClass.getClsDelegate(); } @NotNull @Override protected String fileName() { return getTestName(true) + ".kt"; } }