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