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 false; 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 @NotNull 081 public PsiElement getFunToken() { 082 PsiElement element = findChildByType(JetTokens.FUN_KEYWORD); 083 assert element != null : "'fun' must be present: " + JetPsiUtil.getElementTextWithContext(this); 084 return element; 085 } 086 087 @Override 088 @Nullable 089 public PsiElement getEqualsToken() { 090 return findChildByType(JetTokens.EQ); 091 } 092 093 @Override 094 @Nullable 095 public JetExpression getInitializer() { 096 return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class); 097 } 098 099 @Override 100 public boolean hasInitializer() { 101 return getInitializer() != null; 102 } 103 104 @Override 105 public ItemPresentation getPresentation() { 106 return ItemPresentationProviders.getItemPresentation(this); 107 } 108 109 @Override 110 @Nullable 111 public JetParameterList getValueParameterList() { 112 return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST); 113 } 114 115 @Override 116 @NotNull 117 public List<JetParameter> getValueParameters() { 118 JetParameterList list = getValueParameterList(); 119 return list != null ? list.getParameters() : Collections.<JetParameter>emptyList(); 120 } 121 122 @Override 123 @Nullable 124 public JetExpression getBodyExpression() { 125 return findChildByClass(JetExpression.class); 126 } 127 128 @Override 129 public boolean hasBody() { 130 KotlinFunctionStub stub = getStub(); 131 if (stub != null) { 132 return stub.hasBody(); 133 } 134 return getBodyExpression() != null; 135 } 136 137 @Override 138 public boolean hasDeclaredReturnType() { 139 return getTypeReference() != null; 140 } 141 142 @Override 143 @Nullable 144 public JetTypeReference getReceiverTypeReference() { 145 KotlinFunctionStub stub = getStub(); 146 if (stub != null) { 147 if (!stub.isExtension()) { 148 return null; 149 } 150 List<JetTypeReference> childTypeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE); 151 if (!childTypeReferences.isEmpty()) { 152 return childTypeReferences.get(0); 153 } 154 else { 155 return null; 156 } 157 } 158 return getReceiverTypeRefByTree(); 159 } 160 161 @Nullable 162 private JetTypeReference getReceiverTypeRefByTree() { 163 PsiElement child = getFirstChild(); 164 while (child != null) { 165 IElementType tt = child.getNode().getElementType(); 166 if (tt == JetTokens.LPAR || tt == JetTokens.COLON) break; 167 if (child instanceof JetTypeReference) { 168 return (JetTypeReference) child; 169 } 170 child = child.getNextSibling(); 171 } 172 173 return null; 174 } 175 176 @Override 177 @Nullable 178 public JetTypeReference getTypeReference() { 179 KotlinFunctionStub stub = getStub(); 180 if (stub != null) { 181 List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE); 182 int returnTypeIndex = stub.isExtension() ? 1 : 0; 183 if (returnTypeIndex >= typeReferences.size()) { 184 return null; 185 } 186 return typeReferences.get(returnTypeIndex); 187 } 188 return TypeRefHelpersPackage.getTypeReference(this); 189 } 190 191 @Override 192 @Nullable 193 public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) { 194 return TypeRefHelpersPackage.setTypeReference(this, getValueParameterList(), typeRef); 195 } 196 197 @Nullable 198 @Override 199 public PsiElement getColon() { 200 return findChildByType(JetTokens.COLON); 201 } 202 203 @Override 204 public boolean isLocal() { 205 PsiElement parent = getParent(); 206 return !(parent instanceof JetFile || parent instanceof JetClassBody); 207 } 208 209 @Override 210 public boolean shouldChangeModificationCount(PsiElement place) { 211 // Suppress Java check for out-of-block 212 return false; 213 } 214 }