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.ConstructorItem 20 import com.android.tools.metalava.model.MethodItem 21 import com.intellij.psi.JavaPsiFacade 22 import com.intellij.psi.PsiClass 23 import com.intellij.psi.PsiElement 24 import com.intellij.psi.PsiExpressionStatement 25 import com.intellij.psi.PsiKeyword 26 import com.intellij.psi.PsiMethod 27 import com.intellij.psi.PsiMethodCallExpression 28 import com.intellij.psi.PsiWhiteSpace 29 30 class PsiConstructorItem( 31 codebase: PsiBasedCodebase, 32 psiMethod: PsiMethod, 33 containingClass: PsiClassItem, 34 name: String, 35 modifiers: PsiModifierItem, 36 documentation: String, 37 parameters: List<PsiParameterItem>, 38 returnType: PsiTypeItem, 39 val implicitConstructor: Boolean = false 40 ) : 41 PsiMethodItem( 42 codebase = codebase, 43 modifiers = modifiers, 44 documentation = documentation, 45 psiMethod = psiMethod, 46 containingClass = containingClass, 47 name = name, 48 returnType = returnType, 49 parameters = parameters 50 ), ConstructorItem { 51 52 init { 53 if (implicitConstructor) { 54 setThrowsTypes(emptyList()) 55 } 56 } 57 58 override fun isImplicitConstructor(): Boolean = implicitConstructor 59 override fun isConstructor(): Boolean = true 60 override var superConstructor: ConstructorItem? = null 61 override fun isCloned(): Boolean = false 62 63 private var _superMethods: List<MethodItem>? = null 64 override fun superMethods(): List<MethodItem> { 65 if (_superMethods == null) { 66 val result = mutableListOf<MethodItem>() 67 psiMethod.findSuperMethods().mapTo(result) { codebase.findMethod(it) } 68 69 if (result.isEmpty() && isConstructor() && containingClass().superClass() != null) { 70 // Try a little harder; psi findSuperMethod doesn't seem to find super constructors in 71 // some cases, but maybe we can find it by resolving actual super() calls! 72 // TODO: Port to UAST 73 var curr: PsiElement? = psiMethod.body?.firstBodyElement 74 while (curr != null && curr is PsiWhiteSpace) { 75 curr = curr.nextSibling 76 } 77 if (curr is PsiExpressionStatement && curr.expression is PsiMethodCallExpression && 78 curr.expression.firstChild?.lastChild is PsiKeyword && 79 curr.expression.firstChild?.lastChild?.text == "super" 80 ) { 81 val resolved = (curr.expression as PsiMethodCallExpression).resolveMethod() 82 if (resolved is PsiMethod) { 83 val superConstructor = codebase.findMethod(resolved) 84 result.add(superConstructor) 85 } 86 } 87 } 88 _superMethods = result 89 } 90 91 return _superMethods!! 92 } 93 94 override fun psi(): PsiElement? { 95 // If no PSI element, is this a synthetic/implicit constructor? If so 96 // grab the parent class' PSI element instead for file/location purposes 97 if (implicitConstructor && element.containingFile?.virtualFile == null) { 98 return containingClass().psi() 99 } 100 101 return element 102 } 103 104 companion object { 105 fun create( 106 codebase: PsiBasedCodebase, 107 containingClass: PsiClassItem, 108 psiMethod: PsiMethod 109 ): PsiConstructorItem { 110 assert(psiMethod.isConstructor) 111 val name = psiMethod.name 112 val commentText = javadoc(psiMethod) 113 val modifiers = modifiers(codebase, psiMethod, commentText) 114 val parameters = psiMethod.parameterList.parameters.mapIndexed { index, parameter -> 115 PsiParameterItem.create(codebase, parameter, index) 116 } 117 118 val constructor = PsiConstructorItem( 119 codebase = codebase, 120 psiMethod = psiMethod, 121 containingClass = containingClass, 122 name = name, 123 documentation = commentText, 124 modifiers = modifiers, 125 parameters = parameters, 126 returnType = codebase.getType(containingClass.psiClass), 127 implicitConstructor = false 128 ) 129 constructor.modifiers.setOwner(constructor) 130 return constructor 131 } 132 133 fun createDefaultConstructor( 134 codebase: PsiBasedCodebase, 135 containingClass: PsiClassItem, 136 psiClass: PsiClass 137 ): PsiConstructorItem { 138 val name = psiClass.name!! 139 140 val factory = JavaPsiFacade.getInstance(psiClass.project).elementFactory 141 val psiMethod = factory.createConstructor(name, psiClass) 142 val flags = containingClass.modifiers.getAccessFlags() 143 val modifiers = PsiModifierItem(codebase, flags, null) 144 145 val item = PsiConstructorItem( 146 codebase = codebase, 147 psiMethod = psiMethod, 148 containingClass = containingClass, 149 name = name, 150 documentation = "", 151 modifiers = modifiers, 152 parameters = emptyList(), 153 returnType = codebase.getType(psiClass), 154 implicitConstructor = true 155 ) 156 modifiers.setOwner(item) 157 return item 158 } 159 } 160 }