001    /*
002     * Copyright 2010-2016 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.asJava.elements;
018    
019    import com.intellij.lang.Language;
020    import com.intellij.openapi.util.TextRange;
021    import com.intellij.psi.*;
022    import com.intellij.psi.search.GlobalSearchScope;
023    import com.intellij.psi.search.LocalSearchScope;
024    import com.intellij.psi.search.SearchScope;
025    import com.intellij.util.ArrayUtil;
026    import com.intellij.util.IncorrectOperationException;
027    import org.jetbrains.annotations.NonNls;
028    import org.jetbrains.annotations.NotNull;
029    import org.jetbrains.annotations.Nullable;
030    import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration;
031    import org.jetbrains.kotlin.idea.KotlinLanguage;
032    import org.jetbrains.kotlin.psi.*;
033    import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
034    
035    import java.util.List;
036    
037    public class KtLightParameter extends LightParameter implements KtLightDeclaration<KtParameter, PsiParameter> {
038        private static String getName(PsiParameter delegate, int index) {
039            String name = delegate.getName();
040            return name != null ? name : "p" + index;
041        }
042    
043        private final PsiModifierList modifierList;
044        private final PsiParameter delegate;
045        private final int index;
046        private final KtLightMethod method;
047        private KtLightIdentifier lightIdentifier = null;
048    
049        public KtLightParameter(final PsiParameter delegate, int index, KtLightMethod method) {
050            super(getName(delegate, index), delegate.getType(), method, KotlinLanguage.INSTANCE);
051    
052            this.delegate = delegate;
053            this.index = index;
054            this.method = method;
055    
056            if (method.getLightMethodOrigin() instanceof LightMemberOriginForDeclaration) {
057                this.modifierList = new KtLightModifierListWithExplicitModifiers(this, ArrayUtil.EMPTY_STRING_ARRAY) {
058                    @Override
059                    public PsiAnnotationOwner getDelegate() {
060                        return delegate.getModifierList();
061                    }
062                };
063            }
064            else {
065                this.modifierList = super.getModifierList();
066            }
067        }
068    
069        @NotNull
070        @Override
071        public PsiModifierList getModifierList() {
072            return modifierList;
073        }
074    
075        @NotNull
076        @Override
077        public PsiParameter getClsDelegate() {
078            return delegate;
079        }
080    
081        @Nullable
082        @Override
083        public KtParameter getKotlinOrigin() {
084            KtDeclaration declaration = method.getKotlinOrigin();
085            if (declaration == null) return null;
086    
087            int jetIndex = KtPsiUtilKt.isExtensionDeclaration(declaration) ? index - 1 : index;
088            if (jetIndex < 0) return null;
089    
090            if (declaration instanceof KtFunction) {
091                List<KtParameter> paramList = ((KtFunction) declaration).getValueParameters();
092                return jetIndex < paramList.size() ? paramList.get(jetIndex) : null;
093            }
094    
095            if (jetIndex != 0) return null;
096    
097            KtPropertyAccessor setter = null;
098            if (declaration instanceof KtPropertyAccessor) {
099                KtPropertyAccessor accessor = (KtPropertyAccessor) declaration;
100                setter = accessor.isSetter() ? accessor : null;
101            }
102            else if (declaration instanceof KtProperty) {
103                setter = ((KtProperty) declaration).getSetter();
104            }
105            else if (declaration instanceof KtParameter) {
106                return (KtParameter) declaration;
107            }
108    
109            return setter != null ? setter.getParameter() : null;
110        }
111    
112        @NotNull
113        @Override
114        public PsiElement getNavigationElement() {
115            KtParameter origin = getKotlinOrigin();
116            return origin != null ? origin : super.getNavigationElement();
117        }
118    
119        @Override
120        public boolean isValid() {
121            return method.isValid();
122        }
123    
124        @Override
125        public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
126            KtParameter origin = getKotlinOrigin();
127            if (origin != null) {
128                origin.setName(name);
129            }
130            return this;
131        }
132    
133        @Override
134        public PsiFile getContainingFile() {
135            return method.getContainingFile();
136        }
137    
138        @NotNull
139        @Override
140        public Language getLanguage() {
141            return KotlinLanguage.INSTANCE;
142        }
143    
144        @NotNull
145        @Override
146        public SearchScope getUseScope() {
147            KtParameter origin = getKotlinOrigin();
148            return origin != null ? origin.getUseScope() : new LocalSearchScope(this);
149        }
150    
151        public KtLightMethod getMethod() {
152            return method;
153        }
154    
155        @Override
156        public String getText() {
157            return "";
158        }
159    
160        @Override
161        public TextRange getTextRange() {
162            KtParameter origin = getKotlinOrigin();
163            return origin != null ? origin.getTextRange() : TextRange.EMPTY_RANGE;
164        }
165    
166        @Override
167        public PsiIdentifier getNameIdentifier() {
168            if (lightIdentifier == null) {
169                lightIdentifier = new KtLightIdentifier(this, getKotlinOrigin());
170            }
171            return lightIdentifier;
172        }
173    
174        @Override
175        public PsiElement getParent() {
176            return getMethod().getParameterList();
177        }
178    
179        @Override
180        public boolean isEquivalentTo(PsiElement another) {
181            KtParameter kotlinOrigin = getKotlinOrigin();
182            if (another instanceof KtLightParameter && kotlinOrigin != null) {
183                KtLightParameter anotherParam = (KtLightParameter) another;
184                return kotlinOrigin.equals(anotherParam.getKotlinOrigin()) && getClsDelegate().equals(anotherParam.getClsDelegate());
185            }
186            return super.isEquivalentTo(another);
187        }
188    
189        @Override
190        public boolean equals(Object obj) {
191            return obj instanceof PsiElement && isEquivalentTo((PsiElement) obj);
192        }
193    }