001 /*
002 * Copyright 2010-2015 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.psi;
018
019 import com.intellij.lang.ASTNode;
020 import com.intellij.navigation.ItemPresentation;
021 import com.intellij.navigation.ItemPresentationProviders;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.PsiModifiableCodeBlock;
024 import com.intellij.psi.tree.IElementType;
025 import com.intellij.psi.util.PsiTreeUtil;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.kotlin.lexer.JetTokens;
029 import org.jetbrains.kotlin.psi.stubs.KotlinFunctionStub;
030 import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
031 import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage;
032
033 import java.util.Collections;
034 import java.util.List;
035
036 public class JetNamedFunction extends JetTypeParameterListOwnerStub<KotlinFunctionStub>
037 implements JetFunction, JetWithExpressionInitializer, PsiModifiableCodeBlock {
038 public JetNamedFunction(@NotNull ASTNode node) {
039 super(node);
040 }
041
042 public JetNamedFunction(@NotNull KotlinFunctionStub stub) {
043 super(stub, JetStubElementTypes.FUNCTION);
044 }
045
046 @Override
047 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
048 return visitor.visitNamedFunction(this, data);
049 }
050
051 public boolean hasTypeParameterListBeforeFunctionName() {
052 KotlinFunctionStub stub = getStub();
053 if (stub != null) {
054 return stub.hasTypeParameterListBeforeFunctionName();
055 }
056 return hasTypeParameterListBeforeFunctionNameByTree();
057 }
058
059 private boolean hasTypeParameterListBeforeFunctionNameByTree() {
060 JetTypeParameterList typeParameterList = getTypeParameterList();
061 if (typeParameterList == null) {
062 return false;
063 }
064 PsiElement nameIdentifier = getNameIdentifier();
065 if (nameIdentifier == null) {
066 return true;
067 }
068 return nameIdentifier.getTextOffset() > typeParameterList.getTextOffset();
069 }
070
071 @Override
072 public boolean hasBlockBody() {
073 KotlinFunctionStub stub = getStub();
074 if (stub != null) {
075 return stub.hasBlockBody();
076 }
077 return getEqualsToken() == null;
078 }
079
080 @Nullable
081 @IfNotParsed // "function" with no "fun" keyword is created by parser for "{...}" on top-level or in class body
082 public PsiElement getFunKeyword() {
083 return findChildByType(JetTokens.FUN_KEYWORD);
084 }
085
086 @Override
087 @Nullable
088 public PsiElement getEqualsToken() {
089 return findChildByType(JetTokens.EQ);
090 }
091
092 @Override
093 @Nullable
094 public JetExpression getInitializer() {
095 return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class);
096 }
097
098 @Override
099 public boolean hasInitializer() {
100 return getInitializer() != null;
101 }
102
103 @Override
104 public ItemPresentation getPresentation() {
105 return ItemPresentationProviders.getItemPresentation(this);
106 }
107
108 @Override
109 @Nullable
110 public JetParameterList getValueParameterList() {
111 return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST);
112 }
113
114 @Override
115 @NotNull
116 public List<JetParameter> getValueParameters() {
117 JetParameterList list = getValueParameterList();
118 return list != null ? list.getParameters() : Collections.<JetParameter>emptyList();
119 }
120
121 @Override
122 @Nullable
123 public JetExpression getBodyExpression() {
124 return findChildByClass(JetExpression.class);
125 }
126
127 @Override
128 public boolean hasBody() {
129 KotlinFunctionStub stub = getStub();
130 if (stub != null) {
131 return stub.hasBody();
132 }
133 return getBodyExpression() != null;
134 }
135
136 @Override
137 public boolean hasDeclaredReturnType() {
138 return getTypeReference() != null;
139 }
140
141 @Override
142 @Nullable
143 public JetTypeReference getReceiverTypeReference() {
144 KotlinFunctionStub stub = getStub();
145 if (stub != null) {
146 if (!stub.isExtension()) {
147 return null;
148 }
149 List<JetTypeReference> childTypeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
150 if (!childTypeReferences.isEmpty()) {
151 return childTypeReferences.get(0);
152 }
153 else {
154 return null;
155 }
156 }
157 return getReceiverTypeRefByTree();
158 }
159
160 @Nullable
161 private JetTypeReference getReceiverTypeRefByTree() {
162 PsiElement child = getFirstChild();
163 while (child != null) {
164 IElementType tt = child.getNode().getElementType();
165 if (tt == JetTokens.LPAR || tt == JetTokens.COLON) break;
166 if (child instanceof JetTypeReference) {
167 return (JetTypeReference) child;
168 }
169 child = child.getNextSibling();
170 }
171
172 return null;
173 }
174
175 @Override
176 @Nullable
177 public JetTypeReference getTypeReference() {
178 KotlinFunctionStub stub = getStub();
179 if (stub != null) {
180 List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
181 int returnTypeIndex = stub.isExtension() ? 1 : 0;
182 if (returnTypeIndex >= typeReferences.size()) {
183 return null;
184 }
185 return typeReferences.get(returnTypeIndex);
186 }
187 return TypeRefHelpersPackage.getTypeReference(this);
188 }
189
190 @Override
191 @Nullable
192 public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) {
193 return TypeRefHelpersPackage.setTypeReference(this, getValueParameterList(), typeRef);
194 }
195
196 @Nullable
197 @Override
198 public PsiElement getColon() {
199 return findChildByType(JetTokens.COLON);
200 }
201
202 @Override
203 public boolean isLocal() {
204 PsiElement parent = getParent();
205 return !(parent instanceof JetFile || parent instanceof JetClassBody);
206 }
207
208 public boolean isTopLevel() {
209 KotlinFunctionStub stub = getStub();
210 if (stub != null) {
211 return stub.isTopLevel();
212 }
213
214 return getParent() instanceof JetFile;
215 }
216
217 @Override
218 public boolean shouldChangeModificationCount(PsiElement place) {
219 // Suppress Java check for out-of-block
220 return false;
221 }
222 }