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