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
017package org.jetbrains.jet.lang.psi;
018
019import com.intellij.lang.ASTNode;
020import com.intellij.psi.PsiElement;
021import com.intellij.psi.stubs.IStubElementType;
022import com.intellij.util.IncorrectOperationException;
023import org.jetbrains.annotations.NonNls;
024import org.jetbrains.annotations.NotNull;
025import org.jetbrains.annotations.Nullable;
026import org.jetbrains.jet.JetNodeTypes;
027import org.jetbrains.jet.lang.psi.stubs.PsiJetObjectStub;
028import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
029import org.jetbrains.jet.lang.resolve.name.FqName;
030import org.jetbrains.jet.lexer.JetToken;
031import org.jetbrains.jet.lexer.JetTokens;
032
033import java.util.Collections;
034import java.util.List;
035
036public class JetObjectDeclaration extends JetNamedDeclarationStub<PsiJetObjectStub> implements JetClassOrObject  {
037    public JetObjectDeclaration(@NotNull ASTNode node) {
038        super(node);
039    }
040
041    public JetObjectDeclaration(@NotNull PsiJetObjectStub stub) {
042        super(stub, JetStubElementTypes.OBJECT_DECLARATION);
043    }
044
045    @NotNull
046    @Override
047    public IStubElementType getElementType() {
048        return JetStubElementTypes.OBJECT_DECLARATION;
049    }
050
051    @Override
052    public String getName() {
053        PsiJetObjectStub stub = getStub();
054        if (stub != null) {
055            return stub.getName();
056        }
057
058        JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
059        return nameAsDeclaration == null ? null : nameAsDeclaration.getName();
060    }
061
062    /**
063     * Could be null for anonymous objects and object declared inside functions
064     * @return
065     */
066    public FqName getFqName() {
067        PsiJetObjectStub stub = getStub();
068        if (stub != null) {
069            return stub.getFqName();
070        }
071
072        return JetPsiUtil.getFQName(this);
073    }
074
075    public boolean isTopLevel() {
076        PsiJetObjectStub stub = getStub();
077        if (stub != null) {
078            return stub.isTopLevel();
079        }
080
081        return getParent() instanceof JetFile;
082    }
083
084    @Override
085    public PsiElement getNameIdentifier() {
086        JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
087        return nameAsDeclaration == null ? null : nameAsDeclaration.getNameIdentifier();
088    }
089
090    @Override
091    public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
092        JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
093        return nameAsDeclaration == null ? null : nameAsDeclaration.setName(name);
094    }
095
096    @Override
097    @Nullable
098    public JetObjectDeclarationName getNameAsDeclaration() {
099        return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
100    }
101
102    @Override
103    @Nullable
104    public JetModifierList getModifierList() {
105        PsiElement parent = getParent();
106        if (isClassObject(parent)) {
107            assert parent instanceof JetDeclaration;
108            return ((JetDeclaration)parent).getModifierList();
109        }
110        return (JetModifierList) findChildByType(JetNodeTypes.MODIFIER_LIST);
111    }
112
113
114    private static boolean isClassObject(@NotNull PsiElement parent) {
115        return parent.getNode().getElementType().equals(JetNodeTypes.CLASS_OBJECT);
116    }
117
118    @Override
119    public boolean hasModifier(JetToken modifier) {
120        JetModifierList modifierList = getModifierList();
121        return modifierList != null && modifierList.hasModifier(modifier);
122    }
123
124    @Override
125    @Nullable
126    public JetDelegationSpecifierList getDelegationSpecifierList() {
127        return (JetDelegationSpecifierList) findChildByType(JetNodeTypes.DELEGATION_SPECIFIER_LIST);
128    }
129
130    @Override
131    @NotNull
132    public List<JetDelegationSpecifier> getDelegationSpecifiers() {
133        JetDelegationSpecifierList list = getDelegationSpecifierList();
134        return list != null ? list.getDelegationSpecifiers() : Collections.<JetDelegationSpecifier>emptyList();
135    }
136
137    @Override
138    @NotNull
139    public List<JetClassInitializer> getAnonymousInitializers() {
140        JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
141        if (body == null) return Collections.emptyList();
142
143        return body.getAnonymousInitializers();
144    }
145
146    @Override
147    public boolean hasPrimaryConstructor() {
148        return true;
149    }
150
151    @Override
152    public JetClassBody getBody() {
153        return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
154    }
155
156    @Override
157    @NotNull
158    public List<JetDeclaration> getDeclarations() {
159        JetClassBody body = getBody();
160        if (body == null) return Collections.emptyList();
161
162        return body.getDeclarations();
163    }
164
165    @Override
166    public void accept(@NotNull JetVisitorVoid visitor) {
167        visitor.visitObjectDeclaration(this);
168    }
169
170    @Override
171    public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
172        return visitor.visitObjectDeclaration(this, data);
173    }
174
175    public boolean isObjectLiteral() {
176        return getNameAsDeclaration() == null;
177    }
178
179    @NotNull
180    public PsiElement getObjectKeyword() {
181        return findChildByType(JetTokens.OBJECT_KEYWORD);
182    }
183
184    @Override
185    public void delete() throws IncorrectOperationException {
186        JetPsiUtil.deleteClass(this);
187    }
188
189    //@Override
190    //public ItemPresentation getPresentation() {
191    //    return ItemPresentationProviders.getItemPresentation(this);
192    //}
193}