1 /* <lambda>null2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava.model.psi 18 19 import com.android.tools.metalava.model.ApiVariantSelectors 20 import com.android.tools.metalava.model.BaseModifierList 21 import com.android.tools.metalava.model.ClassItem 22 import com.android.tools.metalava.model.ClassTypeItem 23 import com.android.tools.metalava.model.ExceptionTypeItem 24 import com.android.tools.metalava.model.ItemDocumentation 25 import com.android.tools.metalava.model.ItemDocumentationFactory 26 import com.android.tools.metalava.model.TypeParameterList 27 import com.android.tools.metalava.model.VisibilityLevel 28 import com.android.tools.metalava.model.createImmutableModifiers 29 import com.android.tools.metalava.model.item.DefaultConstructorItem 30 import com.android.tools.metalava.model.item.ParameterItemsFactory 31 import com.android.tools.metalava.model.psi.PsiCallableItem.Companion.parameterList 32 import com.android.tools.metalava.model.psi.PsiCallableItem.Companion.throwsTypes 33 import com.android.tools.metalava.reporter.FileLocation 34 import com.intellij.psi.JavaPsiFacade 35 import com.intellij.psi.PsiClass 36 import com.intellij.psi.PsiMethod 37 import com.intellij.psi.PsiParameter 38 import org.jetbrains.kotlin.lexer.KtTokens 39 import org.jetbrains.kotlin.psi.KtClassOrObject 40 import org.jetbrains.kotlin.psi.KtConstructor 41 import org.jetbrains.kotlin.psi.KtPrimaryConstructor 42 import org.jetbrains.uast.UMethod 43 44 internal class PsiConstructorItem 45 private constructor( 46 override val codebase: PsiBasedCodebase, 47 override val psiMethod: PsiMethod, 48 fileLocation: FileLocation = PsiFileLocation(psiMethod), 49 containingClass: ClassItem, 50 name: String, 51 modifiers: BaseModifierList, 52 documentationFactory: ItemDocumentationFactory, 53 parameterItemsFactory: ParameterItemsFactory, 54 returnType: ClassTypeItem, 55 typeParameterList: TypeParameterList, 56 throwsTypes: List<ExceptionTypeItem>, 57 implicitConstructor: Boolean = false, 58 isPrimary: Boolean = false 59 ) : 60 DefaultConstructorItem( 61 codebase = codebase, 62 fileLocation = fileLocation, 63 itemLanguage = psiMethod.itemLanguage, 64 modifiers = modifiers, 65 documentationFactory = documentationFactory, 66 variantSelectorsFactory = ApiVariantSelectors.MUTABLE_FACTORY, 67 name = name, 68 containingClass = containingClass, 69 typeParameterList = typeParameterList, 70 returnType = returnType, 71 parameterItemsFactory = parameterItemsFactory, 72 throwsTypes = throwsTypes, 73 callableBodyFactory = { PsiCallableBody(it as PsiCallableItem) }, 74 implicitConstructor = implicitConstructor, 75 isPrimary = isPrimary, 76 ), 77 PsiCallableItem { 78 79 companion object { createnull80 internal fun create( 81 codebase: PsiBasedCodebase, 82 containingClass: ClassItem, 83 psiMethod: PsiMethod, 84 enclosingClassTypeItemFactory: PsiTypeItemFactory, 85 psiParameters: List<PsiParameter> = psiMethod.psiParameters, 86 ): PsiConstructorItem { 87 assert(psiMethod.isConstructor) 88 val name = psiMethod.name 89 val modifiers = PsiModifierItem.create(codebase, psiMethod) 90 91 // After KT-13495, "all constructors of `sealed` classes now have `protected` 92 // visibility by default," and (S|U)LC follows that (hence the same in UAST). 93 // However, that change was made to allow more flexible class hierarchy and 94 // nesting. If they're compiled to JVM bytecode, sealed class's ctor is still 95 // technically `private` to block instantiation from outside class hierarchy. 96 // Another synthetic constructor, along with an internal ctor marker, is added 97 // for subclasses of a sealed class. Therefore, from Metalava's perspective, 98 // it is not necessary to track such semantically protected ctor. Here we force 99 // set the visibility to `private` back to ignore it during signature writing. 100 if (containingClass.modifiers.isSealed()) { 101 modifiers.setVisibilityLevel(VisibilityLevel.PRIVATE) 102 } 103 104 // Create the TypeParameterList for this before wrapping any of the other types used by 105 // it as they may reference a type parameter in the list. 106 val (typeParameterList, constructorTypeItemFactory) = 107 PsiTypeParameterList.create( 108 codebase, 109 enclosingClassTypeItemFactory, 110 "constructor $name", 111 psiMethod 112 ) 113 val constructor = 114 PsiConstructorItem( 115 codebase = codebase, 116 psiMethod = psiMethod, 117 containingClass = containingClass, 118 name = name, 119 modifiers = modifiers, 120 documentationFactory = PsiItemDocumentation.factory(psiMethod, codebase), 121 parameterItemsFactory = { containingCallable -> 122 parameterList( 123 codebase, 124 psiMethod, 125 containingCallable as PsiCallableItem, 126 constructorTypeItemFactory, 127 psiParameters, 128 ) 129 }, 130 returnType = containingClass.type(), 131 typeParameterList = typeParameterList, 132 throwsTypes = throwsTypes(psiMethod, constructorTypeItemFactory), 133 implicitConstructor = false, 134 isPrimary = (psiMethod as? UMethod)?.isPrimaryConstructor ?: false, 135 ) 136 137 // Undo setting of constructors with value class types to private (b/395472914). 138 // Constructors that use value class types are effectively private to java callers, but 139 // they can be public in source to kotlin callers, so we want to track them. 140 if ( 141 constructor.modifiers.isPrivate() && 142 constructor.parameters().any { (it.type() as PsiTypeItem).isValueClassType() } 143 ) { 144 (psiMethod.sourceElement as? KtConstructor<*>)?.let { sourcePsi -> 145 if (!sourcePsi.hasModifier(KtTokens.PRIVATE_KEYWORD)) { 146 constructor.mutateModifiers { 147 val correctedVisibility = 148 when { 149 sourcePsi.hasModifier(KtTokens.PROTECTED_KEYWORD) -> 150 VisibilityLevel.PROTECTED 151 sourcePsi.hasModifier(KtTokens.INTERNAL_KEYWORD) -> 152 VisibilityLevel.INTERNAL 153 else -> VisibilityLevel.PUBLIC 154 } 155 setVisibilityLevel(correctedVisibility) 156 } 157 } 158 } 159 } 160 161 return constructor 162 } 163 createDefaultConstructornull164 fun createDefaultConstructor( 165 codebase: PsiBasedCodebase, 166 containingClass: ClassItem, 167 psiClass: PsiClass, 168 visibilityLevel: VisibilityLevel, 169 ): PsiConstructorItem { 170 val name = psiClass.name!! 171 172 val factory = JavaPsiFacade.getInstance(psiClass.project).elementFactory 173 val psiMethod = factory.createConstructor(name, psiClass) 174 val modifiers = createImmutableModifiers(visibilityLevel) 175 176 val item = 177 PsiConstructorItem( 178 codebase = codebase, 179 psiMethod = psiMethod, 180 // Use the location of the containing class for the implicit default 181 // constructor. 182 fileLocation = containingClass.fileLocation, 183 containingClass = containingClass, 184 name = name, 185 modifiers = modifiers, 186 documentationFactory = ItemDocumentation.NONE_FACTORY, 187 parameterItemsFactory = { emptyList() }, 188 returnType = containingClass.type(), 189 typeParameterList = TypeParameterList.NONE, 190 throwsTypes = emptyList(), 191 implicitConstructor = true, 192 ) 193 return item 194 } 195 196 /** 197 * Whether the [UMethod] is the primary constructor of a Kotlin class. A primary constructor 198 * is declared in the class header, and all other constructors must delegate to it (see 199 * https://kotlinlang.org/docs/classes.html#constructors). 200 */ 201 internal val UMethod.isPrimaryConstructor: Boolean 202 get() = sourcePsi is KtPrimaryConstructor || sourcePsi is KtClassOrObject 203 } 204 } 205