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.util.text.StringUtil; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.PsiFile; 025 import com.intellij.psi.tree.TokenSet; 026 import com.intellij.psi.util.PsiTreeUtil; 027 import com.intellij.util.IncorrectOperationException; 028 import org.jetbrains.annotations.NotNull; 029 import org.jetbrains.annotations.Nullable; 030 import org.jetbrains.kotlin.JetNodeTypes; 031 import org.jetbrains.kotlin.lexer.JetTokens; 032 import org.jetbrains.kotlin.name.FqName; 033 import org.jetbrains.kotlin.psi.stubs.KotlinClassStub; 034 import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; 035 036 import java.util.ArrayList; 037 import java.util.Collections; 038 import java.util.List; 039 040 public class JetClass extends JetTypeParameterListOwnerStub<KotlinClassStub> implements JetClassOrObject { 041 042 public JetClass(@NotNull ASTNode node) { 043 super(node); 044 } 045 046 public JetClass(@NotNull KotlinClassStub stub) { 047 super(stub, JetStubElementTypes.CLASS); 048 } 049 050 @NotNull 051 @Override 052 public List<JetDeclaration> getDeclarations() { 053 JetClassBody body = getBody(); 054 if (body == null) return Collections.emptyList(); 055 056 return body.getDeclarations(); 057 } 058 059 @Override 060 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) { 061 return visitor.visitClass(this, data); 062 } 063 064 @Nullable 065 public JetPrimaryConstructor getPrimaryConstructor() { 066 return getStubOrPsiChild(JetStubElementTypes.PRIMARY_CONSTRUCTOR); 067 } 068 069 @Nullable 070 public JetParameterList getPrimaryConstructorParameterList() { 071 JetPrimaryConstructor primaryConstructor = getPrimaryConstructor(); 072 return primaryConstructor != null ? primaryConstructor.getValueParameterList() : null; 073 } 074 075 @NotNull 076 public List<JetParameter> getPrimaryConstructorParameters() { 077 JetParameterList list = getPrimaryConstructorParameterList(); 078 if (list == null) return Collections.emptyList(); 079 return list.getParameters(); 080 } 081 082 @NotNull 083 public JetPrimaryConstructor createPrimaryConstructorIfAbsent() { 084 JetPrimaryConstructor constructor = getPrimaryConstructor(); 085 if (constructor != null) return constructor; 086 PsiElement anchor = getTypeParameterList(); 087 if (anchor == null) anchor = getNameIdentifier(); 088 if (anchor == null) anchor = getLastChild(); 089 return (JetPrimaryConstructor) addAfter(new JetPsiFactory(getProject()).createPrimaryConstructor(), anchor); 090 } 091 092 @NotNull 093 public JetParameterList createPrimaryConstructorParameterListIfAbsent() { 094 JetPrimaryConstructor constructor = createPrimaryConstructorIfAbsent(); 095 JetParameterList parameterList = constructor.getValueParameterList(); 096 if (parameterList != null) return parameterList; 097 return (JetParameterList) constructor.add(new JetPsiFactory(getProject()).createParameterList("()")); 098 } 099 100 @Override 101 @Nullable 102 public JetDelegationSpecifierList getDelegationSpecifierList() { 103 return getStubOrPsiChild(JetStubElementTypes.DELEGATION_SPECIFIER_LIST); 104 } 105 106 @Override 107 @NotNull 108 public List<JetDelegationSpecifier> getDelegationSpecifiers() { 109 JetDelegationSpecifierList list = getDelegationSpecifierList(); 110 return list != null ? list.getDelegationSpecifiers() : Collections.<JetDelegationSpecifier>emptyList(); 111 } 112 113 @Nullable 114 public JetModifierList getPrimaryConstructorModifierList() { 115 JetPrimaryConstructor primaryConstructor = getPrimaryConstructor(); 116 return primaryConstructor != null ? primaryConstructor.getModifierList() : null; 117 } 118 119 @Override 120 @NotNull 121 public List<JetClassInitializer> getAnonymousInitializers() { 122 JetClassBody body = getBody(); 123 if (body == null) return Collections.emptyList(); 124 125 return body.getAnonymousInitializers(); 126 } 127 128 public boolean hasExplicitPrimaryConstructor() { 129 return getPrimaryConstructor() != null; 130 } 131 132 @Override 133 public JetObjectDeclarationName getNameAsDeclaration() { 134 return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME); 135 } 136 137 @Override 138 public JetClassBody getBody() { 139 return getStubOrPsiChild(JetStubElementTypes.CLASS_BODY); 140 } 141 142 @Nullable 143 public PsiElement getColon() { 144 return findChildByType(JetTokens.COLON); 145 } 146 147 public List<JetProperty> getProperties() { 148 JetClassBody body = getBody(); 149 if (body == null) return Collections.emptyList(); 150 151 return body.getProperties(); 152 } 153 154 public boolean isInterface() { 155 KotlinClassStub stub = getStub(); 156 if (stub != null) { 157 return stub.isInterface(); 158 } 159 160 return findChildByType(JetTokens.TRAIT_KEYWORD) != null || 161 findChildByType(JetTokens.INTERFACE_KEYWORD) != null; 162 } 163 164 public boolean isEnum() { 165 return hasModifier(JetTokens.ENUM_KEYWORD); 166 } 167 168 public boolean isAnnotation() { 169 return hasModifier(JetTokens.ANNOTATION_KEYWORD); 170 } 171 172 public boolean isInner() { 173 return hasModifier(JetTokens.INNER_KEYWORD); 174 } 175 176 @Override 177 public boolean isEquivalentTo(PsiElement another) { 178 if (super.isEquivalentTo(another)) { 179 return true; 180 } 181 if (another instanceof JetClass) { 182 String fq1 = getQualifiedName(); 183 String fq2 = ((JetClass) another).getQualifiedName(); 184 return fq1 != null && fq2 != null && fq1.equals(fq2); 185 } 186 return false; 187 } 188 189 @Nullable 190 private String getQualifiedName() { 191 KotlinClassStub stub = getStub(); 192 if (stub != null) { 193 FqName fqName = stub.getFqName(); 194 return fqName == null ? null : fqName.asString(); 195 } 196 197 List<String> parts = new ArrayList<String>(); 198 JetClassOrObject current = this; 199 while (current != null) { 200 parts.add(current.getName()); 201 current = PsiTreeUtil.getParentOfType(current, JetClassOrObject.class); 202 } 203 PsiFile file = getContainingFile(); 204 if (!(file instanceof JetFile)) return null; 205 String fileQualifiedName = ((JetFile) file).getPackageFqName().asString(); 206 if (!fileQualifiedName.isEmpty()) { 207 parts.add(fileQualifiedName); 208 } 209 Collections.reverse(parts); 210 return StringUtil.join(parts, "."); 211 } 212 213 @Override 214 public ItemPresentation getPresentation() { 215 return ItemPresentationProviders.getItemPresentation(this); 216 } 217 218 @Override 219 public boolean isTopLevel() { 220 return getContainingFile() == getParent(); 221 } 222 223 @Override 224 public boolean isLocal() { 225 KotlinClassStub stub = getStub(); 226 if (stub != null) { 227 return stub.isLocal(); 228 } 229 return JetPsiUtil.isLocal(this); 230 } 231 232 @NotNull 233 public List<JetObjectDeclaration> getCompanionObjects() { 234 JetClassBody body = getBody(); 235 if (body == null) { 236 return Collections.emptyList(); 237 } 238 return body.getAllCompanionObjects(); 239 } 240 241 public boolean hasPrimaryConstructor() { 242 return hasExplicitPrimaryConstructor() || !hasSecondaryConstructors(); 243 } 244 245 private boolean hasSecondaryConstructors() { 246 return !getSecondaryConstructors().isEmpty(); 247 } 248 249 @NotNull 250 public List<JetSecondaryConstructor> getSecondaryConstructors() { 251 JetClassBody body = getBody(); 252 return body != null ? body.getSecondaryConstructors() : Collections.<JetSecondaryConstructor>emptyList(); 253 } 254 255 @Nullable 256 public PsiElement getClassOrInterfaceKeyword() { 257 return findChildByType(TokenSet.create(JetTokens.CLASS_KEYWORD, JetTokens.INTERFACE_KEYWORD)); 258 } 259 }