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.psi.PsiElement;
021    import com.intellij.util.containers.ContainerUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.lexer.JetTokens;
025    import org.jetbrains.kotlin.name.FqName;
026    import org.jetbrains.kotlin.name.Name;
027    import org.jetbrains.kotlin.name.SpecialNames;
028    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
029    import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub;
030    import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
031    
032    import java.util.Collections;
033    import java.util.List;
034    
035    public class JetPackageDirective extends JetModifierListOwnerStub<KotlinPlaceHolderStub<JetPackageDirective>> {
036        private String qualifiedNameCache = null;
037    
038        public JetPackageDirective(@NotNull ASTNode node) {
039            super(node);
040        }
041    
042        public JetPackageDirective(@NotNull KotlinPlaceHolderStub<JetPackageDirective> stub) {
043            super(stub, JetStubElementTypes.PACKAGE_DIRECTIVE);
044        }
045    
046        // This should be either JetSimpleNameExpression, or JetDotQualifiedExpression
047        @Nullable
048        public JetExpression getPackageNameExpression() {
049            return JetStubbedPsiUtil.getStubOrPsiChild(this, JetStubElementTypes.INSIDE_DIRECTIVE_EXPRESSIONS, JetExpression.ARRAY_FACTORY);
050        }
051    
052        @NotNull
053        public List<JetSimpleNameExpression> getPackageNames() {
054            JetExpression nameExpression = getPackageNameExpression();
055            if (nameExpression == null) return Collections.emptyList();
056    
057            List<JetSimpleNameExpression> packageNames = ContainerUtil.newArrayList();
058            while (nameExpression instanceof JetQualifiedExpression) {
059                JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) nameExpression;
060    
061                JetExpression selector = qualifiedExpression.getSelectorExpression();
062                if (selector instanceof JetSimpleNameExpression) {
063                    packageNames.add((JetSimpleNameExpression) selector);
064                }
065    
066                nameExpression = qualifiedExpression.getReceiverExpression();
067            }
068    
069            if (nameExpression instanceof JetSimpleNameExpression) {
070                packageNames.add((JetSimpleNameExpression) nameExpression);
071            }
072    
073            Collections.reverse(packageNames);
074    
075            return packageNames;
076        }
077    
078        @Nullable
079        public JetSimpleNameExpression getLastReferenceExpression() {
080            JetExpression nameExpression = getPackageNameExpression();
081            if (nameExpression == null) return null;
082    
083            return (JetSimpleNameExpression)PsiUtilPackage.getQualifiedElementSelector(nameExpression);
084        }
085    
086        @Nullable
087        public PsiElement getNameIdentifier() {
088            JetSimpleNameExpression lastPart = getLastReferenceExpression();
089            return lastPart != null ? lastPart.getIdentifier() : null;
090        }
091    
092        @Override
093        @NotNull
094        public String getName() {
095            PsiElement nameIdentifier = getNameIdentifier();
096            return nameIdentifier == null ? "" : nameIdentifier.getText();
097        }
098    
099        @NotNull
100        public Name getNameAsName() {
101            PsiElement nameIdentifier = getNameIdentifier();
102            return nameIdentifier == null ? SpecialNames.ROOT_PACKAGE : Name.identifier(nameIdentifier.getText());
103        }
104    
105        public boolean isRoot() {
106            return getName().length() == 0;
107        }
108    
109        @NotNull
110        public FqName getFqName() {
111            String qualifiedName = getQualifiedName();
112            return qualifiedName.isEmpty() ? FqName.ROOT : new FqName(qualifiedName);
113        }
114    
115        @NotNull
116        public FqName getFqName(JetSimpleNameExpression nameExpression) {
117            return new FqName(getQualifiedNameOf(nameExpression));
118        }
119    
120        public void setFqName(@NotNull FqName fqName) {
121            if (fqName.isRoot()) {
122                delete();
123                return;
124            }
125    
126            JetPsiFactory psiFactory = new JetPsiFactory(getProject());
127            PsiElement newExpression = psiFactory.createExpression(fqName.asString());
128            JetExpression currentExpression = getPackageNameExpression();
129            if (currentExpression != null) {
130                currentExpression.replace(newExpression);
131                return;
132            }
133    
134            PsiElement keyword = getPackageKeyword();
135            if (keyword != null) {
136                addAfter(newExpression, keyword);
137                return;
138            }
139    
140            replace(psiFactory.createPackageDirective(fqName));
141        }
142    
143        @NotNull
144        public String getQualifiedName() {
145            if (qualifiedNameCache == null) {
146                qualifiedNameCache = getQualifiedNameOf(null);
147            }
148    
149            return qualifiedNameCache;
150        }
151    
152        @NotNull
153        private String getQualifiedNameOf(@Nullable JetSimpleNameExpression nameExpression) {
154            StringBuilder builder = new StringBuilder();
155            for (JetSimpleNameExpression e : getPackageNames()) {
156                if (builder.length() > 0) {
157                    builder.append(".");
158                }
159                builder.append(e.getReferencedName());
160    
161                if (e == nameExpression) break;
162            }
163            return builder.toString();
164        }
165    
166        @Nullable
167        public PsiElement getPackageKeyword() {
168            return findChildByType(JetTokens.PACKAGE_KEYWORD);
169        }
170    
171        @Override
172        public void subtreeChanged() {
173            qualifiedNameCache = null;
174        }
175    
176        @Override
177        public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
178            return visitor.visitPackageDirective(this, data);
179        }
180    }
181