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 }