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.stubs.IStubElementType;
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.jet.JetNodeTypes;
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.JetTokens;
035
036 import java.util.ArrayList;
037 import java.util.Collections;
038 import java.util.List;
039
040 public class JetClass extends JetTypeParameterListOwnerStub<PsiJetClassStub> implements JetClassOrObject {
041
042 public JetClass(@NotNull ASTNode node) {
043 super(node);
044 }
045
046 public JetClass(@NotNull PsiJetClassStub stub) {
047 super(stub, JetStubElementTypes.CLASS);
048 }
049
050 @NotNull
051 @Override
052 public List<JetDeclaration> getDeclarations() {
053 JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
054 if (body == null) return Collections.emptyList();
055
056 return body.getDeclarations();
057 }
058
059 @Override
060 public void accept(@NotNull JetVisitorVoid visitor) {
061 visitor.visitClass(this);
062 }
063
064 @Override
065 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
066 return visitor.visitClass(this, data);
067 }
068
069 @Nullable
070 public JetParameterList getPrimaryConstructorParameterList() {
071 return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
072 }
073
074 @NotNull
075 public List<JetParameter> getPrimaryConstructorParameters() {
076 JetParameterList list = getPrimaryConstructorParameterList();
077 if (list == null) return Collections.emptyList();
078 return list.getParameters();
079 }
080
081 @Override
082 @Nullable
083 public JetDelegationSpecifierList getDelegationSpecifierList() {
084 return (JetDelegationSpecifierList) findChildByType(JetNodeTypes.DELEGATION_SPECIFIER_LIST);
085 }
086
087 @Override
088 @NotNull
089 public List<JetDelegationSpecifier> getDelegationSpecifiers() {
090 JetDelegationSpecifierList list = getDelegationSpecifierList();
091 return list != null ? list.getDelegationSpecifiers() : Collections.<JetDelegationSpecifier>emptyList();
092 }
093
094 @Nullable
095 public JetModifierList getPrimaryConstructorModifierList() {
096 return (JetModifierList) findChildByType(JetNodeTypes.PRIMARY_CONSTRUCTOR_MODIFIER_LIST);
097 }
098
099 @Override
100 @NotNull
101 public List<JetClassInitializer> getAnonymousInitializers() {
102 JetClassBody body = getBody();
103 if (body == null) return Collections.emptyList();
104
105 return body.getAnonymousInitializers();
106 }
107
108 @Override
109 public boolean hasPrimaryConstructor() {
110 return getPrimaryConstructorParameterList() != null;
111 }
112
113 @Override
114 public JetObjectDeclarationName getNameAsDeclaration() {
115 return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
116 }
117
118 @Override
119 public JetClassBody getBody() {
120 return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
121 }
122
123 @Nullable
124 public JetClassObject getClassObject() {
125 JetClassBody body = getBody();
126 if (body == null) return null;
127 return body.getClassObject();
128 }
129
130 public List<JetProperty> getProperties() {
131 JetClassBody body = getBody();
132 if (body == null) return Collections.emptyList();
133
134 return body.getProperties();
135 }
136
137 public boolean isTrait() {
138 PsiJetClassStub stub = getStub();
139 if (stub != null) {
140 return stub.isTrait();
141 }
142
143 return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
144 }
145
146 public boolean isEnum() {
147 PsiJetClassStub stub = getStub();
148 if (stub != null) {
149 return stub.isEnumClass();
150 }
151
152 return hasModifier(JetTokens.ENUM_KEYWORD);
153 }
154
155 public boolean isAnnotation() {
156 PsiJetClassStub stub = getStub();
157 if (stub != null) {
158 return stub.isAnnotation();
159 }
160
161 return hasModifier(JetTokens.ANNOTATION_KEYWORD);
162 }
163
164 public boolean isInner() {
165 PsiJetClassStub stub = getStub();
166 if (stub != null) {
167 return stub.isInner();
168 }
169
170 return hasModifier(JetTokens.INNER_KEYWORD);
171 }
172
173 @NotNull
174 @Override
175 public IStubElementType getElementType() {
176 return JetStubElementTypes.CLASS;
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).getNamespaceHeader().getQualifiedName();
214 if (!fileQualifiedName.isEmpty()) {
215 parts.add(fileQualifiedName);
216 }
217 Collections.reverse(parts);
218 return StringUtil.join(parts, ".");
219 }
220
221 /**
222 * Returns the list of unqualified names that are indexed as the superclass names of this class. For the names that might be imported
223 * via an aliased import, includes both the original and the aliased name (reference resolution during inheritor search will sort this out).
224 *
225 * @return the list of possible superclass names
226 */
227 @NotNull
228 public List<String> getSuperNames() {
229 PsiJetClassStub stub = getStub();
230 if (stub != null) {
231 return stub.getSuperNames();
232 }
233
234 List<JetDelegationSpecifier> specifiers = getDelegationSpecifiers();
235 if (specifiers.size() == 0) return Collections.emptyList();
236 List<String> result = new ArrayList<String>();
237 for (JetDelegationSpecifier specifier : specifiers) {
238 JetUserType superType = specifier.getTypeAsUserType();
239 if (superType != null) {
240 String referencedName = superType.getReferencedName();
241 if (referencedName != null) {
242 addSuperName(result, referencedName);
243 }
244 }
245 }
246 return result;
247 }
248
249 private void addSuperName(List<String> result, String referencedName) {
250 result.add(referencedName);
251 if (getContainingFile() instanceof JetFile) {
252 JetImportDirective directive = ((JetFile) getContainingFile()).findImportByAlias(referencedName);
253 if (directive != null) {
254 JetExpression reference = directive.getImportedReference();
255 while (reference instanceof JetDotQualifiedExpression) {
256 reference = ((JetDotQualifiedExpression) reference).getSelectorExpression();
257 }
258 if (reference instanceof JetSimpleNameExpression) {
259 result.add(((JetSimpleNameExpression) reference).getReferencedName());
260 }
261 }
262 }
263 }
264
265 @Override
266 public ItemPresentation getPresentation() {
267 return ItemPresentationProviders.getItemPresentation(this);
268 }
269 }