001 /*
002 * Copyright 2010-2013 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.jet.lang.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.jet.JetNodeTypes;
030 import org.jetbrains.jet.lang.psi.addRemoveModifier.AddRemoveModifierPackage;
031 import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub;
032 import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
033 import org.jetbrains.jet.lang.resolve.name.FqName;
034 import org.jetbrains.jet.lexer.JetModifierKeywordToken;
035 import org.jetbrains.jet.lexer.JetTokens;
036
037 import java.util.ArrayList;
038 import java.util.Collections;
039 import java.util.List;
040
041 public class JetClass extends JetTypeParameterListOwnerStub<PsiJetClassStub> implements JetClassOrObject {
042
043 public JetClass(@NotNull ASTNode node) {
044 super(node);
045 }
046
047 public JetClass(@NotNull PsiJetClassStub 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 public void removePrimaryConstructorModifier(@NotNull JetModifierKeywordToken modifier) {
111 JetModifierList list = getPrimaryConstructorModifierList();
112 if (list != null) {
113 PsiElement token = list.getModifier(modifier);
114 if (token != null) {
115 token.delete();
116 }
117 }
118 }
119
120 @Override
121 @NotNull
122 public List<JetClassInitializer> getAnonymousInitializers() {
123 JetClassBody body = getBody();
124 if (body == null) return Collections.emptyList();
125
126 return body.getAnonymousInitializers();
127 }
128
129 @Override
130 public boolean hasPrimaryConstructor() {
131 return getPrimaryConstructorParameterList() != null;
132 }
133
134 @Override
135 public JetObjectDeclarationName getNameAsDeclaration() {
136 return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
137 }
138
139 @Override
140 public JetClassBody getBody() {
141 return getStubOrPsiChild(JetStubElementTypes.CLASS_BODY);
142 }
143
144 @Nullable
145 public JetClassObject getClassObject() {
146 JetClassBody body = getBody();
147 if (body == null) return null;
148 return body.getClassObject();
149 }
150
151 public List<JetProperty> getProperties() {
152 JetClassBody body = getBody();
153 if (body == null) return Collections.emptyList();
154
155 return body.getProperties();
156 }
157
158 public boolean isTrait() {
159 PsiJetClassStub stub = getStub();
160 if (stub != null) {
161 return stub.isTrait();
162 }
163
164 return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
165 }
166
167 public boolean isEnum() {
168 return hasModifier(JetTokens.ENUM_KEYWORD);
169 }
170
171 public boolean isAnnotation() {
172 return hasModifier(JetTokens.ANNOTATION_KEYWORD);
173 }
174
175 public boolean isInner() {
176 return hasModifier(JetTokens.INNER_KEYWORD);
177 }
178
179 @Override
180 public void delete() throws IncorrectOperationException {
181 JetPsiUtil.deleteClass(this);
182 }
183
184 @Override
185 public boolean isEquivalentTo(PsiElement another) {
186 if (super.isEquivalentTo(another)) {
187 return true;
188 }
189 if (another instanceof JetClass) {
190 String fq1 = getQualifiedName();
191 String fq2 = ((JetClass) another).getQualifiedName();
192 return fq1 != null && fq2 != null && fq1.equals(fq2);
193 }
194 return false;
195 }
196
197 @Nullable
198 private String getQualifiedName() {
199 PsiJetClassStub stub = getStub();
200 if (stub != null) {
201 FqName fqName = stub.getFqName();
202 return fqName == null ? null : fqName.asString();
203 }
204
205 List<String> parts = new ArrayList<String>();
206 JetClassOrObject current = this;
207 while (current != null) {
208 parts.add(current.getName());
209 current = PsiTreeUtil.getParentOfType(current, JetClassOrObject.class);
210 }
211 PsiFile file = getContainingFile();
212 if (!(file instanceof JetFile)) return null;
213 String fileQualifiedName = ((JetFile) file).getPackageFqName().asString();
214 if (!fileQualifiedName.isEmpty()) {
215 parts.add(fileQualifiedName);
216 }
217 Collections.reverse(parts);
218 return StringUtil.join(parts, ".");
219 }
220
221 @Override
222 public ItemPresentation getPresentation() {
223 return ItemPresentationProviders.getItemPresentation(this);
224 }
225
226 @Override
227 public boolean isTopLevel() {
228 return getContainingFile() == getParent();
229 }
230
231 @Override
232 public boolean isLocal() {
233 PsiJetClassStub stub = getStub();
234 if (stub != null) {
235 return stub.isLocal();
236 }
237 return JetPsiUtil.isLocal(this);
238 }
239 }