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.openapi.diagnostic.Logger; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.PsiModifiableCodeBlock; 025 import com.intellij.psi.tree.IElementType; 026 import com.intellij.psi.tree.TokenSet; 027 import com.intellij.psi.util.PsiTreeUtil; 028 import org.jetbrains.annotations.NotNull; 029 import org.jetbrains.annotations.Nullable; 030 import org.jetbrains.kotlin.KtNodeTypes; 031 import org.jetbrains.kotlin.lexer.KtTokens; 032 import org.jetbrains.kotlin.psi.stubs.KotlinPropertyStub; 033 import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes; 034 import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersKt; 035 036 import java.util.Collections; 037 import java.util.List; 038 039 import static org.jetbrains.kotlin.KtNodeTypes.PROPERTY_DELEGATE; 040 import static org.jetbrains.kotlin.lexer.KtTokens.*; 041 042 public class KtProperty extends KtTypeParameterListOwnerStub<KotlinPropertyStub> 043 implements KtVariableDeclaration, PsiModifiableCodeBlock { 044 045 private static final Logger LOG = Logger.getInstance(KtProperty.class); 046 047 public KtProperty(@NotNull ASTNode node) { 048 super(node); 049 } 050 051 public KtProperty(@NotNull KotlinPropertyStub stub) { 052 super(stub, KtStubElementTypes.PROPERTY); 053 } 054 055 @Override 056 public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) { 057 return visitor.visitProperty(this, data); 058 } 059 060 @Override 061 public boolean isVar() { 062 KotlinPropertyStub stub = getStub(); 063 if (stub != null) { 064 return stub.isVar(); 065 } 066 067 return getNode().findChildByType(KtTokens.VAR_KEYWORD) != null; 068 } 069 070 public boolean isLocal() { 071 PsiElement parent = getParent(); 072 return !(parent instanceof KtFile || parent instanceof KtClassBody); 073 } 074 075 public boolean isTopLevel() { 076 KotlinPropertyStub stub = getStub(); 077 if (stub != null) { 078 return stub.isTopLevel(); 079 } 080 081 return getParent() instanceof KtFile; 082 } 083 084 @Nullable 085 @Override 086 public KtParameterList getValueParameterList() { 087 return null; 088 } 089 090 @NotNull 091 @Override 092 public List<KtParameter> getValueParameters() { 093 return Collections.emptyList(); 094 } 095 096 @Override 097 @Nullable 098 public KtTypeReference getReceiverTypeReference() { 099 KotlinPropertyStub stub = getStub(); 100 if (stub != null) { 101 if (!stub.isExtension()) { 102 return null; 103 } 104 else { 105 return getStubOrPsiChild(KtStubElementTypes.TYPE_REFERENCE); 106 } 107 } 108 return getReceiverTypeRefByTree(); 109 } 110 111 @Nullable 112 private KtTypeReference getReceiverTypeRefByTree() { 113 ASTNode node = getNode().getFirstChildNode(); 114 while (node != null) { 115 IElementType tt = node.getElementType(); 116 if (tt == KtTokens.COLON) break; 117 118 if (tt == KtNodeTypes.TYPE_REFERENCE) { 119 return (KtTypeReference) node.getPsi(); 120 } 121 node = node.getTreeNext(); 122 } 123 124 return null; 125 } 126 127 @Override 128 @Nullable 129 public KtTypeReference getTypeReference() { 130 KotlinPropertyStub stub = getStub(); 131 if (stub != null) { 132 if (!stub.hasReturnTypeRef()) { 133 return null; 134 } 135 else { 136 List<KtTypeReference> typeReferences = getStubOrPsiChildrenAsList(KtStubElementTypes.TYPE_REFERENCE); 137 int returnTypeRefPositionInPsi = stub.isExtension() ? 1 : 0; 138 if (typeReferences.size() <= returnTypeRefPositionInPsi) { 139 LOG.error("Invalid stub structure built for property:\n" + getText()); 140 return null; 141 } 142 return typeReferences.get(returnTypeRefPositionInPsi); 143 } 144 } 145 return TypeRefHelpersKt.getTypeReference(this); 146 } 147 148 @Override 149 @Nullable 150 public KtTypeReference setTypeReference(@Nullable KtTypeReference typeRef) { 151 return TypeRefHelpersKt.setTypeReference(this, getNameIdentifier(), typeRef); 152 } 153 154 @Nullable 155 @Override 156 public PsiElement getColon() { 157 return findChildByType(KtTokens.COLON); 158 } 159 160 @Nullable 161 public PsiElement getEqualsToken() { 162 return findChildByType(KtTokens.EQ); 163 } 164 165 @NotNull 166 public List<KtPropertyAccessor> getAccessors() { 167 return getStubOrPsiChildrenAsList(KtStubElementTypes.PROPERTY_ACCESSOR); 168 } 169 170 @Nullable 171 public KtPropertyAccessor getGetter() { 172 for (KtPropertyAccessor accessor : getAccessors()) { 173 if (accessor.isGetter()) return accessor; 174 } 175 176 return null; 177 } 178 179 @Nullable 180 public KtPropertyAccessor getSetter() { 181 for (KtPropertyAccessor accessor : getAccessors()) { 182 if (accessor.isSetter()) return accessor; 183 } 184 185 return null; 186 } 187 188 public boolean hasDelegate() { 189 KotlinPropertyStub stub = getStub(); 190 if (stub != null) { 191 return stub.hasDelegate(); 192 } 193 return getDelegate() != null; 194 } 195 196 @Nullable 197 public KtPropertyDelegate getDelegate() { 198 return (KtPropertyDelegate) findChildByType(PROPERTY_DELEGATE); 199 } 200 201 public boolean hasDelegateExpression() { 202 KotlinPropertyStub stub = getStub(); 203 if (stub != null) { 204 return stub.hasDelegateExpression(); 205 } 206 return getDelegateExpression() != null; 207 } 208 209 @Nullable 210 public KtExpression getDelegateExpression() { 211 KtPropertyDelegate delegate = getDelegate(); 212 if (delegate != null) { 213 return delegate.getExpression(); 214 } 215 return null; 216 } 217 218 @Override 219 public boolean hasInitializer() { 220 KotlinPropertyStub stub = getStub(); 221 if (stub != null) { 222 return stub.hasInitializer(); 223 } 224 return getInitializer() != null; 225 } 226 227 @Override 228 @Nullable 229 public KtExpression getInitializer() { 230 return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), KtExpression.class); 231 } 232 233 public boolean hasDelegateExpressionOrInitializer() { 234 return hasDelegateExpression() || hasInitializer(); 235 } 236 237 @Nullable 238 public KtExpression setInitializer(@Nullable KtExpression initializer) { 239 KtExpression oldInitializer = getInitializer(); 240 241 if (oldInitializer != null) { 242 if (initializer != null) { 243 return (KtExpression) oldInitializer.replace(initializer); 244 } 245 else { 246 PsiElement nextSibling = oldInitializer.getNextSibling(); 247 PsiElement last = 248 nextSibling != null 249 && nextSibling.getNode() != null 250 && nextSibling.getNode().getElementType() == KtTokens.SEMICOLON 251 ? nextSibling : oldInitializer; 252 253 deleteChildRange(findChildByType(EQ), last); 254 return null; 255 } 256 } 257 else { 258 if (initializer != null) { 259 PsiElement addAfter = getTypeReference(); 260 if (addAfter == null) { 261 addAfter = getNameIdentifier(); 262 } 263 PsiElement eq = addAfter(new KtPsiFactory(getProject()).createEQ(), addAfter); 264 return (KtExpression) addAfter(initializer, eq); 265 } 266 else { 267 return null; 268 } 269 } 270 } 271 272 @Nullable 273 public KtExpression getDelegateExpressionOrInitializer() { 274 KtExpression expression = getDelegateExpression(); 275 if (expression == null) { 276 return getInitializer(); 277 } 278 return expression; 279 } 280 281 @Override 282 @NotNull 283 public PsiElement getValOrVarKeyword() { 284 PsiElement element = findChildByType(VAL_VAR_TOKEN_SET); 285 assert element != null : "Val or var should always exist for property" + this.getText(); 286 return element; 287 } 288 289 private static final TokenSet VAL_VAR_TOKEN_SET = TokenSet.create(KtTokens.VAL_KEYWORD, KtTokens.VAR_KEYWORD); 290 291 @Override 292 public ItemPresentation getPresentation() { 293 return ItemPresentationProviders.getItemPresentation(this); 294 } 295 296 @Override 297 public boolean shouldChangeModificationCount(PsiElement place) { 298 // Suppress Java check for out-of-block 299 return false; 300 } 301 }