1 // 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.
2 package org.jetbrains.plugins.groovy.lang.resolve.ast.contributor
4 import com.intellij.psi.PsiAnnotation
5 import com.intellij.psi.PsiClass
6 import com.intellij.psi.PsiElement
7 import com.intellij.psi.ResolveState
8 import com.intellij.psi.scope.ElementClassHint
9 import com.intellij.psi.scope.PsiScopeProcessor
10 import com.intellij.psi.util.parentOfType
11 import com.intellij.util.SmartList
12 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
13 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
14 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
15 import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnnotationUtil
16 import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightMethodBuilder
17 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR
18 import org.jetbrains.plugins.groovy.lang.resolve.ClosureMemberContributor
19 import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil
21 class SyntheticKeywordConstructorContributor : ClosureMemberContributor() {
23 override fun processMembers(closure: GrClosableBlock, processor: PsiScopeProcessor, place: PsiElement, state: ResolveState) {
24 if (!ResolveUtil.shouldProcessMethods(processor.getHint(ElementClassHint.KEY))) return
25 val nameHint = ResolveUtil.getNameHint(processor)
26 if (nameHint != null && nameHint != "super") return
28 if (closure != place.parentOfType<GrClosableBlock>()) return
29 val anno = closure.parentOfType<PsiAnnotation>()?.takeIf { it.qualifiedName == GROOVY_TRANSFORM_TUPLE_CONSTRUCTOR } ?: return
30 if (GrAnnotationUtil.inferClosureAttribute(anno, "pre") != closure) return
33 val syntheticMethods = createSyntheticConstructors(closure)
35 for (method in syntheticMethods) {
36 if (!processor.execute(method, state)) {
42 private fun createSyntheticConstructors(closure: GrClosableBlock): List<GrMethod> {
43 val outerClass = closure.parentOfType<PsiClass>() ?: return emptyList()
44 val superClass = outerClass.superClass
45 val methods = SmartList<GrMethod>()
46 if (superClass != null) {
47 val constructors = superClass.constructors
48 if (constructors.isEmpty()) {
49 val method = SyntheticKeywordConstructor(outerClass, superClass, "super")
53 for (constructor in constructors) {
54 val method = SyntheticKeywordConstructor(outerClass, superClass, "super")
55 for (param in constructor.parameterList.parameters) {
56 method.addParameter(param.name, param.type)
65 private class SyntheticKeywordConstructor(containingClass: PsiClass, superClass: PsiClass, name: String) :
66 GrLightMethodBuilder(containingClass.manager, name) {
68 assert(name.isReserved())
70 navigationElement = superClass
71 this.containingClass = containingClass
76 private fun String?.isReserved(): Boolean = this == "super"
79 fun isSyntheticConstructorCall(call: GrMethodCall?): Boolean =
80 call?.callReference?.methodName.isReserved() && call?.resolveMethod() is SyntheticKeywordConstructor